feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
284
internal/service/role.go
Normal file
284
internal/service/role.go
Normal file
@@ -0,0 +1,284 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user