package handlers import ( "errors" "strconv" "github.com/gin-gonic/gin" "git.netcell-it.de/projekte/edgeguard-native/internal/handlers/response" "git.netcell-it.de/projekte/edgeguard-native/internal/services/alerts" "git.netcell-it.de/projekte/edgeguard-native/internal/services/audit" ) // AlertsHandler exposes: // // GET /api/v1/alerts/channels // POST /api/v1/alerts/channels // PUT /api/v1/alerts/channels/:id // DELETE /api/v1/alerts/channels/:id // POST /api/v1/alerts/test — Test-Event in alle aktiven Channels // GET /api/v1/alerts/events?limit=N — History type AlertsHandler struct { Service *alerts.Service Audit *audit.Repo NodeID string } func NewAlertsHandler(s *alerts.Service, a *audit.Repo, nodeID string) *AlertsHandler { return &AlertsHandler{Service: s, Audit: a, NodeID: nodeID} } func (h *AlertsHandler) Register(rg *gin.RouterGroup) { g := rg.Group("/alerts") g.GET("/channels", h.ListChannels) g.POST("/channels", h.CreateChannel) g.PUT("/channels/:id", h.UpdateChannel) g.DELETE("/channels/:id", h.DeleteChannel) g.POST("/test", h.TestFire) g.GET("/events", h.ListEvents) } func (h *AlertsHandler) ListChannels(c *gin.Context) { out, err := h.Service.ListChannels(c.Request.Context()) if err != nil { response.Internal(c, err) return } response.OK(c, gin.H{"channels": out}) } func (h *AlertsHandler) CreateChannel(c *gin.Context) { var req alerts.Channel if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, err) return } out, err := h.Service.CreateChannel(c.Request.Context(), req) if err != nil { response.Internal(c, err) return } _ = h.Audit.Log(c.Request.Context(), actorOf(c), "alert.channel.create", out.Name, out, h.NodeID) response.Created(c, out) } func (h *AlertsHandler) UpdateChannel(c *gin.Context) { id, ok := parseID(c) if !ok { return } var req alerts.Channel if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, err) return } out, err := h.Service.UpdateChannel(c.Request.Context(), id, req) if err != nil { if errors.Is(err, alerts.ErrNotFound) { response.NotFound(c, err) return } response.Internal(c, err) return } _ = h.Audit.Log(c.Request.Context(), actorOf(c), "alert.channel.update", out.Name, out, h.NodeID) response.OK(c, out) } func (h *AlertsHandler) DeleteChannel(c *gin.Context) { id, ok := parseID(c) if !ok { return } if err := h.Service.DeleteChannel(c.Request.Context(), id); err != nil { if errors.Is(err, alerts.ErrNotFound) { response.NotFound(c, err) return } response.Internal(c, err) return } _ = h.Audit.Log(c.Request.Context(), actorOf(c), "alert.channel.delete", strconv.FormatInt(id, 10), gin.H{"id": id}, h.NodeID) response.NoContent(c) } func (h *AlertsHandler) TestFire(c *gin.Context) { ev, err := h.Service.Fire(c.Request.Context(), "test", alerts.SeverityInfo, "EdgeGuard-Test-Alert", "Dies ist ein Test-Event. Wenn du das siehst, funktionieren deine Alert-Channels.") if err != nil { response.Internal(c, err) return } _ = h.Audit.Log(c.Request.Context(), actorOf(c), "alert.test", "test", ev, h.NodeID) response.OK(c, ev) } func (h *AlertsHandler) ListEvents(c *gin.Context) { limit := 100 if v := c.Query("limit"); v != "" { if n, err := strconv.Atoi(v); err == nil { limit = n } } out, err := h.Service.ListEvents(c.Request.Context(), limit) if err != nil { response.Internal(c, err) return } response.OK(c, gin.H{"events": out}) }