From 3a3e7422963b57d610f27b4c44f4a81ba2c2c5c3 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 3 Sep 2025 18:08:43 +0530 Subject: [PATCH] Added the API to get modules for project level configuration --- Marco.Pms.Services/Service/ProjectServices.cs | 130 +++++++++++++----- 1 file changed, 94 insertions(+), 36 deletions(-) diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index c223eda..ea6cc8a 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -1478,11 +1478,7 @@ namespace Marco.Pms.Services.Service /// Tenant Guid. /// Currently logged in employee. /// API response indicating the result. - public async Task> ManageProjectLevelPermissionAsync( - ProjctLevelPermissionDto model, - Guid tenantId, - Employee loggedInEmployee - ) + public async Task> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Guid tenantId, Employee loggedInEmployee) { // Log: Method entry and received parameters _logger.LogInfo("ManageProjectLevelPermissionAsync started for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}", @@ -1602,44 +1598,86 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(response, "Project-Level permission assigned successfully", 200); } + /// + /// Retrieves the project-level permissions assigned to a specific employee for a given project and tenant. + /// + /// Unique identifier of the employee. + /// Unique identifier of the project. + /// Unique identifier of the tenant. + /// The authenticated employee making this request. + /// ApiResponse containing the permission mappings or error details. public async Task> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee) { - var projectLevelPermissionMappings = await _context.ProjectLevelPermissionMappings + // Log the attempt to fetch project-level permissions + _logger.LogInfo( + "Fetching project-level permissions for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId} by {LoggedInEmployeeId}", + employeeId, projectId, tenantId, loggedInEmployee.Id); + + // Query the database for relevant project-level permission mappings + var permissionMappings = await _context.ProjectLevelPermissionMappings .Include(p => p.Employee) .ThenInclude(e => e!.JobRole) .Include(p => p.Project) .Include(p => p.Permission) .ThenInclude(fp => fp!.Feature) .AsNoTracking() - .Where(p => p.EmployeeId == employeeId && p.ProjectId == projectId && p.TenantId == tenantId) - .GroupBy(p => p.EmployeeId) - .Select(g => new - { - Employee = g.Select(p => _mapper.Map(p.Employee)).FirstOrDefault(), - Project = g.Select(p => _mapper.Map(p.Project)).FirstOrDefault(), - Permissions = g.Select(p => _mapper.Map(p.Permission)).ToList() - }) - .FirstOrDefaultAsync(); + .Where(p => p.EmployeeId == employeeId + && p.ProjectId == projectId + && p.TenantId == tenantId) + .ToListAsync(); - if (projectLevelPermissionMappings == null) + if (permissionMappings == null || !permissionMappings.Any()) { + _logger.LogWarning("No project-level permissions found for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}", + employeeId, projectId, tenantId); return ApiResponse.ErrorResponse("Project-Level Permissions not found", "Project-Level Permissions not found in database", 404); } - if (projectLevelPermissionMappings.Employee == null) + // Map the employee, project, and permissions. + var employee = _mapper.Map(permissionMappings.First().Employee); + var project = _mapper.Map(permissionMappings.First().Project); + var permissions = permissionMappings + .Select(p => _mapper.Map(p.Permission)) + .ToList(); + + if (employee == null) { + _logger.LogWarning("Employee record missing for EmployeeId: {EmployeeId}", employeeId); return ApiResponse.ErrorResponse("Employee not found", "Employee not found in database", 404); } - if (projectLevelPermissionMappings.Project == null) + if (project == null) { + _logger.LogWarning("Project record missing for ProjectId: {ProjectId}", projectId); return ApiResponse.ErrorResponse("Project not found", "Project not found in database", 404); } - return ApiResponse.SuccessResponse(projectLevelPermissionMappings, "Project-Level Permissions fetched successfully", 200); + // Prepare the result object. + var result = new + { + Employee = employee, + Project = project, + Permissions = permissions + }; + + _logger.LogInfo("Project-level permissions fetched successfully for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}", + employeeId, projectId, tenantId); + + return ApiResponse.SuccessResponse(result, "Project-Level Permissions fetched successfully", 200); } + + /// + /// Assigns features at the project module level for the given tenant and employee. + /// + /// Tenant ID associated with assignment. + /// Logged-in employee context. + /// API response containing feature details associated with specified modules. public async Task> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee) { - var moduleList = new Guid[] + // Log entry at the start of the method. + _logger.LogInfo("AssignProjectLevelModulesAsync called for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id); + + // Define target module IDs. These could alternatively be stored in a config file or DB. + var projectModuleIds = new HashSet { Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"), Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), @@ -1648,24 +1686,44 @@ namespace Marco.Pms.Services.Service Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462") }; - var features = await _context.Features - .Include(f => f.FeaturePermissions) - .Include(f => f.Module) - .Where(f => moduleList.Contains(f.Id) && f.Module != null) - .Select(f => new FeatureVM - { - Id = f.Id, - Name = f.Name, - Description = f.Description, - FeaturePermissions = _mapper.Map>(f.FeaturePermissions), - ModuleId = f.ModuleId, - ModuleName = f.Module!.Name, - IsActive = f.IsActive, - ModuleKey = f.Module!.Key - }).ToListAsync(); + try + { + // Query features associated with specified modules. Also include module and permissions. + _logger.LogDebug("Querying Features with module filters: {ModuleIds}", string.Join(", ", projectModuleIds)); - return ApiResponse.SuccessResponse(features); + var features = await _context.Features + .AsNoTracking() // Improves read-only query performance + .Include(f => f.FeaturePermissions) + .Include(f => f.Module) + .Where(f => projectModuleIds.Contains(f.Id) && f.Module != null) + .Select(f => new FeatureVM + { + Id = f.Id, + Name = f.Name, + Description = f.Description, + FeaturePermissions = _mapper.Map>(f.FeaturePermissions), + ModuleId = f.ModuleId, + ModuleName = f.Module!.Name, + IsActive = f.IsActive, + ModuleKey = f.Module!.Key + }) + .ToListAsync(); + + _logger.LogInfo("Features successfully retrieved for TenantId: {TenantId}. FeatureCount: {FeatureCount}", tenantId, features.Count); + + // Return successful response. + return ApiResponse.SuccessResponse(features, "Feature Permission for project-level is fetched successfully", 200); + } + catch (Exception ex) + { + // Log the error for further diagnostics. + _logger.LogError(ex, "Error in AssignProjectLevelModulesAsync for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id); + + // Return an appropriate error response to consumer. + return ApiResponse.ErrorResponse("Failed to assign project-level modules.", ex.Message); + } } + #endregion #region =================================================================== Helper Functions ===================================================================