admin_backend/model/permission.go
2026-05-07 14:39:24 +08:00

676 lines
22 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 model
import (
"backend/util"
"fmt"
"strings"
)
type PermissionUserGroup struct {
ID int `json:"id" db:"id"`
GroupCode string `json:"group_code" db:"group_code"`
GroupName string `json:"group_name" db:"group_name"`
Status int `json:"status" db:"status"`
Remark string `json:"remark" db:"remark"`
CreateTime int `json:"createTime" db:"createTime"`
UpdateTime int `json:"updateTime" db:"updateTime"`
}
type PermissionRole struct {
ID int `json:"id" db:"id"`
RoleCode string `json:"role_code" db:"role_code"`
RoleName string `json:"role_name" db:"role_name"`
Status int `json:"status" db:"status"`
IsSystem int `json:"is_system" db:"is_system"`
Remark string `json:"remark" db:"remark"`
CreateTime int `json:"createTime" db:"createTime"`
UpdateTime int `json:"updateTime" db:"updateTime"`
}
type PermissionPoint struct {
ID int `json:"id" db:"id"`
PermissionCode string `json:"permission_code" db:"permission_code"`
PermissionName string `json:"permission_name" db:"permission_name"`
PermissionGroup string `json:"permission_group" db:"permission_group"`
APIPath string `json:"api_path" db:"api_path"`
HTTPMethod string `json:"http_method" db:"http_method"`
Status int `json:"status" db:"status"`
Remark string `json:"remark" db:"remark"`
CreateTime int `json:"createTime" db:"createTime"`
UpdateTime int `json:"updateTime" db:"updateTime"`
}
type PermissionUserGroupListParams struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
GroupCode string `json:"group_code"`
GroupName string `json:"group_name"`
}
type PermissionRoleListParams struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
RoleCode string `json:"role_code"`
RoleName string `json:"role_name"`
}
type PermissionPointListParams struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
PermissionCode string `json:"permission_code"`
PermissionName string `json:"permission_name"`
PermissionGroup string `json:"permission_group"`
}
func normalizePage(page, pageSize int) (int, int) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
return page, pageSize
}
func ListPermissionUserGroups(params PermissionUserGroupListParams) ([]PermissionUserGroup, int, error) {
page, pageSize := normalizePage(params.Page, params.PageSize)
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, 0, fmt.Errorf("failed to get database connection")
}
whereParts := []string{"1=1"}
args := []interface{}{}
if params.GroupCode != "" {
whereParts = append(whereParts, "group_code LIKE ?")
args = append(args, "%"+params.GroupCode+"%")
}
if params.GroupName != "" {
whereParts = append(whereParts, "group_name LIKE ?")
args = append(args, "%"+params.GroupName+"%")
}
where := strings.Join(whereParts, " AND ")
var total int
countArgs := append([]interface{}{}, args...)
if err := db.Get(&total, "SELECT COUNT(*) FROM admin_user_group WHERE "+where, countArgs...); err != nil {
return nil, 0, err
}
list := []PermissionUserGroup{}
listArgs := append(args, pageSize, (page-1)*pageSize)
query := "SELECT id, group_code, group_name, status, remark, createTime, updateTime FROM admin_user_group WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?"
if err := db.Select(&list, query, listArgs...); err != nil {
return nil, 0, err
}
return list, total, nil
}
func CreatePermissionUserGroup(item *PermissionUserGroup, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
now := int(util.Now())
item.CreateTime = now
item.UpdateTime = now
result, err := db.NamedExec("INSERT INTO admin_user_group (group_code, group_name, status, remark, create_admin, update_admin, createTime, updateTime) VALUES (:group_code, :group_name, :status, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{
"group_code": item.GroupCode,
"group_name": item.GroupName,
"status": item.Status,
"remark": item.Remark,
"create_admin": admin,
"update_admin": admin,
"createTime": item.CreateTime,
"updateTime": item.UpdateTime,
})
if err != nil {
return err
}
id, err := result.LastInsertId()
if err == nil {
item.ID = int(id)
}
return nil
}
func UpdatePermissionUserGroup(item *PermissionUserGroup, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
item.UpdateTime = int(util.Now())
_, err := db.NamedExec("UPDATE admin_user_group SET group_code = :group_code, group_name = :group_name, status = :status, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{
"id": item.ID,
"group_code": item.GroupCode,
"group_name": item.GroupName,
"status": item.Status,
"remark": item.Remark,
"update_admin": admin,
"updateTime": item.UpdateTime,
})
return err
}
func DeletePermissionUserGroup(id int) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
_, err := db.Exec("DELETE FROM admin_user_group WHERE id = ?", id)
return err
}
func ListPermissionRoles(params PermissionRoleListParams) ([]PermissionRole, int, error) {
page, pageSize := normalizePage(params.Page, params.PageSize)
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, 0, fmt.Errorf("failed to get database connection")
}
whereParts := []string{"1=1"}
args := []interface{}{}
if params.RoleCode != "" {
whereParts = append(whereParts, "role_code LIKE ?")
args = append(args, "%"+params.RoleCode+"%")
}
if params.RoleName != "" {
whereParts = append(whereParts, "role_name LIKE ?")
args = append(args, "%"+params.RoleName+"%")
}
where := strings.Join(whereParts, " AND ")
var total int
if err := db.Get(&total, "SELECT COUNT(*) FROM admin_role WHERE "+where, args...); err != nil {
return nil, 0, err
}
list := []PermissionRole{}
listArgs := append(args, pageSize, (page-1)*pageSize)
query := "SELECT id, role_code, role_name, status, is_system, remark, createTime, updateTime FROM admin_role WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?"
if err := db.Select(&list, query, listArgs...); err != nil {
return nil, 0, err
}
return list, total, nil
}
func CreatePermissionRole(item *PermissionRole, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
now := int(util.Now())
item.CreateTime = now
item.UpdateTime = now
result, err := db.NamedExec("INSERT INTO admin_role (role_code, role_name, status, is_system, remark, create_admin, update_admin, createTime, updateTime) VALUES (:role_code, :role_name, :status, :is_system, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{
"role_code": item.RoleCode,
"role_name": item.RoleName,
"status": item.Status,
"is_system": item.IsSystem,
"remark": item.Remark,
"create_admin": admin,
"update_admin": admin,
"createTime": item.CreateTime,
"updateTime": item.UpdateTime,
})
if err != nil {
return err
}
id, err := result.LastInsertId()
if err == nil {
item.ID = int(id)
}
return nil
}
func UpdatePermissionRole(item *PermissionRole, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
item.UpdateTime = int(util.Now())
_, err := db.NamedExec("UPDATE admin_role SET role_code = :role_code, role_name = :role_name, status = :status, is_system = :is_system, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{
"id": item.ID,
"role_code": item.RoleCode,
"role_name": item.RoleName,
"status": item.Status,
"is_system": item.IsSystem,
"remark": item.Remark,
"update_admin": admin,
"updateTime": item.UpdateTime,
})
return err
}
func DeletePermissionRole(id int) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
var isSystem int
if err := db.Get(&isSystem, "SELECT is_system FROM admin_role WHERE id = ?", id); err != nil {
return err
}
if isSystem == 1 {
return fmt.Errorf("system role cannot be deleted")
}
_, err := db.Exec("DELETE FROM admin_role WHERE id = ?", id)
return err
}
func ListPermissionPoints(params PermissionPointListParams) ([]PermissionPoint, int, error) {
page, pageSize := normalizePage(params.Page, params.PageSize)
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, 0, fmt.Errorf("failed to get database connection")
}
whereParts := []string{"1=1"}
args := []interface{}{}
if params.PermissionCode != "" {
whereParts = append(whereParts, "permission_code LIKE ?")
args = append(args, "%"+params.PermissionCode+"%")
}
if params.PermissionName != "" {
whereParts = append(whereParts, "permission_name LIKE ?")
args = append(args, "%"+params.PermissionName+"%")
}
if params.PermissionGroup != "" {
whereParts = append(whereParts, "permission_group LIKE ?")
args = append(args, "%"+params.PermissionGroup+"%")
}
where := strings.Join(whereParts, " AND ")
var total int
if err := db.Get(&total, "SELECT COUNT(*) FROM admin_permission WHERE "+where, args...); err != nil {
return nil, 0, err
}
list := []PermissionPoint{}
listArgs := append(args, pageSize, (page-1)*pageSize)
query := "SELECT id, permission_code, permission_name, permission_group, api_path, http_method, status, remark, createTime, updateTime FROM admin_permission WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?"
if err := db.Select(&list, query, listArgs...); err != nil {
return nil, 0, err
}
return list, total, nil
}
func CreatePermissionPoint(item *PermissionPoint, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
now := int(util.Now())
item.CreateTime = now
item.UpdateTime = now
result, err := db.NamedExec("INSERT INTO admin_permission (permission_code, permission_name, permission_group, api_path, http_method, status, remark, create_admin, update_admin, createTime, updateTime) VALUES (:permission_code, :permission_name, :permission_group, :api_path, :http_method, :status, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{
"permission_code": item.PermissionCode,
"permission_name": item.PermissionName,
"permission_group": item.PermissionGroup,
"api_path": item.APIPath,
"http_method": item.HTTPMethod,
"status": item.Status,
"remark": item.Remark,
"create_admin": admin,
"update_admin": admin,
"createTime": item.CreateTime,
"updateTime": item.UpdateTime,
})
if err != nil {
return err
}
id, err := result.LastInsertId()
if err == nil {
item.ID = int(id)
}
return nil
}
func UpdatePermissionPoint(item *PermissionPoint, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
item.UpdateTime = int(util.Now())
_, err := db.NamedExec("UPDATE admin_permission SET permission_code = :permission_code, permission_name = :permission_name, permission_group = :permission_group, api_path = :api_path, http_method = :http_method, status = :status, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{
"id": item.ID,
"permission_code": item.PermissionCode,
"permission_name": item.PermissionName,
"permission_group": item.PermissionGroup,
"api_path": item.APIPath,
"http_method": item.HTTPMethod,
"status": item.Status,
"remark": item.Remark,
"update_admin": admin,
"updateTime": item.UpdateTime,
})
return err
}
func DeletePermissionPoint(id int) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
_, err := db.Exec("DELETE FROM admin_permission WHERE id = ?", id)
return err
}
func SetGroupRoles(groupID int, roleIDs []int, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err = tx.Exec("DELETE FROM admin_group_role_rel WHERE group_id = ?", groupID); err != nil {
return err
}
now := int(util.Now())
for _, roleID := range roleIDs {
if _, err = tx.Exec("INSERT INTO admin_group_role_rel (group_id, role_id, create_admin, createTime) VALUES (?, ?, ?, ?)", groupID, roleID, admin, now); err != nil {
return err
}
}
return tx.Commit()
}
func ListGroupRoles(groupID int) ([]PermissionRole, error) {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
list := []PermissionRole{}
query := "SELECT r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime FROM admin_role r INNER JOIN admin_group_role_rel rel ON rel.role_id = r.id WHERE rel.group_id = ? ORDER BY r.id DESC"
if err := db.Select(&list, query, groupID); err != nil {
return nil, err
}
return list, nil
}
func SetRolePermissions(roleID int, permissionIDs []int, admin string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err = tx.Exec("DELETE FROM admin_role_permission_rel WHERE role_id = ?", roleID); err != nil {
return err
}
now := int(util.Now())
for _, permissionID := range permissionIDs {
if _, err = tx.Exec("INSERT INTO admin_role_permission_rel (role_id, permission_id, create_admin, createTime) VALUES (?, ?, ?, ?)", roleID, permissionID, admin, now); err != nil {
return err
}
}
return tx.Commit()
}
func ListRolePermissions(roleID int) ([]PermissionPoint, error) {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
list := []PermissionPoint{}
query := "SELECT p.id, p.permission_code, p.permission_name, p.permission_group, p.api_path, p.http_method, p.status, p.remark, p.createTime, p.updateTime FROM admin_permission p INNER JOIN admin_role_permission_rel rel ON rel.permission_id = p.id WHERE rel.role_id = ? ORDER BY p.id DESC"
if err := db.Select(&list, query, roleID); err != nil {
return nil, err
}
return list, nil
}
func SetUserGroups(adminID int, groupIDs []int, operator string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err = tx.Exec("DELETE FROM admin_user_group_rel WHERE admin_id = ?", adminID); err != nil {
return err
}
now := int(util.Now())
for _, groupID := range groupIDs {
if _, err = tx.Exec("INSERT INTO admin_user_group_rel (admin_id, group_id, create_admin, createTime) VALUES (?, ?, ?, ?)", adminID, groupID, operator, now); err != nil {
return err
}
}
return tx.Commit()
}
func ListUserGroups(adminID int) ([]PermissionUserGroup, error) {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
list := []PermissionUserGroup{}
query := "SELECT g.id, g.group_code, g.group_name, g.status, g.remark, g.createTime, g.updateTime FROM admin_user_group g INNER JOIN admin_user_group_rel rel ON rel.group_id = g.id WHERE rel.admin_id = ? ORDER BY g.id DESC"
if err := db.Select(&list, query, adminID); err != nil {
return nil, err
}
return list, nil
}
// UserPermissionItem 用户直接单点权限条目
type UserPermissionItem struct {
PermissionID int `json:"permission_id" db:"permission_id"`
GrantType int `json:"grant_type" db:"grant_type"` // 1=允许 2=拒绝
}
func ListUserPermissions(adminID int) ([]UserPermissionItem, error) {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
list := []UserPermissionItem{}
query := "SELECT permission_id, grant_type FROM admin_user_permission_rel WHERE admin_id = ? ORDER BY permission_id ASC"
if err := db.Select(&list, query, adminID); err != nil {
return nil, err
}
return list, nil
}
func SetUserPermissions(adminID int, permissions []UserPermissionItem, operator string) error {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return fmt.Errorf("failed to get database connection")
}
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err = tx.Exec("DELETE FROM admin_user_permission_rel WHERE admin_id = ?", adminID); err != nil {
return err
}
now := int(util.Now())
for _, p := range permissions {
if _, err = tx.Exec("INSERT INTO admin_user_permission_rel (admin_id, permission_id, grant_type, create_admin, createTime) VALUES (?, ?, ?, ?, ?)", adminID, p.PermissionID, p.GrantType, operator, now); err != nil {
return err
}
}
return tx.Commit()
}
// ListUserRoles 返回用户通过用户组继承的所有角色(去重)
func ListUserRoles(adminID int) ([]PermissionRole, error) {
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
list := []PermissionRole{}
query := `SELECT DISTINCT r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime
FROM admin_role r
INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id
INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id
WHERE ugr.admin_id = ?
ORDER BY r.id DESC`
if err := db.Select(&list, query, adminID); err != nil {
return nil, err
}
return list, nil
}
func ListUserRolesByAdminIDs(adminIDs []int) (map[int][]PermissionRole, error) {
result := make(map[int][]PermissionRole, len(adminIDs))
if len(adminIDs) == 0 {
return result, nil
}
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
placeholders := strings.TrimRight(strings.Repeat("?,", len(adminIDs)), ",")
args := make([]interface{}, 0, len(adminIDs))
for _, adminID := range adminIDs {
args = append(args, adminID)
result[adminID] = []PermissionRole{}
}
type userRoleRow struct {
AdminID int `db:"admin_id"`
PermissionRole
}
rows := []userRoleRow{}
query := `SELECT DISTINCT ugr.admin_id, r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime
FROM admin_role r
INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id
INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id
WHERE ugr.admin_id IN (` + placeholders + `)
ORDER BY ugr.admin_id ASC, r.id DESC`
if err := db.Select(&rows, query, args...); err != nil {
return nil, err
}
for _, row := range rows {
result[row.AdminID] = append(result[row.AdminID], row.PermissionRole)
}
return result, nil
}
// UserEffectiveInfo 用户登录后的有效权限摘要
type UserEffectiveInfo struct {
// Roles 用户通过用户组继承的角色 code 列表
Roles []string `json:"roles"`
// Permissions 用户最终有效的权限 code 列表:
// 角色链路授予 + 直接允许grant_type=1再减去直接拒绝grant_type=2
Permissions []string `json:"permissions"`
}
// GetUserEffectiveInfo 一次查询返回用户的有效角色和权限列表。
// adminID 为 admin 表的 idisSuperAdmin 时直接返回空列表(表示不受控)。
func GetUserEffectiveInfo(adminID int, isSuperAdmin bool) (*UserEffectiveInfo, error) {
if isSuperAdmin {
return &UserEffectiveInfo{Roles: []string{}, Permissions: []string{}}, nil
}
db := util.MPool.GetGameDB()
if db == nil {
return nil, fmt.Errorf("failed to get database connection")
}
defer db.Close()
// 1. 角色 code 列表(用户组 → 角色)
var roleCodes []string
roleQuery := `SELECT DISTINCT r.role_code
FROM admin_role r
INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id
INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id
WHERE ugr.admin_id = ? AND r.status = 1`
if err := db.Select(&roleCodes, roleQuery, adminID); err != nil {
return nil, err
}
if roleCodes == nil {
roleCodes = []string{}
}
// 2. 通过角色链路获得的权限 code 集合
permSet := map[string]struct{}{}
if len(roleCodes) > 0 {
ph := strings.Repeat("?,", len(roleCodes))
ph = ph[:len(ph)-1]
args := make([]interface{}, len(roleCodes))
for i, c := range roleCodes {
args[i] = c
}
var rolePerm []string
q := fmt.Sprintf(`SELECT DISTINCT p.permission_code
FROM admin_permission p
INNER JOIN admin_role_permission_rel rpr ON rpr.permission_id = p.id
INNER JOIN admin_role r ON r.id = rpr.role_id
WHERE r.role_code IN (%s) AND p.status = 1`, ph)
if err := db.Select(&rolePerm, q, args...); err != nil {
return nil, err
}
for _, code := range rolePerm {
permSet[code] = struct{}{}
}
}
// 3. 直接单点权限:允许补入,拒绝剔除
var directPerms []struct {
Code string `db:"permission_code"`
GrantType int `db:"grant_type"`
}
directQuery := `SELECT p.permission_code, rel.grant_type
FROM admin_permission p
INNER JOIN admin_user_permission_rel rel ON rel.permission_id = p.id
WHERE rel.admin_id = ? AND p.status = 1`
if err := db.Select(&directPerms, directQuery, adminID); err != nil {
return nil, err
}
for _, dp := range directPerms {
if dp.GrantType == 1 {
permSet[dp.Code] = struct{}{}
} else if dp.GrantType == 2 {
delete(permSet, dp.Code)
}
}
perms := make([]string, 0, len(permSet))
for code := range permSet {
perms = append(perms, code)
}
return &UserEffectiveInfo{
Roles: roleCodes,
Permissions: perms,
}, nil
}