package api import ( "database/sql" "net/http" "strconv" "strings" ) func (s *Server) alertRoutes(w http.ResponseWriter, r *http.Request, path string) { if path == "alerts" && r.Method == "GET" { scopes, ok := s.scopeIndex(w, r) if !ok { return } a, e := s.store.Alerts() if e != nil { fail(w, 500, "cannot read alerts") return } filtered := a[:0] for _, alert := range a { if scopes == nil || scopes.MatchesResource(alert.ResourceID, requestScope(r)) { filtered = append(filtered, alert) } } respond(w, 200, filtered) return } if path == "alerts/check" && r.Method == "POST" { if e := s.alerts.Check(r.Context()); e != nil { fail(w, 500, "alert check failed") return } respond(w, 200, map[string]bool{"ok": true}) return } if path == "alerts/settings" && (r.Method == "GET" || r.Method == "PUT") { c, e := s.store.AlertSettings() if e != nil { fail(w, 500, "cannot read alert settings") return } if r.Method == "PUT" { var body struct { WebhookEnabled *bool `json:"webhookEnabled"` WebhookURL string `json:"webhookURL"` WebhookSecret string `json:"webhookSecret"` ClearWebhook bool `json:"clearWebhook"` AuthFailureThreshold *int `json:"authFailureThreshold"` AuthFailureWindowSeconds *int `json:"authFailureWindowSeconds"` CertificateReminderDays *int `json:"certificateReminderDays"` HasWebhookURL bool `json:"hasWebhookURL"` HasWebhookSecret bool `json:"hasWebhookSecret"` } if !decode(w, r, &body) { return } if body.WebhookEnabled != nil { c.WebhookEnabled = *body.WebhookEnabled } if body.WebhookURL != "" { c.WebhookURL = body.WebhookURL } if body.WebhookSecret != "" { c.WebhookSecret = body.WebhookSecret } if body.ClearWebhook { c.WebhookURL = "" c.WebhookSecret = "" c.WebhookEnabled = false } if body.AuthFailureThreshold != nil { c.AuthFailureThreshold = *body.AuthFailureThreshold } if body.AuthFailureWindowSeconds != nil { c.AuthFailureWindowSeconds = *body.AuthFailureWindowSeconds } if body.CertificateReminderDays != nil { c.CertificateReminderDays = *body.CertificateReminderDays } if e = c.Validate(); e != nil { fail(w, 400, e.Error()) return } if e = s.store.SaveAlertSettings(c); e != nil { fail(w, 500, "cannot save alert settings") return } s.store.Event("", source(r), "alert_settings_updated", "") } respond(w, 200, map[string]any{"webhookEnabled": c.WebhookEnabled, "webhookURL": "", "webhookSecret": "", "hasWebhookURL": c.WebhookURL != "", "hasWebhookSecret": c.WebhookSecret != "", "authFailureThreshold": c.AuthFailureThreshold, "authFailureWindowSeconds": c.AuthFailureWindowSeconds, "certificateReminderDays": c.CertificateReminderDays}) return } parts := strings.Split(path, "/") if len(parts) == 3 && parts[0] == "alerts" && parts[2] == "ack" && r.Method == "POST" { id, e := strconv.ParseInt(parts[1], 10, 64) if e != nil || id < 1 { fail(w, 400, "invalid alert ID") return } e = s.store.AcknowledgeAlert(id) if e == sql.ErrNoRows { fail(w, 404, "alert not found") return } if e != nil { fail(w, 500, "cannot acknowledge alert") return } s.store.Event("", source(r), "alert_acknowledged", parts[1]) respond(w, 200, map[string]bool{"ok": true}) return } fail(w, 405, "method not allowed") }