From 2c445878d0d805c5cfc935e527373954cfcc9cc2 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 1 Jul 2025 12:39:07 +0530 Subject: [PATCH] project details API is split into three APIs. --- .../ViewModels/Projects/ProjectVM.cs | 13 +- .../Controllers/ProjectController.cs | 281 +++++++++++------- 2 files changed, 179 insertions(+), 115 deletions(-) diff --git a/Marco.Pms.Model/ViewModels/Projects/ProjectVM.cs b/Marco.Pms.Model/ViewModels/Projects/ProjectVM.cs index cd349bb..240b35f 100644 --- a/Marco.Pms.Model/ViewModels/Projects/ProjectVM.cs +++ b/Marco.Pms.Model/ViewModels/Projects/ProjectVM.cs @@ -1,10 +1,17 @@ -using Marco.Pms.Model.Dtos.Project; +using Marco.Pms.Model.Master; namespace Marco.Pms.Model.ViewModels.Projects { - public class ProjectVM : ProjectDto + public class ProjectVM { - public List? Buildings { get; set; } + public Guid Id { get; set; } + public string? Name { get; set; } + public string? ShortName { get; set; } + public string? ProjectAddress { get; set; } + public string? ContactPerson { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public StatusMaster? ProjectStatus { get; set; } } } diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 6b83a6c..6490c54 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -1,14 +1,13 @@ using Marco.Pms.DataAccess.Data; -using Marco.Pms.Model.Activities; using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; -using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Model.ViewModels.Projects; using Marco.Pms.Services.Hubs; +using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; @@ -29,9 +28,16 @@ namespace MarcoBMS.Services.Controllers private readonly RolesHelper _rolesHelper; private readonly ProjectsHelper _projectsHelper; private readonly IHubContext _signalR; + private readonly PermissionServices _permission; + private readonly Guid ViewProjects; + private readonly Guid ManageProject; + private readonly Guid ViewInfra; + private readonly Guid ManageInfra; + private readonly Guid tenantId; - public ProjectController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, RolesHelper rolesHelper, ProjectsHelper projectHelper, IHubContext signalR) + public ProjectController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, RolesHelper rolesHelper, ProjectsHelper projectHelper, + IHubContext signalR, PermissionServices permission) { _context = context; _userHelper = userHelper; @@ -39,6 +45,12 @@ namespace MarcoBMS.Services.Controllers _rolesHelper = rolesHelper; _projectsHelper = projectHelper; _signalR = signalR; + _permission = permission; + ViewProjects = Guid.Parse("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"); + ManageProject = Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614"); + ViewInfra = Guid.Parse("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"); + ManageInfra = Guid.Parse("f2aee20a-b754-4537-8166-f9507b44585b"); + tenantId = _userHelper.GetTenantId(); } @@ -177,133 +189,68 @@ namespace MarcoBMS.Services.Controllers [HttpGet("details/{id}")] public async Task Details([FromRoute] Guid id) { - // ProjectDetailsVM vm = new ProjectDetailsVM(); - + // Step 1: Validate model state if (!ModelState.IsValid) { var errors = ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage) .ToList(); - return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); + _logger.LogWarning("Invalid model state in Details endpoint. Errors: {@Errors}", errors); + return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); } - var project = await _context.Projects.Where(c => c.TenantId == _userHelper.GetTenantId() && c.Id == id).Include(c => c.ProjectStatus).SingleOrDefaultAsync(); // includeProperties: "ProjectStatus,Tenant"); //_context.Stock.FindAsync(id); + // Step 2: Get logged-in employee + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + _logger.LogInfo("Details requested by EmployeeId: {EmployeeId} for ProjectId: {ProjectId}", loggedInEmployee.Id, id); + + // Step 3: Check global view project permission + var hasViewProjectPermission = await _permission.HasPermission(ViewProjects, loggedInEmployee.Id); + if (!hasViewProjectPermission) + { + _logger.LogWarning("ViewProjects permission denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "You don't have permission to view projects", 403)); + } + + // Step 4: Check permission for this specific project + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, id.ToString()); + if (!hasProjectPermission) + { + _logger.LogWarning("Project-specific access denied. EmployeeId: {EmployeeId}, ProjectId: {ProjectId}", loggedInEmployee.Id, id); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "You don't have access to this project", 403)); + } + + // Step 5: Fetch project with status + var project = await _context.Projects + .Include(c => c.ProjectStatus) + .FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Id == id); if (project == null) { + _logger.LogWarning("Project not found. ProjectId: {ProjectId}", id); return NotFound(ApiResponse.ErrorResponse("Project not found", "Project not found", 404)); - - } - else - { - //var project = projects.Where(c => c.Id == id).SingleOrDefault(); - ProjectDetailsVM vm = await GetProjectViewModel(id, project); - - ProjectVM projectVM = new ProjectVM(); - if (vm.project != null) - { - projectVM.Id = vm.project.Id; - projectVM.Name = vm.project.Name; - projectVM.ShortName = vm.project.ShortName; - projectVM.ProjectAddress = vm.project.ProjectAddress; - projectVM.ContactPerson = vm.project.ContactPerson; - projectVM.StartDate = vm.project.StartDate; - projectVM.EndDate = vm.project.EndDate; - projectVM.ProjectStatusId = vm.project.ProjectStatusId; - } - projectVM.Buildings = new List(); - if (vm.buildings != null) - { - foreach (Building build in vm.buildings) - { - BuildingVM buildVM = new BuildingVM() { Id = build.Id, Description = build.Description, Name = build.Name }; - buildVM.Floors = new List(); - if (vm.floors != null) - { - foreach (Floor floorDto in vm.floors.Where(c => c.BuildingId == build.Id).ToList()) - { - FloorsVM floorVM = new FloorsVM() { FloorName = floorDto.FloorName, Id = floorDto.Id }; - floorVM.WorkAreas = new List(); - - if (vm.workAreas != null) - { - foreach (WorkArea workAreaDto in vm.workAreas.Where(c => c.FloorId == floorVM.Id).ToList()) - { - WorkAreaVM workAreaVM = new WorkAreaVM() { Id = workAreaDto.Id, AreaName = workAreaDto.AreaName, WorkItems = new List() }; - - if (vm.workItems != null) - { - foreach (WorkItem workItemDto in vm.workItems.Where(c => c.WorkAreaId == workAreaDto.Id).ToList()) - { - WorkItemVM workItemVM = new WorkItemVM() { WorkItemId = workItemDto.Id, WorkItem = workItemDto }; - - workItemVM.WorkItem.WorkArea = new WorkArea(); - - if (workItemVM.WorkItem.ActivityMaster != null) - { - workItemVM.WorkItem.ActivityMaster.Tenant = new Tenant(); - } - workItemVM.WorkItem.Tenant = new Tenant(); - - double todaysAssigned = 0; - if (vm.Tasks != null) - { - var tasks = vm.Tasks.Where(t => t.WorkItemId == workItemDto.Id).ToList(); - foreach (TaskAllocation task in tasks) - { - todaysAssigned += task.PlannedTask; - } - } - workItemVM.TodaysAssigned = todaysAssigned; - - workAreaVM.WorkItems.Add(workItemVM); - } - } - - floorVM.WorkAreas.Add(workAreaVM); - } - } - - buildVM.Floors.Add(floorVM); - } - } - projectVM.Buildings.Add(buildVM); - } - } - return Ok(ApiResponse.SuccessResponse(projectVM, "Success.", 200)); } - + // Step 6: Map and return result + var projectVM = GetProjectViewModel(project); + _logger.LogInfo("Project details fetched successfully. ProjectId: {ProjectId}", id); + return Ok(ApiResponse.SuccessResponse(projectVM, "Project details fetched successfully", 200)); } - private async Task GetProjectViewModel(Guid? id, Project project) + private ProjectVM GetProjectViewModel(Project project) { - ProjectDetailsVM vm = new ProjectDetailsVM(); - - // List buildings = _unitOfWork.Building.GetAll(c => c.ProjectId == id).ToList(); - List buildings = await _context.Buildings.Where(c => c.ProjectId == id).ToListAsync(); - List idList = buildings.Select(o => o.Id).ToList(); - // List floors = _unitOfWork.Floor.GetAll(c => idList.Contains(c.Id)).ToList(); - List floors = await _context.Floor.Where(c => idList.Contains(c.BuildingId)).ToListAsync(); - idList = floors.Select(o => o.Id).ToList(); - //List workAreas = _unitOfWork.WorkArea.GetAll(c => idList.Contains(c.Id), includeProperties: "WorkItems,WorkItems.ActivityMaster").ToList(); - - List workAreas = await _context.WorkAreas.Where(c => idList.Contains(c.FloorId)).ToListAsync(); - - idList = workAreas.Select(o => o.Id).ToList(); - List workItems = await _context.WorkItems.Include(c => c.WorkCategoryMaster).Where(c => idList.Contains(c.WorkAreaId)).Include(c => c.ActivityMaster).ToListAsync(); - // List workItems = _unitOfWork.WorkItem.GetAll(c => idList.Contains(c.WorkAreaId), includeProperties: "ActivityMaster").ToList(); - idList = workItems.Select(t => t.Id).ToList(); - List tasks = await _context.TaskAllocations.Where(t => idList.Contains(t.WorkItemId) && t.AssignmentDate.Date == DateTime.UtcNow.Date).ToListAsync(); - vm.project = project; - vm.buildings = buildings; - vm.floors = floors; - vm.workAreas = workAreas; - vm.workItems = workItems; - vm.Tasks = tasks; - return vm; + return new ProjectVM + { + Id = project.Id, + Name = project.Name, + ShortName = project.ShortName, + StartDate = project.StartDate, + EndDate = project.EndDate, + ProjectStatus = project.ProjectStatus, + ContactPerson = project.ContactPerson, + ProjectAddress = project.ProjectAddress, + }; } private Guid GetTenantId() @@ -594,6 +541,116 @@ namespace MarcoBMS.Services.Controllers } + + [HttpGet("infra-details/{projectId}")] + public async Task GetInfraDetails(Guid projectId) + { + _logger.LogInfo("GetInfraDetails called for ProjectId: {ProjectId}", projectId); + + // Step 1: Get logged-in employee + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Step 2: Check project-specific permission + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.ToString()); + if (!hasProjectPermission) + { + _logger.LogWarning("Project access denied for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}", loggedInEmployee.Id, projectId); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "You don't have access to this project", 403)); + } + + // Step 3: Check 'ViewInfra' permission + var hasViewInfraPermission = await _permission.HasPermission(ViewInfra, loggedInEmployee.Id); + if (!hasViewInfraPermission) + { + _logger.LogWarning("ViewInfra permission denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "You don't have access to view infra", 403)); + } + + // Step 4: Fetch buildings for the project + var buildings = await _context.Buildings + .Where(b => b.ProjectId == projectId) + .ToListAsync(); + + var buildingIds = buildings.Select(b => b.Id).ToList(); + + // Step 5: Fetch floors associated with the buildings + var floors = await _context.Floor + .Where(f => buildingIds.Contains(f.BuildingId)) + .ToListAsync(); + + var floorIds = floors.Select(f => f.Id).ToList(); + + // Step 6: Fetch work areas associated with the floors + var workAreas = await _context.WorkAreas + .Where(wa => floorIds.Contains(wa.FloorId)) + .ToListAsync(); + + // Step 7: Build the infra hierarchy (Building > Floors > Work Areas) + var infraVM = buildings.Select(b => + { + var selectedFloors = floors + .Where(f => f.BuildingId == b.Id) + .Select(f => new + { + Id = f.Id, + FloorName = f.FloorName, + WorkAreas = workAreas + .Where(wa => wa.FloorId == f.Id) + .Select(wa => new { wa.Id, wa.AreaName }) + .ToList() + }).ToList(); + + return new + { + Id = b.Id, + BuildingName = b.Name, + Floors = selectedFloors + }; + }).ToList(); + + _logger.LogInfo("Infra details fetched successfully for ProjectId: {ProjectId}, EmployeeId: {EmployeeId}, Buildings: {Count}", + projectId, loggedInEmployee.Id, infraVM.Count); + + return Ok(ApiResponse.SuccessResponse(infraVM, "Infra details fetched successfully", 200)); + } + + [HttpGet("tasks/{workAreaId}")] + public async Task GetWorkItems(Guid workAreaId) + { + _logger.LogInfo("GetWorkItems called for WorkAreaId: {WorkAreaId}", workAreaId); + + // Step 1: Get the currently logged-in employee + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Step 2: Check if the employee has ViewInfra permission + var hasViewInfraPermission = await _permission.HasPermission(ViewInfra, loggedInEmployee.Id); + if (!hasViewInfraPermission) + { + _logger.LogWarning("ViewInfra permission denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "You don't have permission to view infrastructure", 403)); + } + + // Step 3: Check if the specified Work Area exists + var isWorkAreaExist = await _context.WorkAreas.AnyAsync(wa => wa.Id == workAreaId); + if (!isWorkAreaExist) + { + _logger.LogWarning("Work Area not found for WorkAreaId: {WorkAreaId}", workAreaId); + return NotFound(ApiResponse.ErrorResponse("Work Area not found", "Work Area not found in database", 404)); + } + + // Step 4: Fetch WorkItems with related Activity and Work Category data + var workItems = await _context.WorkItems + .Include(wi => wi.ActivityMaster) + .Include(wi => wi.WorkCategoryMaster) + .Where(wi => wi.WorkAreaId == workAreaId) + .ToListAsync(); + + _logger.LogInfo("{Count} work items fetched successfully for WorkAreaId: {WorkAreaId}", workItems.Count, workAreaId); + + // Step 5: Return result + return Ok(ApiResponse.SuccessResponse(workItems, $"{workItems.Count} records of tasks fetched successfully", 200)); + } + [HttpPost("task")] public async Task CreateProjectTask(List workItemDtos) {