Firebase_Implementation #135
@ -1420,15 +1420,14 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the logged in employee has permission to delete OR is the owner of the document attachment
|
// Check if the logged in employee has permission to delete OR is the owner of the document attachment
|
||||||
var hasDeletePermission = await _permission.HasPermission(PermissionsMaster.DeleteDocument, loggedInEmployee.Id);
|
var hasDeletePermission = false;
|
||||||
var hasViewPermission = false;
|
|
||||||
if (ProjectEntity == documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId)
|
if (ProjectEntity == documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId)
|
||||||
{
|
{
|
||||||
hasViewPermission = await _permission.HasPermission(PermissionsMaster.ViewDocument, loggedInEmployee.Id, documentAttachment.EntityId);
|
hasDeletePermission = await _permission.HasPermission(PermissionsMaster.DeleteDocument, loggedInEmployee.Id, documentAttachment.EntityId);
|
||||||
}
|
}
|
||||||
else if (EmployeeEntity == documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId)
|
else if (EmployeeEntity == documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId)
|
||||||
{
|
{
|
||||||
hasViewPermission = await _permission.HasPermission(PermissionsMaster.ViewDocument, loggedInEmployee.Id);
|
hasDeletePermission = await _permission.HasPermission(PermissionsMaster.DeleteDocument, loggedInEmployee.Id);
|
||||||
}
|
}
|
||||||
if (!hasDeletePermission && loggedInEmployee.Id != documentAttachment.EntityId)
|
if (!hasDeletePermission && loggedInEmployee.Id != documentAttachment.EntityId)
|
||||||
{
|
{
|
||||||
|
@ -148,12 +148,13 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
.Distinct()
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
result = await _context.Employees
|
var employees = await _context.Employees
|
||||||
.Include(fp => fp.JobRole)
|
.Include(fp => fp.JobRole)
|
||||||
.Where(e => employeeIds.Contains(e.Id) && e.IsActive && e.TenantId == tenantId)
|
.Where(e => employeeIds.Contains(e.Id) && e.JobRole != null && e.IsActive && e.TenantId == tenantId)
|
||||||
.Select(e => e.ToEmployeeVMFromEmployee())
|
.Distinct()
|
||||||
.Distinct()
|
.ToListAsync();
|
||||||
.ToListAsync();
|
|
||||||
|
result = employees.Select(e => e.ToEmployeeVMFromEmployee()).ToList();
|
||||||
|
|
||||||
_logger.LogInfo("Employee list fetched using limited access (active only).");
|
_logger.LogInfo("Employee list fetched using limited access (active only).");
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using AutoMapper;
|
||||||
|
using Marco.Pms.DataAccess.Data;
|
||||||
|
using Marco.Pms.Helpers.Utility;
|
||||||
using Marco.Pms.Model.Dtos.Util;
|
using Marco.Pms.Model.Dtos.Util;
|
||||||
using Marco.Pms.Model.Mapper;
|
using Marco.Pms.Model.Mapper;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using MarcoBMS.Services.Helpers;
|
using Marco.Pms.Model.ViewModels.Tenant;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -14,24 +17,30 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class MarketController : ControllerBase
|
public class MarketController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly FeatureDetailsHelper _featureDetailsHelper;
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly IEmailSender _emailSender;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
public MarketController(ApplicationDbContext context, UserHelper userHelper, RefreshTokenService refreshTokenService,
|
public MarketController(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||||
IEmailSender emailSender, IConfiguration configuration, EmployeeHelper employeeHelper)
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
|
IEmailSender emailSender,
|
||||||
|
IConfiguration configuration,
|
||||||
|
FeatureDetailsHelper featureDetailsHelper)
|
||||||
{
|
{
|
||||||
_context = context;
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||||
_userHelper = userHelper;
|
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender ?? throw new ArgumentNullException(nameof(emailSender));
|
||||||
_configuration = configuration;
|
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||||
|
_featureDetailsHelper = featureDetailsHelper ?? throw new ArgumentNullException(nameof(featureDetailsHelper));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("industries")]
|
[Route("industries")]
|
||||||
public async Task<IActionResult> GetIndustries()
|
public async Task<IActionResult> GetIndustries()
|
||||||
{
|
{
|
||||||
var tenantId = _userHelper.GetTenantId();
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
var industries = await _context.Industries.ToListAsync();
|
var industries = await _context.Industries.ToListAsync();
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
|
||||||
@ -40,6 +49,8 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
[HttpPost("enquire")]
|
[HttpPost("enquire")]
|
||||||
public async Task<IActionResult> RequestDemo([FromBody] InquiryDto inquiryDto)
|
public async Task<IActionResult> RequestDemo([FromBody] InquiryDto inquiryDto)
|
||||||
{
|
{
|
||||||
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto();
|
Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto();
|
||||||
_context.Inquiries.Add(inquiry);
|
_context.Inquiries.Add(inquiry);
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
@ -58,5 +69,66 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("list/subscription-plan")]
|
||||||
|
public async Task<IActionResult> GetSubscriptionPlanList([FromQuery] PLAN_FREQUENCY? frequency)
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
|
||||||
|
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
|
||||||
|
var _mapper = scope.ServiceProvider.GetRequiredService<IMapper>();
|
||||||
|
_logger.LogInfo("GetSubscriptionPlanList called with frequency: {Frequency}", frequency ?? PLAN_FREQUENCY.MONTHLY);
|
||||||
|
|
||||||
|
// Initialize the list to store subscription plan view models
|
||||||
|
List<SubscriptionPlanVM> detailsVM = new List<SubscriptionPlanVM>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create DbContext
|
||||||
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
|
// Load subscription plans with optional frequency filtering
|
||||||
|
IQueryable<SubscriptionPlanDetails> query = _context.SubscriptionPlanDetails.Include(sp => sp.Plan).Include(sp => sp.Currency);
|
||||||
|
|
||||||
|
if (frequency.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(sp => sp.Frequency == frequency.Value);
|
||||||
|
_logger.LogInfo("Filtering subscription plans by frequency: {Frequency}", frequency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Fetching all subscription plans without frequency filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
var subscriptionPlans = await query.ToListAsync();
|
||||||
|
|
||||||
|
// Map and fetch feature details for each subscription plan
|
||||||
|
foreach (var subscriptionPlan in subscriptionPlans)
|
||||||
|
{
|
||||||
|
var response = _mapper.Map<SubscriptionPlanVM>(subscriptionPlan);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response.Features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId);
|
||||||
|
}
|
||||||
|
catch (Exception exFeature)
|
||||||
|
{
|
||||||
|
_logger.LogError(exFeature, "Failed to fetch features for FeaturesId: {FeaturesId}", subscriptionPlan.FeaturesId);
|
||||||
|
response.Features = null; // or set to a default/fallback value
|
||||||
|
}
|
||||||
|
|
||||||
|
detailsVM.Add(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("Successfully fetched {Count} subscription plans", detailsVM.Count);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(detailsVM, "List of plans fetched successfully", 200));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error occurred while fetching subscription plans");
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("An error occurred while fetching subscription plans."));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,6 +470,13 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var response = await _projectServices.GetAssignedProjectLevelPermissionAsync(employeeId, projectId, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetAssignedProjectLevelPermissionAsync(employeeId, projectId, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
[HttpGet("get/all/project-level-permission/{projectId}")]
|
||||||
|
public async Task<IActionResult> GetAllPermissionFroProject(Guid projectId)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _projectServices.GetAllPermissionFroProjectAsync(projectId, loggedInEmployee, tenantId);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
[HttpGet("get/proejct-level/modules")]
|
[HttpGet("get/proejct-level/modules")]
|
||||||
public async Task<IActionResult> AssignProjectLevelModules()
|
public async Task<IActionResult> AssignProjectLevelModules()
|
||||||
{
|
{
|
||||||
|
@ -85,12 +85,12 @@ namespace MarcoBMS.Services.Helpers
|
|||||||
.Distinct()
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
result = await _context.Employees
|
var employees = await _context.Employees
|
||||||
.Include(fp => fp.JobRole)
|
.Include(fp => fp.JobRole)
|
||||||
.Where(e => employeeIds.Contains(e.Id) && e.IsActive && e.TenantId == tenantId)
|
.Where(e => employeeIds.Contains(e.Id) && e.JobRole != null && e.IsActive && e.TenantId == tenantId)
|
||||||
.Select(e => e.ToEmployeeVMFromEmployee())
|
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
result = employees.Select(e => e.ToEmployeeVMFromEmployee()).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ShowInActive)
|
else if (ShowInActive)
|
||||||
|
@ -88,7 +88,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
||||||
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
||||||
Guid.Parse("81ab8a87-8ccd-4015-a917-0627cee6a100"),
|
|
||||||
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
||||||
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@ using Marco.Pms.Model.ViewModels.Master;
|
|||||||
using Marco.Pms.Model.ViewModels.Projects;
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
using Marco.Pms.Services.Helpers;
|
using Marco.Pms.Services.Helpers;
|
||||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -29,7 +30,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly ApplicationDbContext _context; // Keeping this for direct scoped context use where appropriate
|
private readonly ApplicationDbContext _context; // Keeping this for direct scoped context use where appropriate
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
private readonly PermissionServices _permission;
|
|
||||||
private readonly CacheUpdateHelper _cache;
|
private readonly CacheUpdateHelper _cache;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
public ProjectServices(
|
public ProjectServices(
|
||||||
@ -37,17 +37,15 @@ namespace Marco.Pms.Services.Service
|
|||||||
IServiceScopeFactory serviceScopeFactory,
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
ApplicationDbContext context,
|
ApplicationDbContext context,
|
||||||
ILoggingService logger,
|
ILoggingService logger,
|
||||||
PermissionServices permission,
|
|
||||||
CacheUpdateHelper cache,
|
CacheUpdateHelper cache,
|
||||||
IMapper mapper)
|
IMapper mapper)
|
||||||
{
|
{
|
||||||
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||||
|
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
|
||||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_permission = permission ?? throw new ArgumentNullException(nameof(permission));
|
|
||||||
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
|
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
|
||||||
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||||
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region =================================================================== Project Get APIs ===================================================================
|
#region =================================================================== Project Get APIs ===================================================================
|
||||||
@ -87,7 +85,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetAllProjectsAsync(Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetAllProjectsAsync(Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -146,11 +143,12 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetProjectAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetProjectAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
// --- Step 1: Run independent operations in PARALLEL ---
|
// --- Step 1: Run independent operations in PARALLEL ---
|
||||||
// We can check permissions and fetch data at the same time to reduce latency.
|
// We can check permissions and fetch data at the same time to reduce latency.
|
||||||
var permissionTask = _permission.HasProjectPermission(loggedInEmployee, id);
|
var permissionTask = _permission.HasProjectPermission(loggedInEmployee, id);
|
||||||
@ -190,13 +188,15 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", null, 500);
|
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", null, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetProjectDetailsAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetProjectDetailsAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Details requested by EmployeeId: {EmployeeId} for ProjectId: {ProjectId}", loggedInEmployee.Id, id);
|
_logger.LogInfo("Details requested by EmployeeId: {EmployeeId} for ProjectId: {ProjectId}", loggedInEmployee.Id, id);
|
||||||
|
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// Step 1: Check global view project permission
|
// Step 1: Check global view project permission
|
||||||
var hasViewProjectPermission = await _permission.HasPermission(PermissionsMaster.ViewProject, loggedInEmployee.Id, id);
|
var hasViewProjectPermission = await _permission.HasPermission(PermissionsMaster.ViewProject, loggedInEmployee.Id, id);
|
||||||
if (!hasViewProjectPermission)
|
if (!hasViewProjectPermission)
|
||||||
@ -252,7 +252,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
return ApiResponse<object>.ErrorResponse("An internal server error occurred. Please try again later.", null, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetProjectDetailsOldAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetProjectDetailsOldAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
var project = await _context.Projects
|
var project = await _context.Projects
|
||||||
@ -419,6 +418,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
// --- Step 1: Fetch the Existing Entity from the Database ---
|
// --- Step 1: Fetch the Existing Entity from the Database ---
|
||||||
// This is crucial to avoid the data loss bug. We only want to modify an existing record.
|
// This is crucial to avoid the data loss bug. We only want to modify an existing record.
|
||||||
var existingProject = await _context.Projects
|
var existingProject = await _context.Projects
|
||||||
@ -519,6 +519,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- CRITICAL: Security Check ---
|
// --- CRITICAL: Security Check ---
|
||||||
// Before fetching data, you MUST verify the user has permission to see it.
|
// Before fetching data, you MUST verify the user has permission to see it.
|
||||||
// This is a placeholder for your actual permission logic.
|
// This is a placeholder for your actual permission logic.
|
||||||
@ -589,6 +592,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- Step 2: Security and Existence Checks ---
|
// --- Step 2: Security and Existence Checks ---
|
||||||
// Before fetching data, you MUST verify the user has permission to see it.
|
// Before fetching data, you MUST verify the user has permission to see it.
|
||||||
// This is a placeholder for your actual permission logic.
|
// This is a placeholder for your actual permission logic.
|
||||||
@ -660,11 +666,14 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
_logger.LogInfo("Starting to manage {AllocationCount} allocations for user {UserId}.", allocationsDto.Count, loggedInEmployee.Id);
|
_logger.LogInfo("Starting to manage {AllocationCount} allocations for user {UserId}.", allocationsDto.Count, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- (Placeholder) Security Check ---
|
// --- (Placeholder) Security Check ---
|
||||||
// In a real application, you would check if the loggedInEmployee has permission
|
// In a real application, you would check if the loggedInEmployee has permission
|
||||||
// to manage allocations for ALL projects involved in this batch.
|
// to manage allocations for ALL projects involved in this batch.
|
||||||
var projectIdsInBatch = allocationsDto.Select(a => a.ProjectId).Distinct().ToList();
|
var projectIdsInBatch = allocationsDto.Select(a => a.ProjectId).Distinct().ToList();
|
||||||
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id);
|
var projectId = projectIdsInBatch.FirstOrDefault();
|
||||||
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id, projectId);
|
||||||
if (!hasPermission)
|
if (!hasPermission)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Access DENIED for user {UserId} trying to manage allocations for projects.", loggedInEmployee.Id);
|
_logger.LogWarning("Access DENIED for user {UserId} trying to manage allocations for projects.", loggedInEmployee.Id);
|
||||||
@ -779,6 +788,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- Step 2: Clarified Security Check ---
|
// --- Step 2: Clarified Security Check ---
|
||||||
// The permission should be about viewing another employee's assignments, not a generic "Manage Team".
|
// The permission should be about viewing another employee's assignments, not a generic "Manage Team".
|
||||||
// This is a placeholder for your actual, more specific permission logic.
|
// This is a placeholder for your actual, more specific permission logic.
|
||||||
@ -855,15 +867,20 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
_logger.LogInfo("Starting to manage {AllocationCount} project assignments for Employee {EmployeeId}.", allocationsDto.Count, employeeId);
|
_logger.LogInfo("Starting to manage {AllocationCount} project assignments for Employee {EmployeeId}.", allocationsDto.Count, employeeId);
|
||||||
|
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- (Placeholder) Security Check ---
|
// --- (Placeholder) Security Check ---
|
||||||
// You MUST verify that the loggedInEmployee has permission to modify the assignments for the target employeeId.
|
// You MUST verify that the loggedInEmployee has permission to modify the assignments for the target employeeId.
|
||||||
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id);
|
foreach (var allocation in allocationsDto)
|
||||||
if (!hasPermission)
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Access DENIED for user {UserId} trying to manage assignments for employee {TargetEmployeeId}.", loggedInEmployee.Id, employeeId);
|
if (!await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id, allocation.ProjectId))
|
||||||
return ApiResponse<List<ProjectAllocationVM>>.ErrorResponse("Access Denied.", "You do not have permission to manage this employee's assignments.", 403);
|
{
|
||||||
|
_logger.LogWarning("Access DENIED for user {UserId} trying to manage assignments for employee {TargetEmployeeId}.", loggedInEmployee.Id, employeeId);
|
||||||
|
return ApiResponse<List<ProjectAllocationVM>>.ErrorResponse("Access Denied.", "You do not have permission to manage this employee's assignments.", 403);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Step 2: Fetch all relevant existing data in ONE database call ---
|
// --- Step 2: Fetch all relevant existing data in ONE database call ---
|
||||||
var projectIdsInDto = allocationsDto.Select(p => p.ProjectId).ToList();
|
var projectIdsInDto = allocationsDto.Select(p => p.ProjectId).ToList();
|
||||||
|
|
||||||
@ -1038,18 +1055,34 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
// --- Step 1: Run independent permission checks in PARALLEL ---
|
// --- Step 1: Run independent permission checks in PARALLEL ---
|
||||||
var projectPermissionTask = _permission.HasProjectPermission(loggedInEmployee, projectId);
|
var projectPermissionTask = _permission.HasProjectPermission(loggedInEmployee, projectId);
|
||||||
var viewInfraPermissionTask = _permission.HasPermission(PermissionsMaster.ViewProjectInfra, loggedInEmployee.Id, projectId);
|
var viewInfraPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var newScope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permission = newScope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permission.HasPermission(PermissionsMaster.ViewProjectInfra, loggedInEmployee.Id, projectId);
|
||||||
|
});
|
||||||
|
var manageInfraPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var newScope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permission = newScope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permission.HasPermission(PermissionsMaster.ManageProjectInfra, loggedInEmployee.Id, projectId);
|
||||||
|
});
|
||||||
|
|
||||||
await Task.WhenAll(projectPermissionTask, viewInfraPermissionTask);
|
await Task.WhenAll(projectPermissionTask, viewInfraPermissionTask, manageInfraPermissionTask);
|
||||||
|
|
||||||
if (!await projectPermissionTask)
|
var hasProjectPermission = projectPermissionTask.Result;
|
||||||
|
var hasViewInfraPermission = viewInfraPermissionTask.Result;
|
||||||
|
var hasManageInfraPermission = manageInfraPermissionTask.Result;
|
||||||
|
|
||||||
|
if (!hasProjectPermission)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Project access denied for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}", loggedInEmployee.Id, projectId);
|
_logger.LogWarning("Project access denied for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}", loggedInEmployee.Id, projectId);
|
||||||
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have access to this project", 403);
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have access to this project", 403);
|
||||||
}
|
}
|
||||||
if (!await viewInfraPermissionTask)
|
if (!hasViewInfraPermission && !hasManageInfraPermission)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("ViewInfra permission denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
_logger.LogWarning("ViewInfra permission denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have access to view this project's infrastructure", 403);
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have access to view this project's infrastructure", 403);
|
||||||
@ -1097,6 +1130,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
// --- Step 1: Cache-First Strategy ---
|
// --- Step 1: Cache-First Strategy ---
|
||||||
var cachedWorkItems = await _cache.GetWorkItemDetailsByWorkArea(workAreaId);
|
var cachedWorkItems = await _cache.GetWorkItemDetailsByWorkArea(workAreaId);
|
||||||
if (cachedWorkItems != null)
|
if (cachedWorkItems != null)
|
||||||
@ -1335,6 +1369,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
||||||
|
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// --- Step 1: Input Validation ---
|
// --- Step 1: Input Validation ---
|
||||||
if (workItemDtos == null || !workItemDtos.Any())
|
if (workItemDtos == null || !workItemDtos.Any())
|
||||||
{
|
{
|
||||||
@ -1472,7 +1508,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
return ApiResponse<List<WorkItemVM>>.SuccessResponse(responseList, message, 200);
|
return ApiResponse<List<WorkItemVM>>.SuccessResponse(responseList, message, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
@ -1586,6 +1621,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogInfo("ManageProjectLevelPermissionAsync started for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
_logger.LogInfo("ManageProjectLevelPermissionAsync started for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
||||||
model.EmployeeId, model.ProjectId, tenantId);
|
model.EmployeeId, model.ProjectId, tenantId);
|
||||||
|
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
var hasTeamPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id, model.ProjectId);
|
var hasTeamPermission = await _permission.HasPermission(PermissionsMaster.ManageTeam, loggedInEmployee.Id, model.ProjectId);
|
||||||
if (!hasTeamPermission)
|
if (!hasTeamPermission)
|
||||||
{
|
{
|
||||||
@ -1724,31 +1762,30 @@ namespace Marco.Pms.Services.Service
|
|||||||
employeeId, projectId, tenantId, loggedInEmployee.Id);
|
employeeId, projectId, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
// Query the database for relevant project-level permission mappings
|
// Query the database for relevant project-level permission mappings
|
||||||
var permissionMappings = await _context.ProjectLevelPermissionMappings
|
var employeeTask = Task.Run(async () =>
|
||||||
.Include(p => p.Employee)
|
|
||||||
.ThenInclude(e => e!.JobRole)
|
|
||||||
.Include(p => p.Project)
|
|
||||||
.Include(p => p.Permission)
|
|
||||||
.ThenInclude(fp => fp!.Feature)
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(p => p.EmployeeId == employeeId
|
|
||||||
&& p.ProjectId == projectId
|
|
||||||
&& p.TenantId == tenantId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
if (permissionMappings == null || !permissionMappings.Any())
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No project-level permissions found for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
employeeId, projectId, tenantId);
|
return await context.Employees.FirstOrDefaultAsync(e => e.Id == employeeId);
|
||||||
return ApiResponse<object>.ErrorResponse("Project-Level Permissions not found", "Project-Level Permissions not found in database", 404);
|
});
|
||||||
}
|
var projectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
var permissionIdsTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
return await GetPermissionIdsByProject(projectId, employeeId, tenantId);
|
||||||
|
});
|
||||||
|
|
||||||
// Map the employee, project, and permissions.
|
await Task.WhenAll(employeeTask, projectTask, permissionIdsTask);
|
||||||
var employee = _mapper.Map<BasicEmployeeVM>(permissionMappings.First().Employee);
|
|
||||||
var project = _mapper.Map<BasicProjectVM>(permissionMappings.First().Project);
|
var employee = employeeTask.Result;
|
||||||
var permissions = permissionMappings
|
var project = projectTask.Result;
|
||||||
.Select(p => _mapper.Map<FeaturePermissionVM>(p.Permission))
|
var permissionIds = permissionIdsTask.Result;
|
||||||
.ToList();
|
|
||||||
|
var permissions = await _context.FeaturePermissions
|
||||||
|
.Include(fp => fp.Feature)
|
||||||
|
.Where(fp => permissionIds.Contains(fp.Id)).ToListAsync();
|
||||||
|
|
||||||
if (employee == null)
|
if (employee == null)
|
||||||
{
|
{
|
||||||
@ -1761,12 +1798,26 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (permissions == null || !permissions.Any())
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No project-level permissions found for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
||||||
|
employeeId, projectId, tenantId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Project-Level Permissions not found", "Project-Level Permissions not found in database", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the employee, project, and permissions.
|
||||||
|
var employeeVm = _mapper.Map<BasicEmployeeVM>(employee);
|
||||||
|
var projectVm = _mapper.Map<BasicProjectVM>(project);
|
||||||
|
var permissionVms = permissions
|
||||||
|
.Select(p => _mapper.Map<FeaturePermissionVM>(p))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
// Prepare the result object.
|
// Prepare the result object.
|
||||||
var result = new
|
var result = new
|
||||||
{
|
{
|
||||||
Employee = employee,
|
Employee = employeeVm,
|
||||||
Project = project,
|
Project = projectVm,
|
||||||
Permissions = permissions
|
Permissions = permissionVms
|
||||||
};
|
};
|
||||||
|
|
||||||
_logger.LogInfo("Project-level permissions fetched successfully for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
_logger.LogInfo("Project-level permissions fetched successfully for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}",
|
||||||
@ -1791,7 +1842,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
||||||
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
||||||
Guid.Parse("81ab8a87-8ccd-4015-a917-0627cee6a100"),
|
|
||||||
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
||||||
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
||||||
};
|
};
|
||||||
@ -1871,6 +1921,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An error occurred while retrieving employees with project-level permissions.", 500);
|
return ApiResponse<object>.ErrorResponse("An error occurred while retrieving employees with project-level permissions.", 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task<ApiResponse<object>> GetAllPermissionFroProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
var featurePermissionIds = await GetPermissionIdsByProject(projectId, loggedInEmployee.Id, tenantId);
|
||||||
|
return ApiResponse<object>.SuccessResponse(featurePermissionIds, "Successfully featched the permission ids", 200);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
@ -1880,13 +1935,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
List<Project> alloc = await _context.Projects.Where(c => c.TenantId == tanentId).ToListAsync();
|
List<Project> alloc = await _context.Projects.Where(c => c.TenantId == tanentId).ToListAsync();
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ProjectAllocation>> GetProjectByEmployeeID(Guid employeeId)
|
public async Task<List<ProjectAllocation>> GetProjectByEmployeeID(Guid employeeId)
|
||||||
{
|
{
|
||||||
List<ProjectAllocation> alloc = await _context.ProjectAllocations.Where(c => c.EmployeeId == employeeId && c.IsActive == true).Include(c => c.Project).ToListAsync();
|
List<ProjectAllocation> alloc = await _context.ProjectAllocations.Where(c => c.EmployeeId == employeeId && c.IsActive == true).Include(c => c.Project).ToListAsync();
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ProjectAllocation>> GetTeamByProject(Guid TenantId, Guid ProjectId, bool IncludeInactive)
|
public async Task<List<ProjectAllocation>> GetTeamByProject(Guid TenantId, Guid ProjectId, bool IncludeInactive)
|
||||||
{
|
{
|
||||||
if (IncludeInactive)
|
if (IncludeInactive)
|
||||||
@ -1903,9 +1956,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
return employees;
|
return employees;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Guid>> GetMyProjects(Guid tenantId, Employee LoggedInEmployee)
|
public async Task<List<Guid>> GetMyProjects(Guid tenantId, Employee LoggedInEmployee)
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
var projectIds = await _cache.GetProjects(LoggedInEmployee.Id);
|
var projectIds = await _cache.GetProjects(LoggedInEmployee.Id);
|
||||||
|
|
||||||
if (projectIds == null)
|
if (projectIds == null)
|
||||||
@ -1929,9 +1984,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
return projectIds;
|
return projectIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Guid>> GetMyProjectIdsAsync(Guid tenantId, Employee loggedInEmployee)
|
public async Task<List<Guid>> GetMyProjectIdsAsync(Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
// 1. Attempt to retrieve the list of project IDs from the cache first.
|
// 1. Attempt to retrieve the list of project IDs from the cache first.
|
||||||
// This is the "happy path" and should be as fast as possible.
|
// This is the "happy path" and should be as fast as possible.
|
||||||
List<Guid>? projectIds = await _cache.GetProjects(loggedInEmployee.Id);
|
List<Guid>? projectIds = await _cache.GetProjects(loggedInEmployee.Id);
|
||||||
@ -1978,7 +2035,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
return newProjectIds;
|
return newProjectIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a list of ProjectInfoVMs by their IDs, using an efficient partial cache-hit strategy.
|
/// Retrieves a list of ProjectInfoVMs by their IDs, using an efficient partial cache-hit strategy.
|
||||||
/// It fetches what it can from the cache (as ProjectMongoDB), gets the rest from the
|
/// It fetches what it can from the cache (as ProjectMongoDB), gets the rest from the
|
||||||
@ -2029,7 +2085,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
return finalViewModels;
|
return finalViewModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ProjectDetailsVM> GetProjectViewModel(Guid? id, Project project)
|
private async Task<ProjectDetailsVM> GetProjectViewModel(Guid? id, Project project)
|
||||||
{
|
{
|
||||||
ProjectDetailsVM vm = new ProjectDetailsVM();
|
ProjectDetailsVM vm = new ProjectDetailsVM();
|
||||||
@ -2179,7 +2234,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
// Map from the database entity to the response ViewModel.
|
// Map from the database entity to the response ViewModel.
|
||||||
return dbProject;
|
return dbProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateCacheInBackground(Project project)
|
private async Task UpdateCacheInBackground(Project project)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -2197,7 +2251,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogError(ex, "Background cache update failed for project {ProjectId} ", project.Id);
|
_logger.LogError(ex, "Background cache update failed for project {ProjectId} ", project.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateCacheAndNotify(Dictionary<Guid, (double Planned, double Completed)> workDelta, List<WorkItem> affectedItems)
|
private async Task UpdateCacheAndNotify(Dictionary<Guid, (double Planned, double Completed)> workDelta, List<WorkItem> affectedItems)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -2219,7 +2272,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogError(ex, "An error occurred during background cache update/notification.");
|
_logger.LogError(ex, "An error occurred during background cache update/notification.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessBuilding(BuildingDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, Employee loggedInEmployee)
|
private void ProcessBuilding(BuildingDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
@ -2256,8 +2308,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
private void ProcessFloor(FloorDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Building> buildings,
|
||||||
private void ProcessFloor(FloorDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Building> buildings, Employee loggedInEmployee)
|
Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
||||||
@ -2297,8 +2349,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
private void ProcessWorkArea(WorkAreaDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Floor> floors,
|
||||||
private void ProcessWorkArea(WorkAreaDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Floor> floors, Employee loggedInEmployee)
|
Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
||||||
@ -2339,6 +2391,62 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
private async Task<List<Guid>> GetPermissionIdsByProject(Guid projectId, Guid EmployeeId, Guid tenantId)
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
|
||||||
|
var _rolesHelper = scope.ServiceProvider.GetRequiredService<RolesHelper>();
|
||||||
|
// 1. Try fetching permissions from cache (fast-path lookup).
|
||||||
|
var featurePermissionIds = await _cache.GetPermissions(EmployeeId);
|
||||||
|
|
||||||
|
// If not found in cache, fallback to database (slower).
|
||||||
|
if (featurePermissionIds == null)
|
||||||
|
{
|
||||||
|
var featurePermissions = await _rolesHelper.GetFeaturePermissionByEmployeeId(EmployeeId);
|
||||||
|
featurePermissionIds = featurePermissions.Select(fp => fp.Id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Handle project-level permission overrides if a project is specified.
|
||||||
|
if (projectId != Guid.Empty)
|
||||||
|
{
|
||||||
|
// Fetch permissions explicitly assigned to this employee in the project.
|
||||||
|
var projectLevelPermissionIds = await context.ProjectLevelPermissionMappings
|
||||||
|
.Where(pl => pl.ProjectId == projectId && pl.EmployeeId == EmployeeId && pl.TenantId == tenantId)
|
||||||
|
.Select(pl => pl.PermissionId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (projectLevelPermissionIds?.Any() ?? false)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Define modules where project-level overrides apply.
|
||||||
|
var projectLevelModuleIds = new HashSet<Guid>
|
||||||
|
{
|
||||||
|
Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
||||||
|
Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
||||||
|
Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
||||||
|
Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get all feature permissions under those modules where the user didn't have explicit project-level grants.
|
||||||
|
var allOverriddenPermissions = await context.FeaturePermissions
|
||||||
|
.Where(fp => projectLevelModuleIds.Contains(fp.FeatureId) &&
|
||||||
|
!projectLevelPermissionIds.Contains(fp.Id))
|
||||||
|
.Select(fp => fp.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Apply overrides:
|
||||||
|
// - Remove global permissions overridden by project-level rules.
|
||||||
|
// - Add explicit project-level permissions.
|
||||||
|
featurePermissionIds = featurePermissionIds
|
||||||
|
.Except(allOverriddenPermissions) // Remove overridden
|
||||||
|
.Concat(projectLevelPermissionIds) // Add project-level
|
||||||
|
.Distinct() // Ensure no duplicates
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return featurePermissionIds;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<object>> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
Task<ApiResponse<object>> GetAllPermissionFroProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user