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 HasPermission(Guid featurePermissionId, Guid employeeId, Guid? projectId = null) //{ // var featurePermissionIds = await _cache.GetPermissions(employeeId); // if (featurePermissionIds == null) // { // List 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.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; //} /// /// Checks whether an employee has a specific feature permission, optionally within a project context. /// /// The target feature permission ID to check. /// The ID of the employee. /// Optional project ID for project-scoped permissions. /// True if the user has the permission, otherwise false. public async Task 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.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 HasPermissionAny(List featurePermissionIds, Guid employeeId) { var allFeaturePermissionIds = await _cache.GetPermissions(employeeId); if (allFeaturePermissionIds == null) { List 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 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); } } }