package handler import ( "encoding/json" "net/http" "strings" "silk-server-go/internal/middleware" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // RegisterUserRoutes 注册用户管理路由(均需 user:manage 权限) func RegisterUserRoutes(rg *gin.RouterGroup, db *gorm.DB) { perm := middleware.RequirePermission(db, "user:manage") rg.GET("/users", perm, listUsers(db)) rg.GET("/users/:id", perm, getUser(db)) rg.PATCH("/users/:id", perm, updateUser(db)) } // toUserPublic 将 User 转为公开信息(不含密码哈希) func toUserPublic(u model.User) gin.H { return gin.H{ "id": u.ID, "username": u.Username, "email": u.Email, "fullName": u.FullName, "role": u.Role, "active": u.Active, "createdAt": u.CreatedAt, } } // listUsers 用户列表 func listUsers(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var users []model.User db.Select("id", "username", "email", "full_name", "role", "active", "created_at"). Order("created_at DESC").Find(&users) result := make([]gin.H, 0, len(users)) for _, u := range users { result = append(result, toUserPublic(u)) } c.JSON(http.StatusOK, result) } } // getUser 用户详情 func getUser(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") var user model.User if db.Select("id", "username", "email", "full_name", "role", "active", "created_at"). Where("id = ?", id).First(&user).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) return } c.JSON(http.StatusOK, toUserPublic(user)) } } // updateUser 更新用户(角色/active/fullName/email),记录审计日志 func updateUser(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") // 先检查用户是否存在 var user model.User if db.Where("id = ?", id).First(&user).Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) return } var body map[string]interface{} if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 只允许更新 fullName/email/role/active updates := make(map[string]interface{}) if v, ok := body["fullName"]; ok { updates["full_name"] = v } if v, ok := body["email"]; ok { updates["email"] = v } if v, ok := body["role"]; ok { roleStr, _ := v.(string) valid := false for _, r := range model.AllRoles { if r == roleStr { valid = true break } } if !valid { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的角色,可选:" + strings.Join(model.AllRoles, ", ")}) return } updates["role"] = v } if v, ok := body["active"]; ok { updates["active"] = v } if len(updates) > 0 { db.Model(&model.User{}).Where("id = ?", id).Updates(updates) } // 记录审计日志 var actorID, actorName *string if u, ok := c.Get("user"); ok { if userMap, ok := u.(map[string]interface{}); ok { if sub, ok := userMap["sub"].(string); ok { s := sub actorID = &s } if uname, ok := userMap["username"].(string); ok { s := uname actorName = &s } } } action := "update" description := "user updated" if _, ok := body["role"]; ok { action = "role_change" if r, ok := body["role"].(string); ok { description = "role changed to " + r } } res := "users" tid := id metaBytes, _ := json.Marshal(body) recordAudit(db, &model.AuditLog{ UserID: actorID, Username: actorName, Action: action, Resource: &res, TargetID: &tid, Description: &description, Metadata: metaBytes, }) // 返回更新后的用户 db.Select("id", "username", "email", "full_name", "role", "active", "created_at"). Where("id = ?", id).First(&user) c.JSON(http.StatusOK, toUserPublic(user)) } }