using Socialize.Infrastructure.Security; using Socialize.Modules.Notifications.Contracts; namespace Socialize.Modules.Assets.Handlers; public record CreateGoogleDriveAssetRequest( Guid WorkspaceId, Guid ContentItemId, string AssetType, string DisplayName, string GoogleDriveFileId, string GoogleDriveLink, string? PreviewUrl); public class CreateGoogleDriveAssetRequestValidator : Validator { public CreateGoogleDriveAssetRequestValidator() { RuleFor(x => x.WorkspaceId).NotEmpty(); RuleFor(x => x.ContentItemId).NotEmpty(); RuleFor(x => x.AssetType).NotEmpty().MaximumLength(64); RuleFor(x => x.DisplayName).NotEmpty().MaximumLength(256); RuleFor(x => x.GoogleDriveFileId).NotEmpty().MaximumLength(256); RuleFor(x => x.GoogleDriveLink).NotEmpty().MaximumLength(2048); RuleFor(x => x.PreviewUrl).MaximumLength(2048); } } public class CreateGoogleDriveAssetHandler( AppDbContext dbContext, AccessScopeService accessScopeService, INotificationEventWriter notificationEventWriter) : Endpoint { public override void Configure() { Post("/api/assets/google-drive"); Options(o => o.WithTags("Assets")); } public override async Task HandleAsync(CreateGoogleDriveAssetRequest request, CancellationToken ct) { ContentItem? contentItem = await dbContext.ContentItems .SingleOrDefaultAsync( candidate => candidate.Id == request.ContentItemId && candidate.WorkspaceId == request.WorkspaceId, ct); if (contentItem is null) { AddError(request => request.ContentItemId, "The selected content item does not exist in the active workspace."); await SendErrorsAsync(StatusCodes.Status400BadRequest, ct); return; } if (!accessScopeService.CanContributeToProject(User, contentItem.WorkspaceId, contentItem.ClientId, contentItem.ProjectId)) { await SendForbiddenAsync(ct); return; } Asset asset = new() { Id = Guid.NewGuid(), WorkspaceId = request.WorkspaceId, ContentItemId = request.ContentItemId, AssetType = request.AssetType.Trim(), SourceType = "GoogleDrive", DisplayName = request.DisplayName.Trim(), GoogleDriveFileId = request.GoogleDriveFileId.Trim(), GoogleDriveLink = request.GoogleDriveLink.Trim(), PreviewUrl = string.IsNullOrWhiteSpace(request.PreviewUrl) ? null : request.PreviewUrl.Trim(), CurrentRevisionNumber = 1, CreatedAt = DateTimeOffset.UtcNow, }; AssetRevision revision = new() { Id = Guid.NewGuid(), AssetId = asset.Id, RevisionNumber = 1, SourceReference = asset.GoogleDriveLink, PreviewUrl = asset.PreviewUrl, CreatedAt = DateTimeOffset.UtcNow, }; dbContext.Assets.Add(asset); dbContext.AssetRevisions.Add(revision); await dbContext.SaveChangesAsync(ct); await notificationEventWriter.WriteAsync( new NotificationEventWriteModel( asset.WorkspaceId, asset.ContentItemId, "asset.google-drive-linked", "Asset", asset.Id, $"Google Drive asset {asset.DisplayName} was linked to {contentItem.Title}.", null, null, $$"""{"googleDriveFileId":"{{asset.GoogleDriveFileId}}"}"""), ct); AssetDto dto = new( asset.Id, asset.WorkspaceId, asset.ContentItemId, asset.AssetType, asset.SourceType, asset.DisplayName, asset.GoogleDriveFileId, asset.GoogleDriveLink, asset.PreviewUrl, asset.CurrentRevisionNumber, asset.CreatedAt, [ new AssetRevisionDto( revision.Id, revision.AssetId, revision.RevisionNumber, revision.SourceReference, revision.PreviewUrl, revision.Notes, revision.CreatedByUserId, revision.CreatedAt) ]); await SendAsync(dto, StatusCodes.Status201Created, ct); } }