mirror of https://github.com/statping/statping
upgrades
parent
7705087345
commit
b4fe30c2cc
|
@ -3,4 +3,6 @@ rice-box.go
|
|||
config.yml
|
||||
statup.db
|
||||
plugins/*.so
|
||||
data
|
||||
data
|
||||
build
|
||||
vendor
|
|
@ -45,6 +45,9 @@ notifications:
|
|||
before_install:
|
||||
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then travis_wait 30 docker pull karalabe/xgo-latest; fi
|
||||
|
||||
after_success:
|
||||
- curl -s -X POST $DOCKER > /dev/null
|
||||
|
||||
before_script:
|
||||
- mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
|
||||
- psql -c 'create database test;' -U postgres
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/GeertJohan/go.rice"
|
||||
packages = [
|
||||
".",
|
||||
"embedded"
|
||||
]
|
||||
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/daaku/go.zipexe"
|
||||
packages = ["."]
|
||||
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/structs"
|
||||
packages = ["."]
|
||||
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-yaml/yaml"
|
||||
packages = ["."]
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/context"
|
||||
packages = ["."]
|
||||
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
||||
version = "v1.6.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/securecookie"
|
||||
packages = ["."]
|
||||
revision = "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/sessions"
|
||||
packages = ["."]
|
||||
revision = "03b6f63cc43ef9c7240a635a5e22b13180e822b8"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kardianos/osext"
|
||||
packages = ["."]
|
||||
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/lib/pq"
|
||||
packages = [
|
||||
".",
|
||||
"oid"
|
||||
]
|
||||
revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
|
||||
version = "v1.9.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"bcrypt",
|
||||
"blowfish"
|
||||
]
|
||||
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
packages = ["cloudsql"]
|
||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "upper.io/db.v3"
|
||||
packages = [
|
||||
".",
|
||||
"internal/cache",
|
||||
"internal/cache/hashstructure",
|
||||
"internal/immutable",
|
||||
"internal/sqladapter",
|
||||
"internal/sqladapter/compat",
|
||||
"internal/sqladapter/exql",
|
||||
"lib/reflectx",
|
||||
"lib/sqlbuilder",
|
||||
"mysql",
|
||||
"postgresql",
|
||||
"sqlite"
|
||||
]
|
||||
revision = "d90922beee6de3f39c93ed677f6da82565d07154"
|
||||
version = "v3.5.3"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d8ed5645d6f4e746646932baa40deb382ea017a84594ec46fda94538f4d00db2"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
|
@ -0,0 +1,62 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/GeertJohan/go.rice"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/structs"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-yaml/yaml"
|
||||
version = "2.2.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/mux"
|
||||
version = "1.6.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/sessions"
|
||||
version = "1.1.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.2"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
name = "upper.io/db.v3"
|
||||
version = "3.5.3"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
9
core.go
9
core.go
|
@ -26,6 +26,15 @@ func (c *Core) Update() (*Core, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func (c Core) AllOnline() bool {
|
||||
for _, s := range services {
|
||||
if !s.Online {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SelectCore() (*Core, error) {
|
||||
var core Core
|
||||
err := dbSession.Collection("core").Find().One(&core)
|
||||
|
|
|
@ -8,11 +8,15 @@ import (
|
|||
func (f *Failure) ParseError() string {
|
||||
err := strings.Contains(f.Issue, "operation timed out")
|
||||
if err {
|
||||
return fmt.Sprintf("HTTP Request timed out after x seconds")
|
||||
return fmt.Sprintf("HTTP Request Timed Out")
|
||||
}
|
||||
err = strings.Contains(f.Issue, "x509: certificate is valid")
|
||||
if err {
|
||||
return fmt.Sprintf("SSL Certificate invalid")
|
||||
}
|
||||
err = strings.Contains(f.Issue, "no such host")
|
||||
if err {
|
||||
return fmt.Sprintf("Domain is offline or not found")
|
||||
}
|
||||
return f.Issue
|
||||
}
|
||||
|
|
22
failures.go
22
failures.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/ararog/timeago"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -9,7 +10,6 @@ type Failure struct {
|
|||
Issue string `db:"issue"`
|
||||
Service int64 `db:"service"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
Ago string
|
||||
}
|
||||
|
||||
func (s *Service) CreateFailure(data FailureData) (int64, error) {
|
||||
|
@ -29,18 +29,32 @@ func (s *Service) CreateFailure(data FailureData) (int64, error) {
|
|||
|
||||
func (s *Service) SelectAllFailures() ([]*Failure, error) {
|
||||
var fails []*Failure
|
||||
col := dbSession.Collection("failures").Find("service", s.Id)
|
||||
col := dbSession.Collection("failures").Find("service", s.Id).OrderBy("-id")
|
||||
err := col.All(&fails)
|
||||
return fails, err
|
||||
}
|
||||
|
||||
func (u *Service) DeleteFailures() {
|
||||
var fails []*Failure
|
||||
col := dbSession.Collection("failures")
|
||||
col.Find("service", u.Id).All(&fails)
|
||||
for _, fail := range fails {
|
||||
fail.Delete()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) LimitedFailures() []*Failure {
|
||||
var fails []*Failure
|
||||
col := dbSession.Collection("failures").Find("service", s.Id).Limit(10)
|
||||
col.All(&fails)
|
||||
col := dbSession.Collection("failures").Find("service", s.Id)
|
||||
col.OrderBy("-id").Limit(10).All(&fails)
|
||||
return fails
|
||||
}
|
||||
|
||||
func (f *Failure) Ago() string {
|
||||
got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
|
||||
return got
|
||||
}
|
||||
|
||||
func (f *Failure) Delete() error {
|
||||
col := dbSession.Collection("failures").Find("id", f.Id)
|
||||
return col.Delete()
|
||||
|
|
12
go.mod
12
go.mod
|
@ -1,12 +0,0 @@
|
|||
module github.com/hunterlong/statup
|
||||
|
||||
require (
|
||||
github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da
|
||||
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb
|
||||
github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d
|
||||
github.com/gorilla/sessions v1.1.1
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
|
||||
github.com/lib/pq v0.0.0-20180523175426-90697d60dd84
|
||||
golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4
|
||||
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405
|
||||
)
|
25
hits.go
25
hits.go
|
@ -1,6 +1,9 @@
|
|||
package main
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
"upper.io/db.v3"
|
||||
)
|
||||
|
||||
type Hit struct {
|
||||
Id int `db:"id,omitempty"`
|
||||
|
@ -9,14 +12,17 @@ type Hit struct {
|
|||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
func hitCol() db.Collection {
|
||||
return dbSession.Collection("hits")
|
||||
}
|
||||
|
||||
func (s *Service) CreateHit(d HitData) (int64, error) {
|
||||
h := Hit{
|
||||
Service: s.Id,
|
||||
Latency: d.Latency,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
col := dbSession.Collection("hits")
|
||||
uuid, err := col.Insert(h)
|
||||
uuid, err := hitCol().Insert(h)
|
||||
if uuid == nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -25,20 +31,27 @@ func (s *Service) CreateHit(d HitData) (int64, error) {
|
|||
|
||||
func (s *Service) Hits() ([]Hit, error) {
|
||||
var hits []Hit
|
||||
col := dbSession.Collection("hits").Find("service", s.Id)
|
||||
col := hitCol().Find("service", s.Id).OrderBy("-id")
|
||||
err := col.All(&hits)
|
||||
return hits, err
|
||||
}
|
||||
|
||||
func (s *Service) LimitedHits() ([]Hit, error) {
|
||||
var hits []Hit
|
||||
col := hitCol().Find("service", s.Id).Limit(256).OrderBy("-id")
|
||||
err := col.All(&hits)
|
||||
return hits, err
|
||||
}
|
||||
|
||||
func (s *Service) SelectHitsGroupBy(group string) ([]Hit, error) {
|
||||
var hits []Hit
|
||||
col := dbSession.Collection("hits").Find("service", s.Id)
|
||||
col := hitCol().Find("service", s.Id)
|
||||
err := col.All(&hits)
|
||||
return hits, err
|
||||
}
|
||||
|
||||
func (s *Service) TotalHits() (uint64, error) {
|
||||
col := dbSession.Collection("hits").Find("service", s.Id)
|
||||
col := hitCol().Find("service", s.Id)
|
||||
amount, err := col.Count()
|
||||
return amount, err
|
||||
}
|
||||
|
|
|
@ -4,16 +4,12 @@ HTML,BODY {
|
|||
}
|
||||
|
||||
.container {
|
||||
max-width: 790px;
|
||||
background-color: white;
|
||||
padding: 50px;
|
||||
border-radius: 7px;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin-left: -50px;
|
||||
margin-top: -50px;
|
||||
width: 790px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
@ -54,7 +50,7 @@ HTML,BODY {
|
|||
}
|
||||
|
||||
.online_list {
|
||||
font-size: 1.5rem;
|
||||
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
@ -90,17 +86,13 @@ HTML,BODY {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-body H3 A {
|
||||
color: #424242;
|
||||
.card-body H4 A {
|
||||
color: #239e07;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
HTML,BODY {
|
||||
background-color: #efefef;
|
||||
margin: 0px 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0px;
|
||||
}
|
||||
|
@ -117,7 +109,7 @@ HTML,BODY {
|
|||
}
|
||||
|
||||
.lg_number {
|
||||
font-size: 22pt;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{template "nav"}}
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<div class="row stats_area mb-4">
|
||||
|
||||
<div class="col-4">
|
||||
|
@ -57,10 +59,12 @@
|
|||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{{ define "footer"}}
|
||||
<div class="footer text-center">
|
||||
{{ if .Core.Footer }}
|
||||
{{ safe .Core.Footer }}
|
||||
{{ end }}
|
||||
<a href="https://statup.io" target="_blank">Statup made with ❤️</a> | <a href="/dashboard">Dashboard</a>
|
||||
</div>
|
||||
{{ end }}
|
|
@ -11,15 +11,12 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{if Auth}}
|
||||
{{template "nav"}}
|
||||
{{end}}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<h2>Statup v{{ VERSION }} Help</h2>
|
||||
|
@ -51,8 +48,6 @@
|
|||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
|
|
|
@ -13,32 +13,42 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container col-md-7 col-sm-12 mt-2">
|
||||
|
||||
<h1 class="text-center mb-4 mt-sm-3">{{.Core.Name}}</h1>
|
||||
|
||||
|
||||
{{ if .Core.Description }}
|
||||
<h5 class="text-center mb-1 mt-sm-2">{{ .Core.Description }}</h5>
|
||||
<h5 class="text-center mb-5 text-muted">{{ .Core.Description }}</h5>
|
||||
{{ end }}
|
||||
|
||||
<div class="container">
|
||||
<div class="col-12 mb-5">
|
||||
|
||||
<div class="col-12 mb-5">
|
||||
|
||||
<div class="list-group online_list">
|
||||
{{ range .Services }}
|
||||
<a href="#" class="list-group-item list-group-item-action {{if .Online}}{{ end }}">
|
||||
{{ .Name }}
|
||||
{{if .Online}}
|
||||
<span class="badge online_badge float-right">ONLINE</span>
|
||||
{{ else }}
|
||||
<span class="badge offline_badge float-right">OFFLINE</span>
|
||||
{{end}}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if .Core.AllOnline }}
|
||||
<div class="alert alert-success mt-2 mb-2" role="alert">
|
||||
All services are online and operational!
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="alert alert-danger mt-2 mb-2" role="alert">
|
||||
There is an offline service!
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="list-group online_list">
|
||||
{{ range .Services }}
|
||||
<a href="#" class="list-group-item list-group-item-action {{if .Online}}{{ end }}">
|
||||
{{ .Name }}
|
||||
{{if .Online}}
|
||||
<span class="badge online_badge float-right">ONLINE</span>
|
||||
{{ else }}
|
||||
<span class="badge offline_badge float-right">OFFLINE</span>
|
||||
{{end}}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
{{ range .Services }}
|
||||
|
@ -50,26 +60,26 @@
|
|||
<div class="progress-bar {{if .Online24Hours}} bg-success {{else}} bg-danger {{end}}" role="progressbar" style="width: {{.Online24Hours}}%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-4"><a href="/service/{{.Id}}">{{ .Name }}</a>
|
||||
<h4 class="mt-4"><a href="/service/{{.Id}}">{{ .Name }}</a>
|
||||
{{if .Online}}
|
||||
<span class="badge online_badge float-right">ONLINE</span>
|
||||
{{ else }}
|
||||
<span class="badge offline_badge float-right">OFFLINE</span>
|
||||
{{end}}</h3>
|
||||
{{end}}</h4>
|
||||
|
||||
<div class="row stats_area mt-5 mb-5">
|
||||
|
||||
<div class="col-4">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<span class="lg_number">{{.Online24}}%</span>
|
||||
Online last 24 Hours
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="col-md-4 col-sm-6">
|
||||
<span class="lg_number">{{.AvgTime}}ms</span>
|
||||
Average Response
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="col-md-4 col-sm-6">
|
||||
<span class="lg_number">{{.AvgUptime}}%</span>
|
||||
Total Uptime
|
||||
</div>
|
||||
|
@ -77,12 +87,19 @@
|
|||
|
||||
<canvas id="service_{{ .Id }}" width="400" height="120"></canvas>
|
||||
|
||||
{{ if .LimitedFailures }}
|
||||
<div class="list-group mt-5">
|
||||
{{ range .LimitedFailures }}
|
||||
<blockquote class="blockquote text-right mt-3">
|
||||
<p class="mb-0">{{.ParseError}}</p>
|
||||
<footer class="blockquote-footer">Reported <cite title="Source Title">{{.Ago}}</cite></footer>
|
||||
</blockquote>
|
||||
{{ end }}
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{.ParseError}}</h5>
|
||||
<small>Reported {{.Ago}}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{.Issue}}</p>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -93,15 +110,11 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="footer text-center">
|
||||
{{ if .Core.Footer }}
|
||||
{{ safe .Core.Footer }}
|
||||
{{ end }}
|
||||
<a href="https://statup.io" target="_blank">Statup made with ❤️</a> | <a href="/dashboard">Dashboard</a>
|
||||
</div>
|
||||
{{template "footer"}}
|
||||
|
||||
<script>
|
||||
{{ range .Services }}
|
||||
{{if .GraphData}}
|
||||
var ctx = document.getElementById("service_{{.Id}}").getContext('2d');
|
||||
|
||||
var chartdata = new Chart(ctx, {
|
||||
|
@ -158,6 +171,7 @@ var chartdata = new Chart(ctx, {
|
|||
}
|
||||
});
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
|
@ -12,12 +12,16 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
{{ if not . }}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Incorrect login information submitted, try again.
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<form action="/dashboard" method="POST">
|
||||
<div class="form-group row">
|
||||
<label for="inputEmail3" class="col-sm-2 col-form-label">Username</label>
|
||||
|
@ -51,11 +55,10 @@
|
|||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
|
||||
{{template "nav"}}
|
||||
|
@ -105,6 +105,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
||||
|
|
|
@ -12,14 +12,13 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{if Auth}}
|
||||
{{template "nav"}}
|
||||
{{end}}
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12">
|
||||
<div class="col-12">
|
||||
|
||||
<div class="col-12 mb-4">
|
||||
|
||||
|
@ -57,9 +56,8 @@
|
|||
</blockquote>
|
||||
{{ end }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{{if Auth}}
|
||||
|
@ -69,44 +67,61 @@
|
|||
|
||||
<form action="/service/{{.Id}}" method="POST">
|
||||
<div class="form-group row">
|
||||
<label for="inputEmail3" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" value="{{.Name}}" id="inputEmail3">
|
||||
<input type="text" name="name" class="form-control" id="service_name" value="{{.Name}}" placeholder="Name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="domain" class="form-control" value="{{.Domain}}" id="inputPassword3">
|
||||
<select name="check_type" class="form-control" id="service_type" value="{{.Type}}">
|
||||
<option value="http" selected>HTTP Service</option>
|
||||
<option value="tcp">TCP Service</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="expected" class="form-control" value="{{.Expected}}" id="inputPassword3">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-8">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" value="{{.Domain}}" placeholder="https://google.com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="expected_status" class="form-control" value="{{.ExpectedStatus}}" id="inputPassword3">
|
||||
<select name="method" class="form-control" id="service_check_type" value="{{.Method}}">
|
||||
<option value="GET" selected>GET</option>
|
||||
<option value="POST">POST</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">HTTP Method</label>
|
||||
<label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="method" class="form-control" value="{{.Method}}" id="inputPassword3">
|
||||
<textarea name="expected" class="form-control" id="service_response" rows="3">{{.Expected}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="interval" class="form-control" value="{{.Interval}}" id="inputPassword3">
|
||||
<input type="number" name="expected_status" class="form-control" value="{{.ExpectedStatus}}" id="service_response_code" value="200">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" value="{{.Port}}" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="interval" class="form-control" value="{{.Interval}}" id="service_interval" placeholder="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<a class="btn btn-primary">Test</a>
|
||||
<button type="submit" class="btn btn-success">Update Service</button>
|
||||
<a href="/service/{{ .Id }}/delete_failures" class="btn btn-danger">Delete All Failures</a>
|
||||
</div>
|
||||
|
@ -127,6 +142,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script>
|
||||
var ctx = document.getElementById("service").getContext('2d');
|
||||
|
|
|
@ -12,13 +12,11 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{template "nav"}}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12">
|
||||
<div class="col-12">
|
||||
|
||||
<h3>Services</h3>
|
||||
|
||||
|
@ -48,53 +46,66 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<h3>Create Service</h3>
|
||||
|
||||
<form action="/services" method="POST">
|
||||
<div class="form-group row">
|
||||
<label for="inputEmail3" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="inputEmail3" placeholder="Name">
|
||||
<input type="text" name="name" class="form-control" id="service_name" placeholder="Name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<label for="service_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="domain" class="form-control" id="inputPassword3" placeholder="https://google.com">
|
||||
<select name="check_type" class="form-control" id="service_type">
|
||||
<option value="http" selected>HTTP Service</option>
|
||||
<option value="tcp">TCP Service</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="expected" class="form-control" id="inputPassword3" placeholder="string">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-8">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" placeholder="https://google.com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="expected_status" class="form-control" id="inputPassword3" placeholder="200">
|
||||
<select name="method" class="form-control" id="service_check_type">
|
||||
<option value="GET" selected>GET</option>
|
||||
<option value="POST">POST</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">HTTP Method</label>
|
||||
<label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="method" class="form-control" id="inputPassword3" placeholder="GET">
|
||||
<textarea name="expected" class="form-control" id="service_response" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="interval" class="form-control" id="inputPassword3" placeholder="10">
|
||||
<input type="number" name="expected_status" class="form-control" id="service_response_code" value="200">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="interval" class="form-control" id="service_interval" placeholder="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<a class="btn btn-primary">Test</a>
|
||||
<button type="submit" class="btn btn-success">Create Service</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -104,8 +115,7 @@
|
|||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{ if .Error }}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
|
@ -102,6 +102,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
<script src="/js/setup.js"></script>
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
<body>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="container col-md-7 col-sm-12 mt-2 bg-light">
|
||||
|
||||
{{template "nav"}}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<h3>Users</h3>
|
||||
|
@ -74,10 +72,10 @@
|
|||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
|
|
25
main_test.go
25
main_test.go
|
@ -168,14 +168,6 @@ func TestService_Check(t *testing.T) {
|
|||
assert.Equal(t, true, out.Online)
|
||||
}
|
||||
|
||||
func TestService_Hits(t *testing.T) {
|
||||
service, err := SelectService(1)
|
||||
assert.Nil(t, err)
|
||||
hits, err := service.Hits()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, len(hits))
|
||||
}
|
||||
|
||||
func TestService_AvgTime(t *testing.T) {
|
||||
service, err := SelectService(1)
|
||||
assert.Nil(t, err)
|
||||
|
@ -193,7 +185,6 @@ func TestService_Online24(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestService_GraphData(t *testing.T) {
|
||||
t.SkipNow()
|
||||
service, err := SelectService(1)
|
||||
assert.Nil(t, err)
|
||||
data := service.GraphData()
|
||||
|
@ -221,6 +212,22 @@ func TestBadService_Check(t *testing.T) {
|
|||
assert.Equal(t, "Github Failing Check", service.Name)
|
||||
}
|
||||
|
||||
func TestService_Hits(t *testing.T) {
|
||||
service, err := SelectService(1)
|
||||
assert.Nil(t, err)
|
||||
hits, err := service.Hits()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, len(hits))
|
||||
}
|
||||
|
||||
func TestService_LimitedHits(t *testing.T) {
|
||||
service, err := SelectService(1)
|
||||
assert.Nil(t, err)
|
||||
hits, err := service.LimitedHits()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, len(hits))
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
var err error
|
||||
configs, err = LoadConfig()
|
||||
|
|
|
@ -69,5 +69,5 @@ type Routing struct {
|
|||
type Info struct {
|
||||
Name string
|
||||
Description string
|
||||
Form string
|
||||
Form string
|
||||
}
|
||||
|
|
33
services.go
33
services.go
|
@ -7,6 +7,7 @@ import (
|
|||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
"upper.io/db.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -32,17 +33,20 @@ type Service struct {
|
|||
Failures []*Failure `json:"failures"`
|
||||
}
|
||||
|
||||
func serviceCol() db.Collection {
|
||||
return dbSession.Collection("services")
|
||||
}
|
||||
|
||||
func SelectService(id int64) (*Service, error) {
|
||||
var service *Service
|
||||
col := dbSession.Collection("services")
|
||||
res := col.Find("id", id)
|
||||
res := serviceCol().Find("id", id)
|
||||
err := res.One(&service)
|
||||
return service, err
|
||||
}
|
||||
|
||||
func SelectAllServices() ([]*Service, error) {
|
||||
var services []*Service
|
||||
col := dbSession.Collection("services").Find()
|
||||
col := serviceCol().Find()
|
||||
err := col.All(&services)
|
||||
return services, err
|
||||
}
|
||||
|
@ -95,7 +99,7 @@ type GraphJson struct {
|
|||
|
||||
func (s *Service) GraphData() string {
|
||||
var d []GraphJson
|
||||
hits, _ := s.Hits()
|
||||
hits, _ := s.LimitedHits()
|
||||
for _, h := range hits {
|
||||
val := h.CreatedAt
|
||||
o := GraphJson{
|
||||
|
@ -112,7 +116,7 @@ func (s *Service) AvgUptime() string {
|
|||
failed, _ := s.TotalFailures()
|
||||
total, _ := s.TotalHits()
|
||||
if failed == 0 {
|
||||
s.TotalUptime = "100.00"
|
||||
s.TotalUptime = "100"
|
||||
return s.TotalUptime
|
||||
}
|
||||
if total == 0 {
|
||||
|
@ -125,35 +129,26 @@ func (s *Service) AvgUptime() string {
|
|||
percent = 0
|
||||
}
|
||||
s.TotalUptime = fmt.Sprintf("%0.2f", percent)
|
||||
if s.TotalUptime == "100.00" {
|
||||
s.TotalUptime = "100"
|
||||
}
|
||||
return s.TotalUptime
|
||||
}
|
||||
|
||||
func (u *Service) Delete() error {
|
||||
col := dbSession.Collection("services")
|
||||
res := col.Find("id", u.Id)
|
||||
res := serviceCol().Find("id", u.Id)
|
||||
err := res.Delete()
|
||||
OnDeletedService(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *Service) DeleteFailures() {
|
||||
var fails []*Failure
|
||||
col := dbSession.Collection("failures")
|
||||
col.Find("service", u.Id).All(&fails)
|
||||
for _, fail := range fails {
|
||||
fail.Delete()
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Service) Update() {
|
||||
|
||||
OnUpdateService(u)
|
||||
}
|
||||
|
||||
func (u *Service) Create() (int64, error) {
|
||||
u.CreatedAt = time.Now()
|
||||
col := dbSession.Collection("services")
|
||||
uuid, err := col.Insert(u)
|
||||
uuid, err := serviceCol().Insert(u)
|
||||
services, _ = SelectAllServices()
|
||||
if uuid == nil {
|
||||
return 0, err
|
||||
|
|
9
setup.go
9
setup.go
|
@ -102,6 +102,15 @@ func SetupResponseError(w http.ResponseWriter, r *http.Request, a interface{}) {
|
|||
ExecuteResponse(w, r, "setup.html", a)
|
||||
}
|
||||
|
||||
func (c *DbConfig) Clean() *DbConfig {
|
||||
if os.Getenv("DB_PORT") != "" {
|
||||
if c.DbConn == "postgres" {
|
||||
c.DbHost = c.DbHost + ":" + os.Getenv("DB_PORT")
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *DbConfig) Save() error {
|
||||
var err error
|
||||
config, err := os.Create("config.yml")
|
||||
|
|
|
@ -32,6 +32,13 @@ CREATE TABLE services (
|
|||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE checkins (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
check_interval integer,
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE hits (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
|
@ -42,6 +49,7 @@ CREATE TABLE hits (
|
|||
CREATE TABLE failures (
|
||||
id SERIAL PRIMARY KEY,
|
||||
issue text,
|
||||
method text,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
created_at TIMESTAMP WITHOUT TIME zone
|
||||
);
|
||||
|
|
24
web.go
24
web.go
|
@ -7,10 +7,10 @@ import (
|
|||
"github.com/gorilla/sessions"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -98,9 +98,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
|||
session.Save(r, w)
|
||||
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
||||
} else {
|
||||
w.WriteHeader(502)
|
||||
w.Header().Set("Content-Type", "plain/text")
|
||||
fmt.Fprintln(w, "bad")
|
||||
ExecuteResponse(w, r, "login.html", auth)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,8 +127,8 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
expected := r.PostForm.Get("expected")
|
||||
status, _ := strconv.Atoi(r.PostForm.Get("expected_status"))
|
||||
interval, _ := strconv.Atoi(r.PostForm.Get("interval"))
|
||||
|
||||
fmt.Println(r.PostForm)
|
||||
port, _ := strconv.Atoi(r.PostForm.Get("port"))
|
||||
checkType := r.PostForm.Get("check_type")
|
||||
|
||||
service := Service{
|
||||
Name: name,
|
||||
|
@ -139,10 +137,10 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
Expected: expected,
|
||||
ExpectedStatus: status,
|
||||
Interval: interval,
|
||||
Type: checkType,
|
||||
Port: port,
|
||||
}
|
||||
|
||||
fmt.Println(service)
|
||||
|
||||
_, err := service.Create()
|
||||
if err != nil {
|
||||
go service.CheckQueue()
|
||||
|
@ -285,7 +283,7 @@ func PluginsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
for _, p := range allPlugins {
|
||||
fields := structs.Map(p.GetInfo())
|
||||
|
||||
pluginFields = append(pluginFields, PluginSelect{p.GetInfo().Name, p.GetForm(),fields})
|
||||
pluginFields = append(pluginFields, PluginSelect{p.GetInfo().Name, p.GetForm(), fields})
|
||||
}
|
||||
|
||||
core.PluginFields = pluginFields
|
||||
|
@ -294,7 +292,7 @@ func PluginsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
type PluginSelect struct {
|
||||
Plugin string
|
||||
Form string
|
||||
Form string
|
||||
Params map[string]interface{}
|
||||
}
|
||||
|
||||
|
@ -375,6 +373,7 @@ func ServicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data interface{}) {
|
||||
nav, _ := tmplBox.String("nav.html")
|
||||
footer, _ := tmplBox.String("footer.html")
|
||||
render, err := tmplBox.String(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -398,6 +397,7 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
|
|||
},
|
||||
})
|
||||
t, _ = t.Parse(nav)
|
||||
t, _ = t.Parse(footer)
|
||||
t.Parse(render)
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
@ -431,8 +431,6 @@ func UsersDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func UnderScoreString(str string) string {
|
||||
|
||||
// convert every letter to lower case
|
||||
|
@ -454,4 +452,4 @@ func UnderScoreString(str string) string {
|
|||
newStr = strings.TrimSuffix(newStr, "_")
|
||||
|
||||
return newStr
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue