Adsing file to delete from S3 in mongoDB while update expenes

This commit is contained in:
ashutosh.nehete 2025-07-23 16:24:59 +05:30
parent 0095cd54f6
commit 4370d5a350
8 changed files with 176 additions and 14 deletions

View File

@ -102,6 +102,16 @@ namespace Marco.Pms.Helpers.CacheHelper
return expense; return expense;
} }
public async Task<bool> DeleteExpenseFromCacheAsync(Guid id, Guid tenantId)
{
var filter = Builders<ExpenseDetailsMongoDB>.Filter.And(
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.Id, id.ToString()),
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.TenantId, tenantId.ToString())
);
var result = await _collection.DeleteOneAsync(filter);
return result.DeletedCount > 0;
}
private async Task InitializeCollectionAsync() private async Task InitializeCollectionAsync()
{ {
var indexKeys = Builders<ExpenseDetailsMongoDB>.IndexKeys.Ascending(x => x.ExpireAt); var indexKeys = Builders<ExpenseDetailsMongoDB>.IndexKeys.Ascending(x => x.ExpireAt);

View File

@ -1,21 +1,28 @@
using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.MongoDBModels.Utility;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
using System.Collections; using System.Collections;
namespace Marco.Pms.Helpers namespace Marco.Pms.Helpers.Utility
{ {
public class UpdateLogHelper public class UtilityMongoDBHelper
{ {
private readonly IMongoDatabase _mongoDatabase; private readonly IMongoDatabase _mongoDatabase;
public UpdateLogHelper(IConfiguration configuration) private readonly IConfiguration _configuration;
private readonly ILogger<UtilityMongoDBHelper> _logger;
public UtilityMongoDBHelper(IConfiguration configuration, ILogger<UtilityMongoDBHelper> logger)
{ {
_configuration = configuration;
_logger = logger;
var connectionString = configuration["MongoDB:ModificationConnectionString"]; var connectionString = configuration["MongoDB:ModificationConnectionString"];
var mongoUrl = new MongoUrl(connectionString); var mongoUrl = new MongoUrl(connectionString);
var client = new MongoClient(mongoUrl); // Your MongoDB connection string var client = new MongoClient(mongoUrl); // Your MongoDB connection string
_mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name _mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
} }
#region =================================================================== Update Log Helper Functions ===================================================================
public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName) public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName)
{ {
var collection = _mongoDatabase.GetCollection<UpdateLogsObject>(collectionName); var collection = _mongoDatabase.GetCollection<UpdateLogsObject>(collectionName);
@ -87,5 +94,35 @@ namespace Marco.Pms.Helpers
return bson; return bson;
} }
#endregion
#region =================================================================== S3 deletion Helper Functions ===================================================================
public async Task PushToS3DeletionAsync(List<S3DeletionObject> deletionObject)
{
var bucketName = _configuration["AWS:BucketName"];
if (bucketName != null)
{
deletionObject = deletionObject.Select(d => new S3DeletionObject
{
BucketName = bucketName,
Key = d.Key,
Deleted = false
}).ToList();
}
_logger.LogInformation("Delection object for bucket {BucketName} added to mongoDB", bucketName);
try
{
var collection = _mongoDatabase.GetCollection<S3DeletionObject>("S3Delection");
await collection.InsertManyAsync(deletionObject);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occured while saving delection object for S3 to MogoDB");
}
_logger.LogInformation("Delection Objects added to MongoDB Successfully");
}
#endregion
} }
} }

View File

@ -0,0 +1,15 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace Marco.Pms.Model.MongoDBModels.Utility
{
public class S3DeletionObject
{
[BsonId]
[BsonRepresentation(BsonType.String)]
public Guid Id { get; set; } = Guid.NewGuid();
public string BucketName { get; set; } = string.Empty;
public string Key { get; set; } = string.Empty;
public bool Deleted { get; set; } = false;
}
}

View File

@ -2,10 +2,12 @@
{ {
public class FileUploadModel public class FileUploadModel
{ {
public Guid? DocumentId { get; set; }
public string? FileName { get; set; } // Name of the file (e.g., "image1.png") public string? FileName { get; set; } // Name of the file (e.g., "image1.png")
public string? Base64Data { get; set; } // Base64-encoded string of the file public string? Base64Data { get; set; } // Base64-encoded string of the file
public string? ContentType { get; set; } // MIME type (e.g., "image/png", "application/pdf") public string? ContentType { get; set; } // MIME type (e.g., "image/png", "application/pdf")
public long FileSize { get; set; } // File size in bytes public long FileSize { get; set; } // File size in bytes
public string? Description { get; set; } // Optional: Description or purpose of the file public string? Description { get; set; } // Optional: Description or purpose of the file
public bool IsActive { get; set; } = true;
} }
} }

View File

@ -1026,12 +1026,49 @@ namespace Marco.Pms.Services.Helpers
public async Task<ExpenseDetailsMongoDB?> GetExpenseDetailsById(Guid id, Guid tenantId) public async Task<ExpenseDetailsMongoDB?> GetExpenseDetailsById(Guid id, Guid tenantId)
{ {
var response = await _expenseCache.GetExpenseDetailsByIdAsync(id, tenantId); try
if (response == null || response.Id == string.Empty)
{ {
return null; var response = await _expenseCache.GetExpenseDetailsByIdAsync(id, tenantId);
if (response != null && response.Id != string.Empty)
{
return response;
}
} }
return response; catch (Exception ex)
{
_logger.LogError(ex, "Error occured while fetching expense details from cache");
}
return null;
}
public async Task ReplaceExpenseAsync(Expenses expense)
{
bool response = false;
try
{
response = await _expenseCache.DeleteExpenseFromCacheAsync(expense.Id, expense.TenantId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occured while deleting expense from cache");
}
if (response)
{
await AddExpenseByObjectAsync(expense);
}
}
public async Task DeleteExpenseAsync(Guid id, Guid tenantId)
{
try
{
var response = await _expenseCache.DeleteExpenseFromCacheAsync(id, tenantId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occured while deleting expense from cache");
}
} }
#endregion #endregion

View File

@ -1,6 +1,7 @@
using Marco.Pms.DataAccess.Data; using Marco.Pms.DataAccess.Data;
using Marco.Pms.Helpers; using Marco.Pms.Helpers;
using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.Helpers.CacheHelper;
using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.Authentication; using Marco.Pms.Model.Authentication;
using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Utilities; using Marco.Pms.Model.Utilities;
@ -186,7 +187,7 @@ builder.Services.AddScoped<DirectoryHelper>();
builder.Services.AddScoped<MasterHelper>(); builder.Services.AddScoped<MasterHelper>();
builder.Services.AddScoped<ReportHelper>(); builder.Services.AddScoped<ReportHelper>();
builder.Services.AddScoped<CacheUpdateHelper>(); builder.Services.AddScoped<CacheUpdateHelper>();
builder.Services.AddScoped<UpdateLogHelper>(); builder.Services.AddScoped<UtilityMongoDBHelper>();
#endregion #endregion
#region Cache Services #region Cache Services

View File

@ -1,6 +1,6 @@
using AutoMapper; using AutoMapper;
using Marco.Pms.DataAccess.Data; using Marco.Pms.DataAccess.Data;
using Marco.Pms.Helpers; using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Dtos.Expenses;
using Marco.Pms.Model.Employees; using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Entitlements;
@ -30,7 +30,7 @@ namespace Marco.Pms.Services.Service
private readonly ILoggingService _logger; private readonly ILoggingService _logger;
private readonly S3UploadService _s3Service; private readonly S3UploadService _s3Service;
private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly UpdateLogHelper _updateLogHelper; private readonly UtilityMongoDBHelper _updateLogHelper;
private readonly CacheUpdateHelper _cache; private readonly CacheUpdateHelper _cache;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8");
@ -40,7 +40,7 @@ namespace Marco.Pms.Services.Service
IDbContextFactory<ApplicationDbContext> dbContextFactory, IDbContextFactory<ApplicationDbContext> dbContextFactory,
ApplicationDbContext context, ApplicationDbContext context,
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
UpdateLogHelper updateLogHelper, UtilityMongoDBHelper updateLogHelper,
CacheUpdateHelper cache, CacheUpdateHelper cache,
ILoggingService logger, ILoggingService logger,
S3UploadService s3Service, S3UploadService s3Service,
@ -690,6 +690,63 @@ namespace Marco.Pms.Services.Service
_logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id);
return ApiResponse<object>.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409); return ApiResponse<object>.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409);
} }
if (model.BillAttachments?.Any() ?? false)
{
var newBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId == null && ba.IsActive).ToList();
if (newBillAttachments.Any())
{
await ProcessAndUploadAttachmentsAsync(newBillAttachments, existingExpense, loggedInEmployee.Id, tenantId);
await _context.SaveChangesAsync();
}
var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList();
if (deleteBillAttachments.Any())
{
var documentIds = deleteBillAttachments.Select(d => d.DocumentId).ToList();
var attachmentTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
dbContext.BillAttachments.RemoveRange(attachments);
await dbContext.SaveChangesAsync();
});
var documentsTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
if (documents.Any())
{
dbContext.Documents.RemoveRange(documents);
await dbContext.SaveChangesAsync();
List<S3DeletionObject> deletionObject = new List<S3DeletionObject>();
foreach (var document in documents)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.S3Key
});
if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.ThumbS3Key
});
}
}
await _updateLogHelper.PushToS3DeletionAsync(deletionObject);
}
});
await Task.WhenAll(attachmentTask, documentsTask);
}
}
try try
{ {
// Task to save the detailed audit log to a separate system (e.g., MongoDB). // Task to save the detailed audit log to a separate system (e.g., MongoDB).
@ -718,9 +775,11 @@ namespace Marco.Pms.Services.Service
}); });
}).Unwrap(); }).Unwrap();
await Task.WhenAll(mongoDBTask, getNextStatusesTask); var cacheUpdateTask = _cache.ReplaceExpenseAsync(existingExpense);
var nextPossibleStatuses = await getNextStatusesTask; await Task.WhenAll(mongoDBTask, getNextStatusesTask, cacheUpdateTask);
var nextPossibleStatuses = getNextStatusesTask.Result;
var response = _mapper.Map<ExpenseList>(existingExpense); var response = _mapper.Map<ExpenseList>(existingExpense);
if (nextPossibleStatuses != null) if (nextPossibleStatuses != null)

View File

@ -42,7 +42,8 @@ namespace Marco.Pms.Services.Service
if (allowedFilesType == null || !allowedFilesType.Contains(fileType)) if (allowedFilesType == null || !allowedFilesType.Contains(fileType))
{ {
_logger.LogWarning("Unsupported file type. {FileType}", fileType); _logger.LogWarning("Unsupported file type. {FileType}", fileType);
throw new InvalidOperationException("Unsupported file type."); //throw new InvalidOperationException("Unsupported file type.");
return;
} }
fileBytes = Convert.FromBase64String(base64); fileBytes = Convert.FromBase64String(base64);