using DocumentOperator.Application.Common.Interfaces;
using FluentValidation;
using MediatR;
namespace DocumentOperator.Application.AddAttachments;
///
/// Command to add one or more attachments to a PDF document (supports PDF/A-3)
///
public record AddAttachmentsCommand : IRequest
{
///
/// PDF document stream. Must be positioned at the beginning (Position = 0).
///
public required Stream PdfStream { get; init; }
///
/// List of attachments to embed (filename, content, optional MIME type)
///
public required IReadOnlyList Attachments { get; init; }
}
///
/// Represents a file to be attached to a PDF
///
public record AttachmentFile
{
///
/// File name (e.g., "invoice.xml", "document.pdf")
///
public required string FileName { get; init; }
///
/// File content as byte array
///
public required byte[] Content { get; init; }
///
/// MIME type (optional, e.g., "application/xml", "application/pdf")
/// If not provided, will be inferred from file extension
///
public string? MimeType { get; init; }
}
///
/// Handler for AddAttachmentsCommand
///
public class AddAttachmentsCommandHandler(IPdfProcessor pdfProcessor)
: IRequestHandler
{
public async Task Handle(AddAttachmentsCommand request, CancellationToken cancellationToken)
{
// Convert to tuple list for IPdfProcessor
var attachmentTuples = request.Attachments
.Select(a => (a.FileName, a.Content, a.MimeType))
.ToList();
return await pdfProcessor.AddAttachmentsAsync(request.PdfStream, attachmentTuples);
}
}
///
/// Validator for AddAttachmentsCommand
///
public class AddAttachmentsCommandValidator : AbstractValidator
{
public AddAttachmentsCommandValidator()
{
RuleFor(x => x.PdfStream)
.NotNull()
.WithMessage("PDF stream is required");
RuleFor(x => x.Attachments)
.NotNull()
.NotEmpty()
.WithMessage("At least one attachment is required");
RuleForEach(x => x.Attachments).ChildRules(attachment =>
{
attachment.RuleFor(a => a.FileName)
.NotEmpty()
.WithMessage("Attachment file name is required");
attachment.RuleFor(a => a.Content)
.NotNull()
.NotEmpty()
.WithMessage("Attachment content is required");
});
}
}