Compare commits
27 Commits
67c8bee2c2
...
49b85c4df9
| Author | SHA1 | Date | |
|---|---|---|---|
| 49b85c4df9 | |||
| aebb344a5a | |||
| 56aca323e5 | |||
| 1d318c75d8 | |||
| 8521a68c3e | |||
| 8c85d92ba6 | |||
| 3ce9851a7f | |||
| 3dd5e7f626 | |||
| bc0ef0b88b | |||
| 43e2aeb097 | |||
| 65f3376523 | |||
| 558fd6bd5b | |||
| e4cc6c1578 | |||
| 6373da3144 | |||
| f9ab7bb3c8 | |||
| 800db99fd9 | |||
| 6d8939d942 | |||
| c9ff53a7ac | |||
| a303625d59 | |||
| 62eb914456 | |||
| 1f5a71ef09 | |||
| 8353c384a5 | |||
| 85911c4536 | |||
| afdf51eae3 | |||
| 587e8d2b0b | |||
| b77a5b16cd | |||
| ba1e644fd8 |
3426
Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs
generated
Normal file
3426
Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Marco.Pms.DataAccess.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Added_UploadedBy_ForeginKey_In_Decuments_Table : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "UploadedById",
|
||||
table: "Documents",
|
||||
type: "char(36)",
|
||||
nullable: true,
|
||||
collation: "ascii_general_ci");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Documents_UploadedById",
|
||||
table: "Documents",
|
||||
column: "UploadedById");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Documents_Employees_UploadedById",
|
||||
table: "Documents",
|
||||
column: "UploadedById",
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Documents_Employees_UploadedById",
|
||||
table: "Documents");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Documents_UploadedById",
|
||||
table: "Documents");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UploadedById",
|
||||
table: "Documents");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -752,10 +752,15 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.Property<DateTime>("UploadedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<Guid?>("UploadedById")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("UploadedById");
|
||||
|
||||
b.ToTable("Documents");
|
||||
});
|
||||
|
||||
@ -2951,7 +2956,13 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("UploadedById");
|
||||
|
||||
b.Navigation("Tenant");
|
||||
|
||||
b.Navigation("UploadedBy");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b =>
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
|
||||
namespace Marco.Pms.Model.DocumentManager
|
||||
{
|
||||
@ -16,10 +19,15 @@ namespace Marco.Pms.Model.DocumentManager
|
||||
/// </summary>
|
||||
public string? ThumbS3Key { get; set; }
|
||||
|
||||
public string? Base64Data { get; set; }
|
||||
public string? Base64Data { get; set; } = null;
|
||||
|
||||
public long FileSize { get; set; }
|
||||
public string ContentType { get; set; } = string.Empty;
|
||||
public Guid? UploadedById { get; set; }
|
||||
|
||||
[ValidateNever]
|
||||
[ForeignKey("UploadedById")]
|
||||
public Employee? UploadedBy { get; set; }
|
||||
public DateTime UploadedAt { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
10
Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs
Normal file
10
Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using Marco.Pms.Model.DocumentManager;
|
||||
|
||||
namespace Marco.Pms.Model.Dtos.DocumentManager
|
||||
{
|
||||
public class DocumentBatchDto
|
||||
{
|
||||
public Guid? BatchId { get; set; }
|
||||
public List<Document>? Documents { get; set; }
|
||||
}
|
||||
}
|
||||
@ -90,29 +90,35 @@ namespace Marco.Pms.Model.Mapper
|
||||
};
|
||||
}
|
||||
|
||||
public static Document ToDocumentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, Guid tenantId)
|
||||
public static Document ToDocumentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt,
|
||||
Guid tenantId, Guid batchId, Guid loggedInEmployeeId)
|
||||
{
|
||||
return new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployeeId,
|
||||
FileName = AttachmentDto.FileName,
|
||||
ContentType = AttachmentDto.ContentType,
|
||||
S3Key = objectKey,
|
||||
ThumbS3Key = thumbS3Key,
|
||||
Base64Data = AttachmentDto.Base64Data,
|
||||
//Base64Data = AttachmentDto.Base64Data,
|
||||
FileSize = AttachmentDto.FileSize,
|
||||
UploadedAt = uploadedAt,
|
||||
TenantId = tenantId
|
||||
};
|
||||
}
|
||||
public static Document ToDocumentFromUpdateAttachmentDto(this UpdateAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, Guid tenantId)
|
||||
public static Document ToDocumentFromUpdateAttachmentDto(this UpdateAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt,
|
||||
Guid tenantId, Guid batchId, Guid loggedInEmployeeId)
|
||||
{
|
||||
return new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployeeId,
|
||||
FileName = AttachmentDto.FileName,
|
||||
ContentType = AttachmentDto.ContentType,
|
||||
S3Key = objectKey,
|
||||
ThumbS3Key = thumbS3Key,
|
||||
Base64Data = AttachmentDto.Base64Data,
|
||||
//Base64Data = AttachmentDto.Base64Data,
|
||||
FileSize = AttachmentDto.FileSize,
|
||||
UploadedAt = uploadedAt,
|
||||
TenantId = tenantId
|
||||
|
||||
14
Marco.Pms.Model/Utilities/ImageFilter.cs
Normal file
14
Marco.Pms.Model/Utilities/ImageFilter.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Marco.Pms.Model.Utilities
|
||||
{
|
||||
public class ImageFilter
|
||||
{
|
||||
public List<Guid>? BuildingIds { get; set; }
|
||||
public List<Guid>? FloorIds { get; set; }
|
||||
public List<Guid>? WorkAreaIds { get; set; }
|
||||
public List<Guid>? WorkCategoryIds { get; set; }
|
||||
public List<Guid>? ActivityIds { get; set; }
|
||||
public List<Guid>? UploadedByIds { get; set; }
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
}
|
||||
}
|
||||
@ -603,7 +603,8 @@ namespace MarcoBMS.Services.Controllers
|
||||
}
|
||||
|
||||
Guid tenantId = GetTenantId();
|
||||
var currentEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
@ -704,10 +705,12 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
document = new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployee.Id,
|
||||
FileName = recordAttendanceDot.Image.FileName ?? "",
|
||||
ContentType = recordAttendanceDot.Image.ContentType,
|
||||
S3Key = objectKey,
|
||||
Base64Data = recordAttendanceDot.Image.Base64Data,
|
||||
//Base64Data = recordAttendanceDot.Image.Base64Data,
|
||||
FileSize = recordAttendanceDot.Image.FileSize,
|
||||
UploadedAt = recordAttendanceDot.Date,
|
||||
TenantId = tenantId
|
||||
@ -728,7 +731,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
Longitude = recordAttendanceDot.Longitude,
|
||||
DocumentId = document?.Id,
|
||||
TenantId = tenantId,
|
||||
UpdatedBy = recordAttendanceDot.EmployeeID,
|
||||
UpdatedBy = loggedInEmployee.Id,
|
||||
UpdatedOn = recordAttendanceDot.Date
|
||||
};
|
||||
_context.AttendanceLogs.Add(attendanceLog);
|
||||
@ -755,7 +758,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
var notification = new
|
||||
{
|
||||
LoggedInUserId = currentEmployee.Id,
|
||||
LoggedInUserId = loggedInEmployee.Id,
|
||||
Keyword = "Attendance",
|
||||
Activity = recordAttendanceDot.Id == Guid.Empty ? 1 : 0,
|
||||
ProjectId = attendance.ProjectID,
|
||||
|
||||
@ -48,6 +48,8 @@ namespace Marco.Pms.Services.Controllers
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||
}
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
TicketForum ticketForum = createTicketDto.ToTicketForumFromCreateTicketDto(tenantId);
|
||||
_context.Tickets.Add(ticketForum);
|
||||
await _context.SaveChangesAsync();
|
||||
@ -79,7 +81,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
string objectKey = $"tenant-{tenantId}/project-{createTicketDto.LinkedProjectId}/froum/{fileName}";
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, createTicketDto.CreatedAt, tenantId);
|
||||
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, createTicketDto.CreatedAt, tenantId, batchId, loggedInEmployee.Id);
|
||||
_context.Documents.Add(document);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@ -162,7 +164,15 @@ namespace Marco.Pms.Services.Controllers
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||
}
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var existingTicket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).AsNoTracking().FirstOrDefaultAsync(t => t.Id == updateTicketDto.Id);
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
var existingTicket = await _context.Tickets
|
||||
.Include(t => t.TicketTypeMaster)
|
||||
.Include(t => t.TicketStatusMaster)
|
||||
.Include(t => t.Priority)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(t => t.Id == updateTicketDto.Id);
|
||||
if (existingTicket != null)
|
||||
{
|
||||
TicketForum ticketForum = updateTicketDto.ToTicketForumFromUpdateTicketDto(existingTicket);
|
||||
@ -202,7 +212,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
string objectKey = $"tenant-{tenantId}/project-{updateTicketDto.LinkedProjectId}/froum/{fileName}";
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, updateTicketDto.CreatedAt, tenantId);
|
||||
Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, updateTicketDto.CreatedAt, tenantId, batchId, loggedInEmployee.Id);
|
||||
_context.Documents.Add(document);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@ -344,6 +354,9 @@ namespace Marco.Pms.Services.Controllers
|
||||
}
|
||||
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||
List<Document> documents = new List<Document>();
|
||||
|
||||
@ -381,7 +394,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
string objectKey = $"tenant-{tenantId}/project-{ticket.LinkedProjectId}/froum/{fileName}";
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, addCommentDto.SentAt, tenantId);
|
||||
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, addCommentDto.SentAt, tenantId, batchId, loggedInEmployee.Id);
|
||||
_context.Documents.Add(document);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@ -429,6 +442,9 @@ namespace Marco.Pms.Services.Controllers
|
||||
}
|
||||
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||
|
||||
TicketForum? ticket = await _context.Tickets.FirstOrDefaultAsync(t => t.Id == updateCommentDto.TicketId);
|
||||
@ -473,7 +489,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
string objectKey = $"tenant-{tenantId}/project-{ticket.LinkedProjectId}/froum/{fileName}";
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, existingComment.SentAt, tenantId);
|
||||
Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, existingComment.SentAt, tenantId, batchId, loggedInEmployee.Id);
|
||||
_context.Documents.Add(document);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@ -541,6 +557,9 @@ namespace Marco.Pms.Services.Controllers
|
||||
}
|
||||
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||
|
||||
List<Guid> ticketIds = forumAttachmentDtos.Select(f => f.TicketId.HasValue ? f.TicketId.Value : Guid.Empty).ToList();
|
||||
@ -579,7 +598,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
string objectKey = $"tenant-{tenantId}/project-{ticket?.LinkedProjectId}/froum/{fileName}";
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
Document document = forumAttachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, forumAttachmentDto.SentAt, tenantId);
|
||||
Document document = forumAttachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, forumAttachmentDto.SentAt, tenantId, batchId, loggedInEmployee.Id);
|
||||
_context.Documents.Add(document);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
404
Marco.Pms.Services/Controllers/ImageController.cs
Normal file
404
Marco.Pms.Services/Controllers/ImageController.cs
Normal file
@ -0,0 +1,404 @@
|
||||
using System.Text.Json;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Activities;
|
||||
using Marco.Pms.Model.Dtos.DocumentManager;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Mapper;
|
||||
using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Services.Service;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Marco.Pms.Services.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ImageController : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly S3UploadService _s3Service;
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly PermissionServices _permission;
|
||||
private readonly Guid tenantId;
|
||||
public ImageController(ApplicationDbContext context, S3UploadService s3Service, UserHelper userHelper, ILoggingService logger, PermissionServices permission)
|
||||
{
|
||||
_context = context;
|
||||
_s3Service = s3Service;
|
||||
_userHelper = userHelper;
|
||||
_logger = logger;
|
||||
tenantId = userHelper.GetTenantId();
|
||||
_permission = permission;
|
||||
}
|
||||
|
||||
[HttpGet("images/{projectId}")]
|
||||
|
||||
public async Task<IActionResult> GetImageList(Guid projectId, [FromQuery] string? filter, [FromQuery] int? pageNumber = 1, [FromQuery] int? pageSize = 10)
|
||||
{
|
||||
_logger.LogInfo("[GetImageList] Called by Employee for ProjectId: {ProjectId}", projectId);
|
||||
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Step 1: Validate project existence
|
||||
var isProjectExist = await _context.Projects.AnyAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||
if (!isProjectExist)
|
||||
{
|
||||
_logger.LogWarning("[GetImageList] ProjectId: {ProjectId} not found", projectId);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 400));
|
||||
}
|
||||
|
||||
// Step 2: Check project access permission
|
||||
var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.ToString());
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("[GetImageList] Access denied for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}", loggedInEmployee.Id, projectId);
|
||||
return StatusCode(403, ApiResponse<object>.ErrorResponse("You don't have access", "You don't have access", 403));
|
||||
}
|
||||
|
||||
// Step 3: Deserialize filter
|
||||
ImageFilter? imageFilter = null;
|
||||
if (!string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
//string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
|
||||
//imageFilter = JsonSerializer.Deserialize<ImageFilter>(unescapedJsonString, options);
|
||||
imageFilter = JsonSerializer.Deserialize<ImageFilter>(filter, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("[GetImageList] Failed to parse filter: {Message}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Extract filter values
|
||||
var buildingIds = imageFilter?.BuildingIds;
|
||||
var floorIds = imageFilter?.FloorIds;
|
||||
var workAreaIds = imageFilter?.WorkAreaIds;
|
||||
var activityIds = imageFilter?.ActivityIds;
|
||||
var workCategoryIds = imageFilter?.WorkCategoryIds;
|
||||
var startDate = imageFilter?.StartDate;
|
||||
var endDate = imageFilter?.EndDate;
|
||||
var uploadedByIds = imageFilter?.UploadedByIds;
|
||||
|
||||
// Step 5: Fetch building > floor > area > work item hierarchy
|
||||
List<Building>? buildings = null;
|
||||
List<Floor>? floors = null;
|
||||
List<WorkArea>? workAreas = null;
|
||||
|
||||
if (buildingIds != null && buildingIds.Count > 0)
|
||||
{
|
||||
|
||||
buildings = await _context.Buildings
|
||||
.Where(b => b.ProjectId == projectId && buildingIds.Contains(b.Id))
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
buildings = await _context.Buildings
|
||||
.Where(b => b.ProjectId == projectId)
|
||||
.ToListAsync();
|
||||
|
||||
buildingIds = buildings.Select(b => b.Id).ToList();
|
||||
}
|
||||
|
||||
if (floorIds != null && floorIds.Count > 0)
|
||||
{
|
||||
floors = await _context.Floor
|
||||
.Where(f => buildingIds.Contains(f.BuildingId) && floorIds.Contains(f.Id))
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
floors = await _context.Floor
|
||||
.Where(f => buildingIds.Contains(f.BuildingId))
|
||||
.ToListAsync();
|
||||
|
||||
floorIds = floors.Select(f => f.Id).ToList();
|
||||
}
|
||||
if (workAreaIds != null && workAreaIds.Count > 0)
|
||||
{
|
||||
workAreas = await _context.WorkAreas
|
||||
.Where(wa => floorIds.Contains(wa.FloorId) && workAreaIds.Contains(wa.Id))
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
workAreas = await _context.WorkAreas
|
||||
.Where(wa => floorIds.Contains(wa.FloorId))
|
||||
.ToListAsync();
|
||||
|
||||
workAreaIds = workAreas.Select(wa => wa.Id).ToList();
|
||||
}
|
||||
|
||||
var workItemsQuery = _context.WorkItems.Include(w => w.ActivityMaster).Include(w => w.WorkCategoryMaster)
|
||||
.Where(wi => workAreaIds.Contains(wi.WorkAreaId));
|
||||
if (activityIds?.Any() == true) workItemsQuery = workItemsQuery.Where(wi => activityIds.Contains(wi.ActivityId));
|
||||
|
||||
if (workCategoryIds?.Any() == true)
|
||||
{
|
||||
workItemsQuery = workItemsQuery.Where(wi => wi.WorkCategoryMaster != null && workCategoryIds.Contains(wi.WorkCategoryMaster.Id));
|
||||
}
|
||||
var workItems = await workItemsQuery.ToListAsync();
|
||||
var workItemIds = workItems.Select(wi => wi.Id).ToList();
|
||||
|
||||
// Step 6: Fetch task allocations and comments
|
||||
var tasks = await _context.TaskAllocations.Include(t => t.ReportedBy)
|
||||
.Where(t => workItemIds.Contains(t.WorkItemId)).ToListAsync();
|
||||
var taskIds = tasks.Select(t => t.Id).ToList();
|
||||
|
||||
var comments = await _context.TaskComments.Include(c => c.Employee)
|
||||
.Where(c => taskIds.Contains(c.TaskAllocationId)).ToListAsync();
|
||||
var commentIds = comments.Select(c => c.Id).ToList();
|
||||
|
||||
var attachments = await _context.TaskAttachments
|
||||
.Where(ta => taskIds.Contains(ta.ReferenceId) || commentIds.Contains(ta.ReferenceId)).ToListAsync();
|
||||
|
||||
var documentIds = attachments.Select(ta => ta.DocumentId).ToList();
|
||||
|
||||
// Step 7: Fetch and filter documents
|
||||
List<DocumentBatchDto> documents = new List<DocumentBatchDto>();
|
||||
var docQuery = _context.Documents.Include(d => d.UploadedBy)
|
||||
.Where(d => documentIds.Contains(d.Id) && d.TenantId == tenantId);
|
||||
if (startDate != null && endDate != null)
|
||||
{
|
||||
docQuery = docQuery.Where(d => d.UploadedAt.Date >= startDate.Value.Date && d.UploadedAt.Date <= endDate.Value.Date);
|
||||
}
|
||||
if (pageNumber != null && pageSize != null)
|
||||
{
|
||||
documents = await docQuery
|
||||
.GroupBy(d => d.BatchId)
|
||||
.OrderByDescending(g => g.Max(d => d.UploadedAt))
|
||||
.Skip((pageNumber.Value - 1) * pageSize.Value)
|
||||
.Take(pageSize.Value)
|
||||
.Select(g => new DocumentBatchDto
|
||||
{
|
||||
BatchId = g.Key,
|
||||
Documents = g.ToList()
|
||||
})
|
||||
.ToListAsync();
|
||||
Console.Write("Pagenation Success");
|
||||
}
|
||||
|
||||
|
||||
// Step 8: Build response
|
||||
var documentVM = documents.Select(d =>
|
||||
{
|
||||
var docIds = d.Documents?.Select(x => x.Id).ToList() ?? new List<Guid>();
|
||||
var refId = attachments.FirstOrDefault(ta => docIds.Contains(ta.DocumentId))?.ReferenceId;
|
||||
var task = tasks.FirstOrDefault(t => t.Id == refId);
|
||||
var comment = comments.FirstOrDefault(c => c.Id == refId);
|
||||
|
||||
var source = task != null ? "Report" : comment != null ? "Comment" : "";
|
||||
var uploadedBy = task?.ReportedBy ?? comment?.Employee;
|
||||
|
||||
if (comment != null)
|
||||
{
|
||||
task = tasks.FirstOrDefault(t => t.Id == comment.TaskAllocationId);
|
||||
}
|
||||
if (task != null)
|
||||
{
|
||||
comment = comments.OrderBy(c => c.CommentDate).FirstOrDefault(c => c.TaskAllocationId == task.Id);
|
||||
}
|
||||
|
||||
var workItem = workItems.FirstOrDefault(w => w.Id == task?.WorkItemId);
|
||||
var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId);
|
||||
var floor = floors.FirstOrDefault(f => f.Id == workArea?.FloorId);
|
||||
var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId);
|
||||
|
||||
return new
|
||||
{
|
||||
|
||||
BatchId = d.BatchId,
|
||||
Documents = d.Documents?.Select(x => new
|
||||
{
|
||||
Id = x.Id,
|
||||
thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null),
|
||||
Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null,
|
||||
UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(),
|
||||
UploadedAt = x.UploadedAt,
|
||||
}).ToList(),
|
||||
Source = source,
|
||||
ProjectId = projectId,
|
||||
BuildingId = building?.Id,
|
||||
BuildingName = building?.Name,
|
||||
FloorIds = floor?.Id,
|
||||
FloorName = floor?.FloorName,
|
||||
WorkAreaId = workArea?.Id,
|
||||
WorkAreaName = workArea?.AreaName,
|
||||
TaskId = task?.Id,
|
||||
ActivityId = workItem?.ActivityMaster?.Id,
|
||||
ActivityName = workItem?.ActivityMaster?.ActivityName,
|
||||
WorkCategoryId = workItem?.WorkCategoryMaster?.Id,
|
||||
WorkCategoryName = workItem?.WorkCategoryMaster?.Name,
|
||||
CommentId = comment?.Id,
|
||||
Comment = comment?.Comment
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
if (uploadedByIds?.Any() == true)
|
||||
{
|
||||
documentVM = documentVM.Where(d => d.Documents != null && d.Documents.Any(x => uploadedByIds.Contains(x.UploadedBy?.Id ?? Guid.Empty))).ToList();
|
||||
}
|
||||
|
||||
_logger.LogInfo("[GetImageList] Fetched {Count} documents for ProjectId: {ProjectId}", documentVM.Count, projectId);
|
||||
return Ok(ApiResponse<object>.SuccessResponse(documentVM, $"{documentVM.Count} image records fetched successfully", 200));
|
||||
}
|
||||
|
||||
[HttpGet("batch/{batchId}")]
|
||||
public async Task<IActionResult> GetImagesByBatch(Guid batchId)
|
||||
{
|
||||
_logger.LogInfo("GetImagesByBatch called for BatchId: {BatchId}", batchId);
|
||||
|
||||
// Step 1: Get the logged-in employee
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Step 2: Retrieve all documents in the batch
|
||||
var documents = await _context.Documents
|
||||
.Include(d => d.UploadedBy)
|
||||
.Where(d => d.BatchId == batchId)
|
||||
.ToListAsync();
|
||||
|
||||
if (!documents.Any())
|
||||
{
|
||||
_logger.LogWarning("No documents found for BatchId: {BatchId}", batchId);
|
||||
return NotFound(ApiResponse<object>.ErrorResponse("No images found", "No images associated with this batch", 404));
|
||||
}
|
||||
|
||||
var documentIds = documents.Select(d => d.Id).ToList();
|
||||
|
||||
// Step 3: Get task/comment reference IDs linked to these documents
|
||||
var referenceIds = await _context.TaskAttachments
|
||||
.Where(ta => documentIds.Contains(ta.DocumentId))
|
||||
.Select(ta => ta.ReferenceId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
// Step 4: Try to identify the source of the attachment (task or comment)
|
||||
var task = await _context.TaskAllocations
|
||||
.Include(t => t.ReportedBy)
|
||||
.FirstOrDefaultAsync(t => referenceIds.Contains(t.Id));
|
||||
|
||||
TaskComment? comment = null;
|
||||
WorkItem? workItem = null;
|
||||
Employee? uploadedBy = null;
|
||||
string source = "";
|
||||
|
||||
if (task != null)
|
||||
{
|
||||
uploadedBy = task.ReportedBy;
|
||||
workItem = await _context.WorkItems
|
||||
.Include(wi => wi.ActivityMaster)
|
||||
.Include(wi => wi.WorkCategoryMaster)
|
||||
.FirstOrDefaultAsync(wi => wi.Id == task.WorkItemId);
|
||||
source = "Report";
|
||||
}
|
||||
else
|
||||
{
|
||||
comment = await _context.TaskComments
|
||||
.Include(tc => tc.TaskAllocation)
|
||||
.Include(tc => tc.Employee)
|
||||
.FirstOrDefaultAsync(tc => referenceIds.Contains(tc.Id));
|
||||
var workItemId = comment?.TaskAllocation?.WorkItemId;
|
||||
|
||||
uploadedBy = comment?.Employee;
|
||||
workItem = await _context.WorkItems
|
||||
.Include(wi => wi.ActivityMaster)
|
||||
.Include(wi => wi.WorkCategoryMaster)
|
||||
.FirstOrDefaultAsync(wi => wi.Id == workItemId);
|
||||
source = "Comment";
|
||||
}
|
||||
|
||||
// Step 5: Traverse up to building level
|
||||
var workAreaId = workItem?.WorkAreaId;
|
||||
var workArea = await _context.WorkAreas
|
||||
.Include(wa => wa.Floor)
|
||||
.FirstOrDefaultAsync(wa => wa.Id == workAreaId);
|
||||
|
||||
var buildingId = workArea?.Floor?.BuildingId;
|
||||
var building = await _context.Buildings
|
||||
.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
|
||||
// Step 6: Construct the response
|
||||
var response = new
|
||||
{
|
||||
|
||||
BatchId = batchId,
|
||||
Documents = documents?.Select(x => new
|
||||
{
|
||||
Id = x.Id,
|
||||
thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null),
|
||||
Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null,
|
||||
UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(),
|
||||
UploadedAt = x.UploadedAt,
|
||||
}).ToList(),
|
||||
Source = source,
|
||||
ProjectId = building?.ProjectId,
|
||||
BuildingId = building?.Id,
|
||||
BuildingName = building?.Name,
|
||||
FloorIds = workArea?.Floor?.Id,
|
||||
FloorName = workArea?.Floor?.FloorName,
|
||||
WorkAreaId = workArea?.Id,
|
||||
WorkAreaName = workArea?.AreaName,
|
||||
TaskId = task?.Id,
|
||||
ActivityId = workItem?.ActivityMaster?.Id,
|
||||
ActivityName = workItem?.ActivityMaster?.ActivityName,
|
||||
WorkCategoryId = workItem?.WorkCategoryMaster?.Id,
|
||||
WorkCategoryName = workItem?.WorkCategoryMaster?.Name,
|
||||
CommentId = comment?.Id,
|
||||
Comment = comment?.Comment
|
||||
};
|
||||
|
||||
_logger.LogInfo("Fetched {Count} image(s) for BatchId: {BatchId}", response.Documents?.Count ?? 0, batchId);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Images for provided batchId fetched successfully", 200));
|
||||
}
|
||||
|
||||
[HttpGet("{documentId}")]
|
||||
public async Task<IActionResult> GetImage(Guid documentId)
|
||||
{
|
||||
// Log the start of the image fetch process
|
||||
_logger.LogInfo("GetImage called for DocumentId: {DocumentId}", documentId);
|
||||
|
||||
// Step 1: Get the currently logged-in employee (for future use like permission checks or auditing)
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Step 2: Fetch the document from the database based on the provided ID
|
||||
var document = await _context.Documents.FirstOrDefaultAsync(d => d.Id == documentId);
|
||||
|
||||
// Step 3: If document doesn't exist, return a 400 Bad Request response
|
||||
if (document == null)
|
||||
{
|
||||
_logger.LogWarning("Document not found for DocumentId: {DocumentId}", documentId);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Document not found", "Document not found", 400));
|
||||
}
|
||||
|
||||
// Step 4: Generate pre-signed URLs for thumbnail and full image (if keys exist)
|
||||
string? thumbnailUrl = document.ThumbS3Key != null
|
||||
? _s3Service.GeneratePreSignedUrlAsync(document.ThumbS3Key)
|
||||
: null;
|
||||
|
||||
string? imageUrl = document.S3Key != null
|
||||
? _s3Service.GeneratePreSignedUrlAsync(document.S3Key)
|
||||
: null;
|
||||
|
||||
// Step 5: Prepare the response object
|
||||
var response = new
|
||||
{
|
||||
ThumbnailUrl = thumbnailUrl,
|
||||
ImageUrl = imageUrl
|
||||
};
|
||||
|
||||
// Step 6: Log successful fetch and return the result
|
||||
_logger.LogInfo("Image fetched successfully for DocumentId: {DocumentId}", documentId);
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Image fetched successfully", 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,13 @@ using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Model.ViewModels.Activities;
|
||||
using Marco.Pms.Services.Helpers;
|
||||
using Marco.Pms.Services.Hubs;
|
||||
using Marco.Pms.Services.Service;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Document = Marco.Pms.Model.DocumentManager.Document;
|
||||
@ -28,17 +30,20 @@ namespace MarcoBMS.Services.Controllers
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly S3UploadService _s3Service;
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly IHubContext<MarcoHub> _signalR;
|
||||
private readonly PermissionServices _permissionServices;
|
||||
private readonly CacheUpdateHelper _cache;
|
||||
private readonly Guid Approve_Task;
|
||||
private readonly Guid Assign_Report_Task;
|
||||
|
||||
public TaskController(ApplicationDbContext context, UserHelper userHelper, S3UploadService s3Service, ILoggingService logger, PermissionServices permissionServices, CacheUpdateHelper cache)
|
||||
public TaskController(ApplicationDbContext context, UserHelper userHelper, S3UploadService s3Service, ILoggingService logger, PermissionServices permissionServices,
|
||||
IHubContext<MarcoHub> signalR, CacheUpdateHelper cache)
|
||||
{
|
||||
_context = context;
|
||||
_userHelper = userHelper;
|
||||
_s3Service = s3Service;
|
||||
_logger = logger;
|
||||
_signalR = signalR;
|
||||
_permissionServices = permissionServices;
|
||||
_cache = cache;
|
||||
Approve_Task = Guid.Parse("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c");
|
||||
@ -199,16 +204,22 @@ namespace MarcoBMS.Services.Controllers
|
||||
var comment = reportTask.ToCommentFromReportTaskDto(tenantId, loggedInEmployee.Id);
|
||||
_context.TaskComments.Add(comment);
|
||||
|
||||
int numberofImages = 0;
|
||||
|
||||
var workAreaId = taskAllocation.WorkItem?.WorkAreaId;
|
||||
var workArea = await _context.WorkAreas.Include(a => a.Floor)
|
||||
.FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea();
|
||||
|
||||
var buildingId = workArea.Floor?.BuildingId;
|
||||
|
||||
var building = await _context.Buildings
|
||||
.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
var batchId = Guid.NewGuid();
|
||||
var projectId = building?.ProjectId;
|
||||
|
||||
if (reportTask.Images?.Any() == true)
|
||||
{
|
||||
var workAreaId = taskAllocation.WorkItem?.WorkAreaId;
|
||||
var workArea = await _context.WorkAreas.Include(a => a.Floor)
|
||||
.FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea();
|
||||
|
||||
var buildingId = workArea.Floor?.BuildingId;
|
||||
|
||||
var building = await _context.Buildings
|
||||
.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
|
||||
foreach (var image in reportTask.Images)
|
||||
{
|
||||
@ -224,16 +235,18 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
var fileType = _s3Service.GetContentTypeFromBase64(base64);
|
||||
var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_report");
|
||||
var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Actitvity/{fileName}";
|
||||
var objectKey = $"tenant-{tenantId}/project-{projectId}/Actitvity/{fileName}";
|
||||
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
var document = new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployee.Id,
|
||||
FileName = image.FileName ?? "",
|
||||
ContentType = image.ContentType ?? "",
|
||||
S3Key = objectKey,
|
||||
Base64Data = image.Base64Data,
|
||||
//Base64Data = image.Base64Data,
|
||||
FileSize = image.FileSize,
|
||||
UploadedAt = DateTime.UtcNow,
|
||||
TenantId = tenantId
|
||||
@ -246,6 +259,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
ReferenceId = reportTask.Id
|
||||
};
|
||||
_context.TaskAttachments.Add(attachment);
|
||||
numberofImages += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +277,9 @@ namespace MarcoBMS.Services.Controllers
|
||||
response.Comments = comments.Select(c => c.ToCommentVMFromTaskComment()).ToList();
|
||||
response.checkList = checkListVMs;
|
||||
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", NumberOfImages = numberofImages, ProjectId = projectId };
|
||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||
|
||||
_logger.LogInfo("Task {TaskId} reported successfully by Employee {EmployeeId}", taskAllocation.Id, loggedInEmployee.Id);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Task reported successfully", 200));
|
||||
@ -274,7 +291,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
_logger.LogInfo("AddCommentForTask called for TaskAllocationId: {TaskId}", createComment.TaskAllocationId);
|
||||
|
||||
var tenantId = GetTenantId();
|
||||
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Validate Task Allocation and associated WorkItem
|
||||
var taskAllocation = await _context.TaskAllocations
|
||||
@ -294,15 +311,18 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
var buildingId = workArea.Floor?.BuildingId ?? Guid.Empty;
|
||||
var building = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
var projectId = building?.ProjectId;
|
||||
|
||||
// Save comment
|
||||
var comment = createComment.ToCommentFromCommentDto(tenantId, employee.Id);
|
||||
var comment = createComment.ToCommentFromCommentDto(tenantId, loggedInEmployee.Id);
|
||||
_context.TaskComments.Add(comment);
|
||||
await _context.SaveChangesAsync();
|
||||
_logger.LogInfo("Comment saved with Id: {CommentId}", comment.Id);
|
||||
|
||||
// Process image uploads
|
||||
var images = createComment.Images;
|
||||
var batchId = Guid.NewGuid();
|
||||
int numberofImages = 0;
|
||||
|
||||
if (images != null && images.Any())
|
||||
{
|
||||
@ -321,17 +341,19 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
var fileType = _s3Service.GetContentTypeFromBase64(base64);
|
||||
var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_comment");
|
||||
var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Activity/{fileName}";
|
||||
var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}";
|
||||
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
_logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey);
|
||||
|
||||
var document = new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployee.Id,
|
||||
FileName = image.FileName ?? string.Empty,
|
||||
ContentType = image.ContentType ?? fileType,
|
||||
S3Key = objectKey,
|
||||
Base64Data = image.Base64Data,
|
||||
//Base64Data = image.Base64Data,
|
||||
FileSize = image.FileSize,
|
||||
UploadedAt = DateTime.UtcNow,
|
||||
TenantId = tenantId
|
||||
@ -346,6 +368,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
};
|
||||
|
||||
_context.TaskAttachments.Add(attachment);
|
||||
numberofImages += 1;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
@ -356,6 +379,9 @@ namespace MarcoBMS.Services.Controllers
|
||||
var response = comment.ToCommentVMFromTaskComment();
|
||||
_logger.LogInfo("Returning response for commentId: {CommentId}", comment.Id);
|
||||
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", NumberOfImages = numberofImages, ProjectId = projectId };
|
||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Comment saved successfully", 200));
|
||||
}
|
||||
|
||||
@ -729,17 +755,21 @@ namespace MarcoBMS.Services.Controllers
|
||||
};
|
||||
_context.TaskComments.Add(comment);
|
||||
|
||||
var workAreaId = taskAllocation.WorkItem?.WorkAreaId;
|
||||
var workArea = await _context.WorkAreas.Include(a => a.Floor)
|
||||
.FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea();
|
||||
|
||||
var buildingId = workArea.Floor?.BuildingId;
|
||||
|
||||
var building = await _context.Buildings
|
||||
.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
var projectId = building?.ProjectId;
|
||||
int numberofImages = 0;
|
||||
|
||||
// Handle image attachments, if any
|
||||
if (approveTask.Images?.Count > 0)
|
||||
{
|
||||
var workAreaId = taskAllocation.WorkItem?.WorkAreaId;
|
||||
var workArea = await _context.WorkAreas.Include(a => a.Floor)
|
||||
.FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea();
|
||||
|
||||
var buildingId = workArea.Floor?.BuildingId;
|
||||
|
||||
var building = await _context.Buildings
|
||||
.FirstOrDefaultAsync(b => b.Id == buildingId);
|
||||
var batchId = Guid.NewGuid();
|
||||
|
||||
foreach (var image in approveTask.Images)
|
||||
{
|
||||
@ -753,16 +783,18 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
var fileType = _s3Service.GetContentTypeFromBase64(base64);
|
||||
var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_comment");
|
||||
var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Activity/{fileName}";
|
||||
var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}";
|
||||
|
||||
await _s3Service.UploadFileAsync(base64, fileType, objectKey);
|
||||
|
||||
var document = new Document
|
||||
{
|
||||
BatchId = batchId,
|
||||
UploadedById = loggedInEmployee.Id,
|
||||
FileName = fileName,
|
||||
ContentType = image.ContentType ?? string.Empty,
|
||||
S3Key = objectKey,
|
||||
Base64Data = image.Base64Data,
|
||||
//Base64Data = image.Base64Data,
|
||||
FileSize = image.FileSize,
|
||||
UploadedAt = DateTime.UtcNow,
|
||||
TenantId = tenantId
|
||||
@ -779,12 +811,16 @@ namespace MarcoBMS.Services.Controllers
|
||||
_context.TaskAttachments.Add(attachment);
|
||||
|
||||
_logger.LogInfo("Attachment uploaded for Task {TaskId}: {FileName}", approveTask.Id, fileName);
|
||||
numberofImages += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit all changes to the database
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", NumberOfImages = numberofImages, ProjectId = projectId };
|
||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||
|
||||
_logger.LogInfo("Task {TaskId} successfully approved by Employee {EmployeeId}", approveTask.Id, loggedInEmployee.Id);
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse("Task has been approved", "Task has been approved", 200));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user