Add PhotoUpload feature for uploading photos to file storage

Adds UploadPhotoCommand/Handler/Validator and PhotoUploadRepository, invoked via MediatR by other features' commands (e.g. a future CreateBreweryPhoto) rather than exposed through its own controller. Wires the feature and IFileStorageProvider into API.Core.
This commit is contained in:
Aaron Po
2026-08-28 00:32:53 -04:00
parent 999c94eedc
commit 05882f36e4
10 changed files with 182 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
using System.Data.Common;
using Dapper;
using Database.Connection;
using Domain.Entities;
using Domain.Exceptions;
namespace Features.ImageUploads.Repository;
public interface IPhotoUploadRepository
{
Task CreateAsync(Photo photo, CancellationToken cancellationToken);
}
public class PhotoUploadRepository(ISqlConnectionFactory connectionFactory)
: DapperRepository(connectionFactory),
IPhotoUploadRepository
{
public async Task CreateAsync(Photo photo, CancellationToken cancellationToken)
{
await using DbConnection connection = await CreateConnection();
await using DbTransaction transaction = await connection.BeginTransactionAsync();
try
{
bool userExists =
await connection.ExecuteScalarAsync<int?>(
new CommandDefinition(
"""
SELECT 1
FROM
dbo.UserAccount
WHERE
UserAccountID = @UploadedById
""",
new { photo.UploadedById },
transaction
)
)
is not null;
if (!userExists)
throw new NotFoundException("User not found.");
await connection.ExecuteAsync(
new CommandDefinition(
"""
INSERT INTO dbo.Photo (Hyperlink, UploadedByID)
VALUES (@Hyperlink, @UploadedById)
""",
new
{
photo.Hyperlink,
photo.UploadedById
},
transaction
)
);
await transaction.CommitAsync(cancellationToken);
}
catch
{
await RollbackQuietlyAsync(transaction);
throw;
}
}
}