150 lines
5.2 KiB
C#
150 lines
5.2 KiB
C#
using Fitness_core_BE.Exceptions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Fitness_core_BE.Helpers
|
|
{
|
|
public class UserRoleHelper
|
|
{
|
|
// Admins/Customer/Client are central-bucket; Staff and CustomerSubscriptions are
|
|
// tenant-bucket.
|
|
private readonly CentralDbContext _central;
|
|
private readonly TenantDbContext _context;
|
|
|
|
public UserRoleHelper(CentralDbContext central, TenantDbContext context)
|
|
{
|
|
_central = central;
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<Guid?> GetAdminId(Guid userId)
|
|
{
|
|
var admin = await _central.Admins
|
|
.AsNoTracking()
|
|
.Where(a => a.FKUserId == userId && a.IsActive)
|
|
.Select(a => a.AdminId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
return admin == Guid.Empty ? null : admin;
|
|
}
|
|
public async Task<Guid> GetCusId(Guid userId)
|
|
{
|
|
var cus = await _central.Customer
|
|
.AsNoTracking()
|
|
.Where(a => a.FKUserId == userId && a.IsActive)
|
|
.Select(a => a.CusId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (cus == Guid.Empty)
|
|
throw new NotFoundException("Customer not found or inactive");
|
|
|
|
return cus;
|
|
}
|
|
|
|
public async Task<Guid?> GetStaffId(Guid userId)
|
|
{
|
|
var staff = await _context.Staff
|
|
.AsNoTracking()
|
|
.Where(s => s.FKUserId == userId && s.IsActive)
|
|
.Select(s => s.StaffId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
return staff == Guid.Empty ? null : staff;
|
|
}
|
|
|
|
public async Task<Guid> GetClientId(Guid userId)
|
|
{
|
|
var clientId = await _central.Client
|
|
.AsNoTracking()
|
|
.Where(c => c.FKUserId == userId)
|
|
.Select(c => c.ClientId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
// Staff can use the same tenant-scoped dashboard and real-time hub.
|
|
if (clientId == Guid.Empty)
|
|
{
|
|
clientId = await _context.Staff
|
|
.AsNoTracking()
|
|
.Where(s => s.FKUserId == userId && s.IsActive)
|
|
.Select(s => s.FKClientId)
|
|
.FirstOrDefaultAsync();
|
|
}
|
|
|
|
if (clientId == Guid.Empty)
|
|
throw new NotFoundException("Client not found");
|
|
|
|
return clientId;
|
|
}
|
|
|
|
// Strict owner lookup used by RBAC decisions. GetClientId intentionally falls
|
|
// back to a staff member's tenant so normal tenant-scoped data queries work;
|
|
// that fallback must never make staff users appear to be gym owners.
|
|
public async Task<Guid?> GetOwnedClientId(Guid userId)
|
|
{
|
|
var clientId = await _central.Client
|
|
.AsNoTracking()
|
|
.Where(c => c.FKUserId == userId)
|
|
.Select(c => c.ClientId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
return clientId == Guid.Empty ? null : clientId;
|
|
}
|
|
|
|
// Single-club deployment: exactly one Client row exists, so any caller that just needs
|
|
// "the club" (rather than a specific user's club) can use this instead of a per-user
|
|
// lookup. Used by TenantResolutionAttribute's Customer branch, which used to read a
|
|
// caller-supplied X-Tenant-Id header to pick from many gyms -- there's only one now.
|
|
public async Task<Guid> GetDefaultClientId()
|
|
{
|
|
var clientId = await _central.Client
|
|
.AsNoTracking()
|
|
.Select(c => c.ClientId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (clientId == Guid.Empty)
|
|
throw new NotFoundException("Club is not configured yet");
|
|
|
|
return clientId;
|
|
}
|
|
|
|
public async Task<Guid> GetClientIdByCusId(Guid cusId)
|
|
{
|
|
var clientId = await _context.CustomerSubscriptions
|
|
.AsNoTracking()
|
|
.Where(s => s.FKCustomerId == cusId && s.IsActive)
|
|
.Select(s => s.CustomerPlan.FKClientId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (clientId == Guid.Empty)
|
|
throw new NotFoundException("No active subscription found for customer");
|
|
|
|
return clientId;
|
|
}
|
|
|
|
public async Task<string> GetUserType(Guid userId)
|
|
{
|
|
var isAdmin = await _central.Admins
|
|
.AsNoTracking()
|
|
.AnyAsync(a => a.FKUserId == userId && a.IsActive);
|
|
if (isAdmin)
|
|
return "Admin";
|
|
var isCustomer = await _central.Customer
|
|
.AsNoTracking()
|
|
.AnyAsync(c => c.FKUserId == userId && c.IsActive);
|
|
if (isCustomer)
|
|
return "Customer";
|
|
var isClient = await _central.Client
|
|
.AsNoTracking()
|
|
.AnyAsync(cl => cl.FKUserId == userId);
|
|
if (isClient)
|
|
return "Client";
|
|
|
|
var isStaff = await _context.Staff
|
|
.AsNoTracking()
|
|
.AnyAsync(s => s.FKUserId == userId && s.IsActive);
|
|
if (isStaff)
|
|
return "Staff";
|
|
throw new NotFoundException("User role not found or inactive");
|
|
}
|
|
}
|
|
}
|