package handler import ( "encoding/json" "strconv" "spider/internal/model" "spider/internal/notification" "spider/internal/store" "github.com/gin-gonic/gin" "gorm.io/datatypes" ) // NotificationHandler handles notification config CRUD. type NotificationHandler struct { store *store.Store manager *notification.Manager } // List handles GET /notification-configs func (h *NotificationHandler) List(c *gin.Context) { var configs []model.NotificationConfig if err := h.store.DB.Order("created_at DESC").Find(&configs).Error; err != nil { Fail(c, 500, err.Error()) return } OK(c, configs) } // Create handles POST /notification-configs func (h *NotificationHandler) Create(c *gin.Context) { var body struct { Name string `json:"name" binding:"required"` EventType string `json:"event_type" binding:"required"` Channel string `json:"channel" binding:"required"` Config map[string]string `json:"config"` Enabled bool `json:"enabled"` } if err := c.ShouldBindJSON(&body); err != nil { Fail(c, 400, err.Error()) return } configJSON, _ := json.Marshal(body.Config) cfg := model.NotificationConfig{ Name: body.Name, EventType: body.EventType, Channel: body.Channel, Config: datatypes.JSON(configJSON), Enabled: body.Enabled, } if err := h.store.DB.Create(&cfg).Error; err != nil { Fail(c, 500, err.Error()) return } LogAudit(h.store, c, "create", "notification", strconv.Itoa(int(cfg.ID)), gin.H{"name": cfg.Name}) OK(c, cfg) } // Update handles PUT /notification-configs/:id func (h *NotificationHandler) Update(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { Fail(c, 400, "invalid id") return } var existing model.NotificationConfig if err := h.store.DB.First(&existing, id).Error; err != nil { Fail(c, 404, "not found") return } var body struct { Name *string `json:"name"` EventType *string `json:"event_type"` Channel *string `json:"channel"` Config *map[string]string `json:"config"` Enabled *bool `json:"enabled"` } if err := c.ShouldBindJSON(&body); err != nil { Fail(c, 400, err.Error()) return } updates := map[string]any{} if body.Name != nil { updates["name"] = *body.Name } if body.EventType != nil { updates["event_type"] = *body.EventType } if body.Channel != nil { updates["channel"] = *body.Channel } if body.Config != nil { configJSON, _ := json.Marshal(*body.Config) updates["config"] = datatypes.JSON(configJSON) } if body.Enabled != nil { updates["enabled"] = *body.Enabled } h.store.DB.Model(&existing).Updates(updates) h.store.DB.First(&existing, id) OK(c, existing) } // Delete handles DELETE /notification-configs/:id func (h *NotificationHandler) Delete(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { Fail(c, 400, "invalid id") return } if err := h.store.DB.Delete(&model.NotificationConfig{}, id).Error; err != nil { Fail(c, 500, err.Error()) return } OK(c, gin.H{"message": "已删除"}) } // Test handles POST /notification-configs/:id/test func (h *NotificationHandler) Test(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { Fail(c, 400, "invalid id") return } var cfg model.NotificationConfig if err := h.store.DB.First(&cfg, id).Error; err != nil { Fail(c, 404, "not found") return } if err := h.manager.SendTest(cfg); err != nil { Fail(c, 500, err.Error()) return } OK(c, gin.H{"message": "测试通知已发送"}) }