diff --git a/core/failures.go b/core/failures.go
index 49b14b49..2df56aca 100644
--- a/core/failures.go
+++ b/core/failures.go
@@ -20,6 +20,7 @@ import (
"github.com/ararog/timeago"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
+ "sort"
"strings"
"time"
)
@@ -29,7 +30,7 @@ type failure struct {
}
const (
- limitedFailures = 64
+ limitedFailures = 32
)
// CreateFailure will create a new failure record for a service
@@ -41,8 +42,9 @@ func (s *Service) CreateFailure(fail types.FailureInterface) (int64, error) {
utils.Log(3, row.Error)
return 0, row.Error
}
- s.Failures = append(s.Failures, f.Select())
- if len(s.Failures) >= limitedFailures {
+ sort.Sort(types.FailSort(s.Failures))
+ s.Failures = append(s.Failures, f)
+ if len(s.Failures) > limitedFailures {
s.Failures = s.Failures[1:]
}
return f.Id, row.Error
diff --git a/core/services.go b/core/services.go
index 8b7724e0..028188e1 100644
--- a/core/services.go
+++ b/core/services.go
@@ -102,10 +102,9 @@ func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
service.Start()
service.CheckinProcess()
}
- failures := service.LimitedFailures(limitedFailures)
- service.Failures = nil
- for _, fail := range failures {
- service.Failures = append(service.Failures, fail.Select())
+ fails := service.LimitedFailures(limitedFailures)
+ for _, f := range fails {
+ service.Failures = append(service.Failures, f)
}
CoreApp.Services = append(CoreApp.Services, service)
}
diff --git a/handlers/api.go b/handlers/api.go
index 2b529cf1..eeffa79d 100644
--- a/handlers/api.go
+++ b/handlers/api.go
@@ -128,14 +128,14 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
- service := core.SelectServicer(utils.StringInt(vars["id"]))
- if service == nil {
+ servicer := core.SelectServicer(utils.StringInt(vars["id"]))
+ if servicer == nil {
sendErrorJson(errors.New("service not found"), w, r)
return
}
-
+ service := servicer.Select()
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(service.Select())
+ json.NewEncoder(w).Encode(service)
}
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
@@ -181,7 +181,7 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
sendErrorJson(err, w, r)
return
}
- service.Check(true)
+ go service.Check(true)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(service)
}
@@ -218,12 +218,8 @@ func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
return
}
services := core.Services()
- var servicesOut []*types.Service
- for _, s := range services {
- servicesOut = append(servicesOut, s.Select())
- }
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(servicesOut)
+ json.NewEncoder(w).Encode(services)
}
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
@@ -250,8 +246,11 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
var notification *notifier.Notification
fmt.Println(r.Body)
decoder := json.NewDecoder(r.Body)
- decoder.Decode(¬ification)
-
+ err := decoder.Decode(¬ification)
+ if err != nil {
+ sendErrorJson(err, w, r)
+ return
+ }
notifer, not, err := notifier.SelectNotifier(vars["notifier"])
if err != nil {
sendErrorJson(err, w, r)
@@ -264,9 +263,9 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
notifer.Port = notification.Port
notifer.Password = notification.Password
notifer.Username = notification.Username
- notifer.Enabled = notification.Enabled
notifer.ApiKey = notification.ApiKey
notifer.ApiSecret = notification.ApiSecret
+ notifer.Enabled = types.NewNullBool(notification.Enabled.Bool)
_, err = notifier.Update(not, notifer)
if err != nil {
@@ -293,6 +292,28 @@ func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(messages)
}
+func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
+ if !isAPIAuthorized(r) {
+ sendUnauthorizedJson(w, r)
+ return
+ }
+ var message *types.Message
+ decoder := json.NewDecoder(r.Body)
+ err := decoder.Decode(&message)
+ if err != nil {
+ sendErrorJson(err, w, r)
+ return
+ }
+ msg := core.ReturnMessage(message)
+ _, err = msg.Create()
+ if err != nil {
+ sendErrorJson(err, w, r)
+ return
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(msg)
+}
+
func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) {
if !isAPIAuthorized(r) {
sendUnauthorizedJson(w, r)
@@ -388,27 +409,6 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(notifiers)
}
-func apiAllServiceFailuresHandler(w http.ResponseWriter, r *http.Request) {
- if !isAPIAuthorized(r) {
- sendUnauthorizedJson(w, r)
- return
- }
- allServices, _ := core.CoreApp.SelectAllServices(false)
- w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(allServices)
-}
-
-func apiServiceFailuresHandler(w http.ResponseWriter, r *http.Request) {
- if !isAPIAuthorized(r) {
- sendUnauthorizedJson(w, r)
- return
- }
- vars := mux.Vars(r)
- service := core.SelectService(utils.StringInt(vars["id"]))
- w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(service.AllFailures())
-}
-
func sendErrorJson(err error, w http.ResponseWriter, r *http.Request) {
output := apiResponse{
Status: "error",
diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go
index dc66ca94..37225957 100644
--- a/handlers/handlers_test.go
+++ b/handlers/handlers_test.go
@@ -17,7 +17,6 @@ package handlers
import (
"github.com/hunterlong/statup/core"
- "github.com/hunterlong/statup/core/notifier"
_ "github.com/hunterlong/statup/notifiers"
"github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/utils"
@@ -364,34 +363,6 @@ func TestPrometheusHandler(t *testing.T) {
assert.True(t, isRouteAuthenticated(req))
}
-func TestSaveNotificationHandler(t *testing.T) {
- notification, _, err := notifier.SelectNotifier("email")
- assert.Nil(t, err)
- assert.False(t, notification.IsRunning())
-
- form := url.Values{}
- form.Add("enable", "on")
- form.Add("host", "smtp.emailer.com")
- form.Add("port", "587")
- form.Add("username", "exampleuser")
- form.Add("password", "password123")
- form.Add("var1", "info@betatude.com")
- form.Add("var2", "sendto@gmail.com")
- form.Add("api_key", "")
- form.Add("api_secret", "")
- form.Add("limits", "7")
- req, err := http.NewRequest("POST", "/settings/notifier/email", strings.NewReader(form.Encode()))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- assert.Nil(t, err)
- rr := httptest.NewRecorder()
- Router().ServeHTTP(rr, req)
- assert.Equal(t, 303, rr.Code)
- assert.True(t, isRouteAuthenticated(req))
- notification, _, err = notifier.SelectNotifier("email")
- assert.Nil(t, err)
- assert.True(t, notification.IsRunning())
-}
-
func TestViewNotificationSettingsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings", nil)
assert.Nil(t, err)
diff --git a/handlers/messages.go b/handlers/messages.go
index 26599df3..c7270536 100644
--- a/handlers/messages.go
+++ b/handlers/messages.go
@@ -16,7 +16,9 @@
package handlers
import (
+ "github.com/gorilla/mux"
"github.com/hunterlong/statup/core"
+ "github.com/hunterlong/statup/utils"
"net/http"
)
@@ -28,3 +30,18 @@ func messagesHandler(w http.ResponseWriter, r *http.Request) {
messages, _ := core.SelectMessages()
executeResponse(w, r, "messages.html", messages, nil)
}
+
+func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
+ if !IsAuthenticated(r) {
+ http.Redirect(w, r, "/", http.StatusSeeOther)
+ return
+ }
+ vars := mux.Vars(r)
+ id := utils.StringInt(vars["id"])
+ message, err := core.SelectMessage(id)
+ if err != nil {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ executeResponse(w, r, "message.html", message, nil)
+}
diff --git a/handlers/routes.go b/handlers/routes.go
index 3996c6fa..cf6d3200 100644
--- a/handlers/routes.go
+++ b/handlers/routes.go
@@ -69,6 +69,7 @@ func Router() *mux.Router {
// MESSAGES Routes
r.Handle("/messages", http.HandlerFunc(messagesHandler)).Methods("GET")
+ r.Handle("/message/{id}", http.HandlerFunc(viewMessageHandler)).Methods("GET")
// SETTINGS Routes
r.Handle("/settings", http.HandlerFunc(settingsHandler)).Methods("GET")
@@ -76,7 +77,6 @@ func Router() *mux.Router {
r.Handle("/settings/css", http.HandlerFunc(saveSASSHandler)).Methods("POST")
r.Handle("/settings/build", http.HandlerFunc(saveAssetsHandler)).Methods("GET")
r.Handle("/settings/delete_assets", http.HandlerFunc(deleteAssetsHandler)).Methods("GET")
- r.Handle("/settings/notifier/{method}", http.HandlerFunc(saveNotificationHandler)).Methods("POST")
r.Handle("/settings/notifier/{method}/test", http.HandlerFunc(testNotificationHandler)).Methods("POST")
r.Handle("/settings/export", http.HandlerFunc(exportHandler)).Methods("GET")
@@ -104,7 +104,6 @@ func Router() *mux.Router {
r.Handle("/api/services/{id}/ping", http.HandlerFunc(apiServicePingDataHandler)).Methods("GET")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceDeleteHandler)).Methods("DELETE")
- r.Handle("/api/service/{id}/failures", http.HandlerFunc(apiServiceFailuresHandler)).Methods("GET")
r.Handle("/api/checkin/{api}", http.HandlerFunc(apiCheckinHandler))
// API USER Routes
@@ -121,7 +120,7 @@ func Router() *mux.Router {
// API MESSAGES Routes
r.Handle("/api/messages", http.HandlerFunc(apiAllMessagesHandler)).Methods("GET")
- r.Handle("/api/messages", http.HandlerFunc(apiNotifierUpdateHandler)).Methods("POST")
+ r.Handle("/api/messages", http.HandlerFunc(apiMessageCreateHandler)).Methods("POST")
r.Handle("/api/messages/{id}", http.HandlerFunc(apiMessageGetHandler)).Methods("GET")
r.Handle("/api/messages/{id}", http.HandlerFunc(apiMessageUpdateHandler)).Methods("POST")
r.Handle("/api/messages/{id}", http.HandlerFunc(apiMessageDeleteHandler)).Methods("DELETE")
diff --git a/handlers/settings.go b/handlers/settings.go
index 039c4942..0aca41d1 100644
--- a/handlers/settings.go
+++ b/handlers/settings.go
@@ -135,70 +135,6 @@ func parseGet(r *http.Request) url.Values {
return r.Form
}
-func saveNotificationHandler(w http.ResponseWriter, r *http.Request) {
- var err error
- if !IsAuthenticated(r) {
- http.Redirect(w, r, "/", http.StatusSeeOther)
- return
- }
- form := parseForm(r)
- vars := mux.Vars(r)
- method := vars["method"]
- enabled := form.Get("enable")
- host := form.Get("host")
- port := int(utils.StringInt(form.Get("port")))
- username := form.Get("username")
- password := form.Get("password")
- var1 := form.Get("var1")
- var2 := form.Get("var2")
- apiKey := form.Get("api_key")
- apiSecret := form.Get("api_secret")
- limits := int(utils.StringInt(form.Get("limits")))
-
- notifer, notif, err := notifier.SelectNotifier(method)
- if err != nil {
- utils.Log(3, fmt.Sprintf("issue saving notifier %v: %v", method, err))
- executeResponse(w, r, "settings.html", core.CoreApp, "/settings")
- return
- }
-
- if host != "" {
- notifer.Host = host
- }
- if port != 0 {
- notifer.Port = port
- }
- if username != "" {
- notifer.Username = username
- }
- if password != "" && password != "##########" {
- notifer.Password = password
- }
- if var1 != "" {
- notifer.Var1 = var1
- }
- if var2 != "" {
- notifer.Var2 = var2
- }
- if apiKey != "" {
- notifer.ApiKey = apiKey
- }
- if apiSecret != "" {
- notifer.ApiSecret = apiSecret
- }
- if limits != 0 {
- notifer.Limits = limits
- }
- notifer.Enabled = types.NewNullBool(enabled == "on")
-
- _, err = notifier.Update(notif, notifer)
- if err != nil {
- utils.Log(3, fmt.Sprintf("issue updating notifier: %v", err))
- }
- notifier.OnSave(notifer.Method)
- executeResponse(w, r, "settings.html", core.CoreApp, "/settings")
-}
-
func testNotificationHandler(w http.ResponseWriter, r *http.Request) {
var err error
if !IsAuthenticated(r) {
diff --git a/source/js/main.js b/source/js/main.js
index 007c55c3..f7cffda8 100644
--- a/source/js/main.js
+++ b/source/js/main.js
@@ -185,7 +185,7 @@ $('form.ajax_form').on('submit', function() {
return
}
if (k.value === "on") {
- k.value = true
+ k.value = (k.value === "on")
}
if($.isNumeric(k.value)){
if (k.name !== "password") {
diff --git a/source/tmpl/message.html b/source/tmpl/message.html
index 862f54d7..d3502327 100644
--- a/source/tmpl/message.html
+++ b/source/tmpl/message.html
@@ -14,15 +14,14 @@
{{define "extra_scripts"}}
-
{{end}}
\ No newline at end of file
diff --git a/source/tmpl/messages.html b/source/tmpl/messages.html
index 8e48ce00..0ac5a110 100644
--- a/source/tmpl/messages.html
+++ b/source/tmpl/messages.html
@@ -45,15 +45,14 @@
{{define "extra_scripts"}}
-
{{end}}
\ No newline at end of file
diff --git a/types/failure.go b/types/failure.go
index 0cc3b374..e2359196 100644
--- a/types/failure.go
+++ b/types/failure.go
@@ -36,3 +36,15 @@ type FailureInterface interface {
Ago() string // Ago returns a human readable timestamp
ParseError() string // ParseError returns a human readable error for a service failure
}
+
+type FailSort []FailureInterface
+
+func (s FailSort) Len() int {
+ return len(s)
+}
+func (s FailSort) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+func (s FailSort) Less(i, j int) bool {
+ return s[i].Select().Id < s[j].Select().Id
+}
diff --git a/types/service.go b/types/service.go
index 672090f0..9eac994f 100644
--- a/types/service.go
+++ b/types/service.go
@@ -21,33 +21,33 @@ import (
// Service is the main struct for Services
type Service struct {
- Id int64 `gorm:"primary_key;column:id" json:"id"`
- Name string `gorm:"column:name" json:"name"`
- Domain string `gorm:"column:domain" json:"domain"`
- Expected NullString `gorm:"column:expected" json:"expected"`
- ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
- Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
- Type string `gorm:"column:check_type" json:"type"`
- Method string `gorm:"column:method" json:"method"`
- PostData NullString `gorm:"column:post_data" json:"post_data"`
- Port int `gorm:"not null;column:port" json:"port"`
- 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"`
- 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"`
- Latency float64 `gorm:"-" json:"latency"`
- PingTime float64 `gorm:"-" json:"ping_time"`
- Online24Hours float32 `gorm:"-" json:"online_24_hours"`
- AvgResponse string `gorm:"-" json:"avg_response"`
- Running chan bool `gorm:"-" json:"-"`
- Checkpoint time.Time `gorm:"-" json:"-"`
- SleepDuration time.Duration `gorm:"-" json:"-"`
- LastResponse string `gorm:"-" json:"-"`
- LastStatusCode int `gorm:"-" json:"status_code"`
- LastOnline time.Time `gorm:"-" json:"last_online"`
- Failures []*Failure `gorm:"-" json:"failures,omitempty"`
+ Id int64 `gorm:"primary_key;column:id" json:"id"`
+ Name string `gorm:"column:name" json:"name"`
+ Domain string `gorm:"column:domain" json:"domain"`
+ Expected NullString `gorm:"column:expected" json:"expected"`
+ ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
+ Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
+ Type string `gorm:"column:check_type" json:"type"`
+ Method string `gorm:"column:method" json:"method"`
+ PostData NullString `gorm:"column:post_data" json:"post_data"`
+ Port int `gorm:"not null;column:port" json:"port"`
+ 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"`
+ 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"`
+ Latency float64 `gorm:"-" json:"latency"`
+ PingTime float64 `gorm:"-" json:"ping_time"`
+ Online24Hours float32 `gorm:"-" json:"online_24_hours"`
+ AvgResponse string `gorm:"-" json:"avg_response"`
+ Running chan bool `gorm:"-" json:"-"`
+ Checkpoint time.Time `gorm:"-" json:"-"`
+ SleepDuration time.Duration `gorm:"-" json:"-"`
+ LastResponse string `gorm:"-" json:"-"`
+ LastStatusCode int `gorm:"-" json:"status_code"`
+ LastOnline time.Time `gorm:"-" json:"last_online"`
+ Failures []FailureInterface `gorm:"-" json:"failures,omitempty"`
}
type ServiceInterface interface {