using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Activities; using Marco.Pms.Model.Dtos.Activities; 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.Activities; using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; using Document = Marco.Pms.Model.DocumentManager.Document; namespace MarcoBMS.Services.Controllers { [Route("api/[controller]")] [ApiController] [Authorize] public class TaskController : ControllerBase { private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; private readonly S3UploadService _s3Service; public TaskController(ApplicationDbContext context, UserHelper userHelper, S3UploadService s3Service) { _context = context; _userHelper = userHelper; _s3Service = s3Service; } private Guid GetTenantId() { return _userHelper.GetTenantId(); } [HttpPost("assign")] public async Task AssignTask([FromBody] AssignTaskDto assignTask) { if (!ModelState.IsValid) { var errors = ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage) .ToList(); return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); } var tenantId = GetTenantId(); var Employee = await _userHelper.GetCurrentEmployeeAsync(); var taskAllocation = assignTask.ToTaskAllocationFromAssignTaskDto(Employee.Id, tenantId); _context.TaskAllocations.Add(taskAllocation); await _context.SaveChangesAsync(); var response = taskAllocation.ToAssignTaskVMFromTaskAllocation(); var teamMembers = new List { }; if (assignTask.TaskTeam != null) { foreach (var teamMember in assignTask.TaskTeam) { var result = new TaskMembers { TaskAllocationId = taskAllocation.Id, EmployeeId = teamMember, TenantId = tenantId, }; teamMembers.Add(result); } } _context.TaskMembers.AddRange(teamMembers); await _context.SaveChangesAsync(); var idList = teamMembers.Select(m => m.EmployeeId); List employees = await _context.Employees.Where(e => idList.Contains(e.Id)).ToListAsync(); List team = new List(); foreach (var employee in employees) { team.Add(employee.ToBasicEmployeeVMFromEmployee()); } response.teamMembers = team; return Ok(ApiResponse.SuccessResponse(response, "Task assignned successfully", 200)); } [HttpPost("report")] public async Task ReportTaskProgress([FromBody] ReportTaskDto reportTask) { if (!ModelState.IsValid) { var errors = ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage) .ToList(); return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); } var tenantId = GetTenantId(); var Employee = await _userHelper.GetCurrentEmployeeAsync(); var taskAllocation = await _context.TaskAllocations.Include(t => t.WorkItem).FirstOrDefaultAsync(t => t.Id == reportTask.Id); var checkListIds = reportTask.CheckList != null ? reportTask.CheckList.Select(c => c.Id).ToList() : new List(); var checkList = await _context.ActivityCheckLists.Where(c => checkListIds.Contains(c.Id)).ToListAsync(); if (taskAllocation == null || taskAllocation.WorkItem == null) { return BadRequest(ApiResponse.ErrorResponse("No such task has been allocated.", "No such task has been allocated.", 400)); } WorkArea workArea = await _context.WorkAreas.Include(a => a.Floor).FirstOrDefaultAsync(a => a.Id == taskAllocation.WorkItem.WorkAreaId) ?? new WorkArea(); var bulding = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == (workArea.Floor != null ? workArea.Floor.BuildingId : Guid.Empty)); if (taskAllocation.WorkItem != null) { if (taskAllocation.CompletedTask != 0) { taskAllocation.WorkItem.CompletedWork -= taskAllocation.CompletedTask; } taskAllocation.ReportedDate = reportTask.ReportedDate; taskAllocation.CompletedTask = reportTask.CompletedTask; taskAllocation.WorkItem.CompletedWork += reportTask.CompletedTask; } List checkListMappings = new List(); List checkListVMs = new List(); if (reportTask.CheckList != null) { foreach (var checkDto in reportTask.CheckList) { checkListVMs.Add(checkDto.ToCheckListVMFromReportCheckListDto(taskAllocation.WorkItem != null ? taskAllocation.WorkItem.ActivityId : Guid.Empty)); if (checkDto.IsChecked) { var check = checkList.Find(c => c.Id == checkDto.Id); if (check != null) { CheckListMappings checkListMapping = new CheckListMappings { CheckListId = check.Id, TaskAllocationId = reportTask.Id }; checkListMappings.Add(checkListMapping); } } } } _context.CheckListMappings.AddRange(checkListMappings); var comment = reportTask.ToCommentFromReportTaskDto(tenantId, Employee.Id); var Images = reportTask.Images; if (Images != null && Images.Count > 0) { foreach (var Image in Images) { if (string.IsNullOrEmpty(Image.Base64Data)) return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); //If base64 has a data URI prefix, strip it var base64 = Image.Base64Data.Contains(",") ? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1) : Image.Base64Data; string fileType = _s3Service.GetContentTypeFromBase64(base64); string fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_report"); string objectKey = $"tenant-{tenantId}/project-{bulding?.ProjectId}/Actitvity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); Document document = new Document { FileName = Image.FileName ?? "", ContentType = Image.ContentType ?? "", S3Key = objectKey, Base64Data = Image.Base64Data, FileSize = Image.FileSize, UploadedAt = DateTime.UtcNow, TenantId = tenantId }; _context.Documents.Add(document); TaskAttachment attachment = new TaskAttachment { DocumentId = document.Id, ReferenceId = reportTask.Id }; _context.TaskAttachments.Add(attachment); } await _context.SaveChangesAsync(); } _context.TaskComments.Add(comment); await _context.SaveChangesAsync(); var response = taskAllocation.ToReportTaskVMFromTaskAllocation(); List comments = await _context.TaskComments.Where(c => c.TaskAllocationId == taskAllocation.Id).ToListAsync(); List resultComments = new List { }; foreach (var result in comments) { resultComments.Add(result.ToCommentVMFromTaskComment()); } response.Comments = resultComments; response.checkList = checkListVMs; return Ok(ApiResponse.SuccessResponse(response, "Task reported successfully", 200)); } [HttpPost("comment")] public async Task AddCommentForTask([FromBody] CreateCommentDto createComment) { var tenantId = GetTenantId(); var Employee = await _userHelper.GetCurrentEmployeeAsync(); var taskAllocation = await _context.TaskAllocations.Include(t => t.WorkItem).FirstOrDefaultAsync(t => t.Id == createComment.TaskAllocationId); if (taskAllocation == null || taskAllocation.WorkItem == null) { return BadRequest(ApiResponse.ErrorResponse("No such task has been allocated.", "No such task has been allocated.", 400)); } WorkArea workArea = await _context.WorkAreas.Include(a => a.Floor).FirstOrDefaultAsync(a => a.Id == taskAllocation.WorkItem.WorkAreaId) ?? new WorkArea(); var bulding = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == (workArea.Floor != null ? workArea.Floor.BuildingId : Guid.Empty)); var comment = createComment.ToCommentFromCommentDto(tenantId, Employee.Id); _context.TaskComments.Add(comment); await _context.SaveChangesAsync(); var Images = createComment.Images; if (Images != null && Images.Count > 0) { foreach (var Image in Images) { if (string.IsNullOrEmpty(Image.Base64Data)) return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); //If base64 has a data URI prefix, strip it var base64 = Image.Base64Data.Contains(",") ? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1) : Image.Base64Data; string fileType = _s3Service.GetContentTypeFromBase64(base64); string fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_report"); string objectKey = $"tenant-{tenantId}/project-{bulding?.ProjectId}/Actitvity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); Document document = new Document { FileName = Image.FileName ?? "", ContentType = Image.ContentType ?? "", S3Key = objectKey, Base64Data = Image.Base64Data, FileSize = Image.FileSize, UploadedAt = DateTime.UtcNow, TenantId = tenantId }; _context.Documents.Add(document); TaskAttachment attachment = new TaskAttachment { DocumentId = document.Id, ReferenceId = comment.Id }; _context.TaskAttachments.Add(attachment); } await _context.SaveChangesAsync(); } CommentVM response = comment.ToCommentVMFromTaskComment(); return Ok(ApiResponse.SuccessResponse(response, "Comment saved successfully", 200)); } [HttpGet("list")] public async Task GetTasksList([FromQuery] Guid projectId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null) { Guid tenantId = GetTenantId(); DateTime fromDate = new DateTime(); DateTime toDate = new DateTime(); if (dateFrom != null && DateTime.TryParse(dateFrom, out fromDate) == false) { return BadRequest(ApiResponse.ErrorResponse("Invalid starting date.", "Invalid starting date.", 400)); } if (dateTo != null && DateTime.TryParse(dateTo, out toDate) == false) { return BadRequest(ApiResponse.ErrorResponse("Invalid ending date.", "Invalid ending date.", 400)); } if (dateFrom == null) fromDate = DateTime.UtcNow.Date; if (dateTo == null) toDate = fromDate.AddDays(1); var jobroles = await _context.JobRoles.Where(r => r.TenantId == tenantId).ToListAsync(); //var taskAllocations = await _context.TaskAllocations.Where(t => t.WorkItem.WorkArea.Floor.Building.ProjectId == projectId && t.AssignmentDate >= fromDate && t.AssignmentDate <= toDate && t.TenantId == tenantId).Include(t => t.WorkItemId).ToListAsync(); List buildings = await _context.Buildings.Where(b => b.ProjectId == projectId && b.TenantId == tenantId).ToListAsync(); List idList = buildings.Select(b => b.Id).ToList(); List floors = await _context.Floor.Where(f => idList.Contains(f.BuildingId) && f.TenantId == tenantId).ToListAsync(); idList = floors.Select(f => f.Id).ToList(); List workAreas = await _context.WorkAreas.Where(a => idList.Contains(a.FloorId) && a.TenantId == tenantId).ToListAsync(); idList = workAreas.Select(a => a.Id).ToList(); List workItems = await _context.WorkItems.Where(i => idList.Contains(i.WorkAreaId) && i.TenantId == tenantId).Include(i => i.ActivityMaster).ToListAsync(); idList = workItems.Select(i => i.Id).ToList(); var activityIdList = workItems.Select(i => i.ActivityId).ToList(); List taskAllocations = await _context.TaskAllocations.Where(t => idList.Contains(t.WorkItemId) && t.AssignmentDate.Date >= fromDate.Date && t.AssignmentDate.Date <= toDate.Date && t.TenantId == tenantId).Include(t => t.WorkItem).Include(t => t.Employee).ToListAsync(); var taskIdList = taskAllocations.Select(t => t.Id).ToList(); List teamMembers = await _context.TaskMembers.Where(t => taskIdList.Contains(t.TaskAllocationId)).ToListAsync(); var employeeIdList = teamMembers.Select(e => e.EmployeeId).ToList(); List employees = await _context.Employees.Where(e => employeeIdList.Contains(e.Id)).Include(e => e.JobRole).ToListAsync(); List allComments = await _context.TaskComments.Where(c => taskIdList.Contains(c.TaskAllocationId)).ToListAsync(); var allCommentIds = allComments.Select(c => c.Id).ToList(); var taskAttachments = await _context.TaskAttachments.Where(t => taskIdList.Contains(t.ReferenceId) || allCommentIds.Contains(t.ReferenceId)).ToListAsync(); var documentIds = taskAttachments.Select(t => t.DocumentId).ToList(); var documents = await _context.Documents.Where(d => documentIds.Contains(d.Id)).ToListAsync(); List tasks = new List(); //foreach (var workItem in workItems) //{ foreach (var taskAllocation in taskAllocations) { var response = taskAllocation.ToListTaskVMFromTaskAllocation(); List comments = allComments.Where(c => c.TaskAllocationId == taskAllocation.Id).ToList(); List team = new List(); List taskMembers = teamMembers.Where(m => m.TaskAllocationId == taskAllocation.Id).ToList(); var taskDocumentIds = taskAttachments.Where(t => t.ReferenceId == taskAllocation.Id).Select(t => t.DocumentId).ToList(); var taskDocuments = documents.Where(d => taskDocumentIds.Contains(d.Id)).ToList(); List taskPreSignedUrls = new List(); foreach (var document in taskDocuments) { string preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); taskPreSignedUrls.Add(preSignedUrl); } response.PreSignedUrls = taskPreSignedUrls; foreach (var taskMember in taskMembers) { var teamMember = employees.Find(e => e.Id == taskMember.EmployeeId); if (teamMember != null) { team.Add(teamMember.ToBasicEmployeeVMFromEmployee()); } } List commentVM = new List { }; foreach (var comment in comments) { var commentDocumentIds = taskAttachments.Where(t => t.ReferenceId == comment.Id).Select(t => t.DocumentId).ToList(); var commentDocuments = documents.Where(d => commentDocumentIds.Contains(d.Id)).ToList(); List commentPreSignedUrls = new List(); foreach (var document in commentDocuments) { string preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); commentPreSignedUrls.Add(preSignedUrl); } CommentVM commentVm = comment.ToCommentVMFromTaskComment(); commentVm.PreSignedUrls = commentPreSignedUrls; commentVM.Add(commentVm); } List checkLists = await _context.ActivityCheckLists.Where(x => x.ActivityId == (taskAllocation.WorkItem != null ? taskAllocation.WorkItem.ActivityId : Guid.Empty)).ToListAsync(); List checkListMappings = await _context.CheckListMappings.Where(c => c.TaskAllocationId == taskAllocation.Id).ToListAsync(); List checkList = new List(); foreach (var check in checkLists) { var checkListMapping = checkListMappings.Find(c => c.CheckListId == check.Id); if (checkListMapping != null) { checkList.Add(check.ToCheckListVMFromActivityCheckList(check.ActivityId, true)); } else { checkList.Add(check.ToCheckListVMFromActivityCheckList(check.ActivityId, false)); } } response.comments = commentVM; response.teamMembers = team; response.CheckList = checkList; tasks.Add(response); } //} return Ok(ApiResponse.SuccessResponse(tasks, "Success", 200)); } [HttpGet("get/{taskId}")] public async Task GetTask(Guid taskId) { if (taskId == Guid.Empty) return BadRequest(ApiResponse.ErrorResponse("Invalid data", "Invalid data", 400)); var taskAllocation = await _context.TaskAllocations.Include(t => t.Tenant).Include(t => t.Employee).Include(t => t.WorkItem).FirstOrDefaultAsync(t => t.Id == taskId); if (taskAllocation != null && taskAllocation.Employee != null && taskAllocation.Tenant != null) { //var employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == taskAllocation.AssignedBy); string employeeName = System.String.Format("{0} {1}", taskAllocation.Employee.FirstName, taskAllocation.Employee.LastName); string tenantName = taskAllocation.Tenant.ContactName ?? string.Empty; if (taskAllocation == null) return NotFound(ApiResponse.ErrorResponse("Task Not Found", "Task not found", 404)); var taskVM = taskAllocation.TaskAllocationToTaskVM(employeeName); var comments = await _context.TaskComments.Where(c => c.TaskAllocationId == taskAllocation.Id).ToListAsync(); var commentIds = comments.Select(c => c.Id).ToList(); var taskAttachments = await _context.TaskAttachments.Where(t => t.ReferenceId == taskAllocation.Id || commentIds.Contains(t.ReferenceId)).ToListAsync(); var documentIds = taskAttachments.Select(t => t.DocumentId).ToList(); var documents = await _context.Documents.Where(d => documentIds.Contains(d.Id)).ToListAsync(); var team = await _context.TaskMembers.Where(m => m.TaskAllocationId == taskAllocation.Id).Include(m => m.Employee).ToListAsync(); var teamMembers = new List { }; var taskDocumentIds = taskAttachments.Where(t => t.ReferenceId == taskAllocation.Id).Select(t => t.DocumentId).ToList(); var taskDocuments = documents.Where(d => taskDocumentIds.Contains(d.Id)).ToList(); List taskPreSignedUrls = new List(); foreach (var document in taskDocuments) { string preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); taskPreSignedUrls.Add(preSignedUrl); } taskVM.PreSignedUrls = taskPreSignedUrls; foreach (var member in team) { var result = member.Employee != null ? member.Employee.ToEmployeeVMFromEmployee() : new EmployeeVM(); teamMembers.Add(result); } List Comments = new List { }; foreach (var comment in comments) { var commentDocumentIds = taskAttachments.Where(t => t.ReferenceId == comment.Id).Select(t => t.DocumentId).ToList(); var commentDocuments = documents.Where(d => commentDocumentIds.Contains(d.Id)).ToList(); List commentPreSignedUrls = new List(); foreach (var document in commentDocuments) { string preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); commentPreSignedUrls.Add(preSignedUrl); } CommentVM commentVM = comment.ToCommentVMFromTaskComment(); commentVM.PreSignedUrls = commentPreSignedUrls; Comments.Add(commentVM); } taskVM.Comments = Comments; taskVM.TeamMembers = teamMembers; return Ok(ApiResponse.SuccessResponse(taskVM, "Success", 200)); } return NotFound(ApiResponse.ErrorResponse("Task Not Found", "Task not Found", 404)); } } }