using Microsoft.AspNetCore.Hosting; using NexusReader.Application.Abstractions.Services; namespace NexusReader.Infrastructure.Services; /// /// Infrastructure implementation of general storage utilizing local filesystem. /// Files are saved in wwwroot/uploads/media. /// public class LocalStorageService : IStorageService { private readonly IWebHostEnvironment _environment; public LocalStorageService(IWebHostEnvironment environment) { _environment = environment; } public async Task UploadFileAsync(byte[] fileBytes, string fileName, string contentType) { using var stream = new MemoryStream(fileBytes); return await UploadFileAsync(stream, fileName, contentType); } public async Task UploadFileAsync(Stream fileStream, string fileName, string contentType) { var mediaFolder = Path.Combine(_environment.WebRootPath, "uploads", "media"); if (!Directory.Exists(mediaFolder)) { Directory.CreateDirectory(mediaFolder); } // Clean file name to prevent path traversal issues var safeFileName = Path.GetFileName(fileName); var uniqueFileName = $"{Guid.NewGuid()}_{safeFileName}"; var filePath = Path.Combine(mediaFolder, uniqueFileName); using (var outputStream = new FileStream(filePath, FileMode.Create)) { await fileStream.CopyToAsync(outputStream); } // Return the public web-relative URL return $"/uploads/media/{uniqueFileName}"; } }