using Socialize.Infrastructure.Security; using Socialize.Modules.Notifications.Contracts; namespace Socialize.Modules.Assets.Handlers; public record CreateAssetRevisionRequest( string SourceReference, string? PreviewUrl, string? Notes); public class CreateAssetRevisionRequestValidator : Validator { 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 { 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("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.CanContributeToProject(User, contentItem.WorkspaceId, contentItem.ClientId, contentItem.ProjectId)) { 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); } }