Files
social-media/backend/src/Socialize.Api/Modules/Assets/Handlers/CreateAssetRevision.cs

108 lines
3.7 KiB
C#

using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using Socialize.Api.Data;
using Socialize.Api.Infrastructure.Security;
using Socialize.Api.Modules.Assets.Data;
using Socialize.Api.Modules.ContentItems.Data;
using Socialize.Api.Modules.Notifications.Contracts;
namespace Socialize.Api.Modules.Assets.Handlers;
public record CreateAssetRevisionRequest(
string SourceReference,
string? PreviewUrl,
string? Notes);
public class CreateAssetRevisionRequestValidator
: Validator<CreateAssetRevisionRequest>
{
public CreateAssetRevisionRequestValidator()
{
RuleFor(x => x.SourceReference).NotEmpty().MaximumLength(2048);
RuleFor(x => x.PreviewUrl).MaximumLength(2048);
RuleFor(x => x.Notes).MaximumLength(1024);
}
}
public class CreateAssetRevisionHandler(
AppDbContext dbContext,
AccessScopeService accessScopeService,
INotificationEventWriter notificationEventWriter)
: Endpoint<CreateAssetRevisionRequest, AssetRevisionDto>
{
public override void Configure()
{
Post("/api/assets/{id}/revisions");
Options(o => o.WithTags("Assets"));
}
public override async Task HandleAsync(CreateAssetRevisionRequest request, CancellationToken ct)
{
Guid id = Route<Guid>("id");
Asset? asset = await dbContext.Assets.SingleOrDefaultAsync(candidate => candidate.Id == id, ct);
if (asset is null)
{
await SendNotFoundAsync(ct);
return;
}
ContentItem? contentItem = await dbContext.ContentItems
.SingleOrDefaultAsync(candidate => candidate.Id == asset.ContentItemId, ct);
if (contentItem is not null &&
!accessScopeService.CanContributeToCampaign(User, contentItem.WorkspaceId, contentItem.ClientId, contentItem.CampaignId))
{
await SendForbiddenAsync(ct);
return;
}
int revisionNumber = asset.CurrentRevisionNumber + 1;
asset.CurrentRevisionNumber = revisionNumber;
asset.PreviewUrl = string.IsNullOrWhiteSpace(request.PreviewUrl) ? asset.PreviewUrl : request.PreviewUrl.Trim();
AssetRevision revision = new()
{
Id = Guid.NewGuid(),
AssetId = asset.Id,
RevisionNumber = revisionNumber,
SourceReference = request.SourceReference.Trim(),
PreviewUrl = string.IsNullOrWhiteSpace(request.PreviewUrl) ? null : request.PreviewUrl.Trim(),
Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(),
CreatedByUserId = User.GetUserId(),
CreatedAt = DateTimeOffset.UtcNow,
};
dbContext.AssetRevisions.Add(revision);
await dbContext.SaveChangesAsync(ct);
if (contentItem is not null)
{
await notificationEventWriter.WriteAsync(
new NotificationEventWriteModel(
asset.WorkspaceId,
asset.ContentItemId,
"asset.revision.created",
"AssetRevision",
revision.Id,
$"A new asset revision was added to {asset.DisplayName}.",
User.GetUserId(),
User.GetEmail(),
$$"""{"revisionNumber":"{{revisionNumber}}"}"""),
ct);
}
AssetRevisionDto dto = new(
revision.Id,
revision.AssetId,
revision.RevisionNumber,
revision.SourceReference,
revision.PreviewUrl,
revision.Notes,
revision.CreatedByUserId,
revision.CreatedAt);
await SendAsync(dto, StatusCodes.Status201Created, ct);
}
}