From 47493c8f19efb1f20616c26e93846888589ee061 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Mon, 31 Dec 2018 03:41:19 -0800 Subject: [PATCH 1/6] groups - public visibility --- core/database.go | 7 +++++- core/groups.go | 10 +++++++++ handlers/services.go | 6 +++++- source/tmpl/form_service.gohtml | 20 +++++++++++++++++ source/tmpl/messages.gohtml | 8 +++---- source/tmpl/services.gohtml | 38 +++++++++++++++++++++++++++++++-- source/wiki.go | 2 +- types/group.go | 11 ++++++++++ types/service.go | 2 ++ 9 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 core/groups.go create mode 100644 types/group.go diff --git a/core/database.go b/core/database.go index b4eb4b95..809c138f 100644 --- a/core/database.go +++ b/core/database.go @@ -36,7 +36,7 @@ var ( ) func init() { - DbModels = []interface{}{&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Checkin{}, &types.CheckinHit{}, ¬ifier.Notification{}} + DbModels = []interface{}{&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Group{}, &types.Checkin{}, &types.CheckinHit{}, ¬ifier.Notification{}} } // DbConfig stores the config.yml file for the statup configuration @@ -82,6 +82,11 @@ func messagesDb() *gorm.DB { return DbSession.Model(&types.Message{}) } +// messagesDb returns the Checkin records for a service +func groupsDb() *gorm.DB { + return DbSession.Model(&types.Group{}) +} + // HitsBetween returns the gorm database query for a collection of service hits between a time range func (s *Service) HitsBetween(t1, t2 time.Time, group string, column string) *gorm.DB { selector := Dbtimestamp(group, column) diff --git a/core/groups.go b/core/groups.go new file mode 100644 index 00000000..06449371 --- /dev/null +++ b/core/groups.go @@ -0,0 +1,10 @@ +package core + +import "github.com/hunterlong/statping/types" + +// SelectGroups returns all messages +func SelectGroups() ([]*types.Group, error) { + var groups []*types.Group + db := groupsDb().Find(&groups).Order("id desc") + return groups, db.Error +} diff --git a/handlers/services.go b/handlers/services.go index bb98bb27..230de225 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -51,7 +51,11 @@ func servicesHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusSeeOther) return } - ExecuteResponse(w, r, "services.gohtml", core.CoreApp.Services, nil) + data := map[string]interface{}{ + "Services": core.CoreApp.Services, + "Groups": core.CoreApp.Services, + } + ExecuteResponse(w, r, "services.gohtml", data, nil) } type serviceOrder struct { diff --git a/source/tmpl/form_service.gohtml b/source/tmpl/form_service.gohtml index 53bdff16..558fbf04 100644 --- a/source/tmpl/form_service.gohtml +++ b/source/tmpl/form_service.gohtml @@ -101,6 +101,26 @@ +
+ +
+ + Use HTTP if you are checking a website or use TCP if you are checking a server +
+
+
+ +
+ + + + +
+
diff --git a/source/tmpl/messages.gohtml b/source/tmpl/messages.gohtml index 72bcd7cd..f3fe44a4 100644 --- a/source/tmpl/messages.gohtml +++ b/source/tmpl/messages.gohtml @@ -9,8 +9,8 @@ Title - Service - Begins + Service + Begins @@ -18,8 +18,8 @@ {{range .}} {{.Title}} - {{if .Service}}{{.Service.Name}}{{end}} - {{.StartOn}} + {{if .Service}}{{.Service.Name}}{{end}} + {{.StartOn}} {{if Auth}}
Edit diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 575bdeb4..3d587071 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -4,7 +4,7 @@ {{template "nav"}}
- {{if ne (len .) 0}} + {{if ne (len .Services) 0}}

Services

@@ -15,7 +15,7 @@ - {{range .}} + {{range .Services}} @@ -35,6 +35,40 @@ {{template "form_service" NewService}} {{end}} + +
+ {{if ne (len .Groups) 0}} +

Groups

+
{{.Name}} {{if .Online}}ONLINE{{else}}OFFLINE{{end}}
+ + + + + + + + + {{range .Groups}} + + + + + + {{end}} + +
NameStatus
{{.Name}}{{if .Online}}ONLINE{{else}}OFFLINE{{end}} +
+ View + {{if Auth}}{{end}} +
+
+ {{end}} + {{if Auth}} +

Create Service

+ {{template "form_service" NewService}} + {{end}} +
+
{{end}} {{define "extra_scripts"}} diff --git a/source/wiki.go b/source/wiki.go index b80f2dbf..40883468 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2018-12-19 21:35:31.636341 -0800 PST m=+0.699027992 +// 2018-12-31 03:39:26.710899 -0800 PST m=+0.479547222 // // This contains the most recently Markdown source for the Statping Wiki. package source diff --git a/types/group.go b/types/group.go new file mode 100644 index 00000000..3cde59da --- /dev/null +++ b/types/group.go @@ -0,0 +1,11 @@ +package types + +import "time" + +// Group is the main struct for Groups +type Group struct { + Id int64 `gorm:"primary_key;column:id" json:"id"` + Name string `gorm:"column:name" json:"name"` + CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` +} diff --git a/types/service.go b/types/service.go index 971509b9..78ef42d4 100644 --- a/types/service.go +++ b/types/service.go @@ -34,6 +34,8 @@ type Service struct { Timeout int `gorm:"default:30;column:timeout" json:"timeout"` Order int `gorm:"default:0;column:order_id" json:"order_id"` AllowNotifications NullBool `gorm:"default:false;column:allow_notifications" json:"allow_notifications"` + Public NullBool `gorm:"default:false;column:public" json:"public"` + GroupId int `gorm:"default:0;column:group_id" json:"group_id"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` Online bool `gorm:"-" json:"online"` From 5e60b5578b47d8608e2d19bcdac3ba53434c597d Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Mon, 31 Dec 2018 13:36:58 -0800 Subject: [PATCH 2/6] grouping - public option --- core/groups.go | 51 +++- core/sample.go | 14 + handlers/api.go | 6 + handlers/groups.go | 110 ++++++++ handlers/handlers.go | 8 +- handlers/routes.go | 7 + handlers/services.go | 2 +- source/tmpl/form_group.gohtml | 26 ++ source/tmpl/form_service.gohtml | 15 +- source/tmpl/postman.json | 484 ++++++++++++++++++++++++++++++++ source/tmpl/services.gohtml | 10 +- source/wiki.go | 2 +- 12 files changed, 713 insertions(+), 22 deletions(-) create mode 100644 handlers/groups.go create mode 100644 source/tmpl/form_group.gohtml diff --git a/core/groups.go b/core/groups.go index 06449371..5e01c4ae 100644 --- a/core/groups.go +++ b/core/groups.go @@ -1,10 +1,49 @@ package core -import "github.com/hunterlong/statping/types" +import ( + "github.com/hunterlong/statping/types" + "time" +) -// SelectGroups returns all messages -func SelectGroups() ([]*types.Group, error) { - var groups []*types.Group - db := groupsDb().Find(&groups).Order("id desc") - return groups, db.Error +type Group struct { + *types.Group +} + +// Delete will remove a group +func (g *Group) Delete() error { + err := messagesDb().Delete(g) + if err.Error != nil { + return err.Error + } + return err.Error +} + +// Update will update a group in the database +func (g *Group) Update() error { + err := servicesDB().Update(&g) + return err.Error +} + +// Create will create a group and insert it into the database +func (g *Group) Create() (int64, error) { + g.CreatedAt = time.Now() + db := groupsDb().Create(g) + return g.Id, db.Error +} + +// SelectGroups returns all groups +func SelectGroups() []*Group { + var groups []*Group + groupsDb().Find(&groups).Order("id desc") + return groups +} + +// SelectGroup returns a *core.Group +func SelectGroup(id int64) *Group { + for _, g := range SelectGroups() { + if g.Id == id { + return g + } + } + return nil } diff --git a/core/sample.go b/core/sample.go index 613e21f3..7de53968 100644 --- a/core/sample.go +++ b/core/sample.go @@ -86,11 +86,25 @@ func InsertSampleData() error { insertMessages() + insertSampleGroups() + utils.Log(1, "Sample data has finished importing") return nil } +func insertSampleGroups() error { + group1 := &Group{&types.Group{ + Name: "Main Services", + }} + _, err := group1.Create() + group2 := &Group{&types.Group{ + Name: "Linked Services", + }} + _, err = group2.Create() + return err +} + // insertSampleCheckins will create 2 checkins with 60 successful hits per Checkin func insertSampleCheckins() error { s1 := SelectService(1) diff --git a/handlers/api.go b/handlers/api.go index 16c1450d..95bbb3bc 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -88,6 +88,12 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht case *core.User: objName = "user" objId = v.Id + case *types.Group: + objName = "group" + objId = v.Id + case *core.Group: + objName = "group" + objId = v.Id case *core.Checkin: objName = "checkin" objId = v.Id diff --git a/handlers/groups.go b/handlers/groups.go new file mode 100644 index 00000000..9ee68852 --- /dev/null +++ b/handlers/groups.go @@ -0,0 +1,110 @@ +// Statup +// Copyright (C) 2018. Hunter Long and the project contributors +// Written by Hunter Long and the project contributors +// +// https://github.com/hunterlong/statup +// +// The licenses for most software and other practical works are designed +// to take away your freedom to share and change the works. By contrast, +// the GNU General Public License is intended to guarantee your freedom to +// share and change all versions of a program--to make sure it remains free +// software for all its users. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package handlers + +import ( + "encoding/json" + "errors" + "github.com/gorilla/mux" + "github.com/hunterlong/statping/core" + "github.com/hunterlong/statping/utils" + "net/http" +) + +func apiAllGroupHandler(w http.ResponseWriter, r *http.Request) { + if !IsReadAuthenticated(r) { + sendUnauthorizedJson(w, r) + return + } + groups := core.SelectGroups() + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(groups) +} + +func apiGroupHandler(w http.ResponseWriter, r *http.Request) { + if !IsReadAuthenticated(r) { + sendUnauthorizedJson(w, r) + return + } + vars := mux.Vars(r) + group := core.SelectGroup(utils.ToInt(vars["id"])) + if group == nil { + sendErrorJson(errors.New("group not found"), w, r) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(group) +} + +func apiCreateGroupHandler(w http.ResponseWriter, r *http.Request) { + if !IsFullAuthenticated(r) { + sendUnauthorizedJson(w, r) + return + } + var group *core.Group + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&group) + if err != nil { + sendErrorJson(err, w, r) + return + } + _, err = group.Create() + if err != nil { + sendErrorJson(err, w, r) + return + } + sendJsonAction(group, "create", w, r) +} + +func apiGroupUpdateHandler(w http.ResponseWriter, r *http.Request) { + if !IsFullAuthenticated(r) { + sendUnauthorizedJson(w, r) + return + } + vars := mux.Vars(r) + group := core.SelectGroup(utils.ToInt(vars["id"])) + if group == nil { + sendErrorJson(errors.New("group not found"), w, r) + return + } + decoder := json.NewDecoder(r.Body) + decoder.Decode(&group) + err := group.Update() + if err != nil { + sendErrorJson(err, w, r) + return + } + sendJsonAction(group, "update", w, r) +} + +func apiGroupDeleteHandler(w http.ResponseWriter, r *http.Request) { + if !IsFullAuthenticated(r) { + sendUnauthorizedJson(w, r) + return + } + vars := mux.Vars(r) + group := core.SelectGroup(utils.ToInt(vars["id"])) + if group == nil { + sendErrorJson(errors.New("group not found"), w, r) + return + } + err := group.Delete() + if err != nil { + sendErrorJson(err, w, r) + return + } + sendJsonAction(group, "delete", w, r) +} diff --git a/handlers/handlers.go b/handlers/handlers.go index f54a6bf2..342242d6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -192,6 +192,9 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap "Services": func() []types.ServiceInterface { return core.CoreApp.Services }, + "Groups": func() []*core.Group { + return core.SelectGroups() + }, "len": func(g []types.ServiceInterface) int { return len(g) }, @@ -259,6 +262,9 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap "NewMessage": func() *types.Message { return new(types.Message) }, + "NewGroup": func() *types.Group { + return new(types.Group) + }, } } @@ -276,7 +282,7 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains") } - templates := []string{"base.gohtml", "head.gohtml", "nav.gohtml", "footer.gohtml", "scripts.gohtml", "form_service.gohtml", "form_notifier.gohtml", "form_user.gohtml", "form_checkin.gohtml", "form_message.gohtml"} + templates := []string{"base.gohtml", "head.gohtml", "nav.gohtml", "footer.gohtml", "scripts.gohtml", "form_service.gohtml", "form_notifier.gohtml", "form_group.gohtml", "form_user.gohtml", "form_checkin.gohtml", "form_message.gohtml"} javascripts := []string{"charts.js", "chart_index.js"} render, err := source.TmplBox.String(file) diff --git a/handlers/routes.go b/handlers/routes.go index 2feaaab8..6e4e4fe6 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -85,6 +85,13 @@ func Router() *mux.Router { r.Handle("/service/{id}/edit", http.HandlerFunc(servicesViewHandler)) r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET") + // API GROUPS Routes + r.Handle("/api/groups", http.HandlerFunc(apiAllGroupHandler)).Methods("GET") + r.Handle("/api/groups", http.HandlerFunc(apiCreateGroupHandler)).Methods("POST") + r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupHandler)).Methods("GET") + r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupUpdateHandler)).Methods("POST") + r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupDeleteHandler)).Methods("DELETE") + // API Routes r.Handle("/api", http.HandlerFunc(apiIndexHandler)) r.Handle("/api/renew", http.HandlerFunc(apiRenewHandler)) diff --git a/handlers/services.go b/handlers/services.go index 230de225..c74a8b46 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -53,7 +53,7 @@ func servicesHandler(w http.ResponseWriter, r *http.Request) { } data := map[string]interface{}{ "Services": core.CoreApp.Services, - "Groups": core.CoreApp.Services, + "Groups": core.SelectGroups(), } ExecuteResponse(w, r, "services.gohtml", data, nil) } diff --git a/source/tmpl/form_group.gohtml b/source/tmpl/form_group.gohtml new file mode 100644 index 00000000..9badb4cd --- /dev/null +++ b/source/tmpl/form_group.gohtml @@ -0,0 +1,26 @@ +{{define "form_group"}} +
+
+{{$message := .}} +{{if ne .Id 0}} +
+{{else}} + +{{end}} +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+{{end}} diff --git a/source/tmpl/form_service.gohtml b/source/tmpl/form_service.gohtml index 558fbf04..6ca2bbaf 100644 --- a/source/tmpl/form_service.gohtml +++ b/source/tmpl/form_service.gohtml @@ -104,20 +104,21 @@
- + + {{range Groups}} + + {{end}} - Use HTTP if you are checking a website or use TCP if you are checking a server + Attach this service to a group
- - + +
diff --git a/source/tmpl/postman.json b/source/tmpl/postman.json index d12e5c70..3407dbf9 100644 --- a/source/tmpl/postman.json +++ b/source/tmpl/postman.json @@ -769,6 +769,490 @@ } ] }, + { + "name": "Groups", + "item": [ + { + "name": "All Groups", + "event": [ + { + "listen": "test", + "script": { + "id": "d87f8a4e-7640-45b8-9d45-4f6e6f2463ee", + "exec": [ + "pm.test(\"View All Groups\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length).to.eql(2);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups" + ] + }, + "description": "View an array of all Services added to your Statping instance." + }, + "response": [] + }, + { + "name": "View Group", + "event": [ + { + "listen": "test", + "script": { + "id": "023c5643-6cb1-4cd0-b775-566f232d68f8", + "exec": [ + "pm.test(\"View Group\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.name).to.eql(\"Main Services\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups/1", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups", + "1" + ] + }, + "description": "View a specific service, this will include the service's failures and checkins." + }, + "response": [ + { + "name": "View Service", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/services/1", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:31:19 GMT" + }, + { + "key": "Content-Length", + "value": "482" + } + ], + "cookie": [], + "body": "{\n \"id\": 1,\n \"name\": \"Google\",\n \"domain\": \"https://google.com\",\n \"expected\": null,\n \"expected_status\": 200,\n \"check_interval\": 10,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": null,\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 1,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:15:42.24769-08:00\",\n \"updated_at\": \"2018-12-10T11:15:42.247837-08:00\",\n \"online\": true,\n \"latency\": 0.190599816,\n \"ping_time\": 0.00476598,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:13.511139-08:00\"\n}" + } + ] + }, + { + "name": "Create Group", + "event": [ + { + "listen": "test", + "script": { + "id": "d4eb16fe-8495-40e5-9ca3-be20951e5133", + "exec": [ + "pm.test(\"Create Group\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.output.name).to.eql(\"New Group\");", + " pm.globals.set(\"group_id\", jsonData.output.id);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"New Group\"\n}" + }, + "url": { + "raw": "{{endpoint}}/api/groups", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups" + ] + }, + "description": "Create a new service and begin monitoring." + }, + "response": [ + { + "name": "Create Service", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"New Service\",\n \"domain\": \"https://statping.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0\n}" + }, + "url": { + "raw": "{{endpoint}}/api/services", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:31:47 GMT" + }, + { + "key": "Content-Length", + "value": "528" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"create\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"New Service\",\n \"domain\": \"https://statping.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": false,\n \"latency\": 0,\n \"ping_time\": 0,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 0,\n \"last_success\": \"0001-01-01T00:00:00Z\"\n }\n}" + } + ] + }, + { + "name": "Update Group", + "event": [ + { + "listen": "test", + "script": { + "id": "b5a67a19-fd08-40b0-a961-3e9474ab78c6", + "exec": [ + "pm.test(\"Update Service\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.output.name).to.eql(\"Updated Group\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Updated Group\"\n}" + }, + "url": { + "raw": "{{endpoint}}/api/groups/{{group_id}}", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups", + "{{group_id}}" + ] + }, + "description": "Update a service with new values and begin monitoring." + }, + "response": [ + { + "name": "Update Service", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}" + }, + "url": { + "raw": "{{endpoint}}/api/services/{{service_id}}", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "{{service_id}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:31:54 GMT" + }, + { + "key": "Content-Length", + "value": "567" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"update\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.550636193,\n \"ping_time\": 0.073339805,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:49.161389-08:00\"\n }\n}" + } + ] + }, + { + "name": "Delete Group", + "event": [ + { + "listen": "test", + "script": { + "id": "dd4d721d-d874-448b-abc9-59c1afceb58e", + "exec": [ + "pm.test(\"Delete Service\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.type).to.eql(\"group\");", + " pm.expect(jsonData.method).to.eql(\"delete\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups/{{group_id}}", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups", + "{{group_id}}" + ] + }, + "description": "Delete a group" + }, + "response": [ + { + "name": "Delete Service", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/services/{{service_id}}", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "{{service_id}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:32:06 GMT" + }, + { + "key": "Content-Length", + "value": "567" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"delete\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.203382878,\n \"ping_time\": 0.001664491,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:55.455091-08:00\"\n }\n}" + } + ] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "id": "4cd2ab82-e60d-45cd-9b74-cb4b5d893f4d", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "c7cb2b6d-289a-4073-b291-202bbec8cb44", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, { "name": "Users", "item": [ diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 3d587071..2051d552 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -43,19 +43,17 @@ Name - Status {{range .Groups}} - + {{.Name}} - {{if .Online}}ONLINE{{else}}OFFLINE{{end}}
View - {{if Auth}}{{end}} + {{if Auth}}{{end}}
@@ -64,8 +62,8 @@ {{end}} {{if Auth}} -

Create Service

- {{template "form_service" NewService}} +

Create Group

+ {{template "form_group" NewGroup}} {{end}}
diff --git a/source/wiki.go b/source/wiki.go index 40883468..0e5c5ba3 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2018-12-31 03:39:26.710899 -0800 PST m=+0.479547222 +// 2018-12-31 13:16:43.415892 -0800 PST m=+1.140052566 // // This contains the most recently Markdown source for the Statping Wiki. package source From bcedc75c8e05488e7647b62f7f28ff42b740be0d Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Thu, 3 Jan 2019 09:36:30 -0800 Subject: [PATCH 3/6] grouping --- handlers/handlers_test.go | 4 ++-- source/tmpl/services.gohtml | 11 ++++------- source/wiki.go | 2 +- version.txt | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index c8679aba..94ea49a9 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -31,8 +31,8 @@ import ( func TestResetHandlerDatabase(t *testing.T) { Clean() - loadDatabase() - createDatabase() + //loadDatabase() + //createDatabase() } func TestFailedHTTPServer(t *testing.T) { diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 2051d552..958c342b 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -36,8 +36,7 @@ {{end}}
-
- {{if ne (len .Groups) 0}} +

Groups

@@ -46,21 +45,19 @@ - + {{range .Groups}} - + {{end}}
{{.Name}}{{.Name}}
- View - {{if Auth}}{{end}} + {{if Auth}}{{end}}
- {{end}} {{if Auth}}

Create Group

{{template "form_group" NewGroup}} diff --git a/source/wiki.go b/source/wiki.go index 0e5c5ba3..a3200182 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2018-12-31 13:16:43.415892 -0800 PST m=+1.140052566 +// 2019-01-03 07:34:25.019934 -0800 PST m=+0.528929648 // // This contains the most recently Markdown source for the Statping Wiki. package source diff --git a/version.txt b/version.txt index 8342a762..a58f9cfd 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.80.32 \ No newline at end of file +0.80.33 \ No newline at end of file From 0b7687aa855c8975ad2e3c8113144437d1de1f2d Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Thu, 3 Jan 2019 11:13:48 -0800 Subject: [PATCH 4/6] grouping --- core/groups.go | 21 ++- core/sample.go | 12 +- core/services_test.go | 3 + handlers/groups.go | 21 --- handlers/handlers.go | 5 +- handlers/routes.go | 1 - source/tmpl/form_service.gohtml | 7 +- source/tmpl/index.gohtml | 46 ++++-- source/tmpl/postman.json | 250 +------------------------------- source/tmpl/services.gohtml | 4 +- source/wiki.go | 2 +- 11 files changed, 77 insertions(+), 295 deletions(-) diff --git a/core/groups.go b/core/groups.go index 5e01c4ae..fcd4d9f7 100644 --- a/core/groups.go +++ b/core/groups.go @@ -11,6 +11,10 @@ type Group struct { // Delete will remove a group func (g *Group) Delete() error { + for _, s := range g.Services() { + s.GroupId = 0 + s.Update(false) + } err := messagesDb().Delete(g) if err.Error != nil { return err.Error @@ -18,12 +22,6 @@ func (g *Group) Delete() error { return err.Error } -// Update will update a group in the database -func (g *Group) Update() error { - err := servicesDB().Update(&g) - return err.Error -} - // Create will create a group and insert it into the database func (g *Group) Create() (int64, error) { g.CreatedAt = time.Now() @@ -31,6 +29,17 @@ func (g *Group) Create() (int64, error) { return g.Id, db.Error } +// Services returns all services belonging to a group +func (g *Group) Services() []*Service { + var services []*Service + for _, s := range Services() { + if s.Select().GroupId == int(g.Id) { + services = append(services, s.(*Service)) + } + } + return services +} + // SelectGroups returns all groups func SelectGroups() []*Group { var groups []*Group diff --git a/core/sample.go b/core/sample.go index 7de53968..f4a72f2f 100644 --- a/core/sample.go +++ b/core/sample.go @@ -26,6 +26,9 @@ import ( // InsertSampleData will create the example/dummy services for a brand new Statping installation func InsertSampleData() error { utils.Log(1, "Inserting Sample Data...") + + insertSampleGroups() + s1 := ReturnService(&types.Service{ Name: "Google", Domain: "https://google.com", @@ -35,6 +38,7 @@ func InsertSampleData() error { Method: "GET", Timeout: 10, Order: 1, + GroupId: 1, }) s2 := ReturnService(&types.Service{ Name: "Statping Github", @@ -55,6 +59,8 @@ func InsertSampleData() error { Method: "GET", Timeout: 30, Order: 3, + Public: types.NewNullBool(true), + GroupId: 2, }) s4 := ReturnService(&types.Service{ Name: "JSON API Tester", @@ -67,6 +73,8 @@ func InsertSampleData() error { PostData: types.NewNullString(`{ "title": "statup", "body": "bar", "userId": 19999 }`), Timeout: 30, Order: 4, + Public: types.NewNullBool(true), + GroupId: 2, }) s5 := ReturnService(&types.Service{ Name: "Google DNS", @@ -76,6 +84,8 @@ func InsertSampleData() error { Port: 53, Timeout: 120, Order: 5, + Public: types.NewNullBool(true), + GroupId: 1, }) s1.Create(false) @@ -86,8 +96,6 @@ func InsertSampleData() error { insertMessages() - insertSampleGroups() - utils.Log(1, "Sample data has finished importing") return nil diff --git a/core/services_test.go b/core/services_test.go index c7e0c5ab..d08f3d9d 100644 --- a/core/services_test.go +++ b/core/services_test.go @@ -189,6 +189,7 @@ func TestCreateService(t *testing.T) { Type: "http", Method: "GET", Timeout: 20, + GroupId: 1, }) var err error newServiceId, err = s.Create(false) @@ -212,6 +213,7 @@ func TestCreateFailingHTTPService(t *testing.T) { Type: "http", Method: "GET", Timeout: 5, + GroupId: 1, }) var err error newServiceId, err = s.Create(false) @@ -238,6 +240,7 @@ func TestCreateFailingTCPService(t *testing.T) { Interval: 30, Type: "tcp", Timeout: 5, + GroupId: 1, }) var err error newServiceId, err = s.Create(false) diff --git a/handlers/groups.go b/handlers/groups.go index 9ee68852..bffff987 100644 --- a/handlers/groups.go +++ b/handlers/groups.go @@ -69,27 +69,6 @@ func apiCreateGroupHandler(w http.ResponseWriter, r *http.Request) { sendJsonAction(group, "create", w, r) } -func apiGroupUpdateHandler(w http.ResponseWriter, r *http.Request) { - if !IsFullAuthenticated(r) { - sendUnauthorizedJson(w, r) - return - } - vars := mux.Vars(r) - group := core.SelectGroup(utils.ToInt(vars["id"])) - if group == nil { - sendErrorJson(errors.New("group not found"), w, r) - return - } - decoder := json.NewDecoder(r.Body) - decoder.Decode(&group) - err := group.Update() - if err != nil { - sendErrorJson(err, w, r) - return - } - sendJsonAction(group, "update", w, r) -} - func apiGroupDeleteHandler(w http.ResponseWriter, r *http.Request) { if !IsFullAuthenticated(r) { sendUnauthorizedJson(w, r) diff --git a/handlers/handlers.go b/handlers/handlers.go index 342242d6..2c2cd9f8 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -195,8 +195,9 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap "Groups": func() []*core.Group { return core.SelectGroups() }, - "len": func(g []types.ServiceInterface) int { - return len(g) + "len": func(g interface{}) int { + val := reflect.ValueOf(g) + return val.Len() }, "IsNil": func(g interface{}) bool { return g == nil diff --git a/handlers/routes.go b/handlers/routes.go index 6e4e4fe6..1f1386cc 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -89,7 +89,6 @@ func Router() *mux.Router { r.Handle("/api/groups", http.HandlerFunc(apiAllGroupHandler)).Methods("GET") r.Handle("/api/groups", http.HandlerFunc(apiCreateGroupHandler)).Methods("POST") r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupHandler)).Methods("GET") - r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupUpdateHandler)).Methods("POST") r.Handle("/api/groups/{id}", http.HandlerFunc(apiGroupDeleteHandler)).Methods("DELETE") // API Routes diff --git a/source/tmpl/form_service.gohtml b/source/tmpl/form_service.gohtml index 6ca2bbaf..eada6fbd 100644 --- a/source/tmpl/form_service.gohtml +++ b/source/tmpl/form_service.gohtml @@ -1,6 +1,7 @@ {{define "form_service"}}
+{{$s := .}} {{if ne .Id 0}}
{{else}} @@ -104,10 +105,10 @@
- + {{range Groups}} - + {{end}} Attach this service to a group diff --git a/source/tmpl/index.gohtml b/source/tmpl/index.gohtml index b587887b..b9edaae1 100644 --- a/source/tmpl/index.gohtml +++ b/source/tmpl/index.gohtml @@ -8,21 +8,39 @@
{{ .Description }}
{{ end }} - + {{else}} + +
+ {{end}} {{ if .Messages }}
diff --git a/source/tmpl/postman.json b/source/tmpl/postman.json index 3407dbf9..c60ce2d7 100644 --- a/source/tmpl/postman.json +++ b/source/tmpl/postman.json @@ -816,7 +816,7 @@ "groups" ] }, - "description": "View an array of all Services added to your Statping instance." + "description": "View an array of all Groups added to your Statping instance." }, "response": [] }, @@ -872,58 +872,9 @@ "1" ] }, - "description": "View a specific service, this will include the service's failures and checkins." + "description": "View a specific group" }, - "response": [ - { - "name": "View Service", - "originalRequest": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{endpoint}}/api/services/1", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:31:19 GMT" - }, - { - "key": "Content-Length", - "value": "482" - } - ], - "cookie": [], - "body": "{\n \"id\": 1,\n \"name\": \"Google\",\n \"domain\": \"https://google.com\",\n \"expected\": null,\n \"expected_status\": 200,\n \"check_interval\": 10,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": null,\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 1,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:15:42.24769-08:00\",\n \"updated_at\": \"2018-12-10T11:15:42.247837-08:00\",\n \"online\": true,\n \"latency\": 0.190599816,\n \"ping_time\": 0.00476598,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:13.511139-08:00\"\n}" - } - ] + "response": [] }, { "name": "Create Group", @@ -975,156 +926,9 @@ "groups" ] }, - "description": "Create a new service and begin monitoring." + "description": "Create a new Group to organize services." }, - "response": [ - { - "name": "Create Service", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"New Service\",\n \"domain\": \"https://statping.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0\n}" - }, - "url": { - "raw": "{{endpoint}}/api/services", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:31:47 GMT" - }, - { - "key": "Content-Length", - "value": "528" - } - ], - "cookie": [], - "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"create\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"New Service\",\n \"domain\": \"https://statping.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": false,\n \"latency\": 0,\n \"ping_time\": 0,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 0,\n \"last_success\": \"0001-01-01T00:00:00Z\"\n }\n}" - } - ] - }, - { - "name": "Update Group", - "event": [ - { - "listen": "test", - "script": { - "id": "b5a67a19-fd08-40b0-a961-3e9474ab78c6", - "exec": [ - "pm.test(\"Update Service\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.output.name).to.eql(\"Updated Group\");", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Updated Group\"\n}" - }, - "url": { - "raw": "{{endpoint}}/api/groups/{{group_id}}", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "groups", - "{{group_id}}" - ] - }, - "description": "Update a service with new values and begin monitoring." - }, - "response": [ - { - "name": "Update Service", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}" - }, - "url": { - "raw": "{{endpoint}}/api/services/{{service_id}}", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services", - "{{service_id}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:31:54 GMT" - }, - { - "key": "Content-Length", - "value": "567" - } - ], - "cookie": [], - "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"update\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.550636193,\n \"ping_time\": 0.073339805,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:49.161389-08:00\"\n }\n}" - } - ] + "response": [] }, { "name": "Delete Group", @@ -1175,49 +979,7 @@ }, "description": "Delete a group" }, - "response": [ - { - "name": "Delete Service", - "originalRequest": { - "method": "DELETE", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{endpoint}}/api/services/{{service_id}}", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services", - "{{service_id}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:32:06 GMT" - }, - { - "key": "Content-Length", - "value": "567" - } - ], - "cookie": [], - "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"delete\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.203382878,\n \"ping_time\": 0.001664491,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:55.455091-08:00\"\n }\n}" - } - ] + "response": [] } ], "auth": { diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 958c342b..6d71009d 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -42,13 +42,15 @@ Name + Services - + {{range .Groups}} {{.Name}} + {{len .Services}}
{{if Auth}}{{end}} diff --git a/source/wiki.go b/source/wiki.go index a3200182..4f790729 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2019-01-03 07:34:25.019934 -0800 PST m=+0.528929648 +// 2019-01-03 11:12:03.7014 -0800 PST m=+0.913709962 // // This contains the most recently Markdown source for the Statping Wiki. package source From df2eb5c50af744e83dad749bcd67dacc28cb59b5 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Thu, 3 Jan 2019 13:09:11 -0800 Subject: [PATCH 5/6] grouping - http proxy --- core/groups.go | 20 ++++++++++++--- core/sample.go | 6 +++-- handlers/groups.go | 7 +++++- handlers/handlers.go | 5 ++-- handlers/services.go | 1 - source/tmpl/form_group.gohtml | 10 +++++++- source/tmpl/form_service.gohtml | 2 +- source/tmpl/index.gohtml | 44 +++++++++++---------------------- source/tmpl/services.gohtml | 8 ++++-- source/wiki.go | 2 +- types/group.go | 1 + utils/utils.go | 2 ++ 12 files changed, 64 insertions(+), 44 deletions(-) diff --git a/core/groups.go b/core/groups.go index fcd4d9f7..785eb9ed 100644 --- a/core/groups.go +++ b/core/groups.go @@ -41,15 +41,29 @@ func (g *Group) Services() []*Service { } // SelectGroups returns all groups -func SelectGroups() []*Group { +func SelectGroups(includeAll bool, auth bool) []*Group { var groups []*Group + var validGroups []*Group groupsDb().Find(&groups).Order("id desc") - return groups + if includeAll { + emptyGroup := &Group{&types.Group{Id: 0, Public: types.NewNullBool(true)}} + groups = append(groups, emptyGroup) + } + for _, g := range groups { + if !g.Public.Bool { + if auth { + validGroups = append(validGroups, g) + } + } else { + validGroups = append(validGroups, g) + } + } + return validGroups } // SelectGroup returns a *core.Group func SelectGroup(id int64) *Group { - for _, g := range SelectGroups() { + for _, g := range SelectGroups(false, false) { if g.Id == id { return g } diff --git a/core/sample.go b/core/sample.go index f4a72f2f..3b6dc473 100644 --- a/core/sample.go +++ b/core/sample.go @@ -103,11 +103,13 @@ func InsertSampleData() error { func insertSampleGroups() error { group1 := &Group{&types.Group{ - Name: "Main Services", + Name: "Main Services", + Public: types.NewNullBool(true), }} _, err := group1.Create() group2 := &Group{&types.Group{ - Name: "Linked Services", + Name: "Linked Services", + Public: types.NewNullBool(false), }} _, err = group2.Create() return err diff --git a/handlers/groups.go b/handlers/groups.go index bffff987..4a801b5b 100644 --- a/handlers/groups.go +++ b/handlers/groups.go @@ -24,16 +24,19 @@ import ( "net/http" ) +// apiAllGroupHandler will show all the groups func apiAllGroupHandler(w http.ResponseWriter, r *http.Request) { if !IsReadAuthenticated(r) { sendUnauthorizedJson(w, r) return } - groups := core.SelectGroups() + auth := IsUser(r) + groups := core.SelectGroups(false, auth) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(groups) } +// apiGroupHandler will show a single group func apiGroupHandler(w http.ResponseWriter, r *http.Request) { if !IsReadAuthenticated(r) { sendUnauthorizedJson(w, r) @@ -49,6 +52,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(group) } +// apiCreateGroupHandler accepts a POST method to create new groups func apiCreateGroupHandler(w http.ResponseWriter, r *http.Request) { if !IsFullAuthenticated(r) { sendUnauthorizedJson(w, r) @@ -69,6 +73,7 @@ func apiCreateGroupHandler(w http.ResponseWriter, r *http.Request) { sendJsonAction(group, "create", w, r) } +// apiGroupDeleteHandler accepts a DELETE method to delete groups func apiGroupDeleteHandler(w http.ResponseWriter, r *http.Request) { if !IsFullAuthenticated(r) { sendUnauthorizedJson(w, r) diff --git a/handlers/handlers.go b/handlers/handlers.go index 2c2cd9f8..cfbb372f 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -192,8 +192,9 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap "Services": func() []types.ServiceInterface { return core.CoreApp.Services }, - "Groups": func() []*core.Group { - return core.SelectGroups() + "Groups": func(includeAll bool) []*core.Group { + auth := IsUser(r) + return core.SelectGroups(includeAll, auth) }, "len": func(g interface{}) int { val := reflect.ValueOf(g) diff --git a/handlers/services.go b/handlers/services.go index c74a8b46..5265fc03 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -53,7 +53,6 @@ func servicesHandler(w http.ResponseWriter, r *http.Request) { } data := map[string]interface{}{ "Services": core.CoreApp.Services, - "Groups": core.SelectGroups(), } ExecuteResponse(w, r, "services.gohtml", data, nil) } diff --git a/source/tmpl/form_group.gohtml b/source/tmpl/form_group.gohtml index 9badb4cd..c011bb11 100644 --- a/source/tmpl/form_group.gohtml +++ b/source/tmpl/form_group.gohtml @@ -13,7 +13,15 @@
- +
+ +
+ + + + +
+
diff --git a/source/tmpl/form_service.gohtml b/source/tmpl/form_service.gohtml index eada6fbd..8b146463 100644 --- a/source/tmpl/form_service.gohtml +++ b/source/tmpl/form_service.gohtml @@ -107,7 +107,7 @@
diff --git a/source/tmpl/index.gohtml b/source/tmpl/index.gohtml index b9edaae1..e5fa5993 100644 --- a/source/tmpl/index.gohtml +++ b/source/tmpl/index.gohtml @@ -8,39 +8,23 @@
{{ .Description }}
{{ end }} - {{if ne (len Groups) 0}} - {{ range Groups }} -
-

{{.Name}}

- -
- {{end}} - {{else}} +{{ range Groups true }} + - {{end}} +
+{{end}} {{ if .Messages }}
diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 6d71009d..551e8cbe 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -11,6 +11,7 @@ Name Status + Visibility @@ -18,7 +19,8 @@ {{range .Services}} {{.Name}} - {{if .Online}}ONLINE{{else}}OFFLINE{{end}} + {{if .Online}}ONLINE{{else}}OFFLINE{{end}} + {{if .Public.Bool}}PUBLIC{{else}}PRIVATE{{end}}
View @@ -43,14 +45,16 @@ Name Services + Visibility - {{range .Groups}} + {{range Groups false}} {{.Name}} {{len .Services}} + {{if .Public.Bool}}PUBLIC{{else}}PRIVATE{{end}}
{{if Auth}}{{end}} diff --git a/source/wiki.go b/source/wiki.go index 4f790729..e11f17e4 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2019-01-03 11:12:03.7014 -0800 PST m=+0.913709962 +// 2019-01-03 13:06:31.051097 -0800 PST m=+1.051596230 // // This contains the most recently Markdown source for the Statping Wiki. package source diff --git a/types/group.go b/types/group.go index 3cde59da..18384ef5 100644 --- a/types/group.go +++ b/types/group.go @@ -6,6 +6,7 @@ import "time" type Group struct { Id int64 `gorm:"primary_key;column:id" json:"id"` Name string `gorm:"column:name" json:"name"` + Public NullBool `gorm:"default:false;column:public" json:"public"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` } diff --git a/utils/utils.go b/utils/utils.go index eced735f..753a7915 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -231,6 +231,7 @@ func SaveFile(filename string, data []byte) error { // // headers - An array of Headers to be sent (KEY=VALUE) []string{"Authentication=12345", ...} // // body - The body or form data to send with HTTP request // // timeout - Specific duration to timeout on. time.Duration(30 * time.Seconds) +// // You can use a HTTP Proxy if you HTTP_PROXY environment variable func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration) ([]byte, *http.Response, error) { var err error transport := &http.Transport{ @@ -240,6 +241,7 @@ func HttpRequest(url, method string, content interface{}, headers []string, body DisableKeepAlives: true, ResponseHeaderTimeout: timeout, TLSHandshakeTimeout: timeout, + Proxy: http.ProxyFromEnvironment, } client := &http.Client{ Transport: transport, From c90bc93049e6b3c7b4a5b790e706fec98cb0233d Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Thu, 3 Jan 2019 13:59:58 -0800 Subject: [PATCH 6/6] testing --- source/tmpl/postman.json | 188 +++++++++++++++++++++++++++++++++++++-- source/wiki.go | 2 +- 2 files changed, 184 insertions(+), 6 deletions(-) diff --git a/source/tmpl/postman.json b/source/tmpl/postman.json index c60ce2d7..53d3117c 100644 --- a/source/tmpl/postman.json +++ b/source/tmpl/postman.json @@ -818,7 +818,48 @@ }, "description": "View an array of all Groups added to your Statping instance." }, - "response": [] + "response": [ + { + "name": "All Groups", + "originalRequest": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 03 Jan 2019 21:48:40 GMT" + }, + { + "key": "Content-Length", + "value": "301" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": 1,\n \"name\": \"Main Services\",\n \"public\": true,\n \"created_at\": \"2019-01-03T13:48:23.488553261-08:00\",\n \"updated_at\": \"2019-01-03T13:48:23.488614502-08:00\"\n },\n {\n \"id\": 2,\n \"name\": \"Linked Services\",\n \"public\": false,\n \"created_at\": \"2019-01-03T13:48:23.489693923-08:00\",\n \"updated_at\": \"2019-01-03T13:48:23.489719447-08:00\"\n }\n]" + } + ] }, { "name": "View Group", @@ -874,7 +915,56 @@ }, "description": "View a specific group" }, - "response": [] + "response": [ + { + "name": "View Group", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups/1", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 03 Jan 2019 21:48:58 GMT" + }, + { + "key": "Content-Length", + "value": "148" + } + ], + "cookie": [], + "body": "{\n \"id\": 1,\n \"name\": \"Main Services\",\n \"public\": true,\n \"created_at\": \"2019-01-03T13:48:23.488553261-08:00\",\n \"updated_at\": \"2019-01-03T13:48:23.488614502-08:00\"\n}" + } + ] }, { "name": "Create Group", @@ -914,7 +1004,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"New Group\"\n}" + "raw": "{\n \"name\": \"New Group\",\n \"public\": true\n}" }, "url": { "raw": "{{endpoint}}/api/groups", @@ -928,7 +1018,53 @@ }, "description": "Create a new Group to organize services." }, - "response": [] + "response": [ + { + "name": "Create Group", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"New Group\",\n \"public\": true\n}" + }, + "url": { + "raw": "{{endpoint}}/api/groups", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 03 Jan 2019 21:49:25 GMT" + }, + { + "key": "Content-Length", + "value": "214" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"group\",\n \"method\": \"create\",\n \"id\": 3,\n \"output\": {\n \"id\": 3,\n \"name\": \"New Group\",\n \"public\": true,\n \"created_at\": \"2019-01-03T13:49:25.947069211-08:00\",\n \"updated_at\": \"2019-01-03T13:49:25.947120276-08:00\"\n }\n}" + } + ] }, { "name": "Delete Group", @@ -979,7 +1115,49 @@ }, "description": "Delete a group" }, - "response": [] + "response": [ + { + "name": "Delete Group", + "originalRequest": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/groups/{{group_id}}", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "groups", + "{{group_id}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 03 Jan 2019 21:49:49 GMT" + }, + { + "key": "Content-Length", + "value": "214" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"group\",\n \"method\": \"delete\",\n \"id\": 3,\n \"output\": {\n \"id\": 3,\n \"name\": \"New Group\",\n \"public\": true,\n \"created_at\": \"2019-01-03T13:49:25.947069211-08:00\",\n \"updated_at\": \"2019-01-03T13:49:25.947120276-08:00\"\n }\n}" + } + ] } ], "auth": { diff --git a/source/wiki.go b/source/wiki.go index e11f17e4..1c78bfe8 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2019-01-03 13:06:31.051097 -0800 PST m=+1.051596230 +// 2019-01-03 13:55:35.224765 -0800 PST m=+0.695466687 // // This contains the most recently Markdown source for the Statping Wiki. package source