2024-02-11 19:28:00 +00:00
|
|
|
package handlers
|
2024-02-10 11:59:58 +00:00
|
|
|
|
|
|
|
import (
|
2024-02-22 16:29:17 +00:00
|
|
|
"context"
|
2024-02-10 11:59:58 +00:00
|
|
|
"net/http"
|
2024-02-22 16:29:17 +00:00
|
|
|
"time"
|
2024-02-10 11:59:58 +00:00
|
|
|
|
2024-02-27 11:04:05 +00:00
|
|
|
"code.tjo.space/mentos1386/zdravko/database/models"
|
2024-02-22 16:29:17 +00:00
|
|
|
"code.tjo.space/mentos1386/zdravko/internal/services"
|
2024-02-12 10:22:14 +00:00
|
|
|
"code.tjo.space/mentos1386/zdravko/web/templates/components"
|
2024-02-20 10:24:04 +00:00
|
|
|
"github.com/labstack/echo/v4"
|
2024-02-10 11:59:58 +00:00
|
|
|
)
|
|
|
|
|
2024-02-12 13:20:38 +00:00
|
|
|
type IndexData struct {
|
|
|
|
*components.Base
|
2024-05-16 20:15:14 +00:00
|
|
|
Checks map[string]ChecksAndStatus
|
|
|
|
ChecksLength int
|
2024-05-17 19:54:14 +00:00
|
|
|
TimeRange string
|
|
|
|
Status models.CheckStatus
|
2024-02-12 13:20:38 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
type Check struct {
|
2024-02-29 22:42:56 +00:00
|
|
|
Name string
|
2024-03-03 14:28:25 +00:00
|
|
|
Group string
|
2024-05-16 20:15:14 +00:00
|
|
|
Status models.CheckStatus
|
2024-02-29 22:42:56 +00:00
|
|
|
History *History
|
2024-02-12 13:20:38 +00:00
|
|
|
}
|
|
|
|
|
2024-03-04 13:20:01 +00:00
|
|
|
type HistoryItem struct {
|
2024-05-16 20:15:14 +00:00
|
|
|
Status models.CheckStatus
|
2024-03-04 13:20:01 +00:00
|
|
|
Date time.Time
|
|
|
|
}
|
|
|
|
|
2024-02-22 16:29:17 +00:00
|
|
|
type History struct {
|
2024-03-04 13:20:01 +00:00
|
|
|
List []HistoryItem
|
2024-05-17 19:54:14 +00:00
|
|
|
Uptime float64
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
type ChecksAndStatus struct {
|
2024-05-17 19:54:14 +00:00
|
|
|
Status models.CheckStatus
|
2024-05-16 20:15:14 +00:00
|
|
|
Checks []*Check
|
2024-03-04 13:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getDateString(date time.Time) string {
|
2024-02-29 22:57:23 +00:00
|
|
|
return date.UTC().Format("2006-01-02T15:04:05")
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
func getHistory(history []*models.CheckHistory, period time.Duration, buckets int) *History {
|
|
|
|
historyMap := map[string]models.CheckStatus{}
|
2024-05-17 19:54:14 +00:00
|
|
|
numOfSuccess := 0.0
|
|
|
|
numTotal := 0.0
|
2024-02-22 16:29:17 +00:00
|
|
|
|
2024-02-29 22:42:56 +00:00
|
|
|
for i := 0; i < buckets; i++ {
|
2024-03-04 13:20:01 +00:00
|
|
|
dateString := getDateString(time.Now().Add(period * time.Duration(-i)).Truncate(period))
|
2024-05-16 20:15:14 +00:00
|
|
|
historyMap[dateString] = models.CheckUnknown
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, _history := range history {
|
2024-03-04 13:20:01 +00:00
|
|
|
dateString := getDateString(_history.CreatedAt.Time.Truncate(period))
|
2024-02-22 16:29:17 +00:00
|
|
|
|
2024-02-29 22:42:56 +00:00
|
|
|
// Skip if not part of the "buckets"
|
2024-03-04 13:20:01 +00:00
|
|
|
if _, ok := historyMap[dateString]; !ok {
|
2024-02-22 16:29:17 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
numTotal++
|
2024-05-16 20:15:14 +00:00
|
|
|
if _history.Status == models.CheckSuccess {
|
2024-02-22 16:29:17 +00:00
|
|
|
numOfSuccess++
|
|
|
|
}
|
|
|
|
|
2024-02-29 22:42:56 +00:00
|
|
|
// skip if it is already set to failure
|
2024-05-16 20:15:14 +00:00
|
|
|
if historyMap[dateString] == models.CheckFailure {
|
2024-02-22 16:29:17 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-03-04 13:20:01 +00:00
|
|
|
// FIXME: This is wrong! As we can have multiple checks in dateString.
|
|
|
|
// We should look at only the newest one.
|
|
|
|
historyMap[dateString] = _history.Status
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-03-04 13:20:01 +00:00
|
|
|
historyItems := make([]HistoryItem, buckets)
|
2024-02-29 22:42:56 +00:00
|
|
|
for i := 0; i < buckets; i++ {
|
2024-03-04 13:20:01 +00:00
|
|
|
date := time.Now().Add(period * time.Duration(-buckets+i+1)).Truncate(period)
|
|
|
|
datestring := getDateString(date)
|
|
|
|
historyItems[i] = HistoryItem{
|
|
|
|
Status: historyMap[datestring],
|
|
|
|
Date: date,
|
|
|
|
}
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-05-17 19:54:14 +00:00
|
|
|
uptime := 0.0
|
2024-02-22 19:20:34 +00:00
|
|
|
if numTotal > 0 {
|
2024-05-17 19:54:14 +00:00
|
|
|
uptime = 100.0 * numOfSuccess / numTotal
|
2024-02-22 19:20:34 +00:00
|
|
|
}
|
|
|
|
|
2024-02-22 16:29:17 +00:00
|
|
|
return &History{
|
2024-03-04 13:20:01 +00:00
|
|
|
List: historyItems,
|
2024-02-29 22:42:56 +00:00
|
|
|
Uptime: uptime,
|
2024-02-12 13:20:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-20 10:24:04 +00:00
|
|
|
func (h *BaseHandler) Index(c echo.Context) error {
|
2024-02-22 16:29:17 +00:00
|
|
|
ctx := context.Background()
|
2024-05-16 20:15:14 +00:00
|
|
|
checks, err := services.GetChecks(ctx, h.db)
|
2024-02-22 16:29:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
timeRange := c.QueryParam("time-range")
|
2024-02-29 22:42:56 +00:00
|
|
|
if timeRange != "48hours" && timeRange != "90days" && timeRange != "90minutes" {
|
2024-02-22 16:29:17 +00:00
|
|
|
timeRange = "90days"
|
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
overallStatus := models.CheckUnknown
|
|
|
|
statusByGroup := make(map[string]models.CheckStatus)
|
2024-02-22 16:29:17 +00:00
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
checksWithHistory := make([]*Check, len(checks))
|
|
|
|
for i, check := range checks {
|
|
|
|
history, err := services.GetCheckHistoryForCheck(ctx, h.db, check.Id)
|
2024-02-27 11:04:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-02-29 22:42:56 +00:00
|
|
|
var historyResult *History
|
|
|
|
switch timeRange {
|
|
|
|
case "48hours":
|
|
|
|
historyResult = getHistory(history, time.Hour, 48)
|
|
|
|
case "90days":
|
|
|
|
historyResult = getHistory(history, time.Hour*24, 90)
|
|
|
|
case "90minutes":
|
|
|
|
historyResult = getHistory(history, time.Minute, 90)
|
|
|
|
}
|
2024-02-22 16:29:17 +00:00
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
if statusByGroup[check.Group] == "" {
|
|
|
|
statusByGroup[check.Group] = models.CheckUnknown
|
2024-03-04 13:20:01 +00:00
|
|
|
}
|
|
|
|
|
2024-02-29 22:42:56 +00:00
|
|
|
status := historyResult.List[len(historyResult.List)-1]
|
2024-05-16 20:15:14 +00:00
|
|
|
if status.Status == models.CheckSuccess {
|
|
|
|
if overallStatus == models.CheckUnknown {
|
2024-03-04 13:20:01 +00:00
|
|
|
overallStatus = status.Status
|
|
|
|
}
|
2024-05-16 20:15:14 +00:00
|
|
|
if statusByGroup[check.Group] == models.CheckUnknown {
|
|
|
|
statusByGroup[check.Group] = status.Status
|
2024-03-04 13:20:01 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-16 20:15:14 +00:00
|
|
|
if status.Status != models.CheckSuccess && status.Status != models.CheckUnknown {
|
2024-03-04 13:20:01 +00:00
|
|
|
overallStatus = status.Status
|
2024-05-16 20:15:14 +00:00
|
|
|
statusByGroup[check.Group] = status.Status
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
checksWithHistory[i] = &Check{
|
|
|
|
Name: check.Name,
|
|
|
|
Group: check.Group,
|
2024-03-04 13:20:01 +00:00
|
|
|
Status: status.Status,
|
2024-02-29 22:42:56 +00:00
|
|
|
History: historyResult,
|
2024-02-22 16:29:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-16 20:15:14 +00:00
|
|
|
checksByGroup := map[string]ChecksAndStatus{}
|
|
|
|
for _, check := range checksWithHistory {
|
|
|
|
checksByGroup[check.Group] = ChecksAndStatus{
|
2024-05-17 19:54:14 +00:00
|
|
|
Status: statusByGroup[check.Group],
|
2024-05-16 20:15:14 +00:00
|
|
|
Checks: append(checksByGroup[check.Group].Checks, check),
|
2024-03-04 13:20:01 +00:00
|
|
|
}
|
2024-03-03 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
2024-04-28 14:23:41 +00:00
|
|
|
c.Response().Header().Set("Cache-Control", "max-age=10")
|
|
|
|
|
2024-02-20 10:24:04 +00:00
|
|
|
return c.Render(http.StatusOK, "index.tmpl", &IndexData{
|
2024-02-12 13:20:38 +00:00
|
|
|
Base: &components.Base{
|
2024-02-15 22:47:56 +00:00
|
|
|
NavbarActive: GetPageByTitle(Pages, "Status"),
|
|
|
|
Navbar: Pages,
|
2024-02-12 13:20:38 +00:00
|
|
|
},
|
2024-05-17 19:54:14 +00:00
|
|
|
Checks: checksByGroup,
|
2024-03-03 14:28:25 +00:00
|
|
|
TimeRange: timeRange,
|
|
|
|
Status: overallStatus,
|
2024-02-12 10:22:14 +00:00
|
|
|
})
|
2024-02-10 11:59:58 +00:00
|
|
|
}
|