Removing the project stored in cache for employee who have the project manage permission
This commit is contained in:
parent
3c8a044d66
commit
8e3eedbfa7
@ -137,6 +137,20 @@ namespace Marco.Pms.CacheHelper
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public async Task<bool> ClearAllProjectIdsByPermissionIdFromCache(Guid permissionId)
|
||||||
|
{
|
||||||
|
var filter = Builders<EmployeePermissionMongoDB>.Filter.AnyEq(e => e.PermissionIds, permissionId.ToString());
|
||||||
|
|
||||||
|
var update = Builders<EmployeePermissionMongoDB>.Update
|
||||||
|
.Set(e => e.ProjectIds, new List<string>());
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update);
|
||||||
|
|
||||||
|
if (result.MatchedCount == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public async Task<bool> RemoveRoleIdFromCache(Guid employeeId, Guid roleId)
|
public async Task<bool> RemoveRoleIdFromCache(Guid employeeId, Guid roleId)
|
||||||
{
|
{
|
||||||
var filter = Builders<EmployeePermissionMongoDB>.Filter
|
var filter = Builders<EmployeePermissionMongoDB>.Filter
|
||||||
|
@ -36,6 +36,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
private readonly IHubContext<MarcoHub> _signalR;
|
private readonly IHubContext<MarcoHub> _signalR;
|
||||||
private readonly PermissionServices _permission;
|
private readonly PermissionServices _permission;
|
||||||
private readonly CacheUpdateHelper _cache;
|
private readonly CacheUpdateHelper _cache;
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly Guid ViewProjects;
|
private readonly Guid ViewProjects;
|
||||||
private readonly Guid ManageProject;
|
private readonly Guid ManageProject;
|
||||||
private readonly Guid ViewInfra;
|
private readonly Guid ViewInfra;
|
||||||
@ -44,7 +45,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
|
|
||||||
public ProjectController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, RolesHelper rolesHelper, ProjectsHelper projectHelper,
|
public ProjectController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, RolesHelper rolesHelper, ProjectsHelper projectHelper,
|
||||||
IHubContext<MarcoHub> signalR, PermissionServices permission, CacheUpdateHelper cache)
|
IHubContext<MarcoHub> signalR, PermissionServices permission, CacheUpdateHelper cache, IServiceScopeFactory serviceScopeFactory)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
@ -59,6 +60,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
ViewInfra = Guid.Parse("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4");
|
ViewInfra = Guid.Parse("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4");
|
||||||
ManageInfra = Guid.Parse("f2aee20a-b754-4537-8166-f9507b44585b");
|
ManageInfra = Guid.Parse("f2aee20a-b754-4537-8166-f9507b44585b");
|
||||||
tenantId = _userHelper.GetTenantId();
|
tenantId = _userHelper.GetTenantId();
|
||||||
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("list/basic")]
|
[HttpGet("list/basic")]
|
||||||
@ -436,31 +438,56 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> Create([FromBody] CreateProjectDto projectDto)
|
public async Task<IActionResult> Create([FromBody] CreateProjectDto projectDto)
|
||||||
{
|
{
|
||||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
// 1. Validate input first (early exit)
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
var errors = ModelState.Values
|
var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList();
|
||||||
.SelectMany(v => v.Errors)
|
|
||||||
.Select(e => e.ErrorMessage)
|
|
||||||
.ToList();
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Guid TenantId = GetTenantId();
|
// 2. Prepare data without I/O
|
||||||
var project = projectDto.ToProjectFromCreateProjectDto(TenantId);
|
Guid tenantId = _userHelper.GetTenantId(); // Assuming this is fast and from claims
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var loggedInUserId = loggedInEmployee.Id;
|
||||||
|
var project = projectDto.ToProjectFromCreateProjectDto(tenantId);
|
||||||
|
|
||||||
_context.Projects.Add(project);
|
// 3. Store it to database
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_context.Projects.Add(project);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log the detailed exception
|
||||||
|
_logger.LogError("Failed to create project in database. Rolling back transaction. : {Error}", ex.Message);
|
||||||
|
// Return a server error as the primary operation failed
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("An error occurred while saving the project.", ex.Message, 500));
|
||||||
|
}
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
// 4. Perform non-critical side-effects (caching, notifications) concurrently
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// These operations do not depend on each other, so they can run in parallel.
|
||||||
|
Task cacheAddDetailsTask = _cache.AddProjectDetails(project);
|
||||||
|
Task cacheClearListTask = _cache.ClearAllProjectIdsByPermissionId(ManageProject);
|
||||||
|
|
||||||
await _cache.AddProjectDetails(project);
|
var notification = new { LoggedInUserId = loggedInUserId, Keyword = "Create_Project", Response = project.ToProjectDto() };
|
||||||
|
// Send notification only to the relevant group (e.g., users in the same tenant)
|
||||||
|
Task notificationTask = _signalR.Clients.Group(tenantId.ToString()).SendAsync("NotificationEventHandler", notification);
|
||||||
|
|
||||||
var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "Create_Project", Response = project.ToProjectDto() };
|
// Await all side-effect tasks to complete in parallel
|
||||||
|
await Task.WhenAll(cacheAddDetailsTask, cacheClearListTask, notificationTask);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// The project was created successfully, but a side-effect failed.
|
||||||
|
// Log this as a warning, as the primary operation succeeded. Don't return an error to the user.
|
||||||
|
_logger.LogWarning("Project {ProjectId} was created, but a post-creation side-effect (caching/notification) failed. : {Error}", project.Id, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
// 5. Return a success response to the user as soon as the critical data is saved.
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(project.ToProjectDto(), "Project created successfully.", 200));
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(project.ToProjectDto(), "Success.", 200));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
|
@ -298,6 +298,17 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
_logger.LogWarning("Error occured while deleting projectIds from Cache for Application Role {RoleId}: {Error}", roleId, ex.Message);
|
_logger.LogWarning("Error occured while deleting projectIds from Cache for Application Role {RoleId}: {Error}", roleId, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task ClearAllProjectIdsByPermissionId(Guid permissionId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _employeeCache.ClearAllProjectIdsByPermissionIdFromCache(permissionId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Error occured while deleting projectIds from Cache for Permission {PermissionId}: {Error}", permissionId, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
public async Task ClearAllPermissionIdsByEmployeeID(Guid employeeId)
|
public async Task ClearAllPermissionIdsByEmployeeID(Guid employeeId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
Loading…
x
Reference in New Issue
Block a user