244 lines
5.8 KiB
Go
244 lines
5.8 KiB
Go
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
|
|
}
|