Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions Dappi.HeadlessCms/Interfaces/IMediaUploadService.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using Dappi.HeadlessCms.Core.Requests;
using Dappi.HeadlessCms.Enums;
using Dappi.HeadlessCms.Models;
using Microsoft.AspNetCore.Http;

namespace Dappi.HeadlessCms.Interfaces
{
public interface IMediaUploadService
{
public void DeleteMedia(MediaInfo media);
Task UpdateStatusAsync(Guid mediaId, MediaUploadStatus status);
Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndExtensionPair);
Task SaveFileAsync(Guid mediaId, IFormFile file);
public void ValidateFile(IFormFile file);
}
}
using Dappi.HeadlessCms.Core.Requests;
using Dappi.HeadlessCms.Enums;
using Dappi.HeadlessCms.Models;
using Microsoft.AspNetCore.Http;

namespace Dappi.HeadlessCms.Interfaces
{
public interface IMediaUploadService
{
public void DeleteMedia(MediaInfo media);
Task UpdateStatusAsync(Guid mediaId, MediaUploadStatus status);
Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndExtensionPair);
Task SaveFileAsync(Guid mediaId, IFormFile file);
}
}
2 changes: 2 additions & 0 deletions Dappi.HeadlessCms/Models/AwsStorageOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ public class AwsStorageOptions
{
public const string AwsStorage = "AWS:Storage";
public string? BucketName { get; set; }
public string? CdnUrl { get; set; }
public List<string>? SupportedExtensions { get; set; }
}
40 changes: 14 additions & 26 deletions Dappi.HeadlessCms/Services/StorageServices/AwsS3StorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,24 @@ IS3ClientFactory factory
) : IMediaUploadService
{
private readonly IAmazonS3 _s3Client = factory.CreateClient();
private readonly AwsStorageOptions _storageOptions = configuration
.GetSection(AwsStorageOptions.AwsStorage)
.Get<AwsStorageOptions>()!;
private readonly AwsAccountOptions _accountOptions = configuration
.GetSection(AwsAccountOptions.AwsAccount)
.Get<AwsAccountOptions>()!;

public void DeleteMedia(MediaInfo media)
{
if (string.IsNullOrEmpty(media.Url))
return;

var bucketName = configuration["AWS:Storage:BucketName"];

var uri = new Uri(media.Url);
var objectKey = Path.GetFileName(uri.LocalPath);

var deleteRequest = new DeleteObjectRequest
{
BucketName = bucketName,
BucketName = _storageOptions.BucketName,
Key = objectKey,
};

Expand All @@ -49,34 +53,29 @@ public async Task SaveFileAsync(Guid mediaId, IFormFile file)

public async Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndExtensionPair)
{
var bucketName = configuration["AWS:Storage:BucketName"];
var cdnUrl = configuration["AWS:Storage:CdnUrl"];
var regionName = configuration["AWS:Account:Region"];

var useCdn =
bool.TryParse(configuration["AWS:Storage:UseCdn"], out var parsed) && parsed;

var extension = streamAndExtensionPair.Extension.StartsWith(".")
? streamAndExtensionPair.Extension
: "." + streamAndExtensionPair.Extension;

var objectKey = $"{mediaId}{extension}";

var region = Amazon.RegionEndpoint.GetBySystemName(regionName ?? "eu-central-1");
var region = Amazon.RegionEndpoint.GetBySystemName(
_accountOptions.Region ?? "eu-central-1"
);

var putRequest = new PutObjectRequest
{
BucketName = bucketName,
BucketName = _storageOptions.BucketName,
Key = objectKey,
InputStream = streamAndExtensionPair.Stream,
AutoCloseStream = true,
ContentType = GetContentType(extension),
};
await _s3Client.PutObjectAsync(putRequest);

var baseUrl = useCdn
? $"{cdnUrl}/{objectKey}"
: $"https://{bucketName}.s3.{region.SystemName}.amazonaws.com/{objectKey}";
var baseUrl = !string.IsNullOrEmpty(_storageOptions.CdnUrl)
? $"{_storageOptions.CdnUrl}/{objectKey}"
: $"https://{_storageOptions.BucketName}.s3.{region.SystemName}.amazonaws.com/{objectKey}";

var media = await dbContext
.DbContext.Set<MediaInfo>()
Expand All @@ -89,17 +88,6 @@ public async Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndEx
}
}

public void ValidateFile(IFormFile file)
{
if (file == null || file.Length == 0)
throw new Exception("No file was uploaded.");

var fileExtension = Path.GetExtension(file.FileName);

if (GetContentType(fileExtension) == "unsupported")
throw new Exception("Unsupported media type.");
}

public async Task UpdateStatusAsync(Guid mediaId, MediaUploadStatus status)
{
var media = await dbContext
Expand Down
224 changes: 109 additions & 115 deletions Dappi.HeadlessCms/Services/StorageServices/LocalStorageUploadService.cs
Original file line number Diff line number Diff line change
@@ -1,115 +1,109 @@
using System.Net.Mime;
using Dappi.HeadlessCms.Core.Requests;
using Dappi.HeadlessCms.Enums;
using Dappi.HeadlessCms.Interfaces;
using Dappi.HeadlessCms.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;

namespace Dappi.HeadlessCms.Services.StorageServices
{
public class LocalStorageUploadService(IDbContextAccessor dbContext) : IMediaUploadService
{
public void DeleteMedia(MediaInfo media)
{
if (media.Url == null) throw new ArgumentNullException(media.Url);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", media.Url);
if (File.Exists(filePath)) File.Delete(filePath);
}

public void ValidateFile(IFormFile file)
{
if (file == null || file.Length == 0)
throw new Exception("No file was uploaded.");

var fileExtension = Path.GetExtension(file.FileName);

if (GetContentType(fileExtension) == "unsupported")
throw new Exception("Unsupported media type.");
}

public async Task SaveFileAsync(Guid mediaId, IFormFile file)
{
var uploadsFolder = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot",
"uploads");

if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder);

var fileExtension = Path.GetExtension(file.FileName);
var fileName = $"{Guid.NewGuid()}_{mediaId}{fileExtension}";
var filePath = Path.Combine(uploadsFolder, fileName);

await using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}

var relativePath = $"uploads{Path.DirectorySeparatorChar}{fileName}";

var media = await dbContext.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId).FirstOrDefaultAsync();

if (media == null) return;

media.Url = relativePath;
await dbContext.DbContext.SaveChangesAsync();
}

public async Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndExtensionPair)
{
var uploadsFolder = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot",
"uploads");

if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder);

var fileName = $"{Guid.NewGuid()}_{mediaId}{streamAndExtensionPair.Extension}";
var filePath = Path.Combine(uploadsFolder, fileName);

await using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await streamAndExtensionPair.Stream.CopyToAsync(fileStream);
}

var relativePath = $"uploads{Path.DirectorySeparatorChar}{fileName}";

var media = await dbContext.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId).FirstOrDefaultAsync();

if (media == null) return;

media.Url = relativePath;
await dbContext.DbContext.SaveChangesAsync();
}

public async Task UpdateStatusAsync(Guid mediaId, MediaUploadStatus status)
{
var media = await dbContext.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId).FirstOrDefaultAsync();

if (media == null) return;

media.Status = status;
await dbContext.DbContext.SaveChangesAsync();
}

private string GetContentType(string fileExtension)
{
return fileExtension.ToLower() switch
{
".pdf" => MediaTypeNames.Application.Pdf,
".jpg" or ".jpeg" => MediaTypeNames.Image.Jpeg,
".png" => MediaTypeNames.Image.Png,
".gif" => MediaTypeNames.Image.Gif,
_ => "unsupported",
};
}

public override string ToString() => "local";
}
}
using System.Net.Mime;
using Dappi.HeadlessCms.Core.Requests;
using Dappi.HeadlessCms.Enums;
using Dappi.HeadlessCms.Interfaces;
using Dappi.HeadlessCms.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;

namespace Dappi.HeadlessCms.Services.StorageServices
{
public class LocalStorageUploadService(IDbContextAccessor dbContext) : IMediaUploadService
{
public void DeleteMedia(MediaInfo media)
{
if (media.Url == null)
throw new ArgumentNullException(media.Url);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", media.Url);
if (File.Exists(filePath))
File.Delete(filePath);
}

public async Task SaveFileAsync(Guid mediaId, IFormFile file)
{
var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");

if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder);

var fileExtension = Path.GetExtension(file.FileName);
var fileName = $"{Guid.NewGuid()}_{mediaId}{fileExtension}";
var filePath = Path.Combine(uploadsFolder, fileName);

await using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}

var relativePath = $"uploads{Path.DirectorySeparatorChar}{fileName}";

var media = await dbContext
.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId)
.FirstOrDefaultAsync();

if (media == null)
return;

media.Url = relativePath;
await dbContext.DbContext.SaveChangesAsync();
}

public async Task SaveFileAsync(Guid mediaId, StreamAndExtensionPair streamAndExtensionPair)
{
var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");

if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder);

var fileName = $"{Guid.NewGuid()}_{mediaId}{streamAndExtensionPair.Extension}";
var filePath = Path.Combine(uploadsFolder, fileName);

await using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await streamAndExtensionPair.Stream.CopyToAsync(fileStream);
}

var relativePath = $"uploads{Path.DirectorySeparatorChar}{fileName}";

var media = await dbContext
.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId)
.FirstOrDefaultAsync();

if (media == null)
return;

media.Url = relativePath;
await dbContext.DbContext.SaveChangesAsync();
}

public async Task UpdateStatusAsync(Guid mediaId, MediaUploadStatus status)
{
var media = await dbContext
.DbContext.Set<MediaInfo>()
.Where(m => m.Id == mediaId)
.FirstOrDefaultAsync();

if (media == null)
return;

media.Status = status;
await dbContext.DbContext.SaveChangesAsync();
}

private string GetContentType(string fileExtension)
{
return fileExtension.ToLower() switch
{
".pdf" => MediaTypeNames.Application.Pdf,
".jpg" or ".jpeg" => MediaTypeNames.Image.Jpeg,
".png" => MediaTypeNames.Image.Png,
".gif" => MediaTypeNames.Image.Gif,
_ => "unsupported",
};
}

public override string ToString() => "local";
}
}
Loading
Loading