Compare commits
No commits in common. "main" and "Ashutosh_Enhancement#1452" have entirely different histories.
main
...
Ashutosh_E
@ -212,48 +212,6 @@ namespace Marco.Pms.Helpers.CacheHelper
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public async Task<bool> ClearAllEmployeesFromCacheByOnlyEmployeeId(Guid employeeId)
|
|
||||||
{
|
|
||||||
var employeeIdString = employeeId.ToString();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.Id, employeeIdString);
|
|
||||||
|
|
||||||
var result = await _collection.DeleteManyAsync(filter);
|
|
||||||
|
|
||||||
if (result.DeletedCount == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error occured while deleting employee profile");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task<bool> ClearAllEmployeesFromCacheByTenantId(Guid tenantId)
|
|
||||||
{
|
|
||||||
var tenantIdString = tenantId.ToString();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var filter = Builders<EmployeePermissionMongoDB>.Filter.Eq(e => e.TenantId, tenantIdString);
|
|
||||||
|
|
||||||
var result = await _collection.DeleteManyAsync(filter);
|
|
||||||
|
|
||||||
if (result.DeletedCount == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error occured while deleting employee profile");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task<bool> ClearAllEmployeesFromCacheByEmployeeIds(List<string> employeeIds, Guid tenantId)
|
public async Task<bool> ClearAllEmployeesFromCacheByEmployeeIds(List<string> employeeIds, Guid tenantId)
|
||||||
{
|
{
|
||||||
var tenantIdString = tenantId.ToString();
|
var tenantIdString = tenantId.ToString();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class CreateWorkStatusMasterDto
|
public class CreateWorkStatusMasterDto
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
public class UpdateWorkStatusMasterDto
|
public class UpdateWorkStatusMasterDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class CreateContactCategoryDto
|
public class CreateContactCategoryDto
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class CreateContactTagDto
|
public class CreateContactTagDto
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class UpdateContactCategoryDto
|
public class UpdateContactCategoryDto
|
||||||
{
|
{
|
||||||
public required Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
public class UpdateContactTagDto
|
public class UpdateContactTagDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public required string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public required string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using Marco.Pms.Model.Employees;
|
|||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Tenant;
|
using Marco.Pms.Model.ViewModels.Tenant;
|
||||||
using Marco.Pms.Services.Helpers;
|
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -1470,9 +1469,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
// Generate and store refresh token
|
// Generate and store refresh token
|
||||||
var refreshToken = await _refreshTokenService.CreateRefreshToken(loggedInEmployee.ApplicationUserId, tenantId.ToString(), loggedInEmployee.OrganizationId, _jwtSettings);
|
var refreshToken = await _refreshTokenService.CreateRefreshToken(loggedInEmployee.ApplicationUserId, tenantId.ToString(), loggedInEmployee.OrganizationId, _jwtSettings);
|
||||||
|
|
||||||
var _cache = scope.ServiceProvider.GetRequiredService<CacheUpdateHelper>();
|
|
||||||
await _cache.ClearAllEmployeesFromCacheByOnlyEmployeeId(loggedInEmployee.Id);
|
|
||||||
|
|
||||||
_logger.LogInfo("Tenant selected and tokens generated for TenantId: {TenantId} and Employee: {EmployeeEmail}", tenantId, loggedInEmployee.Email ?? string.Empty);
|
_logger.LogInfo("Tenant selected and tokens generated for TenantId: {TenantId} and Employee: {EmployeeEmail}", tenantId, loggedInEmployee.Email ?? string.Empty);
|
||||||
|
|
||||||
// Return success response including tokens
|
// Return success response including tokens
|
||||||
|
@ -9,7 +9,6 @@ using Marco.Pms.Model.ViewModels.Activities;
|
|||||||
using Marco.Pms.Model.ViewModels.Master;
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
using Marco.Pms.Model.ViewModels.Organization;
|
using Marco.Pms.Model.ViewModels.Organization;
|
||||||
using Marco.Pms.Model.ViewModels.Projects;
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
using Marco.Pms.Services.Helpers;
|
|
||||||
using Marco.Pms.Services.Service;
|
using Marco.Pms.Services.Service;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
@ -31,7 +30,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
private readonly Guid tenantId;
|
private readonly Guid tenantId;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly Guid loggedOrganizationId;
|
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
|
|
||||||
private static readonly Guid PMCProvider = Guid.Parse("b1877a3b-8832-47b1-bbe3-dc7e98672f49");
|
private static readonly Guid PMCProvider = Guid.Parse("b1877a3b-8832-47b1-bbe3-dc7e98672f49");
|
||||||
@ -49,7 +47,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_userHelper = userHelper ?? throw new ArgumentNullException(nameof(userHelper));
|
_userHelper = userHelper ?? throw new ArgumentNullException(nameof(userHelper));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||||
loggedOrganizationId = _userHelper.GetCurrentOrganizationId();
|
|
||||||
tenantId = userHelper.GetTenantId();
|
tenantId = userHelper.GetTenantId();
|
||||||
}
|
}
|
||||||
#region =================================================================== Get Functions ===================================================================
|
#region =================================================================== Get Functions ===================================================================
|
||||||
@ -672,8 +669,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
Service = _mapper.Map<ServiceMasterVM>(s)
|
Service = _mapper.Map<ServiceMasterVM>(s)
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
await AssignApplicationRoleToOrganization(organization.Id, project.TenantId);
|
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Organization successfully assigned to the project", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Organization successfully assigned to the project", 200));
|
||||||
}
|
}
|
||||||
catch (DbUpdateException dbEx)
|
catch (DbUpdateException dbEx)
|
||||||
@ -722,36 +717,34 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found in database", 404));
|
return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found in database", 404));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (organizationTenantMapping != null)
|
if (organizationTenantMapping == null)
|
||||||
|
{
|
||||||
|
// Create new tenant-organization mapping if none exists
|
||||||
|
var newMapping = new TenantOrgMapping
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
SPRID = organization.SPRID,
|
||||||
|
AssignedDate = DateTime.UtcNow,
|
||||||
|
IsActive = true,
|
||||||
|
AssignedById = loggedInEmployee.Id,
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
_context.TenantOrgMappings.Add(newMapping);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
_logger.LogInfo("Assigned organization {OrganizationId} to tenant {TenantId} successfully.", organizationId, tenantId);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Organization {OrganizationId} is already assigned to tenant {TenantId}. No action taken.", organizationId, tenantId);
|
_logger.LogInfo("Organization {OrganizationId} is already assigned to tenant {TenantId}. No action taken.", organizationId, tenantId);
|
||||||
// Commit transaction anyway to complete scope cleanly (optional)
|
// Commit transaction anyway to complete scope cleanly (optional)
|
||||||
await transaction.RollbackAsync();
|
await transaction.CommitAsync();
|
||||||
return StatusCode(409, ApiResponse<object>.ErrorResponse("Organization is already assigned to tenant", "Organization is already assigned to tenant", 409));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new tenant-organization mapping if none exists
|
|
||||||
var newMapping = new TenantOrgMapping
|
|
||||||
{
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
SPRID = organization.SPRID,
|
|
||||||
AssignedDate = DateTime.UtcNow,
|
|
||||||
IsActive = true,
|
|
||||||
AssignedById = loggedInEmployee.Id,
|
|
||||||
TenantId = tenantId
|
|
||||||
};
|
|
||||||
_context.TenantOrgMappings.Add(newMapping);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
await transaction.CommitAsync();
|
|
||||||
|
|
||||||
_logger.LogInfo("Assigned organization {OrganizationId} to tenant {TenantId} successfully.", organizationId, tenantId);
|
|
||||||
|
|
||||||
|
|
||||||
// Prepare response view model
|
// Prepare response view model
|
||||||
var response = _mapper.Map<BasicOrganizationVm>(organization);
|
var response = _mapper.Map<BasicOrganizationVm>(organization);
|
||||||
|
|
||||||
await AssignApplicationRoleToOrganization(organization.Id, tenantId);
|
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Organization has been assigned to tenant", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Organization has been assigned to tenant", 200));
|
||||||
}
|
}
|
||||||
catch (DbUpdateException dbEx)
|
catch (DbUpdateException dbEx)
|
||||||
@ -945,98 +938,45 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
|
//private ServicesProviderFilter? TryDeserializeServicesProviderFilter(string? filter)
|
||||||
|
//{
|
||||||
|
// if (string.IsNullOrWhiteSpace(filter))
|
||||||
|
// {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
private async Task AssignApplicationRoleToOrganization(Guid organizationId, Guid tenantId)
|
// var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||||
{
|
// ServicesProviderFilter? documentFilter = null;
|
||||||
if (loggedOrganizationId == organizationId)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
using var scope = _serviceScope.CreateScope();
|
|
||||||
|
|
||||||
var rootEmployee = await _context.Employees
|
// try
|
||||||
.Include(e => e.ApplicationUser)
|
// {
|
||||||
.FirstOrDefaultAsync(e => e.ApplicationUser != null && e.ApplicationUser.IsRootUser.HasValue && e.ApplicationUser.IsRootUser.Value && e.OrganizationId == organizationId && e.IsPrimary);
|
// // First, try to deserialize directly. This is the expected case (e.g., from a web client).
|
||||||
if (rootEmployee == null)
|
// documentFilter = JsonSerializer.Deserialize<ServicesProviderFilter>(filter, options);
|
||||||
{
|
// }
|
||||||
return;
|
// catch (JsonException ex)
|
||||||
}
|
// {
|
||||||
string serviceProviderRoleName = "Service Provider Role";
|
// _logger.LogError(ex, "[{MethodName}] Failed to directly deserialize filter. Attempting to unescape and re-parse. Filter: {Filter}", nameof(TryDeserializeServicesProviderFilter), filter);
|
||||||
|
|
||||||
var serviceProviderRole = await _context.ApplicationRoles.FirstOrDefaultAsync(ar => ar.Role == serviceProviderRoleName && ar.TenantId == tenantId);
|
// // If direct deserialization fails, it might be an escaped string (common with tools like Postman or some mobile clients).
|
||||||
if (serviceProviderRole == null)
|
// try
|
||||||
{
|
// {
|
||||||
serviceProviderRole = new Model.Roles.ApplicationRole
|
// // Unescape the string first, then deserialize the result.
|
||||||
{
|
// string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
|
||||||
Id = Guid.NewGuid(),
|
// if (!string.IsNullOrWhiteSpace(unescapedJsonString))
|
||||||
Role = serviceProviderRoleName,
|
// {
|
||||||
Description = serviceProviderRoleName,
|
// documentFilter = JsonSerializer.Deserialize<ServicesProviderFilter>(unescapedJsonString, options);
|
||||||
IsSystem = true,
|
// }
|
||||||
TenantId = tenantId
|
// }
|
||||||
};
|
// catch (JsonException ex1)
|
||||||
_context.ApplicationRoles.Add(serviceProviderRole);
|
// {
|
||||||
|
// // If both attempts fail, log the final error and return null.
|
||||||
|
// _logger.LogError(ex1, "[{MethodName}] All attempts to deserialize the filter failed. Filter will be ignored. Filter: {Filter}", nameof(TryDeserializeServicesProviderFilter), filter);
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return documentFilter;
|
||||||
|
//}
|
||||||
|
|
||||||
var rolePermissionMappigs = new List<RolePermissionMappings> {
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.ViewProject
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.ViewProjectInfra
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.ViewTask
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.ViewAllEmployees
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.TeamAttendance
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.AssignRoles
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.ManageProjectInfra
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.AssignAndReportProgress
|
|
||||||
},
|
|
||||||
new RolePermissionMappings
|
|
||||||
{
|
|
||||||
ApplicationRoleId = serviceProviderRole.Id,
|
|
||||||
FeaturePermissionId = PermissionsMaster.AddAndEditTask
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_context.RolePermissionMappings.AddRange(rolePermissionMappigs);
|
|
||||||
}
|
|
||||||
_context.EmployeeRoleMappings.Add(new EmployeeRoleMapping
|
|
||||||
{
|
|
||||||
EmployeeId = rootEmployee.Id,
|
|
||||||
RoleId = serviceProviderRole.Id,
|
|
||||||
IsEnabled = true,
|
|
||||||
TenantId = tenantId
|
|
||||||
});
|
|
||||||
|
|
||||||
var _cache = scope.ServiceProvider.GetRequiredService<CacheUpdateHelper>();
|
|
||||||
await _cache.ClearAllPermissionIdsByEmployeeID(rootEmployee.Id, tenantId);
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,13 +560,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var response = await _projectServices.GetAssignedOrganizationsToProjectAsync(projectId, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetAssignedOrganizationsToProjectAsync(projectId, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
[HttpGet("get/assigned/organization/dropdown/{projectId}")]
|
|
||||||
public async Task<IActionResult> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId)
|
|
||||||
{
|
|
||||||
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
||||||
var response = await _projectServices.GetAssignedOrganizationsToProjectForDropdownAsync(projectId, tenantId, loggedInEmployee);
|
|
||||||
return StatusCode(response.StatusCode, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -1013,6 +1013,10 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await ClearPermissionForTenant();
|
||||||
|
});
|
||||||
var features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId);
|
var features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId);
|
||||||
if (features == null)
|
if (features == null)
|
||||||
{
|
{
|
||||||
@ -1065,7 +1069,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
// Get root employee and role for this tenant
|
// Get root employee and role for this tenant
|
||||||
var rootEmployee = await _context.Employees
|
var rootEmployee = await _context.Employees
|
||||||
.Include(e => e.ApplicationUser)
|
.Include(e => e.ApplicationUser)
|
||||||
.FirstOrDefaultAsync(e => e.ApplicationUser != null && (e.ApplicationUser.IsRootUser ?? false) && e.OrganizationId == tenant.OrganizationId);
|
.FirstOrDefaultAsync(e => e.ApplicationUser != null && (e.ApplicationUser.IsRootUser ?? false) && e.TenantId == model.TenantId);
|
||||||
|
|
||||||
if (rootEmployee == null)
|
if (rootEmployee == null)
|
||||||
{
|
{
|
||||||
@ -1123,9 +1127,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_logger.LogInfo("Removed {Count} role permission mappings for role {RoleId}", deleteMappings.Count, roleId);
|
_logger.LogInfo("Removed {Count} role permission mappings for role {RoleId}", deleteMappings.Count, roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _cache = scope.ServiceProvider.GetRequiredService<CacheUpdateHelper>();
|
|
||||||
await _cache.ClearAllEmployeesFromCacheByTenantId(tenant.Id);
|
|
||||||
|
|
||||||
var _masteData = scope.ServiceProvider.GetRequiredService<MasterDataService>();
|
var _masteData = scope.ServiceProvider.GetRequiredService<MasterDataService>();
|
||||||
|
|
||||||
if (features.Modules?.ProjectManagement?.Enabled ?? false)
|
if (features.Modules?.ProjectManagement?.Enabled ?? false)
|
||||||
@ -1324,6 +1325,10 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_logger.LogInfo("Subscription plan changed: Tenant={TenantId}, NewPlan={PlanId}",
|
_logger.LogInfo("Subscription plan changed: Tenant={TenantId}, NewPlan={PlanId}",
|
||||||
model.TenantId, model.PlanId);
|
model.TenantId, model.PlanId);
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await ClearPermissionForTenant();
|
||||||
|
});
|
||||||
|
|
||||||
// 8. Update tenant permissions based on subscription features.
|
// 8. Update tenant permissions based on subscription features.
|
||||||
var features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId);
|
var features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId);
|
||||||
@ -1358,7 +1363,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
// 8c. Find root employee & role for this tenant.
|
// 8c. Find root employee & role for this tenant.
|
||||||
var rootEmployee = await context.Employees
|
var rootEmployee = await context.Employees
|
||||||
.Include(e => e.ApplicationUser)
|
.Include(e => e.ApplicationUser)
|
||||||
.FirstOrDefaultAsync(e => e.ApplicationUser != null && (e.ApplicationUser.IsRootUser ?? false) && e.OrganizationId == tenant.OrganizationId);
|
.FirstOrDefaultAsync(e => e.ApplicationUser != null && (e.ApplicationUser.IsRootUser ?? false) && e.TenantId == model.TenantId);
|
||||||
|
|
||||||
if (rootEmployee == null)
|
if (rootEmployee == null)
|
||||||
{
|
{
|
||||||
@ -1369,8 +1374,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
var rootRoleId = await context.EmployeeRoleMappings
|
var rootRoleId = await context.EmployeeRoleMappings
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(er => er.Role)
|
.Where(er => er.EmployeeId == rootEmployee.Id && er.TenantId == model.TenantId)
|
||||||
.Where(er => er.EmployeeId == rootEmployee.Id && er.TenantId == model.TenantId && er.Role != null && er.Role.Role == "Super User")
|
|
||||||
.Select(er => er.RoleId)
|
.Select(er => er.RoleId)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
@ -1435,9 +1439,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_logger.LogInfo("Permissions revoked: {Count} for Role={RoleId}", mappingsToRemove.Count, rootRoleId);
|
_logger.LogInfo("Permissions revoked: {Count} for Role={RoleId}", mappingsToRemove.Count, rootRoleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _cache = scope.ServiceProvider.GetRequiredService<CacheUpdateHelper>();
|
|
||||||
await _cache.ClearAllEmployeesFromCacheByTenantId(tenant.Id);
|
|
||||||
|
|
||||||
var _masteData = scope.ServiceProvider.GetRequiredService<MasterDataService>();
|
var _masteData = scope.ServiceProvider.GetRequiredService<MasterDataService>();
|
||||||
|
|
||||||
if (features.Modules?.ProjectManagement?.Enabled ?? false)
|
if (features.Modules?.ProjectManagement?.Enabled ?? false)
|
||||||
@ -1822,6 +1823,19 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return ApiResponse<SubscriptionPlanVM>.SuccessResponse(VM, "Success", 200);
|
return ApiResponse<SubscriptionPlanVM>.SuccessResponse(VM, "Success", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ClearPermissionForTenant()
|
||||||
|
{
|
||||||
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
|
||||||
|
var _cache = scope.ServiceProvider.GetRequiredService<CacheUpdateHelper>();
|
||||||
|
var _cacheLogger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
|
||||||
|
|
||||||
|
var employeeIds = await _context.Employees.Where(e => e.TenantId == tenantId).Select(e => e.Id).ToListAsync();
|
||||||
|
await _cache.ClearAllEmployeesFromCacheByEmployeeIds(employeeIds, tenantId);
|
||||||
|
_cacheLogger.LogInfo("{EmployeeCount} number of employee deleted", employeeIds.Count);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -956,28 +956,6 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
_logger.LogError(ex, "Error occured while deleting all employees from Cache");
|
_logger.LogError(ex, "Error occured while deleting all employees from Cache");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task ClearAllEmployeesFromCacheByOnlyEmployeeId(Guid employeeId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await _employeeCache.ClearAllEmployeesFromCacheByOnlyEmployeeId(employeeId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error occured while deleting all employees from Cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task ClearAllEmployeesFromCacheByTenantId(Guid tenantId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await _employeeCache.ClearAllEmployeesFromCacheByTenantId(tenantId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error occured while deleting all employees from Cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task ClearAllEmployees()
|
public async Task ClearAllEmployees()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -379,27 +379,6 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ======================================================= Contact Category Master =======================================================
|
|
||||||
CreateMap<CreateContactCategoryDto, ContactCategoryMaster>();
|
|
||||||
CreateMap<UpdateContactCategoryDto, ContactCategoryMaster>();
|
|
||||||
CreateMap<ContactCategoryMaster, ContactCategoryVM>();
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Contact Tag Master =======================================================
|
|
||||||
CreateMap<CreateContactTagDto, ContactTagMaster>();
|
|
||||||
CreateMap<UpdateContactTagDto, ContactTagMaster>();
|
|
||||||
CreateMap<ContactTagMaster, ContactTagVM>();
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Expenses Status Master =======================================================
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Expenses Status Master =======================================================
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Expenses Status Master =======================================================
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Expenses Status Master =======================================================
|
|
||||||
#endregion
|
|
||||||
#region ======================================================= Expenses Status Master =======================================================
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ======================================================= Document =======================================================
|
#region ======================================================= Document =======================================================
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2805,128 +2805,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500);
|
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task<ApiResponse<object>> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee)
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Started fetching assigned organizations for ProjectId: {ProjectId} and TenantId: {TenantId} by user {UserId}",
|
|
||||||
projectId, tenantId, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Create a scoped PermissionServices instance for permission checks
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
|
|
||||||
// Retrieve the project by projectId and tenantId
|
|
||||||
var projectTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await context.Projects.AsNoTracking().Include(p => p.Promoter).Include(p => p.PMC).FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
|
||||||
});
|
|
||||||
|
|
||||||
var tenantTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await context.Tenants.AsNoTracking().Include(t => t.Organization).FirstOrDefaultAsync(t => t.Id == tenantId);
|
|
||||||
});
|
|
||||||
var projectServiceTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await context.ProjectServiceMappings
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(ps => ps!.Service)
|
|
||||||
.Where(ps => ps.ProjectId == projectId && ps.TenantId == tenantId).ToListAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(projectTask, tenantTask, projectServiceTask);
|
|
||||||
|
|
||||||
var project = projectTask.Result;
|
|
||||||
var tenant = tenantTask.Result;
|
|
||||||
var projectService = projectServiceTask.Result;
|
|
||||||
|
|
||||||
if (project == null || tenant == null)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Project {ProjectId} not found in database for tenant {TenantId}", projectId, tenantId);
|
|
||||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the logged in employee has permission to access the project
|
|
||||||
var hasPermission = await permissionService.HasProjectPermission(loggedInEmployee, projectId);
|
|
||||||
if (!hasPermission)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Access denied for user {UserId} on project {ProjectId}", loggedInEmployee.Id, projectId);
|
|
||||||
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to access this project.", 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all project-organization mappings with related service and organization data
|
|
||||||
var projectOrgMappingsQuery = _context.ProjectOrgMappings
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(po => po.ProjectService)
|
|
||||||
.ThenInclude(ps => ps!.Service)
|
|
||||||
.Include(po => po.AssignedBy)
|
|
||||||
.Include(po => po.OrganizationType)
|
|
||||||
.Include(po => po.Organization)
|
|
||||||
.Where(po => po.ProjectService != null
|
|
||||||
&& po.ProjectService.ProjectId == projectId
|
|
||||||
&& po.TenantId == tenantId);
|
|
||||||
|
|
||||||
if (loggedInEmployee.OrganizationId != project.PMCId && loggedInEmployee.OrganizationId != project.PromoterId && loggedInEmployee.OrganizationId != tenant.OrganizationId)
|
|
||||||
{
|
|
||||||
projectOrgMappingsQuery = projectOrgMappingsQuery.Where(po => po.ParentOrganizationId == loggedInEmployee.OrganizationId || po.OrganizationId == loggedInEmployee.OrganizationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var projectOrgMappings = await projectOrgMappingsQuery
|
|
||||||
.Distinct()
|
|
||||||
.ToListAsync();
|
|
||||||
var organizations = projectOrgMappings.Select(po => po.Organization!).ToList();
|
|
||||||
|
|
||||||
if (loggedInEmployee.OrganizationId == project.PMCId || loggedInEmployee.OrganizationId == project.PromoterId || loggedInEmployee.OrganizationId == tenant.OrganizationId)
|
|
||||||
{
|
|
||||||
var pmc = project.PMC;
|
|
||||||
var promoter = project.Promoter;
|
|
||||||
var organization = tenant.Organization;
|
|
||||||
|
|
||||||
if (!organizations.Any(r => r.Id == project.PMCId) && pmc != null)
|
|
||||||
{
|
|
||||||
organizations.Add(pmc);
|
|
||||||
}
|
|
||||||
if (!organizations.Any(r => r.Id == project.PromoterId) && promoter != null)
|
|
||||||
{
|
|
||||||
organizations.Add(promoter);
|
|
||||||
}
|
|
||||||
if (!organizations.Any(r => r.Id == tenant.OrganizationId) && organization != null)
|
|
||||||
{
|
|
||||||
organizations.Add(organization);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
organizations = organizations.DistinctBy(o => o.Id).ToList();
|
|
||||||
|
|
||||||
// Filter and map the data to the desired view model
|
|
||||||
var response = organizations
|
|
||||||
.Select(o => new ProjectOrganizationVM
|
|
||||||
{
|
|
||||||
Id = o.Id,
|
|
||||||
Name = o.Name,
|
|
||||||
SPRID = 0
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
_logger.LogInfo("Fetched {Count} assigned organizations for ProjectId: {ProjectId}", response.Count, projectId);
|
|
||||||
|
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the list of organizations assigned to the project", 200);
|
|
||||||
}
|
|
||||||
catch (DbUpdateException dbEx)
|
|
||||||
{
|
|
||||||
_logger.LogError(dbEx, "Database exception while fetching assigned organizations for ProjectId: {ProjectId}", projectId);
|
|
||||||
return ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Unhandled exception while fetching assigned organizations for ProjectId: {ProjectId}", projectId);
|
|
||||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<object>> DeassignServiceToProjectAsync(DeassignServiceDto model, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> DeassignServiceToProjectAsync(DeassignServiceDto model, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
|
||||||
Task<ApiResponse<object>> GetAssignedOrganizationsToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetAssignedOrganizationsToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user