Files
EnvelopeGenerator/EnvelopeGenerator.Application/PdfSigning/SignPdfByElementCommand.cs
TekH 67d0b07926 Add support for signing PDFs with DocReceiverElement
Extended `DocReceiverElementDto` to include an optional `Document` reference. Enhanced `ReadDocReceiverElementQuery` with `Id` and `IncludeDocument` properties for filtering and document inclusion.

Updated `ReadDocReceiverElementQueryHandler` to handle new query properties, enabling filtering by `Id` and optionally including associated documents.

Introduced `SignPdfByElementCommand` and its handler to support signing PDFs using either a provided `DocReceiverElementDto` or an `ElementId`. Added validation via `SignPdfByElementCommandValidator` to ensure proper usage.

Refactored and added necessary `using` directives for new dependencies.
2026-10-20 10:55:41 +02:00

85 lines
2.7 KiB
C#

using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Interfaces.Doc;
using EnvelopeGenerator.Application.Common.Interfaces.Services;
using EnvelopeGenerator.Application.DocReceiverElements.Queries;
using MediatR;
namespace EnvelopeGenerator.Application.PdfSigning;
/// <summary>
///
/// </summary>
public record SignPdfByElementCommand : IRequest<Stream>
{
/// <summary>
///
/// </summary>
public DocReceiverElementDto? Element { get; set; }
/// <summary>
///
/// </summary>
public int? ElementId { get; init; }
}
/// <summary>
///
/// </summary>
/// <param name="signService"></param>
public class SignPdfCommandHandler(ISender sender, IPdfDigitalSignatureService signService, IPdfPageImageRenderer imgRenderer) : IRequestHandler<SignPdfByElementCommand, Stream>
{
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<Stream> Handle(SignPdfByElementCommand request, CancellationToken cancellationToken)
{
// ensure element
if(request.Element is null)
{
var elements = await sender.Send(new ReadDocReceiverElementQuery()
{
Id = request.ElementId!,
IncludeDocument= true
}, cancellationToken);
if (!elements.Any())
throw new NotFoundException($"Element with ID {request.ElementId} not found.");
request.Element = elements.FirstOrDefault();
}
// ensure document
var doc = request.Element!.Document;
if(doc is null || doc.ByteData is null || doc.ByteData.Length == 0)
throw new NotFoundException("Document data is missing or empty.");
// create signature image from element
var img = imgRenderer.ComposeSignaturePreviewPng(request.Element);
// sign pdf
var inputPdf = new MemoryStream(doc.ByteData);
var outputPdf = new MemoryStream();
await signService.SignPdfAsync(
inputPdf: inputPdf,
outputPdf: outputPdf,
options: new PdfSignOptionsDto
{
Appearance = new PdfSignatureAppearanceDto(
PageNumber: request.Element.Page,
Left: request.Element.Left,
Bottom: request.Element.Y,
Width: request.Element.Width,
Height: request.Element.Height)
},
image: img,
cancellationToken: cancellationToken);
return outputPdf;
}
}