| | | 1 | | using Microsoft.Extensions.Configuration; |
| | | 2 | | using Microsoft.Extensions.Logging; |
| | | 3 | | |
| | | 4 | | namespace FAU.Logica.Services; |
| | | 5 | | |
| | | 6 | | public class FilesystemStorageService : IStorageService |
| | | 7 | | { |
| | | 8 | | private readonly string _basePath; |
| | | 9 | | private readonly ILogger<FilesystemStorageService> _logger; |
| | | 10 | | |
| | 1 | 11 | | private static readonly HashSet<string> _allowedMimeTypes = new(StringComparer.OrdinalIgnoreCase) |
| | 1 | 12 | | { |
| | 1 | 13 | | "application/pdf", |
| | 1 | 14 | | "image/jpeg", |
| | 1 | 15 | | "image/jpg", |
| | 1 | 16 | | "image/png", |
| | 1 | 17 | | "image/tiff" |
| | 1 | 18 | | }; |
| | | 19 | | |
| | 8 | 20 | | public FilesystemStorageService(IConfiguration config, ILogger<FilesystemStorageService> logger) |
| | | 21 | | { |
| | 8 | 22 | | _basePath = config["Storage:BasePath"] ?? string.Empty; |
| | 8 | 23 | | _logger = logger; |
| | | 24 | | |
| | 8 | 25 | | if (string.IsNullOrEmpty(_basePath)) |
| | 0 | 26 | | _logger.LogWarning("Storage:BasePath no está configurado. Las operaciones de archivo fallarán si se intentan |
| | 8 | 27 | | } |
| | | 28 | | |
| | | 29 | | private void VerificarBasePath() |
| | | 30 | | { |
| | 11 | 31 | | if (string.IsNullOrEmpty(_basePath)) |
| | 0 | 32 | | throw new InvalidOperationException("Storage:BasePath no está configurado. Defina la variable de entorno Sto |
| | 11 | 33 | | } |
| | | 34 | | |
| | | 35 | | public async Task<string> GuardarAsync(Stream contenido, string rutaRelativa, string contentType) |
| | | 36 | | { |
| | 6 | 37 | | VerificarBasePath(); |
| | 6 | 38 | | if (!_allowedMimeTypes.Contains(contentType)) |
| | 1 | 39 | | throw new ArgumentException($"Tipo de archivo no permitido: {contentType}. Tipos permitidos: PDF, JPG, PNG, |
| | | 40 | | |
| | 5 | 41 | | var rutaCompleta = Path.Combine(_basePath, rutaRelativa); |
| | 5 | 42 | | var directorio = Path.GetDirectoryName(rutaCompleta)!; |
| | | 43 | | |
| | 5 | 44 | | Directory.CreateDirectory(directorio); |
| | | 45 | | |
| | 5 | 46 | | await using var fs = new FileStream(rutaCompleta, FileMode.Create, FileAccess.Write); |
| | 5 | 47 | | await contenido.CopyToAsync(fs); |
| | | 48 | | |
| | 5 | 49 | | _logger.LogInformation("Archivo guardado: {Ruta}", rutaRelativa); |
| | 5 | 50 | | return rutaRelativa; |
| | 5 | 51 | | } |
| | | 52 | | |
| | | 53 | | public Task EliminarAsync(string rutaRelativa) |
| | | 54 | | { |
| | 3 | 55 | | VerificarBasePath(); |
| | 3 | 56 | | var rutaCompleta = Path.Combine(_basePath, rutaRelativa); |
| | | 57 | | |
| | 3 | 58 | | if (File.Exists(rutaCompleta)) |
| | | 59 | | { |
| | 2 | 60 | | File.Delete(rutaCompleta); |
| | 2 | 61 | | _logger.LogInformation("Archivo eliminado: {Ruta}", rutaRelativa); |
| | | 62 | | |
| | 2 | 63 | | var directorio = Path.GetDirectoryName(rutaCompleta)!; |
| | 2 | 64 | | if (Directory.Exists(directorio) && !Directory.EnumerateFileSystemEntries(directorio).Any()) |
| | 2 | 65 | | Directory.Delete(directorio); |
| | | 66 | | } |
| | | 67 | | |
| | 3 | 68 | | return Task.CompletedTask; |
| | | 69 | | } |
| | | 70 | | |
| | | 71 | | public Task<Stream> ObtenerAsync(string rutaRelativa) |
| | | 72 | | { |
| | 2 | 73 | | VerificarBasePath(); |
| | 2 | 74 | | var rutaCompleta = Path.Combine(_basePath, rutaRelativa); |
| | | 75 | | |
| | 2 | 76 | | if (!File.Exists(rutaCompleta)) |
| | 1 | 77 | | throw new StorageFileNotFoundException($"Archivo no encontrado: {rutaRelativa}"); |
| | | 78 | | |
| | 1 | 79 | | Stream stream = new FileStream(rutaCompleta, FileMode.Open, FileAccess.Read, FileShare.Read); |
| | 1 | 80 | | return Task.FromResult(stream); |
| | | 81 | | } |
| | | 82 | | } |