package application import ( "context" "mengstack/internal/kernel/errors" "mengstack/internal/kernel/tenant" "mengstack/internal/modules/rbac/domain" ) type Service struct { permRepo domain.PermissionRepository roleRepo domain.RoleRepository userRoleRepo domain.UserRoleRepository } func NewService( permRepo domain.PermissionRepository, roleRepo domain.RoleRepository, userRoleRepo domain.UserRoleRepository, ) *Service { return &Service{ permRepo: permRepo, roleRepo: roleRepo, userRoleRepo: userRoleRepo, } } func (s *Service) ListPermissions(ctx context.Context) ([]domain.PermissionDTO, error) { perms, err := s.permRepo.FindAll(ctx) if err != nil { return nil, errors.Wrap(err, "QUERY_PERMS_FAILED", "failed to query permissions", 500) } dtos := make([]domain.PermissionDTO, len(perms)) for i, p := range perms { dtos[i] = domain.ToPermissionDTO(&p) } return dtos, nil } func (s *Service) ListPermissionsByModule(ctx context.Context, module string) ([]domain.PermissionDTO, error) { perms, err := s.permRepo.FindByModule(ctx, module) if err != nil { return nil, errors.Wrap(err, "QUERY_PERMS_FAILED", "failed to query permissions", 500) } dtos := make([]domain.PermissionDTO, len(perms)) for i, p := range perms { dtos[i] = domain.ToPermissionDTO(&p) } return dtos, nil } func (s *Service) CreateRole(ctx context.Context, req domain.CreateRoleRequest) (domain.RoleDTO, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return domain.RoleDTO{}, errors.ErrTenantRequired } role := &domain.Role{ TenantID: tenantID, Name: req.Name, Description: req.Description, } if err := s.roleRepo.Create(ctx, role); err != nil { return domain.RoleDTO{}, errors.Wrap(err, "CREATE_ROLE_FAILED", "failed to create role", 500) } return domain.ToRoleDTO(role), nil } func (s *Service) ListRoles(ctx context.Context) ([]domain.RoleDTO, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return nil, errors.ErrTenantRequired } roles, err := s.roleRepo.FindByTenant(ctx, tenantID) if err != nil { return nil, errors.Wrap(err, "QUERY_ROLES_FAILED", "failed to query roles", 500) } dtos := make([]domain.RoleDTO, len(roles)) for i, r := range roles { dtos[i] = domain.ToRoleDTO(&r) } return dtos, nil } func (s *Service) GetRole(ctx context.Context, roleID uint) (domain.RoleDTO, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return domain.RoleDTO{}, errors.ErrTenantRequired } role, err := s.roleRepo.FindByIDWithPermissions(ctx, tenantID, roleID) if err != nil { return domain.RoleDTO{}, errors.ErrNotFound } return domain.ToRoleDTO(role), nil } func (s *Service) UpdateRole(ctx context.Context, roleID uint, req domain.UpdateRoleRequest) (domain.RoleDTO, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return domain.RoleDTO{}, errors.ErrTenantRequired } role, err := s.roleRepo.FindByID(ctx, tenantID, roleID) if err != nil { return domain.RoleDTO{}, errors.ErrNotFound } if role.IsSystem { return domain.RoleDTO{}, errors.New("SYSTEM_ROLE", "cannot modify system role", 403) } if req.Name != "" { role.Name = req.Name } if req.Description != "" { role.Description = req.Description } if err := s.roleRepo.Update(ctx, role); err != nil { return domain.RoleDTO{}, errors.Wrap(err, "UPDATE_ROLE_FAILED", "failed to update role", 500) } return domain.ToRoleDTO(role), nil } func (s *Service) DeleteRole(ctx context.Context, roleID uint) error { tenantID, ok := tenant.FromContext(ctx) if !ok { return errors.ErrTenantRequired } role, err := s.roleRepo.FindByID(ctx, tenantID, roleID) if err != nil { return errors.ErrNotFound } if role.IsSystem { return errors.New("SYSTEM_ROLE", "cannot delete system role", 403) } if err := s.roleRepo.Delete(ctx, tenantID, roleID); err != nil { return errors.Wrap(err, "DELETE_ROLE_FAILED", "failed to delete role", 500) } return nil } func (s *Service) SetRolePermissions(ctx context.Context, roleID uint, req domain.SetRolePermissionsRequest) error { tenantID, ok := tenant.FromContext(ctx) if !ok { return errors.ErrTenantRequired } role, err := s.roleRepo.FindByID(ctx, tenantID, roleID) if err != nil { return errors.ErrNotFound } if role.IsSystem { return errors.New("SYSTEM_ROLE", "cannot modify system role permissions", 403) } for _, pid := range req.PermissionIDs { if _, err := s.permRepo.FindByID(ctx, pid); err != nil { return errors.New("PERM_NOT_FOUND", "permission not found", 404) } } if err := s.roleRepo.SetPermissions(ctx, roleID, req.PermissionIDs); err != nil { return errors.Wrap(err, "SET_PERMS_FAILED", "failed to set permissions", 500) } return nil } func (s *Service) AssignRoleToUser(ctx context.Context, userID uint, req domain.AssignRoleRequest) error { tenantID, ok := tenant.FromContext(ctx) if !ok { return errors.ErrTenantRequired } if _, err := s.roleRepo.FindByID(ctx, tenantID, req.RoleID); err != nil { return errors.ErrNotFound } ur := &domain.UserRole{ UserID: userID, TenantID: tenantID, RoleID: req.RoleID, } if err := s.userRoleRepo.Assign(ctx, ur); err != nil { return errors.Wrap(err, "ASSIGN_ROLE_FAILED", "failed to assign role", 500) } return nil } func (s *Service) RemoveRoleFromUser(ctx context.Context, userID uint, roleID uint) error { tenantID, ok := tenant.FromContext(ctx) if !ok { return errors.ErrTenantRequired } if err := s.userRoleRepo.Remove(ctx, userID, tenantID, roleID); err != nil { return errors.Wrap(err, "REMOVE_ROLE_FAILED", "failed to remove role", 500) } return nil } func (s *Service) GetUserPermissions(ctx context.Context, userID uint) ([]domain.PermissionDTO, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return nil, errors.ErrTenantRequired } roles, err := s.userRoleRepo.FindRolesByUser(ctx, userID, tenantID) if err != nil { return nil, errors.Wrap(err, "QUERY_USER_ROLES_FAILED", "failed to query user roles", 500) } permMap := make(map[uint]domain.PermissionDTO) for _, role := range roles { for _, perm := range role.Permissions { if _, exists := permMap[perm.ID]; !exists { permMap[perm.ID] = domain.ToPermissionDTO(&perm) } } } dtos := make([]domain.PermissionDTO, 0, len(permMap)) for _, dto := range permMap { dtos = append(dtos, dto) } return dtos, nil } func (s *Service) UserHasPermission(ctx context.Context, userID uint, permCode string) (bool, error) { tenantID, ok := tenant.FromContext(ctx) if !ok { return false, errors.ErrTenantRequired } roles, err := s.userRoleRepo.FindRolesByUser(ctx, userID, tenantID) if err != nil { return false, errors.Wrap(err, "QUERY_USER_ROLES_FAILED", "failed to query user roles", 500) } for _, role := range roles { for _, perm := range role.Permissions { if perm.Code == permCode { return true, nil } } } return false, nil }