156 lines
7.7 KiB
C#
156 lines
7.7 KiB
C#
using Marco.Pms.DataAccess.Data;
|
|
using Marco.Pms.Model.Employees;
|
|
using Marco.Pms.Model.Entitlements;
|
|
using Marco.Pms.Services.Helpers;
|
|
using MarcoBMS.Services.Helpers;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Marco.Pms.Services.Service
|
|
{
|
|
public class PermissionServices
|
|
{
|
|
private readonly ApplicationDbContext _context;
|
|
private readonly RolesHelper _rolesHelper;
|
|
private readonly CacheUpdateHelper _cache;
|
|
public PermissionServices(ApplicationDbContext context, RolesHelper rolesHelper, CacheUpdateHelper cache)
|
|
{
|
|
_context = context;
|
|
_rolesHelper = rolesHelper;
|
|
_cache = cache;
|
|
}
|
|
|
|
//public async Task<bool> HasPermission(Guid featurePermissionId, Guid employeeId, Guid? projectId = null)
|
|
//{
|
|
// var featurePermissionIds = await _cache.GetPermissions(employeeId);
|
|
// if (featurePermissionIds == null)
|
|
// {
|
|
// List<FeaturePermission> featurePermission = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
|
|
// featurePermissionIds = featurePermission.Select(fp => fp.Id).ToList();
|
|
// }
|
|
// if (projectId != null)
|
|
// {
|
|
// var projectLevelPerissionIds = await _context.ProjectLevelPermissionMappings
|
|
// .Where(pl => pl.ProjectId == projectId.Value && pl.EmployeeId == employeeId).Select(pl => pl.PermissionId).ToListAsync();
|
|
|
|
// var projectLevelModuleIds = new HashSet<Guid>
|
|
// {
|
|
// Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
|
// Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
|
// Guid.Parse("81ab8a87-8ccd-4015-a917-0627cee6a100"),
|
|
// Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
|
// Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
|
// };
|
|
|
|
// var allProjectLevelPermissionIds = await _context.FeaturePermissions
|
|
// .Where(fp => projectLevelModuleIds.Contains(fp.FeatureId) && !projectLevelPerissionIds.Contains(fp.Id)).Select(fp => fp.Id).ToListAsync();
|
|
// featurePermissionIds.RemoveRange(allProjectLevelPermissionIds);
|
|
|
|
// featurePermissionIds.AddRange(projectLevelPerissionIds);
|
|
// featurePermissionIds = featurePermissionIds.Distinct().ToList();
|
|
// }
|
|
// var hasPermission = featurePermissionIds.Contains(featurePermissionId);
|
|
// return hasPermission;
|
|
//}
|
|
|
|
/// <summary>
|
|
/// Checks whether an employee has a specific feature permission, optionally within a project context.
|
|
/// </summary>
|
|
/// <param name="featurePermissionId">The target feature permission ID to check.</param>
|
|
/// <param name="employeeId">The ID of the employee.</param>
|
|
/// <param name="projectId">Optional project ID for project-scoped permissions.</param>
|
|
/// <returns>True if the user has the permission, otherwise false.</returns>
|
|
public async Task<bool> HasPermission(Guid featurePermissionId, Guid employeeId, Guid? projectId = null)
|
|
{
|
|
// 1. Try fetching permissions from cache (fast-path lookup).
|
|
var featurePermissionIds = await _cache.GetPermissions(employeeId);
|
|
|
|
// If not found in cache, fallback to database (slower).
|
|
if (featurePermissionIds == null)
|
|
{
|
|
var featurePermissions = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
|
|
featurePermissionIds = featurePermissions.Select(fp => fp.Id).ToList();
|
|
}
|
|
|
|
// 2. Handle project-level permission overrides if a project is specified.
|
|
if (projectId.HasValue)
|
|
{
|
|
// Fetch permissions explicitly assigned to this employee in the project.
|
|
var projectLevelPermissionIds = await _context.ProjectLevelPermissionMappings
|
|
.Where(pl => pl.ProjectId == projectId.Value && pl.EmployeeId == employeeId)
|
|
.Select(pl => pl.PermissionId)
|
|
.ToListAsync();
|
|
|
|
if (projectLevelPermissionIds?.Any() ?? false)
|
|
{
|
|
|
|
// Define modules where project-level overrides apply.
|
|
var projectLevelModuleIds = new HashSet<Guid>
|
|
{
|
|
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
|
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
|
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
|
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
|
};
|
|
|
|
// Get all feature permissions under those modules where the user didn't have explicit project-level grants.
|
|
var allOverriddenPermissions = await _context.FeaturePermissions
|
|
.Where(fp => projectLevelModuleIds.Contains(fp.FeatureId) &&
|
|
!projectLevelPermissionIds.Contains(fp.Id))
|
|
.Select(fp => fp.Id)
|
|
.ToListAsync();
|
|
|
|
// Apply overrides:
|
|
// - Remove global permissions overridden by project-level rules.
|
|
// - Add explicit project-level permissions.
|
|
featurePermissionIds = featurePermissionIds
|
|
.Except(allOverriddenPermissions) // Remove overridden
|
|
.Concat(projectLevelPermissionIds) // Add project-level
|
|
.Distinct() // Ensure no duplicates
|
|
.ToList();
|
|
}
|
|
}
|
|
|
|
// 3. Final check: does the employee have the requested permission?
|
|
return featurePermissionIds.Contains(featurePermissionId);
|
|
}
|
|
public async Task<bool> HasPermissionAny(List<Guid> featurePermissionIds, Guid employeeId)
|
|
{
|
|
var allFeaturePermissionIds = await _cache.GetPermissions(employeeId);
|
|
if (allFeaturePermissionIds == null)
|
|
{
|
|
List<FeaturePermission> featurePermission = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
|
|
allFeaturePermissionIds = featurePermission.Select(fp => fp.Id).ToList();
|
|
}
|
|
var hasPermission = featurePermissionIds.Any(f => allFeaturePermissionIds.Contains(f));
|
|
|
|
return hasPermission;
|
|
}
|
|
public async Task<bool> HasProjectPermission(Employee LoggedInEmployee, Guid projectId)
|
|
{
|
|
var employeeId = LoggedInEmployee.Id;
|
|
var projectIds = await _cache.GetProjects(employeeId);
|
|
|
|
if (projectIds == null)
|
|
{
|
|
var hasPermission = await HasPermission(PermissionsMaster.ManageProject, employeeId);
|
|
if (hasPermission)
|
|
{
|
|
var projects = await _context.Projects.Where(c => c.TenantId == LoggedInEmployee.TenantId).ToListAsync();
|
|
projectIds = projects.Select(p => p.Id).ToList();
|
|
}
|
|
else
|
|
{
|
|
var allocation = await _context.ProjectAllocations.Where(c => c.EmployeeId == employeeId && c.IsActive).ToListAsync();
|
|
if (!allocation.Any())
|
|
{
|
|
return false;
|
|
}
|
|
projectIds = allocation.Select(c => c.ProjectId).Distinct().ToList();
|
|
}
|
|
await _cache.AddProjects(LoggedInEmployee.Id, projectIds);
|
|
}
|
|
return projectIds.Contains(projectId);
|
|
}
|
|
}
|
|
}
|