diff --git a/Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs b/Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs index 844c584..1ca6795 100644 --- a/Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs +++ b/Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs @@ -7,8 +7,8 @@ namespace Marco.Pms.CacheHelper { public class SidebarMenuHelper { - private readonly IMongoCollection _oldCollection; - private readonly IMongoCollection _collection; + private readonly IMongoCollection _webCollection; + private readonly IMongoCollection _mobileCollection; private readonly ILogger _logger; public SidebarMenuHelper(IConfiguration configuration, ILogger logger) @@ -18,8 +18,9 @@ namespace Marco.Pms.CacheHelper var mongoUrl = new MongoUrl(connectionString); var client = new MongoClient(mongoUrl); var database = client.GetDatabase(mongoUrl.DatabaseName); - _oldCollection = database.GetCollection("Menus"); - _collection = database.GetCollection("WebSideMenus"); + _webCollection = database.GetCollection("WebSideMenus"); + _mobileCollection = database.GetCollection("MobileSideMenus"); + } public async Task> GetAllWebMenuSectionsAsync(Guid tenantId) @@ -28,7 +29,7 @@ namespace Marco.Pms.CacheHelper { var filter = Builders.Filter.Eq(e => e.TenantId, tenantId); - var result = await _collection + var result = await _webCollection .Find(filter) .ToListAsync(); if (result.Any()) @@ -39,7 +40,7 @@ namespace Marco.Pms.CacheHelper tenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"); filter = Builders.Filter.Eq(e => e.TenantId, tenantId); - result = await _collection + result = await _webCollection .Find(filter) .ToListAsync(); return result; @@ -50,12 +51,11 @@ namespace Marco.Pms.CacheHelper return new List(); } } - public async Task> AddWebMenuItemAsync(List newItems) { try { - await _collection.InsertManyAsync(newItems); + await _webCollection.InsertManyAsync(newItems); return newItems; } catch (Exception ex) @@ -64,27 +64,48 @@ namespace Marco.Pms.CacheHelper return new List(); } } - - public async Task> GetAllMenuSectionsAsync(Guid tenantId) + public async Task> GetAllMobileMenuSectionsAsync(Guid tenantId) { - var filter = Builders.Filter.Eq(e => e.TenantId, tenantId); - - var result = await _oldCollection - .Find(filter) - .ToListAsync(); - if (result.Any()) + try { + var filter = Builders.Filter.Eq(e => e.TenantId, tenantId); + + var result = await _mobileCollection + .Find(filter) + .ToListAsync(); + if (result.Any()) + { + return result; + } + + tenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"); + filter = Builders.Filter.Eq(e => e.TenantId, tenantId); + + result = await _mobileCollection + .Find(filter) + .ToListAsync(); return result; } - - tenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"); - filter = Builders.Filter.Eq(e => e.TenantId, tenantId); - - result = await _oldCollection - .Find(filter) - .ToListAsync(); - return result; + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while fetching Web Menu Sections."); + return new List(); + } } + public async Task> AddMobileMenuItemAsync(List newItems) + { + try + { + await _mobileCollection.InsertManyAsync(newItems); + return newItems; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while adding Mobile Menu Section."); + return new List(); + } + } + } diff --git a/Marco.Pms.Model/AppMenu/MobileMenu.cs b/Marco.Pms.Model/AppMenu/MobileMenu.cs new file mode 100644 index 0000000..fbe1075 --- /dev/null +++ b/Marco.Pms.Model/AppMenu/MobileMenu.cs @@ -0,0 +1,21 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.AppMenu +{ + public class MobileMenu + { + [BsonId] + [BsonRepresentation(BsonType.String)] + public Guid Id { get; set; } + public string? Name { get; set; } + public bool Available { get; set; } + public string? MobileLink { get; set; } + + [BsonRepresentation(BsonType.String)] + public List PermissionIds { get; set; } = new List(); + + [BsonRepresentation(BsonType.String)] + public Guid TenantId { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/AppMenu/CreateMobileSideMenuItemDto.cs b/Marco.Pms.Model/Dtos/AppMenu/CreateMobileSideMenuItemDto.cs new file mode 100644 index 0000000..c7ba5b4 --- /dev/null +++ b/Marco.Pms.Model/Dtos/AppMenu/CreateMobileSideMenuItemDto.cs @@ -0,0 +1,13 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.Dtos.AppMenu +{ + public class CreateMobileSideMenuItemDto + { + public string? Name { get; set; } + public bool Available { get; set; } + public string? MobileLink { get; set; } + public List PermissionIds { get; set; } = new List(); + } +} diff --git a/Marco.Pms.Model/Dtos/AppMenu/CreateWebSideMenuItemDto.cs b/Marco.Pms.Model/Dtos/AppMenu/CreateWebSideMenuItemDto.cs index e07244c..3415a09 100644 --- a/Marco.Pms.Model/Dtos/AppMenu/CreateWebSideMenuItemDto.cs +++ b/Marco.Pms.Model/Dtos/AppMenu/CreateWebSideMenuItemDto.cs @@ -4,7 +4,7 @@ { public Guid? Id { get; set; } public Guid? ParentMenuId { get; set; } - public string? Text { get; set; } + public string? Name { get; set; } public string? Icon { get; set; } public bool Available { get; set; } = true; public string Link { get; set; } = string.Empty; diff --git a/Marco.Pms.Services/Controllers/AppMenuController.cs b/Marco.Pms.Services/Controllers/AppMenuController.cs index 2fe63dd..d098bbd 100644 --- a/Marco.Pms.Services/Controllers/AppMenuController.cs +++ b/Marco.Pms.Services/Controllers/AppMenuController.cs @@ -2,7 +2,6 @@ using Marco.Pms.CacheHelper; using Marco.Pms.Model.AppMenu; using Marco.Pms.Model.Dtos.AppMenu; -using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.AppMenu; using Marco.Pms.Model.ViewModels.DocumentManager; @@ -26,6 +25,7 @@ namespace Marco.Pms.Services.Controllers private readonly IMapper _mapper; private readonly ILoggingService _logger; private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly PermissionServices _permissionService; private readonly Guid tenantId; private static readonly Guid superTenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"); @@ -42,7 +42,8 @@ namespace Marco.Pms.Services.Controllers SidebarMenuHelper sideBarMenuHelper, IMapper mapper, ILoggingService logger, - IServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory, + PermissionServices permissionService) { _userHelper = userHelper; @@ -51,6 +52,7 @@ namespace Marco.Pms.Services.Controllers _logger = logger; _serviceScopeFactory = serviceScopeFactory; tenantId = userHelper.GetTenantId(); + _permissionService = permissionService; } /// @@ -99,18 +101,13 @@ namespace Marco.Pms.Services.Controllers _logger.LogDebug("GetAppSideBarMenuAsync resolved employee context. EmployeeId: {EmployeeId}, TenantId: {TenantId}, CorrelationId: {CorrelationId}", employeeId, tenantId, correlationId); - // 3. Create scoped permission service - // - Avoid capturing scoped services directly in controller ctor when they depend on per-request state. - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - - // 4. Preload all permission ids for the employee for efficient in-memory checks - var permissionIds = await permissionService.GetPermissionIdsByEmployeeId(employeeId); + // 3. Preload all permission ids for the employee for efficient in-memory checks + var permissionIds = await _permissionService.GetPermissionIdsByEmployeeId(employeeId); _logger.LogDebug("GetAppSideBarMenuAsync loaded {PermissionCount} permissions for EmployeeId: {EmployeeId}, CorrelationId: {CorrelationId}", permissionIds.Count, employeeId, correlationId); - // 5. Fetch all menu entries configured for this tenant + // 4. Fetch all menu entries configured for this tenant var menus = await _sideBarMenuHelper.GetAllWebMenuSectionsAsync(tenantId); if (menus == null || !menus.Any()) @@ -126,7 +123,7 @@ namespace Marco.Pms.Services.Controllers _logger.LogDebug("GetAppSideBarMenuAsync loaded {MenuSectionCount} raw menu records. TenantId: {TenantId}, CorrelationId: {CorrelationId}", menus.Count, tenantId, correlationId); - // 6. Build logical menu sections (root + children) and apply permission filtering + // 5. Build logical menu sections (root + children) and apply permission filtering var responseSections = new List(); // Root container section for the web UI. @@ -153,7 +150,7 @@ namespace Marco.Pms.Services.Controllers // If the menu requires any permission, check now. if (menu.PermissionIds.Any()) { - var hasMenuPermission = permissionService.HasPermissionAny(permissionIds, menu.PermissionIds, employeeId); + var hasMenuPermission = _permissionService.HasPermissionAny(permissionIds, menu.PermissionIds, employeeId); if (!hasMenuPermission) { @@ -175,7 +172,7 @@ namespace Marco.Pms.Services.Controllers // If the submenu requires permissions, validate before adding. if (subMenu.PermissionIds.Any()) { - var hasSubPermission = permissionService.HasPermissionAny(permissionIds, subMenu.PermissionIds, employeeId); + var hasSubPermission = _permissionService.HasPermissionAny(permissionIds, subMenu.PermissionIds, employeeId); if (!hasSubPermission) { @@ -240,7 +237,7 @@ namespace Marco.Pms.Services.Controllers } [HttpPost("add/side-menu")] - public async Task AddMenuItemAsync([FromBody] List model) + public async Task AddWebMenuItemAsync([FromBody] List model) { // Step 1: Validate tenant context if (tenantId == Guid.Empty) @@ -306,9 +303,194 @@ namespace Marco.Pms.Services.Controllers } /// - /// Retrieves the master menu list based on enabled features for the current tenant. + /// Retrieves the mobile sidebar menu sections for the authenticated employee within the current tenant, + /// filtered by employee permissions and structured for mobile application consumption. + /// Supports permission-based access control and tenant isolation. /// - /// List of master menu items available for the tenant + /// A filtered list of accessible mobile menu sections or appropriate error response. + /// Returns filtered mobile menu sections successfully. + /// Invalid tenant identifier provided. + /// Employee context not resolved or insufficient permissions. + /// Internal server error during menu retrieval or processing. + + [HttpGet("get/menu-mobile")] + public async Task GetAppSideBarMenuForMobileAsync() + { + // Correlation ID enables distributed tracing across services, middleware, and structured logs. + var correlationId = HttpContext.TraceIdentifier; + + _logger.LogInfo("GetAppSideBarMenuForMobileAsync started. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + try + { + // 1. Validate tenant isolation - critical for multi-tenant security + if (tenantId == Guid.Empty) + { + _logger.LogWarning("GetAppSideBarMenuForMobileAsync rejected: invalid tenant context. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + var error = ApiResponse.ErrorResponse( + "InvalidTenantContext", + "Tenant identifier is missing or invalid. Verify tenant context and retry.", + 400); + + return BadRequest(error); + } + + // 2. Resolve authenticated employee context with tenant isolation + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + if (loggedInEmployee is null) + { + _logger.LogWarning("GetAppSideBarMenuForMobileAsync failed: employee context not resolved. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + var error = ApiResponse.ErrorResponse("EmployeeContextNotFound", "Current employee context could not be resolved. Please authenticate and retry.", 403); + + return StatusCode(403, error); + } + + var employeeId = loggedInEmployee.Id; + _logger.LogDebug("GetAppSideBarMenuForMobileAsync resolved employee: EmployeeId: {EmployeeId}, TenantId: {TenantId}, CorrelationId: {CorrelationId}", + employeeId, tenantId, correlationId); + + // 3. Bulk-load employee permissions for efficient in-memory permission checks (avoids N+1 queries) + var permissionIds = await _permissionService.GetPermissionIdsByEmployeeId(employeeId); + _logger.LogDebug("GetAppSideBarMenuForMobileAsync loaded {PermissionCount} permissions for EmployeeId: {EmployeeId}, TenantId: {TenantId}, CorrelationId: {CorrelationId}", + permissionIds?.Count ?? 0, employeeId, tenantId, correlationId); + + // 4. Fetch tenant-specific mobile menu configuration + var allMenus = await _sideBarMenuHelper.GetAllMobileMenuSectionsAsync(tenantId); + if (allMenus == null || !allMenus.Any()) + { + _logger.LogInfo("GetAppSideBarMenuForMobileAsync: no mobile menu sections configured. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + var emptyResponse = new List(); + return Ok(ApiResponse.SuccessResponse(emptyResponse, + "No mobile sidebar menu sections configured for this tenant.", 200)); + } + + _logger.LogDebug("GetAppSideBarMenuForMobileAsync loaded {MenuCount} raw sections. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + allMenus.Count, tenantId, correlationId); + + // 5. Filter menus by employee permissions (in-memory for performance) + var accessibleMenus = new List(); + foreach (var menuSection in allMenus) + { + // Skip permission check for public menu items + if (!menuSection.PermissionIds.Any()) + { + accessibleMenus.Add(menuSection); + continue; + } + + // Perform permission intersection check + var hasAccess = _permissionService.HasPermissionAny(permissionIds ?? new List(), + menuSection.PermissionIds, employeeId); + + if (hasAccess) + { + accessibleMenus.Add(menuSection); + _logger.LogDebug("GetAppSideBarMenuForMobileAsync granted menu access. MenuId: {MenuId}, EmployeeId: {EmployeeId}, CorrelationId: {CorrelationId}", + menuSection.Id, employeeId, correlationId); + } + else + { + _logger.LogDebug("GetAppSideBarMenuForMobileAsync denied menu access. MenuId: {MenuId}, EmployeeId: {EmployeeId}, CorrelationId: {CorrelationId}", + menuSection.Id, employeeId, correlationId); + } + } + + // 6. Defensive mapping with null-safety + var response = _mapper.Map>(accessibleMenus); + _logger.LogInfo("GetAppSideBarMenuForMobileAsync completed successfully. AccessibleMenus: {AccessibleCount}/{TotalCount}, EmployeeId: {EmployeeId}, TenantId: {TenantId}, CorrelationId: {CorrelationId}", + accessibleMenus.Count, allMenus.Count, employeeId, tenantId, correlationId); + + return Ok(ApiResponse.SuccessResponse(response, + $"Mobile sidebar menu fetched successfully ({response?.Count ?? 0} sections accessible).", 200)); + } + catch (OperationCanceledException) + { + _logger.LogWarning("GetAppSideBarMenuForMobileAsync cancelled. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + return StatusCode(499, ApiResponse.ErrorResponse("RequestCancelled", + "Request was cancelled by client or timeout.", 499)); + } + catch (UnauthorizedAccessException ex) + { + _logger.LogError(ex, "GetAppSideBarMenuForMobileAsync authorization failed. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + return StatusCode(403, ApiResponse.ErrorResponse("AuthorizationFailed", + "Insufficient permissions to access mobile menu sections.", 403)); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetAppSideBarMenuForMobileAsync failed unexpectedly. TenantId: {TenantId}, CorrelationId: {CorrelationId}", + tenantId, correlationId); + + return StatusCode(500, ApiResponse.ErrorResponse("InternalServerError", + "An unexpected error occurred while fetching the mobile sidebar menu. Please contact support if issue persists.", 500)); + } + } + + + [HttpPost("add/mobile/side-menu")] + public async Task AddMobileMenuItemAsync([FromBody] List model) + { + // Step 1: Validate tenant context + if (tenantId == Guid.Empty) + { + _logger.LogWarning("GetAppSideBarMenuAsync rejected: Invalid TenantId."); + + return BadRequest(ApiResponse.ErrorResponse("Invalid TenantId", "The tenant identifier provided is invalid or missing.", 400)); + } + + // Step 2: Fetch logged-in user + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false; + + // Step 3: Authorization check + if (!isRootUser && tenantId != superTenantId) + { + _logger.LogWarning("Access denied: User {UserId} attempted to add menu item in Tenant {TenantId}", + loggedInEmployee.Id, tenantId); + + return StatusCode(403, ApiResponse.ErrorResponse("Access Denied", "User does not have permission.", 403)); + } + + // Step 4: Input validation + if (model == null) + { + _logger.LogWarning("Invalid AddMenuItem request. Tenant: {TenantId}, UserId: {UserId}", + tenantId, loggedInEmployee.Id); + + return BadRequest(ApiResponse.ErrorResponse("Invalid section ID or menu item payload.", 400)); + } + + // Step 5: Map DTO to entity + var menuItemEntity = _mapper.Map>(model); + + menuItemEntity.ForEach(m => m.TenantId = tenantId); + + // Step 6: Perform Add operation + var result = await _sideBarMenuHelper.AddMobileMenuItemAsync(menuItemEntity); + + if (result == null) + { + _logger.LogWarning("Menu section not found. Unable to add menu item. TenantId: {TenantId}, UserId: {UserId}", tenantId, loggedInEmployee.Id); + + return NotFound(ApiResponse.ErrorResponse("Menu section not found", 404)); + } + + // Step 7: Successful addition + _logger.LogInfo("Menu items added successfully TenantId: {TenantId}, UserId: {UserId}", + tenantId, loggedInEmployee.Id); + + return Ok(ApiResponse.SuccessResponse(result, "Menu item added successfully")); + } [HttpGet("get/master-list")] public async Task GetMasterList() @@ -390,236 +572,6 @@ namespace Marco.Pms.Services.Controllers } } - [HttpGet("get/menu-mobile")] - public async Task GetAppSideBarMenuForobile() - { - // Step 1: Get logged-in employee - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var employeeId = loggedInEmployee.Id; - - using var scope = _serviceScopeFactory.CreateScope(); - var _permissions = scope.ServiceProvider.GetRequiredService(); - - try - { - // Step 2: Fetch all menu sections for the tenant - var menus = await _sideBarMenuHelper.GetAllMenuSectionsAsync(tenantId); - if (!(menus?.Any() ?? false)) - { - menus = new List - { - MenuStaticMaster.menu - }; - } - List response = new List(); - - foreach (var menu in menus) - { - var allowedItems = new List(); - - foreach (var item in menu.Items) - { - // --- Item permission check --- - if (!item.PermissionIds.Any()) - { - MenuSectionApplicationVM menuVM = new MenuSectionApplicationVM - { - Id = item.Id, - Name = item.Text, - Available = true, - MobileLink = item.MobileLink, - }; - response.Add(menuVM); - - if (item.Submenu?.Any() == true) - { - var allowedSubmenus = new List(); - - foreach (var subItem in item.Submenu) - { - if (!subItem.PermissionIds.Any()) - { - MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM - { - Id = subItem.Id, - Name = subItem.Text, - Available = true, - MobileLink = subItem.MobileLink - }; - response.Add(subMenuVM); - continue; - } - - var subMenuPermissionIds = subItem.PermissionIds - .Select(Guid.Parse) - .ToList(); - - bool isSubItemAllowed = await _permissions.HasPermissionAny(subMenuPermissionIds, employeeId); - - if (isSubItemAllowed) - { - MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM - { - Id = subItem.Id, - Name = subItem.Text, - Available = true, - MobileLink = subItem.MobileLink - }; - response.Add(subMenuVM); - } - } - - // Replace with filtered submenus - item.Submenu = allowedSubmenus; - } - } - else - { - // Convert permission string IDs to GUIDs - var menuPermissionIds = item.PermissionIds - .Select(Guid.Parse) - .ToList(); - - bool isAllowed = await _permissions.HasPermissionAny(menuPermissionIds, employeeId); - - // If allowed, filter its submenus as well - if (isAllowed) - { - if (item.Submenu?.Any() == true) - { - var allowedSubmenus = new List(); - - foreach (var subItem in item.Submenu) - { - if (!subItem.PermissionIds.Any()) - { - MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM - { - Id = subItem.Id, - Name = subItem.Text, - Available = true, - MobileLink = subItem.MobileLink - }; - response.Add(subMenuVM); - continue; - } - - var subMenuPermissionIds = subItem.PermissionIds - .Select(Guid.Parse) - .ToList(); - - bool isSubItemAllowed = await _permissions.HasPermissionAny(subMenuPermissionIds, employeeId); - - if (isSubItemAllowed) - { - MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM - { - Id = subItem.Id, - Name = subItem.Text, - Available = true, - MobileLink = subItem.MobileLink, - }; - response.Add(subMenuVM); - } - } - - // Replace with filtered submenus - item.Submenu = allowedSubmenus; - } - - MenuSectionApplicationVM menuVM = new MenuSectionApplicationVM - { - Id = item.Id, - Name = item.Text, - Available = true, - MobileLink = item.MobileLink - }; - response.Add(menuVM); - } - } - } - - // Replace with filtered items - menu.Items = allowedItems; - } - - var viewDocumentTask = Task.Run(async () => - { - using var taskScope = _serviceScopeFactory.CreateScope(); - var permissions = taskScope.ServiceProvider.GetRequiredService(); - return await permissions.HasPermission(PermissionsMaster.ViewDocument, employeeId); - }); - - var uploadDocumentTask = Task.Run(async () => - { - using var taskScope = _serviceScopeFactory.CreateScope(); - var permissions = taskScope.ServiceProvider.GetRequiredService(); - return await permissions.HasPermission(PermissionsMaster.UploadDocument, employeeId); - }); - - var verifyDocumentTask = Task.Run(async () => - { - using var taskScope = _serviceScopeFactory.CreateScope(); - var permissions = taskScope.ServiceProvider.GetRequiredService(); - return await permissions.HasPermission(PermissionsMaster.VerifyDocument, employeeId); - }); - - var downloadDocumentTask = Task.Run(async () => - { - using var taskScope = _serviceScopeFactory.CreateScope(); - var permissions = taskScope.ServiceProvider.GetRequiredService(); - return await permissions.HasPermission(PermissionsMaster.DownloadDocument, employeeId); - }); - - await Task.WhenAll(viewDocumentTask, uploadDocumentTask, verifyDocumentTask, downloadDocumentTask); - - var viewDocument = viewDocumentTask.Result; - var uploadDocument = uploadDocumentTask.Result; - var verifyDocument = verifyDocumentTask.Result; - var downloadDocument = downloadDocumentTask.Result; - - if (viewDocument || uploadDocument || verifyDocument || downloadDocument) - { - response.Add(new MenuSectionApplicationVM - { - Id = Guid.Parse("443d6444-250b-4164-89fd-bcd7cedd9e43"), - Name = "Documents", - Available = true, - MobileLink = "/dashboard/document-main-page" - }); - } - - response.Add(new MenuSectionApplicationVM - { - Id = Guid.Parse("7faddfe7-994b-4712-91c2-32ba44129d9b"), - Name = "Service Projects", - Available = true, - MobileLink = "/dashboard/service-projects" - }); - response.Add(new MenuSectionApplicationVM - { - Id = Guid.Parse("5fab4b88-c9a0-417b-aca2-130980fdb0cf"), - Name = "Infra Projects", - Available = true, - MobileLink = "/dashboard/infra-projects" - }); - - // Step 3: Log success - response = response.Where(ms => !string.IsNullOrWhiteSpace(ms.MobileLink)).ToList(); - _logger.LogInfo("Fetched sidebar menu successfully. Tenant: {TenantId}, EmployeeId: {EmployeeId}, SectionsReturned: {Count}", - tenantId, employeeId, menus.Count); - return Ok(ApiResponse.SuccessResponse(response, "Sidebar menu fetched successfully", 200)); - } - catch (Exception ex) - { - // Step 4: Handle unexpected errors - _logger.LogError(ex, "Error occurred while fetching sidebar menu. Tenant: {TenantId}, EmployeeId: {EmployeeId}", - tenantId, employeeId); - - return StatusCode(500, ApiResponse.ErrorResponse("Server Error", "An unexpected error occurred while fetching the sidebar menu.", 500)); - } - } - } } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 865e668..bd6b2dc 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -580,6 +580,9 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); + CreateMap(); + CreateMap(); + #endregion #region ======================================================= Directory =======================================================