468 lines
22 KiB
C#
468 lines
22 KiB
C#
using AutoMapper;
|
|
using Marco.Pms.CacheHelper;
|
|
using Marco.Pms.Model.AppMenu;
|
|
using Marco.Pms.Model.Dtos.AppMenu;
|
|
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;
|
|
|
|
namespace Marco.Pms.Services.Controllers
|
|
{
|
|
[Authorize]
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class AppMenuController : ControllerBase
|
|
{
|
|
|
|
private readonly UserHelper _userHelper;
|
|
private readonly SidebarMenuHelper _sideBarMenuHelper;
|
|
private readonly IMapper _mapper;
|
|
private readonly ILoggingService _logger;
|
|
private readonly PermissionServices _permissions;
|
|
private readonly Guid tenantId;
|
|
private static readonly Guid superTenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26");
|
|
|
|
public AppMenuController(UserHelper userHelper,
|
|
SidebarMenuHelper sideBarMenuHelper,
|
|
IMapper mapper,
|
|
ILoggingService logger,
|
|
PermissionServices permissions)
|
|
{
|
|
|
|
_userHelper = userHelper;
|
|
_sideBarMenuHelper = sideBarMenuHelper;
|
|
_mapper = mapper;
|
|
_logger = logger;
|
|
_permissions = permissions;
|
|
tenantId = userHelper.GetTenantId();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Creates a new sidebar menu section for the tenant.
|
|
/// Only accessible by root users or for the super tenant.
|
|
/// </summary>
|
|
/// <param name="menuSectionDto">The data for the new menu section.</param>
|
|
/// <returns>HTTP response with result of the operation.</returns>
|
|
|
|
[HttpPost("add/sidebar/menu-section")]
|
|
public async Task<IActionResult> CreateAppSideBarMenu([FromBody] CreateMenuSectionDto menuSectionDto)
|
|
{
|
|
// Step 1: Fetch logged-in user
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
|
|
// Step 2: Authorization check
|
|
if (!isRootUser || tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access denied: Employee {EmployeeId} attempted to create sidebar menu in Tenant {TenantId}", loggedInEmployee.Id, tenantId);
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
|
}
|
|
|
|
// Step 3: Map DTO to entity
|
|
var sideMenuSection = _mapper.Map<MenuSection>(menuSectionDto);
|
|
sideMenuSection.TenantId = tenantId;
|
|
|
|
try
|
|
{
|
|
// Step 4: Save entity using helper
|
|
sideMenuSection = await _sideBarMenuHelper.CreateMenuSectionAsync(sideMenuSection);
|
|
|
|
if (sideMenuSection == null)
|
|
{
|
|
_logger.LogWarning("Failed to create sidebar menu section. Tenant: {TenantId}, Request: {@MenuSectionDto}", tenantId, menuSectionDto);
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid MenuSection", 400));
|
|
}
|
|
|
|
// Step 5: Log success
|
|
_logger.LogInfo("Sidebar menu created successfully. SectionId: {SectionId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
|
sideMenuSection.Id, tenantId, loggedInEmployee.Id);
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(sideMenuSection, "Sidebar menu created successfully.", 201));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Step 6: Handle and log unexpected server errors
|
|
_logger.LogError(ex, "Unexpected error occurred while creating sidebar menu. Tenant: {TenantId}, EmployeeId: {EmployeeId}, Request: {@MenuSectionDto}",
|
|
tenantId, loggedInEmployee.Id, menuSectionDto);
|
|
|
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred.", 500));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates an existing sidebar menu section for the tenant.
|
|
/// Only accessible by root users or for the super tenant.
|
|
/// </summary>
|
|
/// <param name="sectionId">The unique identifier of the section to update.</param>
|
|
/// <param name="updatedSection">The updated data for the sidebar menu section.</param>
|
|
/// <returns>HTTP response with the result of the operation.</returns>
|
|
|
|
[HttpPut("edit/sidebar/menu-section/{sectionId}")]
|
|
public async Task<IActionResult> UpdateMenuSection(Guid sectionId, [FromBody] UpdateMenuSectionDto updatedSection)
|
|
{
|
|
// Step 1: Fetch logged-in user
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
|
|
// Step 2: Authorization check
|
|
if (!isRootUser && tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access denied: User {UserId} attempted to update sidebar menu section {SectionId} in Tenant {TenantId}",
|
|
loggedInEmployee.Id, sectionId, tenantId);
|
|
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
|
}
|
|
|
|
// Step 3: Validate request
|
|
if (sectionId == Guid.Empty || sectionId != updatedSection.Id)
|
|
{
|
|
_logger.LogWarning("Invalid update request. Tenant: {TenantId}, SectionId: {SectionId}, PayloadId: {PayloadId}, UserId: {UserId}",
|
|
tenantId, sectionId, updatedSection.Id, loggedInEmployee.Id);
|
|
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID or mismatched payload.", 400));
|
|
}
|
|
|
|
// Step 4: Map DTO to entity
|
|
var menuSectionEntity = _mapper.Map<MenuSection>(updatedSection);
|
|
|
|
try
|
|
{
|
|
// Step 5: Perform update operation
|
|
var result = await _sideBarMenuHelper.UpdateMenuSectionAsync(sectionId, menuSectionEntity);
|
|
|
|
if (result == null)
|
|
{
|
|
_logger.LogWarning("Menu section not found for update. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
|
sectionId, tenantId, loggedInEmployee.Id);
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu section not found", 404));
|
|
}
|
|
|
|
// Step 6: Successful update
|
|
_logger.LogInfo("Menu section updated successfully. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
|
sectionId, tenantId, loggedInEmployee.Id);
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Menu section updated successfully"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Step 7: Unexpected server error
|
|
_logger.LogError(ex, "Failed to update menu section. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}, Payload: {@UpdatedSection}",
|
|
sectionId, tenantId, loggedInEmployee.Id, updatedSection);
|
|
|
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server error", "An unexpected error occurred while updating the menu section.", 500));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a new menu item to an existing sidebar menu section.
|
|
/// Only accessible by root users or for the super tenant.
|
|
/// </summary>
|
|
/// <param name="sectionId">The unique identifier of the section the item will be added to.</param>
|
|
/// <param name="newItemDto">The details of the new menu item.</param>
|
|
/// <returns>HTTP response with the result of the operation.</returns>
|
|
|
|
[HttpPost("add/sidebar/menus/{sectionId}/items")]
|
|
public async Task<IActionResult> AddMenuItem(Guid sectionId, [FromBody] CreateMenuItemDto newItemDto)
|
|
{
|
|
// Step 1: Fetch logged-in user
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
|
|
// Step 2: Authorization check
|
|
if (!isRootUser && tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access denied: User {UserId} attempted to add menu item to section {SectionId} in Tenant {TenantId}",
|
|
loggedInEmployee.Id, sectionId, tenantId);
|
|
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
|
}
|
|
|
|
// Step 3: Input validation
|
|
if (sectionId == Guid.Empty || newItemDto == null)
|
|
{
|
|
_logger.LogWarning("Invalid AddMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, UserId: {UserId}",
|
|
tenantId, sectionId, loggedInEmployee.Id);
|
|
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID or menu item payload.", 400));
|
|
}
|
|
|
|
try
|
|
{
|
|
// Step 4: Map DTO to entity
|
|
var menuItemEntity = _mapper.Map<MenuItem>(newItemDto);
|
|
|
|
// Step 5: Perform Add operation
|
|
var result = await _sideBarMenuHelper.AddMenuItemAsync(sectionId, menuItemEntity);
|
|
|
|
if (result == null)
|
|
{
|
|
_logger.LogWarning("Menu section not found. Unable to add menu item. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
|
sectionId, tenantId, loggedInEmployee.Id);
|
|
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu section not found", 404));
|
|
}
|
|
|
|
// Step 6: Successful addition
|
|
_logger.LogInfo("Menu item added successfully. SectionId: {SectionId}, MenuItemId: {MenuItemId}, TenantId: {TenantId}, UserId: {UserId}",
|
|
sectionId, result.Id, tenantId, loggedInEmployee.Id);
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Menu item added successfully"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Step 7: Handle unexpected errors
|
|
_logger.LogError(ex, "Error occurred while adding menu item. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}, Payload: {@NewItemDto}",
|
|
sectionId, tenantId, loggedInEmployee.Id, newItemDto);
|
|
|
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server error", "An unexpected error occurred while adding the menu item.", 500));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates an existing menu item inside a sidebar menu section.
|
|
/// Only accessible by root users or within the super tenant.
|
|
/// </summary>
|
|
/// <param name="sectionId">The ID of the sidebar menu section.</param>
|
|
/// <param name="itemId">The ID of the menu item to update.</param>
|
|
/// <param name="updatedMenuItem">The updated menu item details.</param>
|
|
/// <returns>HTTP response with the result of the update operation.</returns>
|
|
|
|
[HttpPut("edit/sidebar/{sectionId}/items/{itemId}")]
|
|
public async Task<IActionResult> UpdateMenuItem(Guid sectionId, Guid itemId, [FromBody] UpdateMenuItemDto updatedMenuItem)
|
|
{
|
|
// Step 1: Fetch logged-in user
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
|
|
// Step 2: Authorization check
|
|
if (!isRootUser && tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access denied: User {UserId} attempted to update menu item {ItemId} in Section {SectionId}, Tenant {TenantId}",
|
|
loggedInEmployee.Id, itemId, sectionId, tenantId);
|
|
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
|
}
|
|
|
|
// Step 3: Input validation
|
|
if (sectionId == Guid.Empty || itemId == Guid.Empty || updatedMenuItem == null || updatedMenuItem.Id != itemId)
|
|
{
|
|
_logger.LogWarning("Invalid UpdateMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
|
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID, item ID, or menu item payload.", 400));
|
|
}
|
|
|
|
// Step 4: Map DTO to entity
|
|
var menuItemEntity = _mapper.Map<MenuItem>(updatedMenuItem);
|
|
|
|
try
|
|
{
|
|
// Step 5: Perform update operation
|
|
var result = await _sideBarMenuHelper.UpdateMenuItemAsync(sectionId, itemId, menuItemEntity);
|
|
|
|
if (result == null)
|
|
{
|
|
_logger.LogWarning("Menu item not found or update failed. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu item not found or update failed.", 404));
|
|
}
|
|
|
|
// Step 6: Success log
|
|
_logger.LogInfo("Menu item updated successfully. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Sidebar menu item updated successfully."));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// ✅ Step 7: Handle server errors
|
|
_logger.LogError(ex, "Error occurred while updating menu item. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}, Payload: {@UpdatedMenuItem}",
|
|
tenantId, sectionId, itemId, loggedInEmployee.Id, updatedMenuItem);
|
|
|
|
return StatusCode(
|
|
500,
|
|
ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while updating the menu item.", 500)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
[HttpPost("add/sidebar/menus/{sectionId}/items/{itemId}/subitems")]
|
|
public async Task<IActionResult> AddSubMenuItem(Guid sectionId, Guid itemId, [FromBody] CreateSubMenuItemDto newSubItem)
|
|
{
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
if (!isRootUser && tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access Denied while adding sub menu item");
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("access denied", "User haven't permission", 403));
|
|
}
|
|
if (sectionId == Guid.Empty || itemId == Guid.Empty)
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid input", 400));
|
|
|
|
try
|
|
{
|
|
var subMenuItem = _mapper.Map<SubMenuItem>(newSubItem);
|
|
|
|
var result = await _sideBarMenuHelper.AddSubMenuItemAsync(sectionId, itemId, subMenuItem);
|
|
|
|
if (result == null)
|
|
{
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu item not found", 404));
|
|
|
|
}
|
|
|
|
_logger.LogInfo("Added SubMenuItem in Section: {SectionId}, MenuItem: {ItemId}");
|
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Submenu item added successfully"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to add submenu item");
|
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server error", ex, 500));
|
|
}
|
|
}
|
|
|
|
|
|
[HttpPut("edit/sidebar/{sectionId}/items/{itemId}/subitems/{subItemId}")]
|
|
public async Task<IActionResult> UpdateSubmenuItem(Guid sectionId, Guid itemId, Guid subItemId, [FromBody] UpdateSubMenuItemDto updatedSubMenuItem)
|
|
{
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
|
if (!isRootUser && tenantId != superTenantId)
|
|
{
|
|
_logger.LogWarning("Access Denied while updating sub menu item");
|
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("access denied", "User haven't permission", 403));
|
|
}
|
|
if (sectionId == Guid.Empty || itemId == Guid.Empty || subItemId == Guid.Empty || updatedSubMenuItem.Id != subItemId)
|
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid input", 400));
|
|
|
|
try
|
|
{
|
|
var SubMenuItem = _mapper.Map<SubMenuItem>(updatedSubMenuItem);
|
|
SubMenuItem = await _sideBarMenuHelper.UpdateSubmenuItemAsync(sectionId, itemId, subItemId, SubMenuItem);
|
|
|
|
if (SubMenuItem == null)
|
|
return NotFound(ApiResponse<object>.ErrorResponse("Submenu item not found", 404));
|
|
|
|
_logger.LogInfo("SidBar Section{SectionId} MenuItem {itemId} SubMenuItem {subItemId} Updated");
|
|
return Ok(ApiResponse<object>.SuccessResponse(SubMenuItem, "Submenu item updated successfully"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error Occurred while Updating Sub-MenuItem");
|
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", ex, 500));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the sidebar menu for the current tenant and filters items based on employee permissions.
|
|
/// </summary>
|
|
/// <returns>The sidebar menu with only the items/sub-items the employee has access to.</returns>
|
|
|
|
[HttpGet("get/menu")]
|
|
public async Task<IActionResult> GetAppSideBarMenu()
|
|
{
|
|
// Step 1: Get logged-in employee
|
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
var employeeId = loggedInEmployee.Id;
|
|
|
|
try
|
|
{
|
|
// Step 2: Fetch all menu sections for the tenant
|
|
var menus = await _sideBarMenuHelper.GetAllMenuSectionsAsync(tenantId);
|
|
|
|
foreach (var menu in menus)
|
|
{
|
|
var allowedItems = new List<MenuItem>();
|
|
|
|
foreach (var item in menu.Items)
|
|
{
|
|
// --- Item permission check ---
|
|
if (!item.PermissionIds.Any())
|
|
{
|
|
allowedItems.Add(item);
|
|
}
|
|
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<SubMenuItem>();
|
|
|
|
foreach (var subItem in item.Submenu)
|
|
{
|
|
if (!subItem.PermissionIds.Any())
|
|
{
|
|
allowedSubmenus.Add(subItem);
|
|
continue;
|
|
}
|
|
|
|
var subMenuPermissionIds = subItem.PermissionIds
|
|
.Select(Guid.Parse)
|
|
.ToList();
|
|
|
|
bool isSubItemAllowed = await _permissions.HasPermissionAny(subMenuPermissionIds, employeeId);
|
|
|
|
if (isSubItemAllowed)
|
|
{
|
|
allowedSubmenus.Add(subItem);
|
|
}
|
|
}
|
|
|
|
// Replace with filtered submenus
|
|
item.Submenu = allowedSubmenus;
|
|
}
|
|
|
|
allowedItems.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Replace with filtered items
|
|
menu.Items = allowedItems;
|
|
}
|
|
|
|
// Step 3: Log success
|
|
_logger.LogInfo("Fetched sidebar menu successfully. Tenant: {TenantId}, EmployeeId: {EmployeeId}, SectionsReturned: {Count}",
|
|
tenantId, employeeId, menus.Count);
|
|
|
|
return Ok(ApiResponse<object>.SuccessResponse(menus, "Sidebar menu fetched successfully"));
|
|
}
|
|
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<object>.ErrorResponse("Server Error", "An unexpected error occurred while fetching the sidebar menu.", 500));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|