Merge pull request 'Added the Get Document Category list API' (#116) from Ashutosh_Task#1018 into Document_Manager

Reviewed-on: #116
This commit is contained in:
ashutosh.nehete 2025-08-28 06:47:43 +00:00
commit a89a2f076f
18 changed files with 184 additions and 33 deletions

View File

@ -0,0 +1,15 @@
using Marco.Pms.Model.Utilities;
namespace Marco.Pms.Model.Dtos.DocumentManager
{
public class DocumentAttachmentDto
{
public required string Name { get; set; }
public string? DocumentId { get; set; }
public required string Description { get; set; }
public Guid EntityId { get; set; }
public required Guid DocumentTypeId { get; set; } // References the type of the document
public required FileUploadModel Attachment { get; set; }
public List<DocumentTagDto>? Tags { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.Model.Dtos.DocumentManager
{
public class DocumentTagDto
{
public required string Name { get; set; }
public required bool IsActive { get; set; }
}
}

View File

@ -0,0 +1,13 @@
namespace Marco.Pms.Model.Filters
{
public class DocumentFilter
{
public List<Guid>? UploadedByIds { get; set; }
public List<Guid>? DocumentTypeIds { get; set; }
public bool IsActive { get; set; } = true;
public bool IsUploadedAt { get; set; } = true;
public bool? IsVerified { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
}

View File

@ -1,4 +1,4 @@
namespace Marco.Pms.Model.Utilities
namespace Marco.Pms.Model.Filters
{
public class ImageFilter
{

View File

@ -1,4 +1,4 @@
namespace Marco.Pms.Model.Utilities
namespace Marco.Pms.Model.Filters
{
public class TenantFilter
{

View File

@ -0,0 +1,9 @@
namespace Marco.Pms.Model.Master
{
public class EntityTypeMaster
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
}

View File

@ -3,9 +3,9 @@
public class FileUploadModel
{
public Guid? DocumentId { get; set; }
public string? FileName { get; set; } // Name of the file (e.g., "image1.png")
public string? Base64Data { get; set; } // Base64-encoded string of the file
public string? ContentType { get; set; } // MIME type (e.g., "image/png", "application/pdf")
public required string FileName { get; set; } // Name of the file (e.g., "image1.png")
public required string Base64Data { get; set; } // Base64-encoded string of the file
public required string ContentType { get; set; } // MIME type (e.g., "image/png", "application/pdf")
public long FileSize { get; set; } // File size in bytes
public string? Description { get; set; } // Optional: Description or purpose of the file
public bool IsActive { get; set; } = true;

View File

@ -0,0 +1,10 @@
namespace Marco.Pms.Model.ViewModels.DocumentManager
{
public class DocumentCategoryVM
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public Guid EntityTypeId { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using Marco.Pms.Model.ViewModels.Activities;
namespace Marco.Pms.Model.ViewModels.DocumentManager
{
public class DocumentListVM
{
public Guid Id { get; set; }
public string? Name { get; set; }
public string? DocumentId { get; set; }
public string? Description { get; set; }
public DateTime UploadedAt { get; set; }
public BasicEmployeeVM? UploadedBy { get; set; }
public DocumentTypeVM? DocumentType { get; set; }
public bool IsActive { get; set; }
public bool IsVerified { get; set; }
}
}

View File

@ -0,0 +1,16 @@
namespace Marco.Pms.Model.ViewModels.DocumentManager
{
public class DocumentTypeVM
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string? RegexExpression { get; set; }
public string AllowedContentType { get; set; } = string.Empty;
public int MaxFilesAllowed { get; set; }
public double MaxSizeAllowedInKB { get; set; }
public bool IsValidationRequired { get; set; }
public bool IsSystem { get; set; }
public bool IsActive { get; set; }
public DocumentCategoryVM? DocumentCategory { get; set; }
}
}

View File

@ -2,6 +2,7 @@
using Marco.Pms.Model.Activities;
using Marco.Pms.Model.Dtos.DocumentManager;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Filters;
using Marco.Pms.Model.Mapper;
using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Utilities;

View File

@ -949,5 +949,17 @@ namespace Marco.Pms.Services.Controllers
}
#endregion
#region =================================================================== Document Category APIs ===================================================================
[HttpGet("document-category/list")]
public async Task<IActionResult> GetDocumentCategoryMasterList([FromQuery] Guid? entityTypeId)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _masterService.GetDocumentCategoryMasterListAsync(entityTypeId, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
}
#endregion
}
}

View File

@ -154,34 +154,6 @@ namespace Marco.Pms.Services.Controllers
}
}
[HttpPost("mail-template1")]
public async Task<IActionResult> AddMailTemplate1([FromBody] MailTemeplateDto mailTemeplateDto)
{
Guid tenantId = _userHelper.GetTenantId();
if (string.IsNullOrWhiteSpace(mailTemeplateDto.Body) && string.IsNullOrWhiteSpace(mailTemeplateDto.Title))
{
_logger.LogWarning("User tries to set email template but send invalid data");
return BadRequest(ApiResponse<object>.ErrorResponse("Provided Invalid data", "Provided Invalid data", 400));
}
var existngTemalate = await _context.MailingList.FirstOrDefaultAsync(t => t.Title.ToLower() == mailTemeplateDto.Title.ToLower());
if (existngTemalate != null)
{
_logger.LogWarning("User tries to set email template, but title already existed in database");
return BadRequest(ApiResponse<object>.ErrorResponse("Email title is already existed", "Email title is already existed", 400));
}
MailingList mailingList = new MailingList
{
Title = mailTemeplateDto.Title,
Body = mailTemeplateDto.Body,
Subject = mailTemeplateDto.Subject,
Keywords = mailTemeplateDto.Keywords,
TenantId = tenantId
};
_context.MailingList.Add(mailingList);
await _context.SaveChangesAsync();
return Ok("Success");
}
/// <summary>
/// Adds a new mail template.
/// </summary>

View File

@ -4,6 +4,7 @@ using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.Dtos.Tenant;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Filters;
using Marco.Pms.Model.MongoDBModels.Utility;
using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Roles;

View File

@ -1,6 +1,8 @@
using AutoMapper;
using Marco.Pms.Model.AppMenu;
using Marco.Pms.Model.DocumentManager;
using Marco.Pms.Model.Dtos.AppMenu;
using Marco.Pms.Model.Dtos.DocumentManager;
using Marco.Pms.Model.Dtos.Expenses;
using Marco.Pms.Model.Dtos.Master;
using Marco.Pms.Model.Dtos.Project;
@ -306,6 +308,16 @@ namespace Marco.Pms.Services.MappingProfiles
dest => dest.DocumentId,
opt => opt.MapFrom(src => Guid.Parse(src.DocumentId)));
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentCategoryMaster, DocumentCategoryVM>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
CreateMap<DocumentAttachmentDto, DocumentAttachment>();
#endregion
#region ======================================================= AppMenu =======================================================

View File

@ -1,12 +1,14 @@
using AutoMapper;
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.DocumentManager;
using Marco.Pms.Model.Dtos.Master;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Master;
using Marco.Pms.Model.MongoDBModels.Utility;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.DocumentManager;
using Marco.Pms.Model.ViewModels.Master;
using Marco.Pms.Services.Helpers;
using Marco.Pms.Services.Service.ServiceInterfaces;
@ -487,6 +489,61 @@ namespace Marco.Pms.Services.Service
}
}
#endregion
#region =================================================================== Document Category APIs ===================================================================
/// <summary>
/// Fetches the list of Document Categories for a given tenant and optional entity type.
/// Ensures tenant validation, mapping, and proper logging.
/// </summary>
/// <param name="entityTypeId">Optional entity type filter (e.g., EmployeeEntity, ProjectEntity).</param>
/// <param name="loggedInEmployee">Currently logged-in employee.</param>
/// <param name="tenantId">Tenant Id context.</param>
/// <returns>ApiResponse containing the document categories or error details.</returns>
public async Task<ApiResponse<object>> GetDocumentCategoryMasterListAsync(Guid? entityTypeId, Employee loggedInEmployee, Guid tenantId)
{
try
{
// ✅ Tenant validation
if (tenantId != loggedInEmployee.TenantId)
{
_logger.LogWarning("Access denied. Employee {EmployeeId} (TenantId: {EmployeeTenantId}) attempted to fetch document categories for TenantId: {RequestedTenantId}",
loggedInEmployee.Id, loggedInEmployee.TenantId, tenantId);
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have access to this information", 403);
}
// ✅ Build query
IQueryable<DocumentCategoryMaster> documentCategoryQuery = _context.DocumentCategoryMasters
.AsNoTracking() // optimization: read-only
.Where(dc => dc.TenantId == tenantId);
// ✅ Apply optional filter
if (entityTypeId.HasValue)
{
documentCategoryQuery = documentCategoryQuery.Where(dc => dc.EntityTypeId == entityTypeId.Value);
}
// ✅ Fetch and map
var documentCategories = await documentCategoryQuery.ToListAsync();
var response = _mapper.Map<List<DocumentCategoryVM>>(documentCategories);
_logger.LogInfo("{Count} document categories fetched successfully for TenantId: {TenantId} by Employee {EmployeeId}",
response.Count, tenantId, loggedInEmployee.Id);
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} document categories have been fetched successfully.", 200);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred while fetching document categories for TenantId: {TenantId} by Employee {EmployeeId}",
tenantId, loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Server Error occured", 500);
}
}
#endregion
#region =================================================================== Helper Function ===================================================================

View File

@ -26,5 +26,13 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);
#endregion
#region =================================================================== Payment mode APIs ===================================================================
Task<ApiResponse<object>> GetDocumentCategoryMasterListAsync(Guid? entityTypeId, Employee loggedInEmployee, Guid tenantId);
//Task<ApiResponse<object>> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId);
//Task<ApiResponse<object>> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId);
//Task<ApiResponse<object>> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);
#endregion
}
}