using Marco.Pms.Model.MongoDBModels.Employees; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using MongoDB.Driver; namespace Marco.Pms.Helpers.CacheHelper { public class EmployeeCache { private readonly IMongoCollection _collection; private readonly ILogger _logger; public EmployeeCache(IConfiguration configuration, ILogger logger) { _logger = logger; var connectionString = configuration["MongoDB:ConnectionString"]; var mongoUrl = new MongoUrl(connectionString); var client = new MongoClient(mongoUrl); // Your MongoDB connection string var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name _collection = mongoDB.GetCollection("EmployeeProfile"); } public async Task AddApplicationRoleToCache(Guid employeeId, List newRoleIds, List newPermissionIds, Guid tenantId) { // 2. Perform database queries concurrently for better performance. var employeeIdString = employeeId.ToString(); var tenantIdString = tenantId.ToString(); // 5. Build a single, efficient update operation. var filter = Builders.Filter.Eq(e => e.Id, employeeIdString); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update .AddToSetEach(e => e.ApplicationRoleIds, newRoleIds) .Set(r => r.ExpireAt, DateTime.UtcNow.Date.AddDays(1)) .Set(r => r.TenantId, tenantIdString) .AddToSetEach(e => e.PermissionIds, newPermissionIds); var options = new UpdateOptions { IsUpsert = true }; var result = await _collection.UpdateOneAsync(filter, update, options); await InitializeCollectionAsync(); // 6. Return a more accurate result indicating success for both updates and upserts. // The operation is successful if an existing document was modified OR a new one was created. return result.IsAcknowledged && (result.ModifiedCount > 0 || result.UpsertedId != null); } public async Task AddProjectsToCache(Guid employeeId, List projectIds, Guid tenantId) { var newprojectIds = projectIds.Select(p => p.ToString()).ToList(); var tenantIdString = tenantId.ToString(); var filter = Builders.Filter.Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update .Set(r => r.ExpireAt, DateTime.UtcNow.Date.AddDays(1)) .Set(r => r.TenantId, tenantIdString) .AddToSetEach(e => e.ProjectIds, newprojectIds); var result = await _collection.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); if (result.MatchedCount == 0) { return false; } await InitializeCollectionAsync(); return true; } public async Task> GetProjectsFromCache(Guid employeeId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter.Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var result = await _collection .Find(filter) .FirstOrDefaultAsync(); var projectIds = new List(); if (result != null) { projectIds = result.ProjectIds.Select(Guid.Parse).ToList(); } return projectIds; } public async Task> GetPermissionsFromCache(Guid employeeId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter.Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var result = await _collection .Find(filter) .FirstOrDefaultAsync(); var permissionIds = new List(); if (result != null) { permissionIds = result.PermissionIds.Select(Guid.Parse).ToList(); } return permissionIds; } public async Task ClearAllProjectIdsFromCache(Guid employeeId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter .Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update .Set(e => e.ProjectIds, new List()); var result = await _collection.UpdateOneAsync(filter, update); if (result.ModifiedCount == 0) return false; return true; } public async Task ClearAllProjectIdsByRoleIdFromCache(Guid roleId) { var filter = Builders.Filter.AnyEq(e => e.ApplicationRoleIds, roleId.ToString()); var update = Builders.Update .Set(e => e.ProjectIds, new List()); var result = await _collection.UpdateOneAsync(filter, update); if (result.MatchedCount == 0) return false; return true; } public async Task ClearAllProjectIdsByPermissionIdFromCache(Guid permissionId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter.AnyEq(e => e.PermissionIds, permissionId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update.Set(e => e.ProjectIds, new List()); var result = await _collection.UpdateManyAsync(filter, update).ConfigureAwait(false); return result.IsAcknowledged && result.ModifiedCount > 0; } public async Task RemoveRoleIdFromCache(Guid employeeId, Guid roleId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter .Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update .Pull(e => e.ApplicationRoleIds, roleId.ToString()); var result = await _collection.UpdateOneAsync(filter, update); if (result.MatchedCount == 0) return false; if (result.ModifiedCount == 0) return false; return true; } public async Task ClearAllPermissionIdsByEmployeeIDFromCache(Guid employeeId, Guid tenantId) { var tenantIdString = tenantId.ToString(); var filter = Builders.Filter .Eq(e => e.Id, employeeId.ToString()); filter &= Builders.Filter.Eq(e => e.TenantId, tenantIdString); var update = Builders.Update .Set(e => e.PermissionIds, new List()); var result = await _collection.UpdateOneAsync(filter, update); if (result.MatchedCount == 0) return false; return true; } public async Task ClearAllPermissionIdsByRoleIdFromCache(Guid roleId) { var filter = Builders.Filter.AnyEq(e => e.ApplicationRoleIds, roleId.ToString()); var update = Builders.Update .Set(e => e.PermissionIds, new List()); var result = await _collection.UpdateOneAsync(filter, update); if (result.MatchedCount == 0) return false; return true; } public async Task ClearAllEmployeesFromCache() { var result = await _collection.DeleteManyAsync(FilterDefinition.Empty); if (result.DeletedCount == 0) return false; return true; } public async Task ClearAllEmployeesFromCacheByTenantId(Guid tenantId) { var tenantIdString = tenantId.ToString(); try { var filter = Builders.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 ClearAllEmployeesFromCacheByEmployeeIds(List employeeIds, Guid tenantId) { var tenantIdString = tenantId.ToString(); try { var filter = Builders.Filter.In(x => x.Id, employeeIds); filter &= Builders.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; } } // A private method to handle the one-time setup of the collection's indexes. private async Task InitializeCollectionAsync() { var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); var indexOptions = new CreateIndexOptions { ExpireAfter = TimeSpan.Zero // required for fixed expiration time }; var indexModel = new CreateIndexModel(indexKeys, indexOptions); await _collection.Indexes.CreateOneAsync(indexModel); } } }