Files
aiops/backend/controller/server_v2.go
T
Logan.Li 83662487cb fix: 接通服务器V2排序链路
- 将排序参数从V2 Handler传递至Service与Repository

- 增加仓储分页排序与参数白名单测试
2026-07-26 23:38:06 +08:00

194 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package handlers_v2 provides thin HTTP handlers that delegate to service layer.
// This is the refactored version — handlers contain ONLY HTTP concerns:
// parse request → call service → return HTTP response.
package controller
import (
"net/http"
"strconv"
"ezops/dto"
"ezops/model"
"ezops/service"
"ezops/utils"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ━━━ Server Handler (v2 thin) ━━━━━━━━━━━━━━━━━━━━━━━━━━
// ServerHandlerV2 服务器处理器 — thin handler,委托给 ServerService
type ServerHandlerV2 struct {
svc *service.ServerService
db *gorm.DB // retained for audit logging until audit is extracted
}
func NewServerHandlerV2(svc *service.ServerService, db *gorm.DB) *ServerHandlerV2 {
return &ServerHandlerV2{svc: svc, db: db}
}
func (h *ServerHandlerV2) recordAudit(c *gin.Context, action, resource, resourceID string, status int, errMsg string) {
userID, _ := c.Get("userID")
username, _ := c.Get("username")
uid, _ := userID.(uint)
uname, _ := username.(string)
h.db.Create(&model.AuditLog{
UserID: &uid,
Username: uname,
IP: c.ClientIP(),
UserAgent: c.Request.UserAgent(),
Module: "server",
Action: action,
Resource: resource,
ResourceID: resourceID,
Status: status,
Error: errMsg,
})
}
func (h *ServerHandlerV2) ListServers(c *gin.Context) {
var query model.PageQuery
if err := c.ShouldBindQuery(&query); err != nil {
utils.BadRequest(c, "请求参数错误")
return
}
status := c.Query("status")
regionID := c.Query("region_id")
list, total, err := h.svc.ListServers(
query.Keyword, status, regionID, query.Sort, query.Order, query.Page, query.PageSize,
)
if err != nil {
utils.InternalError(c, "查询失败")
return
}
utils.ListResponse(c, list, total)
}
func (h *ServerHandlerV2) GetServer(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
server, err := h.svc.GetServer(uint(id))
if err != nil {
utils.NotFound(c, "服务器不存在")
return
}
utils.OK(c, server)
}
func (h *ServerHandlerV2) CreateServer(c *gin.Context) {
var req dto.CreateServerRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "请求参数错误: "+err.Error())
return
}
server, err := h.svc.CreateServer(&req)
if err != nil {
utils.InternalError(c, "创建失败: "+err.Error())
return
}
h.recordAudit(c, "create", server.Hostname+" ("+server.IP+")", strconv.Itoa(int(server.ID)), 1, "")
utils.OK(c, server)
}
func (h *ServerHandlerV2) UpdateServer(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var req dto.UpdateServerRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, "请求参数错误: "+err.Error())
return
}
if err := h.svc.UpdateServer(uint(id), &req); err != nil {
utils.InternalError(c, "更新失败: "+err.Error())
return
}
server, _ := h.svc.GetServer(uint(id))
h.recordAudit(c, "update", server.Hostname+" ("+server.IP+")", strconv.Itoa(int(server.ID)), 1, "")
utils.OK(c, server)
}
func (h *ServerHandlerV2) DeleteServer(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
server, err := h.svc.GetServer(uint(id))
if err != nil {
utils.NotFound(c, "服务器不存在")
return
}
// 清理关联数据
h.db.Unscoped().Where("hostname = ?", server.Hostname).Delete(&model.AgentReport{})
h.db.Unscoped().Where("hostname = ?", server.Hostname).Delete(&model.MetricsAggregate{})
if err := h.svc.DeleteServer(uint(id)); err != nil {
utils.InternalError(c, "删除失败")
return
}
h.recordAudit(c, "delete", server.Hostname+" ("+server.IP+")", strconv.Itoa(int(server.ID)), 1, "")
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "服务器已彻底删除"})
}
func (h *ServerHandlerV2) GetServerStats(c *gin.Context) {
stats, err := h.svc.GetDashboardStats()
if err != nil {
utils.InternalError(c, "获取统计失败")
return
}
utils.OK(c, stats.ServerStats)
}
// BatchCreateServers / BatchDeleteServers — 暂时保留原始逻辑(复杂批量操作待后续迁移)
func (h *ServerHandlerV2) BatchCreateServers(c *gin.Context) {
// 暂时委托给原始 handler 逻辑(从 server.go 复制)
var servers []model.Server
if err := c.ShouldBindJSON(&servers); err != nil {
utils.BadRequest(c, "请求参数错误")
return
}
for i := range servers {
if servers[i].Port == 0 {
servers[i].Port = 22
}
if servers[i].Username == "" {
servers[i].Username = "root"
}
if servers[i].Status == "" {
servers[i].Status = "stopped"
}
}
if err := h.db.Create(&servers).Error; err != nil {
utils.InternalError(c, "批量创建失败")
return
}
utils.OK(c, servers)
}
func (h *ServerHandlerV2) BatchDeleteServers(c *gin.Context) {
// 前端发 { ids: [...] },对齐格式(原期望裸 []uint 导致解析失败 400) // Logan.Li
var req struct {
IDs []uint `json:"ids"`
}
if err := c.ShouldBindJSON(&req); err != nil || len(req.IDs) == 0 {
utils.BadRequest(c, "请求参数错误")
return
}
ids := req.IDs
// 清理关联数据
for _, id := range ids {
var s model.Server
if err := h.db.First(&s, id).Error; err == nil {
h.db.Unscoped().Where("hostname = ?", s.Hostname).Delete(&model.AgentReport{})
h.db.Unscoped().Where("hostname = ?", s.Hostname).Delete(&model.MetricsAggregate{})
}
}
h.db.Unscoped().Delete(&model.Server{}, ids)
utils.OK(c, gin.H{"deleted": len(ids)})
}