package usecase import ( "context" "gateway/internal/model/permission/domain/entity" domrepo "gateway/internal/model/permission/domain/repository" dom "gateway/internal/model/permission/domain/usecase" ) // PolicyReloader is the optional callback invoked after Replace mutates // role_permissions. RBACUseCase.BroadcastReload satisfies it; passing nil // disables the post-replace broadcast (useful in tests). type PolicyReloader func(ctx context.Context, tenantID string) error // RolePermissionUseCaseParam injects all repos needed to replace role // permission sets and the reloader hook. type RolePermissionUseCaseParam struct { Roles domrepo.RoleRepository Permissions domrepo.PermissionRepository RolePermissions domrepo.RolePermissionRepository Reloader PolicyReloader } type rolePermissionUseCase struct { roles domrepo.RoleRepository perms domrepo.PermissionRepository rolePerms domrepo.RolePermissionRepository reload PolicyReloader } // NewRolePermissionUseCase returns the role↔permission editor. func NewRolePermissionUseCase(param RolePermissionUseCaseParam) dom.RolePermissionUseCase { return &rolePermissionUseCase{ roles: param.Roles, perms: param.Permissions, rolePerms: param.RolePermissions, reload: param.Reloader, } } func (uc *rolePermissionUseCase) List( ctx context.Context, tenantID, roleID string, ) ([]*entity.Permission, error) { if _, err := uc.roles.GetByID(ctx, tenantID, roleID); err != nil { return nil, wrapRepoErr(err) } rps, err := uc.rolePerms.ListByRole(ctx, tenantID, roleID) if err != nil { return nil, wrapRepoErr(err) } if len(rps) == 0 { return nil, nil } ids := make([]string, 0, len(rps)) for _, rp := range rps { ids = append(ids, rp.PermissionID) } perms, err := uc.perms.GetByIDs(ctx, ids) if err != nil { return nil, wrapRepoErr(err) } return perms, nil } func (uc *rolePermissionUseCase) Replace( ctx context.Context, tenantID, roleID string, permissionIDs []string, ) error { role, err := uc.roles.GetByID(ctx, tenantID, roleID) if err != nil { return wrapRepoErr(err) } allPerms, err := uc.perms.GetAll(ctx, nil) if err != nil { return wrapRepoErr(err) } allowed := make(map[string]struct{}, len(allPerms)) for _, perm := range allPerms { allowed[perm.ID.Hex()] = struct{}{} } for _, id := range permissionIDs { if _, ok := allowed[id]; !ok { return errb.ResNotFound("permission not in catalog: " + id) } } closure := getFullParentPermissionIDs(permissionIDs, allPerms) if err := uc.rolePerms.SetForRole(ctx, tenantID, roleID, closure); err != nil { return wrapRepoErr(err, "set role permissions") } if uc.reload != nil { if err := uc.reload(ctx, role.TenantID); err != nil { return wrapRepoErr(err, "reload policy") } } return nil } var _ dom.RolePermissionUseCase = (*rolePermissionUseCase)(nil)