155 lines
7.3 KiB
C#
155 lines
7.3 KiB
C#
|
|
|
|
using Marco.Pms.DataAccess.Data;
|
|
using Marco.Pms.Model.Entitlements;
|
|
using Marco.Pms.Services.Helpers;
|
|
using MarcoBMS.Services.Service;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace MarcoBMS.Services.Helpers
|
|
{
|
|
public class RolesHelper
|
|
{
|
|
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
|
private readonly ApplicationDbContext _context;
|
|
private readonly CacheUpdateHelper _cache;
|
|
private readonly ILoggingService _logger;
|
|
public RolesHelper(ApplicationDbContext context, CacheUpdateHelper cache, ILoggingService logger, IDbContextFactory<ApplicationDbContext> dbContextFactory)
|
|
{
|
|
_context = context;
|
|
_cache = cache;
|
|
_logger = logger;
|
|
_dbContextFactory = dbContextFactory;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a unique list of enabled feature permissions for a given employee.
|
|
/// This method is optimized to use a single, composed database query.
|
|
/// </summary>
|
|
/// <param name="EmployeeId">The ID of the employee.</param>
|
|
/// <returns>A distinct list of FeaturePermission objects the employee is granted.</returns>
|
|
public async Task<List<FeaturePermission>> GetFeaturePermissionByEmployeeId(Guid EmployeeId)
|
|
{
|
|
_logger.LogInfo("Fetching feature permissions for EmployeeId: {EmployeeId}", EmployeeId);
|
|
|
|
try
|
|
{
|
|
// --- Step 1: Define the subquery using the main thread's context ---
|
|
// This is safe because the query is not executed yet.
|
|
var employeeRoleIdsQuery = _context.EmployeeRoleMappings
|
|
.Where(erm => erm.EmployeeId == EmployeeId && erm.IsEnabled)
|
|
.Select(erm => erm.RoleId);
|
|
|
|
// --- Step 2: Asynchronously update the cache using the DbContextFactory ---
|
|
_ = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
// Create a NEW, short-lived DbContext instance for this background task.
|
|
await using var contextForCache = await _dbContextFactory.CreateDbContextAsync();
|
|
|
|
// Now, re-create and execute the query using this new, isolated context.
|
|
var roleIds = await contextForCache.EmployeeRoleMappings
|
|
.Where(erm => erm.EmployeeId == EmployeeId && erm.IsEnabled)
|
|
.Select(erm => erm.RoleId)
|
|
.ToListAsync();
|
|
|
|
if (roleIds.Any())
|
|
{
|
|
// The cache service might also need its own context, or you can pass the data directly.
|
|
// Assuming AddApplicationRole takes the data, not a context.
|
|
await _cache.AddApplicationRole(EmployeeId, roleIds);
|
|
_logger.LogInfo("Successfully queued cache update for EmployeeId: {EmployeeId}", EmployeeId);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning("Background cache update failed for EmployeeId {EmployeeId} : {Error}", EmployeeId, ex.Message);
|
|
}
|
|
});
|
|
|
|
// --- Step 3: Execute the main query on the main thread using its original context ---
|
|
// This is now safe because the background task is using a different DbContext instance.
|
|
var permissions = await (
|
|
from rpm in _context.RolePermissionMappings
|
|
join fp in _context.FeaturePermissions.Include(f => f.Feature)
|
|
on rpm.FeaturePermissionId equals fp.Id
|
|
where employeeRoleIdsQuery.Contains(rpm.ApplicationRoleId) && fp.IsEnabled == true
|
|
select fp)
|
|
.Distinct()
|
|
.ToListAsync();
|
|
|
|
_logger.LogInfo("Successfully retrieved {PermissionCount} unique permissions for EmployeeId: {EmployeeId}", permissions.Count, EmployeeId);
|
|
return permissions;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "An error occurred while fetching permissions for EmployeeId {EmployeeId}", EmployeeId);
|
|
return new List<FeaturePermission>();
|
|
}
|
|
}
|
|
|
|
public async Task<List<FeaturePermission>> GetFeaturePermissionByRoleID1(Guid roleId)
|
|
{
|
|
List<Guid> roleMappings = await _context.RolePermissionMappings.Where(c => c.ApplicationRoleId == roleId).Select(c => c.ApplicationRoleId).ToListAsync();
|
|
|
|
// _context.RolePermissionMappings
|
|
|
|
var result = await (from rpm in _context.RolePermissionMappings.Where(c => c.ApplicationRoleId == roleId)
|
|
join fp in _context.FeaturePermissions.Where(c => c.IsEnabled == true).Include(fp => fp.Feature) // Include Feature
|
|
on rpm.FeaturePermissionId equals fp.Id
|
|
select fp)
|
|
.ToListAsync();
|
|
|
|
return result;
|
|
|
|
// return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a unique list of enabled feature permissions for a given role.
|
|
/// This method is optimized to fetch all data in a single, efficient database query.
|
|
/// </summary>
|
|
/// <param name="roleId">The ID of the role.</param>
|
|
/// <returns>A distinct list of FeaturePermission objects granted to the role.</returns>
|
|
public async Task<List<FeaturePermission>> GetFeaturePermissionByRoleID(Guid roleId)
|
|
{
|
|
_logger.LogInfo("Fetching feature permissions for RoleID: {RoleId}", roleId);
|
|
|
|
try
|
|
{
|
|
// This single, efficient query gets all the required data at once.
|
|
// It joins the mapping table to the permissions table and filters by the given roleId.
|
|
var permissions = await (
|
|
// 1. Start with the linking table.
|
|
from rpm in _context.RolePermissionMappings
|
|
|
|
// 2. Join to the FeaturePermissions table on the foreign key.
|
|
join fp in _context.FeaturePermissions on rpm.FeaturePermissionId equals fp.Id
|
|
|
|
// 3. Apply all filters in one 'where' clause for clarity and efficiency.
|
|
where
|
|
rpm.ApplicationRoleId == roleId // Filter by the specific role
|
|
&& fp.IsEnabled == true // And only get enabled permissions
|
|
|
|
// 4. Select the final FeaturePermission object.
|
|
select fp)
|
|
.Include(fp => fp.Feature)
|
|
.Distinct()
|
|
.ToListAsync();
|
|
|
|
_logger.LogInfo("Successfully retrieved {PermissionCount} unique permissions for RoleID: {RoleId}", permissions.Count, roleId);
|
|
|
|
return permissions;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "An error occurred while fetching permissions for RoleId {RoleId}", roleId);
|
|
// Return an empty list as a safe default to prevent downstream failures.
|
|
return new List<FeaturePermission>();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|