using Microsoft.EntityFrameworkCore; using eprintServer.Data; using eprintServer.Entities; using eprintServer.Interfaces; using Amazon.S3; using Amazon.S3.Model; using Amazon.S3.Transfer; namespace eprintServer.Services { public class FileStorageService : IFileStorageService { private readonly IAmazonS3 _s3Client; private readonly DataContext _context; private readonly IConfiguration _config; private readonly string _bucketName; public FileStorageService(IAmazonS3 s3Client, DataContext context, IConfiguration config) { _s3Client = s3Client; _context = context; _config = config; _bucketName = _config["S3Config:BucketName"]; } public async Task SaveFileAsync(IFormFile file, string subDirectory) { var fileExtension = Path.GetExtension(file.FileName); var uniqueFileName = $"{Guid.NewGuid()}{fileExtension}"; // Format the S3 Key (path inside the bucket) var s3Key = $"{subDirectory.TrimEnd('/')}/{uniqueFileName}"; using (var stream = file.OpenReadStream()) { var uploadRequest = new PutObjectRequest { BucketName = _bucketName, Key = s3Key, InputStream = stream, ContentType = file.ContentType, CannedACL = S3CannedACL.PublicRead // Makes the file accessible via URL }; await _s3Client.PutObjectAsync(uploadRequest); } // Construct the public URL // Format: https://{bucket}.fsn1.your-objectstorage.com/{key} var baseUrl = _config["S3Config:ServiceUrl"].Replace("https://", $"https://{_bucketName}."); var fileUrl = $"{baseUrl}/{s3Key}"; var fileModel = new FileModel { Name = file.FileName, Url = fileUrl, // Now saving the full Cloud URL Type = file.ContentType, Size = file.Length }; _context.FileModels.Add(fileModel); await _context.SaveChangesAsync(); return fileModel; } public async Task DeleteFileAsync(long fileId) { var fileModel = await _context.FileModels.FindAsync(fileId); if (fileModel == null) return; // Extract the Key from the URL to delete from S3 // URL looks like: https://bucket.host.com/folder/file.jpg // We need: folder/file.jpg var uri = new Uri(fileModel.Url); var s3Key = uri.AbsolutePath.TrimStart('/'); await _s3Client.DeleteObjectAsync(_bucketName, s3Key); _context.FileModels.Remove(fileModel); await _context.SaveChangesAsync(); } public async Task> SaveAllAsync(List files, string subDirectory) { var savedFiles = new List(); foreach (var file in files) { var savedFile = await SaveFileAsync(file, subDirectory); savedFiles.Add(savedFile); } return savedFiles; } public async Task GetFileByIdAsync(long fileId) { return await _context.FileModels.FindAsync(fileId); } public async Task> GetFilesByIdsAsync(IEnumerable fileIds) { return await _context.FileModels .Where(fm => fileIds.Contains(fm.Id)) .ToListAsync(); } } }