285 lines
7.4 KiB
Go
285 lines
7.4 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"github.com/user-management-system/internal/domain"
|
||
"github.com/user-management-system/internal/repository"
|
||
)
|
||
|
||
// RoleService 角色服务
|
||
type RoleService struct {
|
||
roleRepo *repository.RoleRepository
|
||
rolePermissionRepo *repository.RolePermissionRepository
|
||
}
|
||
|
||
// NewRoleService 创建角色服务
|
||
func NewRoleService(
|
||
roleRepo *repository.RoleRepository,
|
||
rolePermissionRepo *repository.RolePermissionRepository,
|
||
) *RoleService {
|
||
return &RoleService{
|
||
roleRepo: roleRepo,
|
||
rolePermissionRepo: rolePermissionRepo,
|
||
}
|
||
}
|
||
|
||
// CreateRoleRequest 创建角色请求
|
||
type CreateRoleRequest struct {
|
||
Name string `json:"name" binding:"required"`
|
||
Code string `json:"code" binding:"required"`
|
||
Description string `json:"description"`
|
||
ParentID *int64 `json:"parent_id"`
|
||
}
|
||
|
||
// UpdateRoleRequest 更新角色请求
|
||
type UpdateRoleRequest struct {
|
||
Name string `json:"name"`
|
||
Description string `json:"description"`
|
||
ParentID *int64 `json:"parent_id"`
|
||
}
|
||
|
||
// CreateRole 创建角色
|
||
func (s *RoleService) CreateRole(ctx context.Context, req *CreateRoleRequest) (*domain.Role, error) {
|
||
// 检查角色代码是否已存在
|
||
exists, err := s.roleRepo.ExistsByCode(ctx, req.Code)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if exists {
|
||
return nil, errors.New("角色代码已存在")
|
||
}
|
||
|
||
// 设置角色层级
|
||
level := 1
|
||
if req.ParentID != nil {
|
||
parentRole, err := s.roleRepo.GetByID(ctx, *req.ParentID)
|
||
if err != nil {
|
||
return nil, errors.New("父角色不存在")
|
||
}
|
||
level = parentRole.Level + 1
|
||
}
|
||
|
||
// 创建角色
|
||
role := &domain.Role{
|
||
Name: req.Name,
|
||
Code: req.Code,
|
||
Description: req.Description,
|
||
ParentID: req.ParentID,
|
||
Level: level,
|
||
Status: domain.RoleStatusEnabled,
|
||
}
|
||
|
||
if err := s.roleRepo.Create(ctx, role); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return role, nil
|
||
}
|
||
|
||
const maxRoleDepth = 5 // 角色继承深度上限,可配置
|
||
|
||
// UpdateRole 更新角色
|
||
func (s *RoleService) UpdateRole(ctx context.Context, roleID int64, req *UpdateRoleRequest) (*domain.Role, error) {
|
||
role, err := s.roleRepo.GetByID(ctx, roleID)
|
||
if err != nil {
|
||
return nil, errors.New("角色不存在")
|
||
}
|
||
|
||
// 检查父角色是否存在
|
||
if req.ParentID != nil {
|
||
if *req.ParentID == roleID {
|
||
return nil, errors.New("不能将角色设置为自己的父角色")
|
||
}
|
||
// 检测循环继承:检查新父角色的祖先链是否包含当前角色
|
||
if err := s.checkCircularInheritance(ctx, roleID, *req.ParentID); err != nil {
|
||
return nil, err
|
||
}
|
||
// 检测继承深度:计算新父角色的深度 + 1
|
||
if err := s.checkInheritanceDepth(ctx, *req.ParentID, maxRoleDepth-1); err != nil {
|
||
return nil, err
|
||
}
|
||
role.ParentID = req.ParentID
|
||
}
|
||
|
||
// 更新字段
|
||
if req.Name != "" {
|
||
role.Name = req.Name
|
||
}
|
||
if req.Description != "" {
|
||
role.Description = req.Description
|
||
}
|
||
|
||
if err := s.roleRepo.Update(ctx, role); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return role, nil
|
||
}
|
||
|
||
// checkCircularInheritance 检测循环继承
|
||
// 如果将 childID 的父角色设为 parentID,检查 parentID 的祖先链是否包含 childID
|
||
func (s *RoleService) checkCircularInheritance(ctx context.Context, childID, parentID int64) error {
|
||
ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, parentID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
for _, ancestorID := range ancestorIDs {
|
||
if ancestorID == childID {
|
||
return errors.New("检测到循环继承,操作被拒绝")
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// checkInheritanceDepth 检测继承深度是否超限
|
||
func (s *RoleService) checkInheritanceDepth(ctx context.Context, roleID int64, maxDepth int) error {
|
||
if maxDepth <= 0 {
|
||
return errors.New("继承深度超限,最大支持5层")
|
||
}
|
||
|
||
depth := 0
|
||
currentID := roleID
|
||
for {
|
||
role, err := s.roleRepo.GetByID(ctx, currentID)
|
||
if err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
break
|
||
}
|
||
return err
|
||
}
|
||
if role.ParentID == nil {
|
||
break
|
||
}
|
||
depth++
|
||
if depth > maxDepth {
|
||
return errors.New("继承深度超限,最大支持5层")
|
||
}
|
||
currentID = *role.ParentID
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// DeleteRole 删除角色
|
||
func (s *RoleService) DeleteRole(ctx context.Context, roleID int64) error {
|
||
role, err := s.roleRepo.GetByID(ctx, roleID)
|
||
if err != nil {
|
||
return errors.New("角色不存在")
|
||
}
|
||
|
||
// 系统角色不能删除
|
||
if role.IsSystem {
|
||
return errors.New("系统角色不能删除")
|
||
}
|
||
|
||
// 检查是否有子角色
|
||
children, err := s.roleRepo.ListByParentID(ctx, roleID)
|
||
if err == nil && len(children) > 0 {
|
||
return errors.New("存在子角色,无法删除")
|
||
}
|
||
|
||
// 删除角色权限关联
|
||
if err := s.rolePermissionRepo.DeleteByRoleID(ctx, roleID); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 删除角色
|
||
return s.roleRepo.Delete(ctx, roleID)
|
||
}
|
||
|
||
// GetRole 获取角色信息
|
||
func (s *RoleService) GetRole(ctx context.Context, roleID int64) (*domain.Role, error) {
|
||
return s.roleRepo.GetByID(ctx, roleID)
|
||
}
|
||
|
||
// ListRoles 获取角色列表
|
||
type ListRoleRequest struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Status int `json:"status"`
|
||
Keyword string `json:"keyword"`
|
||
}
|
||
|
||
func (s *RoleService) ListRoles(ctx context.Context, req *ListRoleRequest) ([]*domain.Role, int64, error) {
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 20
|
||
}
|
||
offset := (req.Page - 1) * req.PageSize
|
||
|
||
if req.Keyword != "" {
|
||
return s.roleRepo.Search(ctx, req.Keyword, offset, req.PageSize)
|
||
}
|
||
|
||
// Status > 0 表示按状态过滤;0 表示不过滤(查全部)
|
||
if req.Status > 0 {
|
||
return s.roleRepo.ListByStatus(ctx, domain.RoleStatus(req.Status), offset, req.PageSize)
|
||
}
|
||
|
||
return s.roleRepo.List(ctx, offset, req.PageSize)
|
||
}
|
||
|
||
// UpdateRoleStatus 更新角色状态
|
||
func (s *RoleService) UpdateRoleStatus(ctx context.Context, roleID int64, status domain.RoleStatus) error {
|
||
role, err := s.roleRepo.GetByID(ctx, roleID)
|
||
if err != nil {
|
||
return errors.New("角色不存在")
|
||
}
|
||
|
||
// 系统角色不能禁用
|
||
if role.IsSystem && status == domain.RoleStatusDisabled {
|
||
return errors.New("系统角色不能禁用")
|
||
}
|
||
|
||
return s.roleRepo.UpdateStatus(ctx, roleID, status)
|
||
}
|
||
|
||
// GetRolePermissions 获取角色权限(包含继承的父角色权限)
|
||
func (s *RoleService) GetRolePermissions(ctx context.Context, roleID int64) ([]*domain.Permission, error) {
|
||
// 收集所有角色ID(包括当前角色和所有父角色)
|
||
allRoleIDs := []int64{roleID}
|
||
ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, roleID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
allRoleIDs = append(allRoleIDs, ancestorIDs...)
|
||
|
||
// 批量获取所有角色的权限ID
|
||
permissionIDs, err := s.rolePermissionRepo.GetPermissionIDsByRoleIDs(ctx, allRoleIDs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 批量获取权限详情
|
||
permissions, err := s.rolePermissionRepo.GetPermissionsByIDs(ctx, permissionIDs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return permissions, nil
|
||
}
|
||
|
||
// AssignPermissions 分配权限
|
||
func (s *RoleService) AssignPermissions(ctx context.Context, roleID int64, permissionIDs []int64) error {
|
||
// 删除原有权限
|
||
if err := s.rolePermissionRepo.DeleteByRoleID(ctx, roleID); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 创建新权限关联
|
||
var rolePermissions []*domain.RolePermission
|
||
for _, permissionID := range permissionIDs {
|
||
rolePermissions = append(rolePermissions, &domain.RolePermission{
|
||
RoleID: roleID,
|
||
PermissionID: permissionID,
|
||
})
|
||
}
|
||
|
||
return s.rolePermissionRepo.BatchCreate(ctx, rolePermissions)
|
||
}
|