diff --git a/handlers/api.go b/handlers/api.go index a564bd2e..a306dfbb 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -167,7 +167,9 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht case *downtimes.Downtime: objName = "downtime" objId = v.Id - + case *DowntimeService: + objName = "downtime_with_service" + objId = v.Id default: objName = fmt.Sprintf("%T", v) } diff --git a/handlers/downtimes.go b/handlers/downtimes.go index 3a451684..c9f26670 100644 --- a/handlers/downtimes.go +++ b/handlers/downtimes.go @@ -7,6 +7,7 @@ import ( "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "net/http" + "net/url" "time" ) @@ -21,10 +22,75 @@ func findDowntime(r *http.Request) (*downtimes.Downtime, error) { return downtime, nil } +func convertToMap(query url.Values) map[string]string { + vars := make(map[string]string) + if query.Get("start") != "" { + vars["start"] = query.Get("start") + } + if query.Get("end") != "" { + vars["end"] = query.Get("end") + } + if query.Get("sub_status") != "" { + vars["sub_status"] = query.Get("sub_status") + } + if query.Get("service_id") != "" { + vars["service_id"] = query.Get("service_id") + } + if query.Get("type") != "" { + vars["type"] = query.Get("type") + } + if query.Get("skip") != "" { + vars["skip"] = query.Get("skip") + } + if query.Get("count") != "" { + vars["count"] = query.Get("count") + } + return vars +} + +type DowntimeService struct { + Id int64 `gorm:"primary_key;column:id" json:"id"` + Service *services.Service `gorm:"foreignKey:service" json:"service"` + ServiceId int64 `gorm:"index;column:service" json:"service_id"` + SubStatus string `gorm:"column:sub_status" json:"sub_status"` + Failures int `gorm:"column:failures" json:"failures"` + Start *time.Time `gorm:"index;column:start" json:"start"` + End *time.Time `gorm:"column:end" json:"end"` + Type string `gorm:"default:'auto';column:type" json:"type"` +} + +func apiAllDowntimes(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + vars := convertToMap(query) + downtime, err := downtimes.FindAll(vars) + var downtimeWithService []DowntimeService + servicesMap := services.All() + if downtime == nil { + sendJsonAction(downtimeWithService, "fetch", w, r) + return + } + for _, dtime := range *downtime { + var downtimeWithServiceVar DowntimeService + downtimeWithServiceVar.Id = dtime.Id + downtimeWithServiceVar.ServiceId = dtime.ServiceId + downtimeWithServiceVar.SubStatus = dtime.SubStatus + downtimeWithServiceVar.Failures = dtime.Failures + downtimeWithServiceVar.Start = dtime.Start + downtimeWithServiceVar.End = dtime.End + downtimeWithServiceVar.Type = dtime.Type + downtimeWithServiceVar.Service = servicesMap[dtime.ServiceId] + downtimeWithService = append(downtimeWithService, downtimeWithServiceVar) + } + if err != nil { + sendErrorJson(err, w, r) + return + } + sendJsonAction(downtimeWithService, "fetch", w, r) +} + func apiAllDowntimesForServiceHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) serviceId := utils.ToInt(vars["service_id"]) - ninetyDaysAgo := time.Now().Add(time.Duration(-90*24) * time.Hour) downtime, err := downtimes.FindByService(serviceId, ninetyDaysAgo, time.Now()) diff --git a/handlers/routes.go b/handlers/routes.go index cf070068..04dae630 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -193,6 +193,7 @@ func Router() *mux.Router { //r.Handle("/checkin/{api}", http.HandlerFunc(checkinHitHandler)) // API DOWNTIME Routes + api.Handle("/api/downtimes", authenticated(apiAllDowntimes, false)).Methods("GET") api.Handle("/api/service/{service_id}/downtimes", authenticated(apiAllDowntimesForServiceHandler, false)).Methods("GET") api.Handle("/api/downtimes", authenticated(apiCreateDowntimeHandler, false)).Methods("POST") api.Handle("/api/downtimes/{id}", authenticated(apiDowntimeHandler, false)).Methods("GET") diff --git a/types/downtimes/database.go b/types/downtimes/database.go index 0d0f1941..addcee4d 100644 --- a/types/downtimes/database.go +++ b/types/downtimes/database.go @@ -3,6 +3,7 @@ package downtimes import ( "fmt" "github.com/statping/statping/database" + "strconv" "time" ) @@ -58,6 +59,67 @@ func FindByService(service int64, start time.Time, end time.Time) (*[]Downtime, return &downtime, q.Error() } +func ConvertToUnixTime(str string) (time.Time, error) { + i, err := strconv.ParseInt(str, 10, 64) + var t time.Time + if err != nil { + return t, err + } + tm := time.Unix(i, 0) + return tm, nil +} + +func FindAll(vars map[string]string) (*[]Downtime, error) { + var downtime []Downtime + var start time.Time + var end time.Time + st, err1 := vars["start"] + en, err2 := vars["end"] + startInt, err := strconv.ParseInt(st, 10, 64) + endInt, err := strconv.ParseInt(en, 10, 64) + if err1 && err2 && (endInt > startInt) { + start, err = ConvertToUnixTime(vars["start"]) + if err != nil { + return &downtime, err + } + end, err = ConvertToUnixTime(vars["end"]) + if err != nil { + return &downtime, err + } + } else { + ninetyDaysAgo := time.Now().Add(time.Duration(-90*24) * time.Hour) + start = ninetyDaysAgo + end = time.Now() + } + q := db.Where("start BETWEEN ? AND ?", start, end) + if subStatusVar, subStatusErr := vars["sub_status"]; subStatusErr { + q = q.Where("sub_status = ?", subStatusVar) + } + if serviceIdVar, serviceIdErr := vars["service_id"]; serviceIdErr { + q = q.Where("service = ?", serviceIdVar) + } + if typeVar, typeErr := vars["type"]; typeErr { + q = q.Where("type = ?", typeVar) + } + var count int64 + if countVar, countErr := vars["count"]; countErr { + count, err = strconv.ParseInt(countVar, 10, 64) + if count > 100 { + count = 100 + } + } else { + count = 20 + } + var skip int64 + if skipVar, err6 := vars["skip"]; err6 { + skip, err = strconv.ParseInt(skipVar, 10, 64) + } else { + skip = 0 + } + q = q.Order("start DESC") + q = q.Limit((int)(count)).Offset((int)(skip)).Find(&downtime) + return &downtime, q.Error() +} func (c *Downtime) Create() error { q := db.Create(c) return q.Error()