Document_Manager #129

Merged
ashutosh.nehete merged 83 commits from Document_Manager into main 2025-09-11 04:12:01 +00:00
6 changed files with 132 additions and 8 deletions
Showing only changes of commit b336bd3481 - Show all commits

View File

@ -14,6 +14,8 @@ namespace Marco.Pms.Model.ViewModels.DocumentManager
public BasicEmployeeVM? UploadedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
public BasicEmployeeVM? UpdatedBy { get; set; }
public DateTime? VerifiedAt { get; set; }
public BasicEmployeeVM? VerifiedBy { get; set; }
public bool? IsVerified { get; set; }
}
}

View File

@ -424,8 +424,13 @@ namespace Marco.Pms.Services.Controllers
var versionMappingsQuery = _context.AttachmentVersionMappings
.Include(av => av.ChildAttachment)
.ThenInclude(da => da!.UploadedBy)
.ThenInclude(e => e!.JobRole)
.Include(av => av.ChildAttachment)
.ThenInclude(da => da!.UpdatedBy)
.ThenInclude(e => e!.JobRole)
.Include(av => av.ChildAttachment)
.ThenInclude(da => da!.VerifiedBy)
.ThenInclude(e => e!.JobRole)
.Include(av => av.ChildAttachment)
.ThenInclude(da => da!.Document)
.Where(av => av.ParentAttachmentId == parentAttachmentId && av.TenantId == tenantId);

View File

@ -477,6 +477,13 @@ namespace MarcoBMS.Services.Controllers
var response = await _projectServices.AssignProjectLevelModulesAsync(tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response);
}
[HttpGet("get/proejct-level/employees/{projectId}")]
public async Task<IActionResult> GetEmployeeToWhomProjectLevelAssigned(Guid projectId)
{
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _projectServices.GetEmployeeToWhomProjectLevelAssignedAsync(projectId, tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response);
}
}
};

View File

@ -19,16 +19,100 @@ namespace Marco.Pms.Services.Service
_cache = cache;
}
public async Task<bool> HasPermission(Guid featurePermissionId, Guid employeeId)
//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)
{
List<FeaturePermission> featurePermission = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
featurePermissionIds = featurePermission.Select(fp => fp.Id).ToList();
var featurePermissions = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
featurePermissionIds = featurePermissions.Select(fp => fp.Id).ToList();
}
var hasPermission = featurePermissionIds.Contains(featurePermissionId);
return hasPermission;
// 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("81ab8a87-8ccd-4015-a917-0627cee6a100"),
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)
{

View File

@ -1484,6 +1484,14 @@ namespace Marco.Pms.Services.Service
_logger.LogInfo("ManageProjectLevelPermissionAsync started for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
model.EmployeeId, model.ProjectId, tenantId);
var hasTeamPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id, model.ProjectId);
if (!hasTeamPermission)
{
_logger.LogWarning("Access Denied. User {UserId} tried to Manage the project-level permission for Employee {EmployeeId} and Project {ProjectId}"
, loggedInEmployee.Id, model.EmployeeId, model.ProjectId);
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage the project-level permission", 403);
}
// Fetch all required entities in parallel where possible
var featurePermissionIds = model.Permission.Select(p => p.Id).ToList();
@ -1677,7 +1685,7 @@ namespace Marco.Pms.Services.Service
_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>
var projectLevelModuleIds = new HashSet<Guid>
{
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
@ -1689,13 +1697,13 @@ namespace Marco.Pms.Services.Service
try
{
// Query features associated with specified modules. Also include module and permissions.
_logger.LogDebug("Querying Features with module filters: {ModuleIds}", string.Join(", ", projectModuleIds));
_logger.LogDebug("Querying Features with module filters: {ModuleIds}", string.Join(", ", projectLevelModuleIds));
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)
.Where(f => projectLevelModuleIds.Contains(f.Id) && f.Module != null)
.Select(f => new FeatureVM
{
Id = f.Id,
@ -1724,6 +1732,23 @@ namespace Marco.Pms.Services.Service
}
}
public async Task<ApiResponse<object>> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee)
{
var assignedEmployees = await _context.ProjectLevelPermissionMappings
.Include(pl => pl.Employee)
.ThenInclude(e => e!.JobRole)
.AsNoTracking()
.Where(pl => pl.ProjectId == projectId
&& pl.TenantId == tenantId)
.Select(pl => pl.Employee)
.Distinct()
.ToListAsync();
var response = _mapper.Map<List<BasicEmployeeVM>>(assignedEmployees);
return ApiResponse<object>.SuccessResponse(response, "The list of employees with project-level permissions has been successfully retrieved.", 200);
}
#endregion
#region =================================================================== Helper Functions ===================================================================

View File

@ -39,6 +39,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
}
}