From eee07fa4095d8da704387c445157a245ade4e386 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 26 Apr 2025 12:19:28 +0530 Subject: [PATCH] Created CRUD operation APIs for Forum Master Tables. --- .../Dtos/Forum/TicketPriorityMasterDto.cs | 12 + .../Dtos/Forum/TicketStatusMasterDto.cs | 12 + .../Dtos/Forum/TicketTagMasterDto.cs | 11 + .../Dtos/Forum/TicketTypeMasterDto.cs | 11 + .../Dtos/Forum/UpdateCommentDto.cs | 1 - Marco.Pms.Model/Mapper/ForumMapper.cs | 55 +++- .../Controllers/MasterController.cs | 284 ++++++++++++++++++ 7 files changed, 381 insertions(+), 5 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/Forum/TicketPriorityMasterDto.cs create mode 100644 Marco.Pms.Model/Dtos/Forum/TicketStatusMasterDto.cs create mode 100644 Marco.Pms.Model/Dtos/Forum/TicketTagMasterDto.cs create mode 100644 Marco.Pms.Model/Dtos/Forum/TicketTypeMasterDto.cs diff --git a/Marco.Pms.Model/Dtos/Forum/TicketPriorityMasterDto.cs b/Marco.Pms.Model/Dtos/Forum/TicketPriorityMasterDto.cs new file mode 100644 index 0000000..ddadf60 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Forum/TicketPriorityMasterDto.cs @@ -0,0 +1,12 @@ +namespace Marco.Pms.Model.Dtos.Forum +{ + public class TicketPriorityMasterDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; // e.g., Low, Medium, High, Critical + public int Level { get; set; } // 1 = Low, 2 = Medium... + public string? ColorCode { get; set; } + public bool IsDefault { get; set; } + public int TenantId { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Forum/TicketStatusMasterDto.cs b/Marco.Pms.Model/Dtos/Forum/TicketStatusMasterDto.cs new file mode 100644 index 0000000..cb786ab --- /dev/null +++ b/Marco.Pms.Model/Dtos/Forum/TicketStatusMasterDto.cs @@ -0,0 +1,12 @@ +namespace Marco.Pms.Model.Dtos.Forum +{ + public class TicketStatusMasterDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; // e.g., "Open", "In Progress" + public string? Description { get; set; } + public string? ColorCode { get; set; } // e.g., "#FF0000" + public bool IsDefault { get; set; } // true for system defaults + public int TenantId { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Forum/TicketTagMasterDto.cs b/Marco.Pms.Model/Dtos/Forum/TicketTagMasterDto.cs new file mode 100644 index 0000000..21c7e02 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Forum/TicketTagMasterDto.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.Dtos.Forum +{ + public class TicketTagMasterDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; // e.g., "Bug", "UI", "Urgent" + public string? ColorCode { get; set; } + public int TenantId { get; set; } + public bool IsDefault { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Forum/TicketTypeMasterDto.cs b/Marco.Pms.Model/Dtos/Forum/TicketTypeMasterDto.cs new file mode 100644 index 0000000..ad3dd78 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Forum/TicketTypeMasterDto.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.Dtos.Forum +{ + public class TicketTypeMasterDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; // e.g., "Quality Issue" + public string? Description { get; set; } + public bool IsDefault { get; set; } // true for system defaults + public int TenantId { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs b/Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs index 971c30c..d14b58c 100644 --- a/Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs +++ b/Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs @@ -9,6 +9,5 @@ public DateTime SentAt { get; set; } public Guid? ParentMessageId { get; set; } // For threaded replies public ICollection? Attachments { get; set; } - public int TenantId { get; set; } } } diff --git a/Marco.Pms.Model/Mapper/ForumMapper.cs b/Marco.Pms.Model/Mapper/ForumMapper.cs index 3b8ea21..efd16e5 100644 --- a/Marco.Pms.Model/Mapper/ForumMapper.cs +++ b/Marco.Pms.Model/Mapper/ForumMapper.cs @@ -8,7 +8,7 @@ namespace Marco.Pms.Model.Mapper { public static class ForumMapper { - public static TicketForum ToTicketForumFromCreateTicketDto(this CreateTicketDto createTicketDto) + public static TicketForum ToTicketForumFromCreateTicketDto(this CreateTicketDto createTicketDto, int tenantId) { return new TicketForum { @@ -21,7 +21,7 @@ namespace Marco.Pms.Model.Mapper LinkedProjectId = createTicketDto.LinkedProjectId, LinkedActivityId = createTicketDto.LinkedActivityId, PriorityId = createTicketDto.PriorityId, - TenantId = createTicketDto.TenantId, + TenantId = tenantId, }; } public static TicketForum ToTicketForumFromUpdateTicketDto(this UpdateTicketDto updateTicketDto, TicketForum ticket) @@ -42,7 +42,7 @@ namespace Marco.Pms.Model.Mapper }; } - public static TicketComment ToTicketCommentFromAddCommentDto(this AddCommentDto commentDto) + public static TicketComment ToTicketCommentFromAddCommentDto(this AddCommentDto commentDto, int tenantId) { return new TicketComment { @@ -51,7 +51,7 @@ namespace Marco.Pms.Model.Mapper MessageText = commentDto.MessageText, SentAt = commentDto.SentAt, ParentMessageId = commentDto.ParentMessageId, - TenantId = commentDto.TenantId, + TenantId = tenantId, }; } public static TicketComment ToTicketCommentFromUpdateCommentDto(this UpdateCommentDto updateComment, int tenantId, TicketComment comment) @@ -144,6 +144,19 @@ namespace Marco.Pms.Model.Mapper IsDefault = statusMaster.IsDefault }; } + public static TicketStatusMaster ToTicketStatusMasterFromTicketStatusMasterDto(this TicketStatusMasterDto statusMasterDto) + { + return new TicketStatusMaster + { + Id = statusMasterDto.Id, + Name = statusMasterDto.Name, + Description = statusMasterDto.Description, + ColorCode = statusMasterDto.ColorCode, + IsDefault = statusMasterDto.IsDefault, + TenantId = statusMasterDto.TenantId + + }; + } public static TicketPriorityVM ToTicketPriorityVMFromTicketPriorityMaster(this TicketPriorityMaster priorityMaster) { return new TicketPriorityVM @@ -155,6 +168,18 @@ namespace Marco.Pms.Model.Mapper IsDefault = priorityMaster.IsDefault }; } + public static TicketPriorityMaster ToTicketPriorityMasterFromTicketPriorityMasterDto(this TicketPriorityMasterDto priorityMasterDto) + { + return new TicketPriorityMaster + { + Id = priorityMasterDto.Id, + Name = priorityMasterDto.Name, + Level = priorityMasterDto.Level, + ColorCode = priorityMasterDto.ColorCode, + IsDefault = priorityMasterDto.IsDefault, + TenantId = priorityMasterDto.TenantId + }; + } public static TicketTypeVM ToTicketTypeVMFromTicketTypeMaster(this TicketTypeMaster typeMaster) { return new TicketTypeVM @@ -165,6 +190,17 @@ namespace Marco.Pms.Model.Mapper IsDefault = typeMaster.IsDefault }; } + public static TicketTypeMaster ToTicketTypeMasterFromTicketTypeMasterDto(this TicketTypeMasterDto typeMasterDto) + { + return new TicketTypeMaster + { + Id = typeMasterDto.Id, + Name = typeMasterDto.Name, + Description = typeMasterDto.Description, + IsDefault = typeMasterDto.IsDefault, + TenantId = typeMasterDto.TenantId + }; + } public static TicketTagVM ToTicketTagVMFromTicketTagMaster(this TicketTagMaster tagMaster) { return new TicketTagVM @@ -175,5 +211,16 @@ namespace Marco.Pms.Model.Mapper IsDefault = tagMaster.IsDefault }; } + public static TicketTagMaster ToTicketTagMasterFromTicketTagMasterDto(this TicketTagMasterDto tagMasterDto) + { + return new TicketTagMaster + { + Id = tagMasterDto.Id, + Name = tagMasterDto.Name, + ColorCode = tagMasterDto.ColorCode, + IsDefault = tagMasterDto.IsDefault, + TenantId = tagMasterDto.TenantId + }; + } } } diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 129b57a..38ba783 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -1,5 +1,6 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Activities; +using Marco.Pms.Model.Dtos.Forum; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Forum; using Marco.Pms.Model.Mapper; @@ -214,5 +215,288 @@ namespace Marco.Pms.Services.Controllers _logger.LogInfo("{count} Ticket Tag records fetched successfully from tenant {tenantId}", tagVMs.Count, tenantId); return Ok(ApiResponse.SuccessResponse(tagVMs, System.String.Format("{0} Ticket Tag records fetched successfully", tagVMs.Count), 200)); } + + [HttpPost("ticket-status")] + public async Task CreateTicketStatusMaster(TicketStatusMasterDto statusMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (statusMasterDto != null) + { + TicketStatusMaster? statusMaster = statusMasterDto.ToTicketStatusMasterFromTicketStatusMasterDto(); + _context.TicketStatusMasters.Add(statusMaster); + await _context.SaveChangesAsync(); + + TicketStatusVM statusVM = statusMaster.ToTicketStatusVMFromTicketStatusMaster(); + _logger.LogInfo("Ticket Status master {TicketStatusId} updated successfully from tenant {tenantId}", statusMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(statusVM, "Ticket Status master updated successfully", 200)); + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("Sent Empty payload", "Sent Empty payload", 400)); + } + + [HttpPost("ticket-types")] + public async Task CreateTicketTypeMaster(TicketTypeMasterDto typeMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (typeMasterDto != null) + { + TicketTypeMaster? typeMaster = typeMasterDto.ToTicketTypeMasterFromTicketTypeMasterDto(); + _context.TicketTypeMasters.Update(typeMaster); + await _context.SaveChangesAsync(); + + TicketTypeVM typeVM = typeMaster.ToTicketTypeVMFromTicketTypeMaster(); + _logger.LogInfo("Ticket Type master {TicketTypeId} updated successfully from tenant {tenantId}", typeMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket type master updated successfully", 200)); + + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + + [HttpPost("ticket-priorities")] + public async Task CreateTicketPriorityMaster(TicketPriorityMasterDto priorityMasterDto) + { + + var tenantId = _userHelper.GetTenantId(); + if (priorityMasterDto != null) + { + TicketPriorityMaster? typeMaster = priorityMasterDto.ToTicketPriorityMasterFromTicketPriorityMasterDto(); + _context.TicketPriorityMasters.Update(typeMaster); + await _context.SaveChangesAsync(); + + TicketPriorityVM typeVM = typeMaster.ToTicketPriorityVMFromTicketPriorityMaster(); + _logger.LogInfo("Ticket Priority master {TicketPriorityId} updated successfully from tenant {tenantId}", typeMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket Priority master updated successfully", 200)); + } + + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + + [HttpPost("ticket-tags")] + public async Task CreateTicketTagMaster(TicketTagMasterDto tagMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (tagMasterDto != null) + { + TicketTagMaster? tagMaster = tagMasterDto.ToTicketTagMasterFromTicketTagMasterDto(); + _context.TicketTagMasters.Update(tagMaster); + await _context.SaveChangesAsync(); + + TicketTagVM typeVM = tagMaster.ToTicketTagVMFromTicketTagMaster(); + _logger.LogInfo("Ticket Tag master {TicketTypeId} updated successfully from tenant {tenantId}", tagMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket tag master updated successfully", 200)); + + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + [HttpPost("ticket-status/edit")] + public async Task UpdateTicketStatusMaster(TicketStatusMasterDto statusMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (statusMasterDto != null) + { + TicketStatusMaster? statusMaster = await _context.TicketStatusMasters.FirstOrDefaultAsync(s => s.TenantId == tenantId && s.Id == statusMasterDto.Id); + if (statusMaster != null) + { + statusMaster = statusMasterDto.ToTicketStatusMasterFromTicketStatusMasterDto(); + _context.TicketStatusMasters.Update(statusMaster); + await _context.SaveChangesAsync(); + + TicketStatusVM statusVM = statusMaster.ToTicketStatusVMFromTicketStatusMaster(); + _logger.LogInfo("Ticket Status master {TicketStatusId} updated successfully from tenant {tenantId}", statusMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(statusVM, "Ticket Status master updated successfully", 200)); + } + _logger.LogError("Ticket Status master {TicketStatusId} not found in database", statusMasterDto.Id); + return NotFound(ApiResponse.ErrorResponse("Ticket Status master not found", "Ticket Status master not found", 404)); + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("Sent Empty payload", "Sent Empty payload", 400)); + } + + [HttpPost("ticket-types/edit")] + public async Task UpdateTicketTypeMaster(TicketTypeMasterDto typeMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (typeMasterDto != null) + { + TicketTypeMaster? typeMaster = await _context.TicketTypeMasters.FirstOrDefaultAsync(s => s.TenantId == tenantId && s.Id == typeMasterDto.Id); + if (typeMaster != null) + { + typeMaster = typeMasterDto.ToTicketTypeMasterFromTicketTypeMasterDto(); + _context.TicketTypeMasters.Update(typeMaster); + await _context.SaveChangesAsync(); + + TicketTypeVM typeVM = typeMaster.ToTicketTypeVMFromTicketTypeMaster(); + _logger.LogInfo("Ticket Type master {TicketTypeId} updated successfully from tenant {tenantId}", typeMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket type master updated successfully", 200)); + } + _logger.LogError("Ticket type master {TicketTypeId} not found in database", typeMasterDto.Id); + return NotFound(ApiResponse.ErrorResponse("Ticket type master not found", "Ticket type master not found", 404)); + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + + [HttpPost("ticket-priorities/edit")] + public async Task UpdateTicketPriorityMaster(TicketPriorityMasterDto priorityMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (priorityMasterDto != null) + { + TicketPriorityMaster? typeMaster = await _context.TicketPriorityMasters.FirstOrDefaultAsync(s => s.TenantId == tenantId && s.Id == priorityMasterDto.Id); + if (typeMaster != null) + { + typeMaster = priorityMasterDto.ToTicketPriorityMasterFromTicketPriorityMasterDto(); + _context.TicketPriorityMasters.Update(typeMaster); + await _context.SaveChangesAsync(); + + TicketPriorityVM typeVM = typeMaster.ToTicketPriorityVMFromTicketPriorityMaster(); + _logger.LogInfo("Ticket Priority master {TicketPriorityId} updated successfully from tenant {tenantId}", typeMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket Priority master updated successfully", 200)); + } + _logger.LogError("Ticket Priority master {TicketPriorityId} not found in database", priorityMasterDto.Id); + return NotFound(ApiResponse.ErrorResponse("Ticket Priority master not found", "Ticket Priority master not found", 404)); + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + + [HttpPost("ticket-tags/edit")] + public async Task UpdateTicketTagMaster(TicketTagMasterDto tagMasterDto) + { + var tenantId = _userHelper.GetTenantId(); + if (tagMasterDto != null) + { + TicketTagMaster? tagMaster = await _context.TicketTagMasters.FirstOrDefaultAsync(s => s.TenantId == tenantId && s.Id == tagMasterDto.Id); + if (tagMaster != null) + { + tagMaster = tagMasterDto.ToTicketTagMasterFromTicketTagMasterDto(); + _context.TicketTagMasters.Update(tagMaster); + await _context.SaveChangesAsync(); + + TicketTagVM typeVM = tagMaster.ToTicketTagVMFromTicketTagMaster(); + _logger.LogInfo("Ticket Tag master {TicketTypeId} updated successfully from tenant {tenantId}", tagMaster.Id, tenantId); + return Ok(ApiResponse.SuccessResponse(typeVM, "Ticket tag master updated successfully", 200)); + } + _logger.LogError("Ticket tag master {TicketTypeId} not found in database", tagMasterDto.Id); + return NotFound(ApiResponse.ErrorResponse("Ticket tag master not found", "Ticket tag master not found", 404)); + } + _logger.LogError("User sent empyt payload"); + return BadRequest(ApiResponse.ErrorResponse("User sent Empty payload", "User sent Empty payload", 400)); + } + + [HttpDelete("ticket-status/{id}")] + public async Task DeleteTicketStatusMaster(Guid id) + { + var tenantId = _userHelper.GetTenantId(); + TicketStatusMaster? statusMaster = await _context.TicketStatusMasters.FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Id == id); + if (statusMaster != null) + { + if (statusMaster.IsDefault == false) + { + _context.TicketStatusMasters.Remove(statusMaster); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Ticket Status {TickeStatusId} deleted successfully from tenant {tenantId}", id, tenantId); + return Ok(ApiResponse.SuccessResponse(new { }, "Ticket Status deleted successfully", 200)); + } + else + { + _logger.LogWarning("User tries to delete default ticket Status {TickeStatusId}", id); + return BadRequest(ApiResponse.ErrorResponse("Can not delete default ticket Status", "Can not delete default ticket Status", 400)); + } + } + else + { + _logger.LogError("Ticket Status {TickeStatusId} not found in database", id); + return NotFound(ApiResponse.ErrorResponse("Ticket Status not found", "Ticket Status not found", 404)); + } + } + + [HttpDelete("ticket-types/{id}")] + public async Task DeleteTicketTypeMaster(Guid id) + { + var tenantId = _userHelper.GetTenantId(); + TicketTypeMaster? typeMaster = await _context.TicketTypeMasters.FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Id == id); + if (typeMaster != null) + { + if (typeMaster.IsDefault == false) + { + _context.TicketTypeMasters.Remove(typeMaster); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Ticket Type {TickeTypeId} deleted successfully from tenant {tenantId}", id, tenantId); + return Ok(ApiResponse.SuccessResponse(new { }, "Ticket Type deleted successfully", 200)); + } + else + { + _logger.LogWarning("User tries to delete default ticket Type {TickeTypeId}", id); + return BadRequest(ApiResponse.ErrorResponse("Can not delete default ticket Type", "Can not delete default ticket Type", 400)); + } + } + else + { + _logger.LogError("Ticket Type {TickeTypeId} not found in database", id); + return NotFound(ApiResponse.ErrorResponse("Ticket Type not found", "Ticket Type not found", 404)); + } + } + + [HttpDelete("ticket-priorities/{id}")] + public async Task DeleteTicketPriorityMaster(Guid id) + { + var tenantId = _userHelper.GetTenantId(); + TicketPriorityMaster? priorityMaster = await _context.TicketPriorityMasters.FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Id == id); + if (priorityMaster != null) + { + if (priorityMaster.IsDefault == false) + { + _context.TicketPriorityMasters.Remove(priorityMaster); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Ticket Priority {TickePriorityId} deleted successfully from tenant {tenantId}", id, tenantId); + return Ok(ApiResponse.SuccessResponse(new { }, "Ticket Priority deleted successfully", 200)); + } + else + { + _logger.LogWarning("User tries to delete default ticket Priority {TickePriorityId}", id); + return BadRequest(ApiResponse.ErrorResponse("Can not delete default ticket Priority", "Can not delete default ticket Priority", 400)); + } + } + else + { + _logger.LogError("Ticket Priority {TickePriorityId} not found in database", id); + return NotFound(ApiResponse.ErrorResponse("Ticket Priority not found", "Ticket Priority not found", 404)); + } + } + + [HttpDelete("ticket-tags/{id}")] + public async Task DeleteTicketTagMaster(Guid id) + { + var tenantId = _userHelper.GetTenantId(); + TicketTagMaster? tagMaster = await _context.TicketTagMasters.FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Id == id); + if (tagMaster != null) + { + if (tagMaster.IsDefault == false) + { + _context.TicketTagMasters.Remove(tagMaster); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Ticket Tag {TickeTagId} deleted successfully from tenant {tenantId}", id, tenantId); + return Ok(ApiResponse.SuccessResponse(new { }, "Ticket Tag deleted successfully", 200)); + } + else + { + _logger.LogWarning("User tries to delete default ticket tag {TickeTagId}", id); + return BadRequest(ApiResponse.ErrorResponse("Can not delete default ticket tag", "Can not delete default ticket tag", 400)); + } + } + else + { + _logger.LogError("Ticket Tag {TickeTagId} not found in database", id); + return NotFound(ApiResponse.ErrorResponse("Ticket tag not found", "Ticket tag not found", 404)); + } + } } }