chore: 初始化仓库基线(AGENTS.md、git 规范、敏感文件排除)
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user