package usecase import ( "backend/pkg/permission/domain" "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/permission" "backend/pkg/permission/domain/repository" "backend/pkg/permission/domain/usecase" "context" "fmt" "time" "go.mongodb.org/mongo-driver/v2/bson" ) type RoleUseCaseConfig struct { AdminRoleUID string // 管理員角色 UID UIDPrefix string // UID 前綴 (e.g., "ROLE") UIDLength int // UID 長度 (不含前綴) } type RoleUseCaseParam struct { RoleRepo repository.RoleRepository UserRoleRepo repository.UserRoleRepository RolePermUseCase usecase.RolePermissionUseCase Config RoleUseCaseConfig } type roleUseCase struct { RoleUseCaseParam } // NewRoleUseCase 建立角色 UseCase func NewRoleUseCase(param RoleUseCaseParam) usecase.RoleUseCase { // 設定預設值 if param.Config.UIDPrefix == "" { param.Config.UIDPrefix = "ROLE" } if param.Config.UIDLength == 0 { param.Config.UIDLength = 10 } return &roleUseCase{ RoleUseCaseParam: param, } } 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, fmt.Errorf("failed to generate role id: %w", err) } uid := fmt.Sprintf("%s%0*d", uc.Config.UIDPrefix, uc.Config.UIDLength, nextID) // 建立角色 role := &entity.Role{ ID: bson.NewObjectID(), UID: uid, ClientID: req.ClientID, Name: req.Name, Status: domain.RecordActive, } role.CreateTime = time.Now().Unix() role.UpdateTime = role.CreateTime if err := uc.RoleRepo.Create(ctx, role); err != nil { return nil, err } // 設定權限 if len(req.Permissions) > 0 && uc.RolePermUseCase != nil { 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 } role.UpdateTime = time.Now().Unix() if err := uc.RoleRepo.Update(ctx, role); err != nil { return nil, err } // 更新權限 if req.Permissions != nil && uc.RolePermUseCase != nil { if err := uc.RolePermUseCase.UpdateRolePermissions(ctx, uid, req.Permissions); err != nil { return nil, err } } return uc.Get(ctx, uid) } func (uc *roleUseCase) Delete(ctx context.Context, uid string) error { // 檢查角色是否存在 _, err := uc.RoleRepo.GetByUID(ctx, uid) if err != nil { return err } // 檢查是否有使用者使用此角色 users, err := uc.UserRoleRepo.GetByRoleID(ctx, uid) if err != nil { return err } if len(users) > 0 { return fmt.Errorf("role has %d users, cannot delete", len(users)) } // 刪除角色 return uc.RoleRepo.Delete(ctx, uid) } 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 } // 取得權限 var permissions permission.Permissions if uc.RolePermUseCase != nil { permissions, _ = uc.RolePermUseCase.GetByRoleUID(ctx, uid) } if permissions == nil { permissions = make(permission.Permissions) } 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, filter.Permissions), 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 { // 取得權限 var permissions permission.Permissions if uc.RolePermUseCase != nil { permissions, _ = uc.RolePermUseCase.GetByRoleUID(ctx, role.UID) } if permissions == nil { permissions = make(permission.Permissions) } // 權限過濾 (如果有指定) 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 permission.Permissions) *usecase.RoleResponse { if permissions == nil { permissions = make(permission.Permissions) } return &usecase.RoleResponse{ ID: role.ID.Hex(), UID: role.UID, ClientID: role.ClientID, Name: role.Name, Status: role.Status, Permissions: permissions, CreateTime: time.Unix(role.CreateTime, 0).UTC().Format(time.RFC3339), UpdateTime: time.Unix(role.UpdateTime, 0).UTC().Format(time.RFC3339), } } func (uc *roleUseCase) toResponseList(ctx context.Context, roles []*entity.Role, permFilter []string) []*usecase.RoleResponse { result := make([]*usecase.RoleResponse, 0, len(roles)) for _, role := range roles { var permissions permission.Permissions if uc.RolePermUseCase != nil { permissions, _ = uc.RolePermUseCase.GetByRoleUID(ctx, role.UID) } if permissions == nil { permissions = make(permission.Permissions) } // 權限過濾 if len(permFilter) > 0 { hasPermission := false for _, reqPerm := range permFilter { if permissions.HasPermission(reqPerm) { hasPermission = true break } } if !hasPermission { continue } } result = append(result, uc.toResponse(role, permissions)) } return result }