package handlers import ( "context" "fmt" "net/http" "strconv" "strings" "time" "crowdsec-dashy/internal/crowdsec" ) // AlertsHandler manages the alerts page and its POST actions. type AlertsHandler struct { deps Deps } func NewAlertsHandler(deps Deps) *AlertsHandler { return &AlertsHandler{deps: deps} } // AlertsData is passed to the alerts template. type AlertsData struct { PageData Alerts []crowdsec.Alert Filter crowdsec.AlertFilter } // List renders the alerts list. func (h *AlertsHandler) List(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second) defer cancel() filter := crowdsec.AlertFilter{ Limit: 200, Scenario: r.URL.Query().Get("scenario"), IP: r.URL.Query().Get("ip"), Since: r.URL.Query().Get("since"), } alerts, err := h.deps.LAPI.ListAlerts(ctx, filter) if err != nil { h.deps.Renderer.RenderError(w, http.StatusBadGateway, "failed to fetch alerts") return } pd := NewPageData(r, "Alerts", h.deps.CLIAvailable, h.deps.PollInterval) if f := readFlash(r); f.Message != "" { pd.Flash = f } h.deps.Renderer.Render(w, "alerts", AlertsData{ PageData: pd, Alerts: alerts, Filter: filter, }) } // Delete processes alert deletion (POST; `id` field may repeat for bulk). func (h *AlertsHandler) Delete(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, 4096) if err := r.ParseForm(); err != nil { flashRedirect(w, r, "/alerts", "error", "invalid form data") return } if !checkCSRF(r) { http.Error(w, "forbidden", http.StatusForbidden) return } ids := r.Form["id"] if len(ids) == 0 { flashRedirect(w, r, "/alerts", "error", "no alert selected") return } ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second) defer cancel() var errs []string deleted := 0 for _, s := range ids { id, err := strconv.ParseInt(s, 10, 64) if err != nil || id <= 0 { errs = append(errs, fmt.Sprintf("invalid id: %q", s)) continue } if err := h.deps.LAPI.DeleteAlert(ctx, id); err != nil { errs = append(errs, fmt.Sprintf("id %d: %v", id, err)) continue } deleted++ } if len(errs) > 0 { flashRedirect(w, r, "/alerts", "error", strings.Join(errs, "; ")) return } flashRedirect(w, r, "/alerts", "success", fmt.Sprintf("%d alert(s) deleted", deleted)) }