Files

285 lines
7.4 KiB
Go
Raw Permalink 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 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)
}