Files

155 lines
3.8 KiB
Go

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))
}
}