using MediatR; using Mws.Application.Common; using Mws.Application.Permissions; using Mws.Domain.Documents; namespace Mws.Application.Documents; public record MoveDocumentCommand(Guid UserId, Guid DocumentId, Guid? NewParentId) : IRequest; public class MoveDocumentHandler(IUnitOfWork uow) : IRequestHandler { public async Task Handle(MoveDocumentCommand command, CancellationToken ct) { var doc = await DocumentAccess.GetDocumentForUserAsync(uow, command.UserId, command.DocumentId, ct); await DocumentAccess.EnsureDocumentPermissionAsync(uow, command.UserId, doc.ProjectId, PermissionAction.Edit, ct); if (command.NewParentId == command.DocumentId) { throw new BadRequestException("A document cannot be moved into itself"); } if (command.NewParentId is { } parentId) { var parent = await uow.Documents.GetByIdAsync(parentId, ct) ?? throw new NotFoundException("Parent folder not found"); if (parent.ProjectId != doc.ProjectId) { throw new BadRequestException("Parent must belong to the same project"); } if (parent.Type != DocumentType.Folder) { throw new BadRequestException("Parent must be a folder"); } var cursor = parent.ParentId; while (cursor is not null) { if (cursor == command.DocumentId) { throw new BadRequestException("A folder cannot be moved into its own descendant"); } cursor = await uow.Documents.GetParentIdAsync(cursor.Value, ct); } } doc.ParentId = command.NewParentId; doc.UpdatedAt = DateTime.UtcNow; doc.UpdatedBy = command.UserId; await uow.SaveChangesAsync(ct); } }