280 lines
6.7 KiB
Go
280 lines
6.7 KiB
Go
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
|
|
}
|
|
|