package handlers import ( "context" "net/http" "time" "ezops/internal/models" "ezops/pkg/zabbix" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // ZabbixDSHandler Zabbix 数据源管理 handler // Logan.Li type ZabbixDSHandler struct { db *gorm.DB } // NewZabbixDSHandler 创建 Zabbix 数据源 handler func NewZabbixDSHandler(db *gorm.DB) *ZabbixDSHandler { return &ZabbixDSHandler{db: db} } // ============================================ // CRUD // ============================================ // List 数据源列表 // GET /api/v1/zabbix-datasources func (h *ZabbixDSHandler) List(c *gin.Context) { var sources []models.ZabbixDataSource if err := h.db.Order("is_default DESC, id ASC").Find(&sources).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败: " + err.Error()}) return } if sources == nil { sources = []models.ZabbixDataSource{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: sources}) } // Get 获取单个数据源 // GET /api/v1/zabbix-datasources/:id func (h *ZabbixDSHandler) Get(c *gin.Context) { id := c.Param("id") var ds models.ZabbixDataSource if err := h.db.First(&ds, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "数据源不存在"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: ds}) } // Create 创建数据源 // POST /api/v1/zabbix-datasources func (h *ZabbixDSHandler) Create(c *gin.Context) { var req models.CreateZabbixDSReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "参数错误: " + err.Error()}) return } if req.IsDefault { h.db.Model(&models.ZabbixDataSource{}).Where("is_default = ?", true).Update("is_default", false) } ds := models.ZabbixDataSource{ Name: req.Name, URL: req.URL, Username: req.Username, Password: req.Password, TrendsAfter: req.TrendsAfter, TrendsRange: req.TrendsRange, TrendsCacheTTL: req.TrendsCacheTTL, TrendsTimeout: req.TrendsTimeout, DirectDB: req.DirectDB, DisableAcknowledges: req.DisableAcknowledges, DisableDataAlignment: req.DisableDataAlignment, IsDefault: req.IsDefault, Status: 1, } if ds.TrendsCacheTTL <= 0 { ds.TrendsCacheTTL = 3600 } if ds.TrendsTimeout <= 0 { ds.TrendsTimeout = 30 } if err := h.db.Create(&ds).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "创建失败: " + err.Error()}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: ds, Message: "创建成功"}) } // Update 更新数据源 // PUT /api/v1/zabbix-datasources/:id func (h *ZabbixDSHandler) Update(c *gin.Context) { id := c.Param("id") var ds models.ZabbixDataSource if err := h.db.First(&ds, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "数据源不存在"}) return } var req models.UpdateZabbixDSReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "参数错误: " + err.Error()}) return } updates := map[string]interface{}{} if req.Name != nil { updates["name"] = *req.Name } if req.URL != nil { updates["url"] = *req.URL } if req.Username != nil { updates["username"] = *req.Username } if req.Password != nil && *req.Password != "" { updates["password"] = *req.Password } if req.TrendsAfter != nil { updates["trends_after"] = *req.TrendsAfter } if req.TrendsRange != nil { updates["trends_range"] = *req.TrendsRange } if req.TrendsCacheTTL != nil { updates["trends_cache_ttl"] = *req.TrendsCacheTTL } if req.TrendsTimeout != nil { updates["trends_timeout"] = *req.TrendsTimeout } if req.DirectDB != nil { updates["direct_db"] = *req.DirectDB } if req.DisableAcknowledges != nil { updates["disable_acknowledges"] = *req.DisableAcknowledges } if req.DisableDataAlignment != nil { updates["disable_data_alignment"] = *req.DisableDataAlignment } if req.IsDefault != nil { updates["is_default"] = *req.IsDefault if *req.IsDefault { h.db.Model(&models.ZabbixDataSource{}).Where("is_default = ? AND id != ?", true, id).Update("is_default", false) } } if req.Status != nil { updates["status"] = *req.Status } if len(updates) > 0 { if err := h.db.Model(&ds).Updates(updates).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "更新失败: " + err.Error()}) return } } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "更新成功"}) } // Delete 删除数据源 // DELETE /api/v1/zabbix-datasources/:id func (h *ZabbixDSHandler) Delete(c *gin.Context) { id := c.Param("id") if err := h.db.Delete(&models.ZabbixDataSource{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "删除失败: " + err.Error()}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "已删除"}) } // SetDefault 设为默认 // POST /api/v1/zabbix-datasources/:id/default func (h *ZabbixDSHandler) SetDefault(c *gin.Context) { id := c.Param("id") h.db.Model(&models.ZabbixDataSource{}).Where("is_default = ?", true).Update("is_default", false) if err := h.db.Model(&models.ZabbixDataSource{}).Where("id = ?", id).Update("is_default", true).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "设置失败: " + err.Error()}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "已设为默认"}) } // TestConnection 测试 Zabbix 连接 // POST /api/v1/zabbix-datasources/test func (h *ZabbixDSHandler) TestConnection(c *gin.Context) { var req models.TestZabbixDSReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "参数错误: " + err.Error()}) return } client := zabbix.NewClient(req.URL, req.Username, req.Password, zabbix.WithHTTPTimeout(10*time.Second), ) ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second) defer cancel() if err := client.Auth(ctx); err != nil { c.JSON(http.StatusOK, models.Response{ Code: 200, Data: map[string]interface{}{ "success": false, "message": "认证失败: " + err.Error(), }, }) return } token := client.GetAuthToken() c.JSON(http.StatusOK, models.Response{ Code: 200, Data: map[string]interface{}{ "success": true, "message": "连接成功,Zabbix 认证通过", "session_id": token, }, }) }