127 lines
5.5 KiB
C#
127 lines
5.5 KiB
C#
using Fitness_core_BE.DTOs.Rbac;
|
|
using Fitness_core_BE.Exceptions;
|
|
using Fitness_core_BE.Helpers;
|
|
using Fitness_core_BE.Infra.UoW;
|
|
using Fitness_core_BE.Interfaces;
|
|
using Fitness_core_BE.Interfaces.Services;
|
|
using Fitness_core_BE.Models;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Fitness_core_BE.Services
|
|
{
|
|
public class GymRoleService : IGymRoleService
|
|
{
|
|
private readonly IGymRoleRepository _gymRoleRepository;
|
|
private readonly INavItemRepository _navItemRepository;
|
|
private readonly UserRoleHelper _userRoleHelper;
|
|
private readonly IUnitOfWork _uow;
|
|
|
|
public GymRoleService(
|
|
IGymRoleRepository gymRoleRepository,
|
|
INavItemRepository navItemRepository,
|
|
UserRoleHelper userRoleHelper,
|
|
IUnitOfWork uow)
|
|
{
|
|
_gymRoleRepository = gymRoleRepository;
|
|
_navItemRepository = navItemRepository;
|
|
_userRoleHelper = userRoleHelper;
|
|
_uow = uow;
|
|
}
|
|
|
|
public async Task<List<GymRoleDto>> GetRolesAsync(HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var roles = await _gymRoleRepository.GetRolesByClientId(clientId);
|
|
return roles.Select(ToDto).ToList();
|
|
}
|
|
|
|
public async Task<GymRoleDto> CreateRoleAsync(CreateGymRoleRequest request, HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var role = new GymRole { FKClientId = clientId, Name = request.Name };
|
|
var created = await _gymRoleRepository.CreateRole(role);
|
|
await _uow.SaveChangesAsync();
|
|
return ToDto(created);
|
|
}
|
|
|
|
public async Task<GymRoleDto> UpdateRoleAsync(Guid gymRoleId, UpdateGymRoleRequest request, HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var role = await GetOwnedRole(gymRoleId, clientId);
|
|
|
|
if (request.Name != null) role.Name = request.Name;
|
|
if (request.IsActive.HasValue) role.IsActive = request.IsActive.Value;
|
|
|
|
var updated = await _gymRoleRepository.UpdateRole(role);
|
|
await _uow.SaveChangesAsync();
|
|
return ToDto(updated);
|
|
}
|
|
|
|
public async Task DeleteRoleAsync(Guid gymRoleId, HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var role = await GetOwnedRole(gymRoleId, clientId);
|
|
await _gymRoleRepository.DeleteRole(role);
|
|
await _uow.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task<GymRoleDto> SetRolePermissionsAsync(Guid gymRoleId, SetRolePermissionsRequest request, HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var role = await GetOwnedRole(gymRoleId, clientId);
|
|
var requestedKeys = request.NavKeys?.Distinct().ToList() ?? new List<string>();
|
|
var assignableKeys = (await _navItemRepository.GetActiveNavItemsOrdered())
|
|
.Where(item => !item.IsOwnerOnly && item.Key != "dashboard")
|
|
.Select(item => item.Key)
|
|
.ToHashSet();
|
|
var invalidKeys = requestedKeys.Where(key => !assignableKeys.Contains(key)).ToList();
|
|
if (invalidKeys.Count > 0)
|
|
throw new BadRequestException($"Invalid role permission: {string.Join(", ", invalidKeys)}.");
|
|
|
|
await _gymRoleRepository.ReplacePermissions(gymRoleId, requestedKeys);
|
|
await _uow.SaveChangesAsync();
|
|
|
|
var refreshed = await _gymRoleRepository.GetRoleById(gymRoleId)
|
|
?? throw new NotFoundException("Role not found.");
|
|
return ToDto(refreshed);
|
|
}
|
|
|
|
public async Task AssignStaffRoleAsync(Guid staffId, AssignStaffRoleRequest request, HttpContext httpContext)
|
|
{
|
|
var clientId = await GetOwnerClientId(httpContext);
|
|
var assigned = await _gymRoleRepository.AssignStaffRole(staffId, clientId, request.GymRoleId);
|
|
if (!assigned)
|
|
throw new NotFoundException("Staff member or role not found for this gym.");
|
|
await _uow.SaveChangesAsync();
|
|
}
|
|
|
|
// Every public method funnels through here: only a caller who resolves to a Client
|
|
// (the gym owner) can manage roles. Staff — regardless of any nav-section permission
|
|
// they've been granted, including "staff" — are rejected before any GymRole/
|
|
// GymRolePermission data is ever touched.
|
|
private async Task<Guid> GetOwnerClientId(HttpContext httpContext)
|
|
{
|
|
var userId = DataExtractor.GetUserIdFromContext(httpContext);
|
|
return await _userRoleHelper.GetOwnedClientId(userId)
|
|
?? throw new UnauthorizedAccessException("Only the gym owner can manage roles and permissions.");
|
|
}
|
|
|
|
private async Task<GymRole> GetOwnedRole(Guid gymRoleId, Guid clientId)
|
|
{
|
|
var role = await _gymRoleRepository.GetRoleById(gymRoleId)
|
|
?? throw new NotFoundException("Role not found.");
|
|
if (role.FKClientId != clientId)
|
|
throw new NotFoundException("Role not found.");
|
|
return role;
|
|
}
|
|
|
|
private static GymRoleDto ToDto(GymRole role) => new()
|
|
{
|
|
GymRoleId = role.GymRoleId,
|
|
Name = role.Name,
|
|
IsActive = role.IsActive,
|
|
NavKeys = role.Permissions?.Select(p => p.NavItemKey).ToList() ?? new List<string>()
|
|
};
|
|
}
|
|
}
|