Merge pull request 'Directory_Refactor' (#128) from Directory_Refactor into Document_Manager

Reviewed-on: #128
This commit is contained in:
ashutosh.nehete 2025-09-09 11:03:45 +00:00
commit 5263e89df6
17 changed files with 3395 additions and 1740 deletions

View File

@ -24,10 +24,32 @@ namespace Marco.Pms.Helpers.Utility
#region =================================================================== Update Log Helper Functions =================================================================== #region =================================================================== Update Log Helper Functions ===================================================================
public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName) public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName)
{
try
{ {
var collection = _mongoDatabase.GetCollection<UpdateLogsObject>(collectionName); var collection = _mongoDatabase.GetCollection<UpdateLogsObject>(collectionName);
await collection.InsertOneAsync(oldObject); await collection.InsertOneAsync(oldObject);
} }
catch (Exception ex)
{
_logger.LogError(ex, "Exception occured while saving object of update logs in collection: {Collection}", collectionName);
}
}
public async Task PushListToUpdateLogsAsync(List<UpdateLogsObject> oldObjects, string collectionName)
{
try
{
var collection = _mongoDatabase.GetCollection<UpdateLogsObject>(collectionName);
if (oldObjects.Any())
{
await collection.InsertManyAsync(oldObjects);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception occured while saving list of update logs in collection: {Collection}", collectionName);
}
}
public async Task<List<UpdateLogsObject>> GetFromUpdateLogsByEntityIdAsync(Guid entityId, string collectionName) public async Task<List<UpdateLogsObject>> GetFromUpdateLogsByEntityIdAsync(Guid entityId, string collectionName)
{ {

View File

@ -1,6 +1,6 @@
using System.ComponentModel; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace Marco.Pms.Model.Directory namespace Marco.Pms.Model.Directory
{ {

View File

@ -1,6 +1,6 @@
using System.ComponentModel; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace Marco.Pms.Model.Directory namespace Marco.Pms.Model.Directory
{ {

View File

@ -4,6 +4,7 @@
{ {
public string? Label { get; set; } public string? Label { get; set; }
public string? EmailAddress { get; set; } public string? EmailAddress { get; set; }
public bool IsPrimary { get; set; } = false;
} }
} }

View File

@ -4,5 +4,6 @@
{ {
public string? Label { get; set; } public string? Label { get; set; }
public string? PhoneNumber { get; set; } public string? PhoneNumber { get; set; }
public bool IsPrimary { get; set; } = false;
} }
} }

View File

@ -0,0 +1,12 @@
namespace Marco.Pms.Model.Logs
{
public class LogStructure
{
public string LogLevel { get; set; } = "Info";
public string Message { get; set; } = string.Empty;
public DateTime TimeStamp { get; set; }
public string? IpAddress { get; set; }
public string? UserAgent { get; set; }
public string? Details { get; set; } // json serialized string
}
}

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.Model.Utilities
{
public class ContactNoteFilter
{
public List<Guid>? CreatedByIds { get; set; }
public List<string>? Organizations { get; set; }
}
}

View File

@ -1,6 +1,6 @@
using Marco.Pms.Model.Dtos.Directory; using Marco.Pms.Model.Dtos.Directory;
using Marco.Pms.Model.Utilities; using Marco.Pms.Services.Service.ServiceInterfaces;
using Marco.Pms.Services.Helpers; using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service; using MarcoBMS.Services.Service;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -14,14 +14,33 @@ namespace Marco.Pms.Services.Controllers
public class DirectoryController : ControllerBase public class DirectoryController : ControllerBase
{ {
private readonly DirectoryHelper _directoryHelper; private readonly IDirectoryService _directoryService;
private readonly UserHelper _userHelper;
private readonly ILoggingService _logger; private readonly ILoggingService _logger;
private readonly ISignalRService _signalR;
private readonly Guid tenantId;
public DirectoryController(IDirectoryService directoryHelper, UserHelper userHelper, ILoggingService logger, ISignalRService signalR)
public DirectoryController(DirectoryHelper directoryHelper, ILoggingService logger)
{ {
_directoryHelper = directoryHelper; _directoryService = directoryHelper;
_userHelper = userHelper;
_logger = logger; _logger = logger;
tenantId = userHelper.GetTenantId();
_signalR = signalR;
}
#region =================================================================== Contact APIs ===================================================================
#region =================================================================== Contact Get APIs ===================================================================
[HttpGet("list")]
public async Task<IActionResult> GetContactList([FromQuery] string? search, [FromQuery] string? filter, [FromQuery] Guid? projectId, [FromQuery] bool active = true,
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.GetListOfContactsAsync(search: search, filter: filter, projectId: projectId, active: active, pageSize: pageSize, pageNumber: pageNumber, tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response);
} }
[HttpGet] [HttpGet]
@ -32,266 +51,224 @@ namespace Marco.Pms.Services.Controllers
BucketIds = bucketIds, BucketIds = bucketIds,
CategoryIds = categoryIds CategoryIds = categoryIds
}; };
var response = await _directoryHelper.GetListOfContacts(search, active, filterDto, projectId); var response = await _directoryService.GetListOfContactsOld(search, active, filterDto, projectId);
return StatusCode(response.StatusCode, response);
return StatusCode(response.StatusCode, response);
} }
[HttpGet("contact-bucket/{bucketId}")] [HttpGet("contact-bucket/{bucketId}")]
public async Task<IActionResult> GetContactsListByBucketId(Guid bucketId) public async Task<IActionResult> GetContactsListByBucketId(Guid bucketId)
{ {
var response = await _directoryHelper.GetContactsListByBucketId(bucketId); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
return StatusCode(response.StatusCode, response); var response = await _directoryService.GetContactsListByBucketIdAsync(bucketId, tenantId, loggedInEmployee);
}
[HttpPost]
public async Task<IActionResult> CreateContact([FromBody] CreateContactDto createContact)
{
if (!ModelState.IsValid)
{
var errors = ModelState.Values
.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage)
.ToList();
_logger.LogWarning("User sent Invalid Date while marking attendance");
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
}
var response = await _directoryHelper.CreateContact(createContact);
return StatusCode(response.StatusCode, response);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateContact(Guid id, [FromBody] UpdateContactDto updateContact)
{
var response = await _directoryHelper.UpdateContact(id, updateContact);
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
[HttpGet("profile/{id}")] [HttpGet("profile/{id}")]
public async Task<IActionResult> GetContactProfile(Guid id) public async Task<IActionResult> GetContactProfile(Guid id)
{ {
var response = await _directoryHelper.GetContactProfile(id); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.GetContactProfileAsync(id, tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
[HttpGet("organization")] [HttpGet("organization")]
public async Task<IActionResult> GetOrganizationList() public async Task<IActionResult> GetOrganizationList()
{ {
var response = await _directoryHelper.GetOrganizationList(); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
return StatusCode(response.StatusCode, response); var response = await _directoryService.GetOrganizationListAsync(tenantId, loggedInEmployee);
return Ok(response);
} }
[HttpGet("designations")] [HttpGet("designations")]
public async Task<IActionResult> GetDesignationList() public async Task<IActionResult> GetDesignationList()
{ {
var response = await _directoryHelper.GetDesignationList(); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.GetDesignationListAsync(tenantId, loggedInEmployee);
return Ok(response);
}
[HttpGet("contact/filter")]
public async Task<IActionResult> GetContactFilterObject()
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.GetContactFilterObjectAsync(tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response);
}
#endregion
[HttpPost]
public async Task<IActionResult> CreateContact([FromBody] CreateContactDto createContact)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.CreateContactAsync(createContact, tenantId, loggedInEmployee);
if (response.Success)
{
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory", Response = response.Data };
await _signalR.SendNotificationAsync(notification);
}
return StatusCode(response.StatusCode, response);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateContact(Guid id, [FromBody] UpdateContactDto updateContact)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.UpdateContactAsync(id, updateContact, tenantId, loggedInEmployee);
if (response.Success)
{
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory", Response = response.Data };
await _signalR.SendNotificationAsync(notification);
}
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]
public async Task<IActionResult> DeleteContact(Guid id, [FromQuery] bool? active) public async Task<IActionResult> DeleteContact(Guid id, [FromQuery] bool active = false)
{ {
var response = await _directoryHelper.DeleteContact(id, active ?? false); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.DeleteContactAsync(id, active, tenantId, loggedInEmployee);
if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory", Response = id };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
#endregion
// -------------------------------- Contact Notes -------------------------------- #region =================================================================== Contact Notes APIs ===================================================================
[HttpGet("notes")] [HttpGet("notes")]
public async Task<IActionResult> GetListOFAllNotes([FromQuery] Guid? projectId, [FromQuery] int? pageSize, [FromQuery] int pageNumber) public async Task<IActionResult> GetListOFAllNotes([FromQuery] Guid? projectId, [FromQuery] string? searchString, [FromQuery] string? filter, [FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1)
{ {
var response = await _directoryHelper.GetListOFAllNotes(projectId, pageSize ?? 25, pageNumber); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.GetListOFAllNotesAsync(projectId, searchString, filter, pageSize, pageNumber, tenantId, loggedInEmployee);
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
[HttpPost("note")] [HttpPost("note")]
public async Task<IActionResult> CreateContactNote([FromBody] CreateContactNoteDto noteDto) public async Task<IActionResult> CreateContactNote([FromBody] CreateContactNoteDto noteDto)
{ {
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryHelper.CreateContactNote(noteDto); var response = await _directoryService.CreateContactNoteAsync(noteDto, tenantId, loggedInEmployee); ;
if (response.StatusCode == 200) if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Notes", Response = response.Data };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
[HttpGet("notes/{ContactId}")] [HttpGet("notes/{ContactId}")]
public async Task<IActionResult> GetNoteListByContactId(Guid contactId, [FromQuery] bool active = true) public async Task<IActionResult> GetNoteListByContactId(Guid contactId, [FromQuery] bool active = true)
{ {
var response = await _directoryHelper.GetNoteListByContactId(contactId, active); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.GetNoteListByContactIdAsync(contactId, active, tenantId, loggedInEmployee);
{ return StatusCode(response.StatusCode, response);
return Ok(response);
} }
else if (response.StatusCode == 404)
[HttpGet("notes/filter")]
public async Task<IActionResult> GetContactNotesFilterObject()
{ {
return NotFound(response); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
} var response = await _directoryService.GetContactNotesFilterObjectAsync(tenantId, loggedInEmployee);
else return StatusCode(response.StatusCode, response);
{
return BadRequest(response);
}
} }
[HttpPut("note/{id}")] [HttpPut("note/{id}")]
public async Task<IActionResult> UpdateContactNote(Guid id, [FromBody] UpdateContactNoteDto noteDto) public async Task<IActionResult> UpdateContactNote(Guid id, [FromBody] UpdateContactNoteDto noteDto)
{ {
var response = await _directoryHelper.UpdateContactNote(id, noteDto); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.UpdateContactNoteAsync(id, noteDto, tenantId, loggedInEmployee);
if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Notes", Response = response.Data };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
[HttpDelete("note/{id}")] [HttpDelete("note/{id}")]
public async Task<IActionResult> DeleteContactNote(Guid id, [FromQuery] bool? active) public async Task<IActionResult> DeleteContactNote(Guid id, [FromQuery] bool active = false)
{ {
var response = await _directoryHelper.DeleteContactNote(id, active ?? false); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
return Ok(response); var response = await _directoryService.DeleteContactNoteAsync(id, active, tenantId, loggedInEmployee);
if (response.Success)
{
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Notes", Response = response.Data };
await _signalR.SendNotificationAsync(notification);
}
return StatusCode(response.StatusCode, response);
} }
// -------------------------------- Bucket -------------------------------- #endregion
#region =================================================================== Bucket APIs ===================================================================
[HttpGet("buckets")] [HttpGet("buckets")]
public async Task<IActionResult> GetBucketList() public async Task<IActionResult> GetBucketList()
{ {
var response = await _directoryHelper.GetBucketList(); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.GetBucketListAsync(tenantId, loggedInEmployee);
{ return StatusCode(response.StatusCode, response);
return Ok(response);
}
else if (response.StatusCode == 401)
{
return Unauthorized(response);
}
else
{
return BadRequest(response);
}
} }
[HttpPost("bucket")] [HttpPost("bucket")]
public async Task<IActionResult> CreateBucket(CreateBucketDto bucketDto) public async Task<IActionResult> CreateBucket([FromBody] CreateBucketDto bucketDto)
{ {
if (!ModelState.IsValid) var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _directoryService.CreateBucketAsync(bucketDto, tenantId, loggedInEmployee);
if (response.Success)
{ {
var errors = ModelState.Values var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = response.Data };
.SelectMany(v => v.Errors) await _signalR.SendNotificationAsync(notification);
.Select(e => e.ErrorMessage)
.ToList();
_logger.LogWarning("User sent Invalid Date while marking attendance");
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
}
var response = await _directoryHelper.CreateBucket(bucketDto);
if (response.StatusCode == 200)
{
return Ok(response);
}
else if (response.StatusCode == 409)
{
return Conflict(response);
}
else if (response.StatusCode == 401)
{
return Unauthorized(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
[HttpPut("bucket/{id}")] [HttpPut("bucket/{id}")]
public async Task<IActionResult> UpdateBucket(Guid id, [FromBody] UpdateBucketDto bucketDto) public async Task<IActionResult> UpdateBucket(Guid id, [FromBody] UpdateBucketDto bucketDto)
{ {
var response = await _directoryHelper.UpdateBucket(id, bucketDto); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.UpdateBucketAsync(id, bucketDto, tenantId, loggedInEmployee);
if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = response.Data };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else if (response.StatusCode == 401)
{
return Unauthorized(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
[HttpPost("assign-bucket/{bucketId}")] [HttpPost("assign-bucket/{bucketId}")]
public async Task<IActionResult> AssignBucket(Guid bucketId, [FromBody] List<AssignBucketDto> assignBuckets) public async Task<IActionResult> AssignBucket(Guid bucketId, [FromBody] List<AssignBucketDto> assignBuckets)
{ {
var response = await _directoryHelper.AssignBucket(bucketId, assignBuckets); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.AssignBucketAsync(bucketId, assignBuckets, tenantId, loggedInEmployee);
if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = response.Data };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else if (response.StatusCode == 401)
{
return Unauthorized(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
[HttpDelete("bucket/{id}")] [HttpDelete("bucket/{id}")]
public async Task<IActionResult> DeleteBucket(Guid id) public async Task<IActionResult> DeleteBucket(Guid id)
{ {
var response = await _directoryHelper.DeleteBucket(id); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (response.StatusCode == 200) var response = await _directoryService.DeleteBucketAsync(id, tenantId, loggedInEmployee);
if (response.Success)
{ {
return Ok(response); var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Directory_Buckets", Response = id };
} await _signalR.SendNotificationAsync(notification);
else if (response.StatusCode == 404)
{
return NotFound(response);
}
else if (response.StatusCode == 401)
{
return Unauthorized(response);
}
else
{
return BadRequest(response);
} }
return StatusCode(response.StatusCode, response);
} }
#endregion
} }
} }

View File

@ -0,0 +1,128 @@
using Marco.Pms.Model.Logs;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Serilog.Context;
using System.Text.Json;
namespace Marco.Pms.Services.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class LogController : ControllerBase
{
private readonly ILogger<LogController> _logger;
public LogController(ILogger<LogController> logger)
{
_logger = logger;
}
[HttpPost]
/// <summary>
/// Receives a batch of log entries from mobile applications and processes them.
/// Logs are enriched with context properties like UserAgent, Timestamp, and IpAddress.
/// </summary>
/// <param name="logs">A list of LogStructure objects containing log details.</param>
/// <returns>An <see cref="IActionResult"/> indicating the success of the operation.</returns>
public IActionResult MobileLogging([FromBody] List<LogStructure> logs)
{
// Check if logs are provided to avoid processing empty requests
if (logs == null || !logs.Any())
{
_logger.LogWarning("MobileLogging endpoint received an empty or null log list.");
return BadRequest("No log entries provided.");
}
// Iterate through each log entry received from the client
foreach (var log in logs)
{
object? detailsObject = null;
// Attempt to deserialize the 'Details' string into a dynamic object
// This allows structured logging of the details payload.
if (!string.IsNullOrWhiteSpace(log.Details))
{
try
{
// Use JsonDocument for potentially more efficient parsing if you just need the raw JSON or a dynamic object
// For simply logging it as a structured property, object works.
detailsObject = JsonSerializer.Deserialize<Dictionary<string, string>>(log.Details);
}
catch (JsonException ex)
{
// Log a warning if deserialization fails, but continue processing other logs
_logger.LogWarning("Failed to deserialize 'Details' for a log entry. Raw details: '{RawDetails}'. Error: {ErrorMessage}", log.Details, ex.Message);
}
}
// Push common properties to the Serilog LogContext for the current log operation.
// These properties will be attached to the log event itself.
using (LogContext.PushProperty("UserAgent", log.UserAgent))
using (LogContext.PushProperty("Timestamp", log.TimeStamp))
using (LogContext.PushProperty("IpAddress", log.IpAddress))
using (LogContext.PushProperty("LogOrigin", "Mobile Application"))
{
// If details were successfully parsed, push them as a structured property.
if (detailsObject != null)
{
using (LogContext.PushProperty("Details", detailsObject, true)) // 'true' for destructuring
{
LogByLevel(log.LogLevel, log.Message);
}
}
else
{
// If details were null or failed to parse, log without the details property
LogByLevel(log.LogLevel, log.Message);
}
}
}
// Return 200 OK indicating successful receipt of logs.
// As logging is typically a "fire and forget" operation from the client's perspective,
// we don't need to await individual log writes here.
// The logger provider handles the actual writing asynchronously in the background.
_logger.LogInformation("Successfully processed {LogCount} mobile log entries.", logs.Count);
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Logs received successfully.", 200));
}
/// <summary>
/// Logs a message at the specified log level using the injected ILogger.
/// </summary>
/// <param name="logLevel">The string representation of the log level (e.g., "info", "warning").</param>
/// <param name="message">The log message.</param>
private void LogByLevel(string? logLevel, string? message)
{
// Default message if null or empty
message = string.IsNullOrWhiteSpace(message) ? "No message provided." : message;
// Use a switch expression or simple if/else for clarity based on log level
switch (logLevel?.ToLowerInvariant()) // Use ToLowerInvariant for case-insensitive comparison
{
case "debug":
_logger.LogDebug(message);
break;
case "info":
case "information": // Common alias for info
_logger.LogInformation(message);
break;
case "warn":
case "warning":
_logger.LogWarning(message);
break;
case "error":
_logger.LogError(message);
break;
case "critical":
_logger.LogCritical(message);
break;
default:
// Log unknown levels as information to ensure they are captured
_logger.LogInformation("[Unknown Level] {Message}", message);
break;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
using AutoMapper; using AutoMapper;
using Marco.Pms.Model.Directory;
using Marco.Pms.Model.Dtos.Directory;
using Marco.Pms.Model.AppMenu; using Marco.Pms.Model.AppMenu;
using Marco.Pms.Model.DocumentManager; using Marco.Pms.Model.DocumentManager;
using Marco.Pms.Model.Dtos.AppMenu; using Marco.Pms.Model.Dtos.AppMenu;
@ -20,6 +22,7 @@ using Marco.Pms.Model.Projects;
using Marco.Pms.Model.TenantModels; using Marco.Pms.Model.TenantModels;
using Marco.Pms.Model.TenantModels.MongoDBModel; using Marco.Pms.Model.TenantModels.MongoDBModel;
using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Activities;
using Marco.Pms.Model.ViewModels.Directory;
using Marco.Pms.Model.ViewModels.DocumentManager; using Marco.Pms.Model.ViewModels.DocumentManager;
using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Model.ViewModels.Employee;
using Marco.Pms.Model.ViewModels.Expanses; using Marco.Pms.Model.ViewModels.Expanses;
@ -161,6 +164,7 @@ namespace Marco.Pms.Services.MappingProfiles
#endregion #endregion
#region ======================================================= Employee ======================================================= #region ======================================================= Employee =======================================================
CreateMap<Employee, EmployeeVM>(); CreateMap<Employee, EmployeeVM>();
CreateMap<Employee, BasicEmployeeVM>() CreateMap<Employee, BasicEmployeeVM>()
.ForMember( .ForMember(
@ -344,6 +348,43 @@ namespace Marco.Pms.Services.MappingProfiles
dest => dest.Name, dest => dest.Name,
opt => opt.MapFrom(src => src.Text)); opt => opt.MapFrom(src => src.Text));
#endregion #endregion
#region ======================================================= Directory =======================================================
CreateMap<Contact, ContactVM>();
CreateMap<CreateContactDto, Contact>();
CreateMap<UpdateContactDto, Contact>();
CreateMap<Contact, ContactProfileVM>();
CreateMap<ContactPhone, ContactPhoneVM>();
CreateMap<CreateContactPhoneDto, ContactPhone>();
CreateMap<UpdateContactPhoneDto, ContactPhone>();
CreateMap<ContactEmail, ContactEmailVM>();
CreateMap<CreateContactEmailDto, ContactEmail>();
CreateMap<UpdateContactEmailDto, ContactEmail>();
CreateMap<ContactCategoryMaster, ContactCategoryVM>();
CreateMap<ContactTagMaster, ContactTagVM>();
CreateMap<Bucket, BucketVM>();
CreateMap<Bucket, AssignBucketVM>();
CreateMap<ContactNote, ContactNoteVM>()
.ForMember(
dest => dest.ContactName,
opt => opt.MapFrom(src => src.Contact != null ? src.Contact.Name : string.Empty)
)
.ForMember(
dest => dest.OrganizationName,
opt => opt.MapFrom(src => src.Contact != null ? src.Contact.Organization : string.Empty)
);
CreateMap<CreateContactNoteDto, ContactNote>();
CreateMap<UpdateContactNoteDto, ContactNote>();
#endregion
} }
} }
} }

View File

@ -1,6 +1,6 @@
using System.Diagnostics; using MarcoBMS.Services.Service;
using MarcoBMS.Services.Service;
using Serilog.Context; using Serilog.Context;
using System.Diagnostics;
namespace MarcoBMS.Services.Middleware namespace MarcoBMS.Services.Middleware
{ {
@ -34,6 +34,7 @@ namespace MarcoBMS.Services.Middleware
using (LogContext.PushProperty("IpAddress", context.Connection.RemoteIpAddress?.ToString())) using (LogContext.PushProperty("IpAddress", context.Connection.RemoteIpAddress?.ToString()))
using (LogContext.PushProperty("RequestPath", request.Path)) using (LogContext.PushProperty("RequestPath", request.Path))
using (LogContext.PushProperty("Origin", origin)) using (LogContext.PushProperty("Origin", origin))
using (LogContext.PushProperty("LogOrigin", "ASP .NET Api"))

View File

@ -178,14 +178,13 @@ builder.Services.AddScoped<ISignalRService, SignalRService>();
builder.Services.AddScoped<IProjectServices, ProjectServices>(); builder.Services.AddScoped<IProjectServices, ProjectServices>();
builder.Services.AddScoped<IExpensesService, ExpensesService>(); builder.Services.AddScoped<IExpensesService, ExpensesService>();
builder.Services.AddScoped<IMasterService, MasterService>(); builder.Services.AddScoped<IMasterService, MasterService>();
builder.Services.AddScoped<IDirectoryService, DirectoryService>();
#endregion #endregion
#region Helpers #region Helpers
builder.Services.AddScoped<GeneralHelper>(); builder.Services.AddScoped<GeneralHelper>();
builder.Services.AddScoped<UserHelper>(); builder.Services.AddScoped<UserHelper>();
builder.Services.AddScoped<RolesHelper>(); builder.Services.AddScoped<RolesHelper>();
builder.Services.AddScoped<EmployeeHelper>();
builder.Services.AddScoped<DirectoryHelper>();
builder.Services.AddScoped<ReportHelper>(); builder.Services.AddScoped<ReportHelper>();
builder.Services.AddScoped<CacheUpdateHelper>(); builder.Services.AddScoped<CacheUpdateHelper>();
builder.Services.AddScoped<FeatureDetailsHelper>(); builder.Services.AddScoped<FeatureDetailsHelper>();

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
void LogDebug(string? message, params object[]? args); void LogDebug(string? message, params object[]? args);
void LogWarning(string? message, params object[]? args); void LogWarning(string? message, params object[]? args);
void LogError(Exception? ex, string? message, params object[]? args); void LogError(Exception? ex, string? message, params object[]? args);
void LogCritical(string? message, params object[]? args);
} }
} }

View File

@ -61,6 +61,19 @@ namespace MarcoBMS.Services.Service
_logger.LogWarning(message); _logger.LogWarning(message);
} }
} }
public void LogCritical(string? message, params object[]? args)
{
using (LogContext.PushProperty("LogLevel", "Critical"))
if (args != null)
{
_logger.LogCritical(message, args);
}
else
{
_logger.LogCritical(message);
}
}
} }
} }

View File

@ -0,0 +1,38 @@
using Marco.Pms.Model.Dtos.Directory;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
namespace Marco.Pms.Services.Service.ServiceInterfaces
{
public interface IDirectoryService
{
Task<ApiResponse<object>> GetListOfContactsAsync(string? search, string? filter, Guid? projectId, bool active, int pageSize, int pageNumber, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetListOfContactsOld(string? search, bool active, ContactFilterDto? filterDto, Guid? projectId);
Task<ApiResponse<object>> GetContactsListByBucketIdAsync(Guid bucketId, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetContactProfileAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetOrganizationListAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetDesignationListAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetContactFilterObjectAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> CreateContactAsync(CreateContactDto createContact, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> UpdateContactAsync(Guid id, UpdateContactDto updateContact, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> DeleteContactAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetListOFAllNotesAsync(Guid? projectId, string? searchString, string? filter, int pageSize, int pageNumber, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetNoteListByContactIdAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetContactNotesFilterObjectAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> CreateContactNoteAsync(CreateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> UpdateContactNoteAsync(Guid id, UpdateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> DeleteContactNoteAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> GetBucketListAsync(Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> CreateBucketAsync(CreateBucketDto bucketDto, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> UpdateBucketAsync(Guid id, UpdateBucketDto bucketDto, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> AssignBucketAsync(Guid bucketId, List<AssignBucketDto> assignBuckets, Guid tenantId, Employee loggedInEmployee);
Task<ApiResponse<object>> DeleteBucketAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
}
}