206 lines
5.7 KiB
Go
206 lines
5.7 KiB
Go
package handlers
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"strconv"
|
||
"time"
|
||
|
||
"go.mongodb.org/mongo-driver/v2/bson"
|
||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||
|
||
"yh_web/server/config"
|
||
"yh_web/server/models"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
const customRoleIDStart = 1000 // 自定义角色 role_id 从此值起
|
||
|
||
// GetRolePermissionsList 返回所有角色及其权限(含预定义与自定义)
|
||
func GetRolePermissionsList(c *gin.Context) {
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
coll := config.GetDB(config.DBName).Collection("role_permissions")
|
||
cursor, err := coll.Find(ctx, bson.M{})
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
defer cursor.Close(ctx)
|
||
|
||
var docs []models.RolePermissionsDoc
|
||
if err = cursor.All(ctx, &docs); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
permMap := make(map[int][]string)
|
||
nameMap := make(map[int]string)
|
||
for _, d := range docs {
|
||
permMap[d.RoleID] = d.Permissions
|
||
if d.RoleName != "" {
|
||
nameMap[d.RoleID] = d.RoleName
|
||
}
|
||
}
|
||
allKeys := allPermissionKeys()
|
||
// 预定义角色固定在前(9527, 0, 1),再按 role_id 排自定义
|
||
predef := []int{models.RoleIDSuperAdmin, models.RoleIDSuperUser, models.RoleIDUser}
|
||
seen := make(map[int]bool)
|
||
list := make([]gin.H, 0)
|
||
for _, rid := range predef {
|
||
seen[rid] = true
|
||
perms := permMap[rid]
|
||
if perms == nil {
|
||
perms = []string{}
|
||
}
|
||
if rid == models.RoleIDSuperAdmin {
|
||
perms = allKeys
|
||
}
|
||
name := nameMap[rid]
|
||
if name == "" {
|
||
name = models.DefaultRoleNames[rid]
|
||
}
|
||
list = append(list, gin.H{
|
||
"role_id": rid,
|
||
"role_name": name,
|
||
"permissions": perms,
|
||
"is_custom": false,
|
||
})
|
||
}
|
||
for _, d := range docs {
|
||
if seen[d.RoleID] {
|
||
continue
|
||
}
|
||
seen[d.RoleID] = true
|
||
name := d.RoleName
|
||
if name == "" {
|
||
name = "角色" + strconv.Itoa(d.RoleID)
|
||
}
|
||
perms := d.Permissions
|
||
if perms == nil {
|
||
perms = []string{}
|
||
}
|
||
list = append(list, gin.H{
|
||
"role_id": d.RoleID,
|
||
"role_name": name,
|
||
"permissions": perms,
|
||
"is_custom": true,
|
||
})
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"list": list,
|
||
"all_permissions": models.AllPermissions,
|
||
})
|
||
}
|
||
|
||
// UpdateRolePermissions 更新指定角色的权限
|
||
func UpdateRolePermissions(c *gin.Context) {
|
||
roleIDStr := c.Param("role_id")
|
||
roleID, err := strconv.Atoi(roleIDStr)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 role_id"})
|
||
return
|
||
}
|
||
if roleID == models.RoleIDSuperAdmin {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "超级管理员权限不可修改"})
|
||
return
|
||
}
|
||
|
||
var input struct {
|
||
RoleName string `json:"role_name"`
|
||
Permissions []string `json:"permissions"`
|
||
}
|
||
if err := c.ShouldBindJSON(&input); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
coll := config.GetDB(config.DBName).Collection("role_permissions")
|
||
filter := bson.M{"role_id": roleID}
|
||
set := bson.M{"role_id": roleID, "permissions": input.Permissions}
|
||
if input.RoleName != "" && roleID >= customRoleIDStart {
|
||
set["role_name"] = input.RoleName
|
||
}
|
||
update := bson.M{"$set": set}
|
||
opts := options.UpdateOne().SetUpsert(true)
|
||
_, err = coll.UpdateOne(ctx, filter, update, opts)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"message": "保存成功", "role_id": roleID, "permissions": input.Permissions})
|
||
}
|
||
|
||
// CreateRoleInput 创建角色
|
||
type CreateRoleInput struct {
|
||
RoleName string `json:"role_name" binding:"required"`
|
||
Permissions []string `json:"permissions"`
|
||
}
|
||
|
||
// CreateRole 创建自定义角色
|
||
func CreateRole(c *gin.Context) {
|
||
var input CreateRoleInput
|
||
if err := c.ShouldBindJSON(&input); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "请填写角色名称"})
|
||
return
|
||
}
|
||
if input.Permissions == nil {
|
||
input.Permissions = []string{}
|
||
}
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
coll := config.GetDB(config.DBName).Collection("role_permissions")
|
||
cursor, _ := coll.Find(ctx, bson.M{"role_id": bson.M{"$gte": customRoleIDStart}}, options.Find().SetSort(bson.D{{Key: "role_id", Value: -1}}).SetLimit(1))
|
||
var docs []models.RolePermissionsDoc
|
||
_ = cursor.All(ctx, &docs)
|
||
cursor.Close(ctx)
|
||
nextID := customRoleIDStart
|
||
for _, d := range docs {
|
||
if d.RoleID >= customRoleIDStart {
|
||
nextID = d.RoleID + 1
|
||
break
|
||
}
|
||
}
|
||
|
||
doc := models.RolePermissionsDoc{
|
||
RoleID: nextID,
|
||
RoleName: input.RoleName,
|
||
Permissions: input.Permissions,
|
||
}
|
||
_, err := coll.InsertOne(ctx, bson.M{"role_id": doc.RoleID, "role_name": doc.RoleName, "permissions": doc.Permissions})
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"message": "创建成功", "role_id": doc.RoleID, "role_name": doc.RoleName, "permissions": doc.Permissions})
|
||
}
|
||
|
||
// DeleteRole 删除自定义角色(仅 role_id >= customRoleIDStart)
|
||
func DeleteRole(c *gin.Context) {
|
||
roleIDStr := c.Param("role_id")
|
||
roleID, err := strconv.Atoi(roleIDStr)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 role_id"})
|
||
return
|
||
}
|
||
if roleID < customRoleIDStart {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "预定义角色不可删除"})
|
||
return
|
||
}
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
coll := config.GetDB(config.DBName).Collection("role_permissions")
|
||
_, err = coll.DeleteOne(ctx, bson.M{"role_id": roleID})
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
|
||
}
|