package usecase import ( "context" "fmt" "permission/reborn/config" "permission/reborn/domain/entity" "permission/reborn/domain/errors" "permission/reborn/domain/repository" "permission/reborn/domain/usecase" "time" ) type roleUseCase struct { roleRepo repository.RoleRepository userRoleRepo repository.UserRoleRepository rolePermUseCase usecase.RolePermissionUseCase cache repository.CacheRepository config config.RoleConfig } // NewRoleUseCase 建立角色 UseCase func NewRoleUseCase( roleRepo repository.RoleRepository, userRoleRepo repository.UserRoleRepository, rolePermUseCase usecase.RolePermissionUseCase, cache repository.CacheRepository, cfg config.RoleConfig, ) usecase.RoleUseCase { return &roleUseCase{ roleRepo: roleRepo, userRoleRepo: userRoleRepo, rolePermUseCase: rolePermUseCase, cache: cache, config: cfg, } } func (uc *roleUseCase) Create(ctx context.Context, req usecase.CreateRoleRequest) (*usecase.RoleResponse, error) { // 生成 UID nextID, err := uc.roleRepo.NextID(ctx) if err != nil { return nil, errors.Wrap(errors.ErrCodeInternal, "failed to generate role id", err) } uid := fmt.Sprintf("%s%0*d", uc.config.UIDPrefix, uc.config.UIDLength, nextID) // 建立角色 role := &entity.Role{ UID: uid, ClientID: req.ClientID, Name: req.Name, Status: entity.StatusActive, } if err := uc.roleRepo.Create(ctx, role); err != nil { return nil, err } // 設定權限 if len(req.Permissions) > 0 { if err := uc.rolePermUseCase.UpdateRolePermissions(ctx, uid, req.Permissions); err != nil { return nil, err } } // 查詢完整角色資訊 return uc.Get(ctx, uid) } func (uc *roleUseCase) Update(ctx context.Context, uid string, req usecase.UpdateRoleRequest) (*usecase.RoleResponse, error) { // 檢查角色是否存在 role, err := uc.roleRepo.GetByUID(ctx, uid) if err != nil { return nil, err } // 更新欄位 if req.Name != nil { role.Name = *req.Name } if req.Status != nil { role.Status = *req.Status } if err := uc.roleRepo.Update(ctx, role); err != nil { return nil, err } // 更新權限 if req.Permissions != nil { if err := uc.rolePermUseCase.UpdateRolePermissions(ctx, uid, req.Permissions); err != nil { return nil, err } } // 清除快取 if uc.cache != nil { _ = uc.cache.Delete(ctx, repository.CacheKeyRolePermission(uid)) } return uc.Get(ctx, uid) } func (uc *roleUseCase) Delete(ctx context.Context, uid string) error { // 檢查是否有使用者使用此角色 users, err := uc.userRoleRepo.GetByRoleID(ctx, uid) if err != nil { return err } if len(users) > 0 { return errors.ErrRoleHasUsers } // 刪除角色 if err := uc.roleRepo.Delete(ctx, uid); err != nil { return err } // 清除快取 if uc.cache != nil { _ = uc.cache.Delete(ctx, repository.CacheKeyRolePermission(uid)) } return nil } func (uc *roleUseCase) Get(ctx context.Context, uid string) (*usecase.RoleResponse, error) { role, err := uc.roleRepo.GetByUID(ctx, uid) if err != nil { return nil, err } // 取得權限 permissions, err := uc.rolePermUseCase.GetByRoleUID(ctx, uid) if err != nil && !errors.Is(err, errors.ErrPermissionNotFound) { return nil, err } return uc.toResponse(role, permissions), nil } func (uc *roleUseCase) List(ctx context.Context, filter usecase.RoleFilterRequest) ([]*usecase.RoleResponse, error) { repoFilter := repository.RoleFilter{ ClientID: filter.ClientID, Name: filter.Name, Status: filter.Status, } roles, err := uc.roleRepo.List(ctx, repoFilter) if err != nil { return nil, err } return uc.toResponseList(ctx, roles), nil } func (uc *roleUseCase) Page(ctx context.Context, filter usecase.RoleFilterRequest, page, size int) (*usecase.RolePageResponse, error) { repoFilter := repository.RoleFilter{ ClientID: filter.ClientID, Name: filter.Name, Status: filter.Status, } roles, total, err := uc.roleRepo.Page(ctx, repoFilter, page, size) if err != nil { return nil, err } // 取得所有角色的使用者數量 (批量查詢,避免 N+1) roleUIDs := make([]string, len(roles)) for i, role := range roles { roleUIDs[i] = role.UID } userCounts, err := uc.userRoleRepo.CountByRoleID(ctx, roleUIDs) if err != nil { return nil, err } // 組裝回應 list := make([]*usecase.RoleWithUserCountResponse, 0, len(roles)) for _, role := range roles { // 取得權限 permissions, _ := uc.rolePermUseCase.GetByRoleUID(ctx, role.UID) // 權限過濾 (如果有指定) if len(filter.Permissions) > 0 { hasPermission := false for _, reqPerm := range filter.Permissions { if permissions.HasPermission(reqPerm) { hasPermission = true break } } if !hasPermission { continue } } resp := &usecase.RoleWithUserCountResponse{ RoleResponse: *uc.toResponse(role, permissions), UserCount: userCounts[role.UID], } list = append(list, resp) } return &usecase.RolePageResponse{ List: list, Total: total, Page: page, Size: size, }, nil } func (uc *roleUseCase) toResponse(role *entity.Role, permissions entity.Permissions) *usecase.RoleResponse { if permissions == nil { permissions = make(entity.Permissions) } return &usecase.RoleResponse{ ID: role.ID, UID: role.UID, ClientID: role.ClientID, Name: role.Name, Status: role.Status, Permissions: permissions, CreateTime: role.CreateTime.UTC().Format(time.RFC3339), UpdateTime: role.UpdateTime.UTC().Format(time.RFC3339), } } func (uc *roleUseCase) toResponseList(ctx context.Context, roles []*entity.Role) []*usecase.RoleResponse { result := make([]*usecase.RoleResponse, 0, len(roles)) for _, role := range roles { permissions, _ := uc.rolePermUseCase.GetByRoleUID(ctx, role.UID) result = append(result, uc.toResponse(role, permissions)) } return result }