chore: correct namespaces and hiearchy
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
namespace TrackQrApi.Features.Assets.Services;
|
||||
|
||||
public interface IAssetStorageService
|
||||
{
|
||||
Task<string> StoreAsync(Stream stream, string filename, string contentType);
|
||||
Task<(Stream Stream, string ContentType)?> GetAsync(string storageKey);
|
||||
Task DeleteAsync(string storageKey);
|
||||
string GetPublicUrl(string storageKey, HttpContext context);
|
||||
}
|
||||
|
||||
public class LocalAssetStorageService : IAssetStorageService
|
||||
{
|
||||
private readonly string _basePath;
|
||||
private readonly ILogger<LocalAssetStorageService> _logger;
|
||||
|
||||
public LocalAssetStorageService(IConfiguration configuration, ILogger<LocalAssetStorageService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_basePath = configuration["Storage:LocalPath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "uploads");
|
||||
|
||||
// Ensure directory exists
|
||||
if (!Directory.Exists(_basePath)) Directory.CreateDirectory(_basePath);
|
||||
}
|
||||
|
||||
public async Task<string> StoreAsync(Stream stream, string filename, string contentType)
|
||||
{
|
||||
// Generate unique storage key
|
||||
var extension = Path.GetExtension(filename);
|
||||
var storageKey = $"{Guid.NewGuid()}{extension}";
|
||||
var filePath = Path.Combine(_basePath, storageKey);
|
||||
|
||||
await using var fileStream = new FileStream(filePath, FileMode.Create);
|
||||
await stream.CopyToAsync(fileStream);
|
||||
|
||||
_logger.LogDebug("Stored asset at {FilePath}", filePath);
|
||||
|
||||
return storageKey;
|
||||
}
|
||||
|
||||
public Task<(Stream Stream, string ContentType)?> GetAsync(string storageKey)
|
||||
{
|
||||
var filePath = Path.Combine(_basePath, storageKey);
|
||||
|
||||
if (!File.Exists(filePath)) return Task.FromResult<(Stream, string)?>(null);
|
||||
|
||||
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
var contentType = GetContentType(storageKey);
|
||||
|
||||
return Task.FromResult<(Stream, string)?>((stream, contentType));
|
||||
}
|
||||
|
||||
public Task DeleteAsync(string storageKey)
|
||||
{
|
||||
var filePath = Path.Combine(_basePath, storageKey);
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
_logger.LogDebug("Deleted asset at {FilePath}", filePath);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string GetPublicUrl(string storageKey, HttpContext context)
|
||||
{
|
||||
var baseUrl = $"{context.Request.Scheme}://{context.Request.Host}";
|
||||
return $"{baseUrl}/assets/{storageKey}";
|
||||
}
|
||||
|
||||
private static string GetContentType(string filename)
|
||||
{
|
||||
var extension = Path.GetExtension(filename).ToLowerInvariant();
|
||||
return extension switch
|
||||
{
|
||||
".png" => "image/png",
|
||||
".jpg" or ".jpeg" => "image/jpeg",
|
||||
".gif" => "image/gif",
|
||||
".webp" => "image/webp",
|
||||
".svg" => "image/svg+xml",
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user