Add support for visual PDF signatures
Enhanced `PdfSignOptionsDto` with a `VisualSignature` property and introduced the `PdfVisualSignatureOptionsDto` class for configuring visual signature options. Updated `PdfDigitalSignatureService` to handle visual signatures, including page number resolution, signature bounds calculation, and appearance customization. Refactored `PdfSignatureController` to support visual signatures by extending `SignPdfForm` with `SignatureImageFile` and `VSignature` properties. Improved validation for page numbers and signature dimensions. Streamlined `Sign` and `IsSigned` endpoints for better clarity and reduced redundancy. Added XML documentation for improved API clarity and performed general code cleanup to enhance maintainability.
This commit is contained in:
@@ -6,38 +6,102 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Server.Controllers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="signatureService"></param>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class PdfSignatureController(IPdfDigitalSignatureService signatureService) : ControllerBase
|
||||
{
|
||||
public sealed class SignPdfForm
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class CheckPdfSignatureForm
|
||||
{
|
||||
public IFormFile? File { get; set; }
|
||||
public string? UUID { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Reason { get; set; }
|
||||
public string? Location { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public virtual required IFormFile File { get; init; }
|
||||
}
|
||||
|
||||
public sealed class CheckPdfSignatureForm
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class SignPdfForm : CheckPdfSignatureForm
|
||||
{
|
||||
public IFormFile? File { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required IFormFile SignatureImageFile { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? UUID { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? Reason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? Location { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? Email { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string? Phone { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required VSignature Signature { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="PageNumber"></param>
|
||||
/// <param name="Left"></param>
|
||||
/// <param name="Bottom"></param>
|
||||
/// <param name="Width"></param>
|
||||
/// <param name="Height"></param>
|
||||
/// <param name="ShowLabels"></param>
|
||||
public record VSignature(
|
||||
int PageNumber = 1,
|
||||
double Left = 100,
|
||||
double Bottom = 100,
|
||||
double Width = 220,
|
||||
double Height = 80,
|
||||
bool ShowLabels = true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("sign")]
|
||||
[Consumes("multipart/form-data")]
|
||||
public async Task<IActionResult> Sign([FromForm] SignPdfForm request, CancellationToken cancel)
|
||||
{
|
||||
var file = request.File;
|
||||
|
||||
if (file is null || file.Length == 0)
|
||||
return BadRequest("PDF file is required.");
|
||||
|
||||
if (!file.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
return BadRequest("Only PDF files are supported.");
|
||||
await using var signatureImageInput = request.SignatureImageFile.OpenReadStream();
|
||||
using var signatureImageBuffer = new MemoryStream();
|
||||
await signatureImageInput.CopyToAsync(signatureImageBuffer, cancel);
|
||||
|
||||
var signOptions = new PdfSignOptionsDto
|
||||
{
|
||||
@@ -47,31 +111,37 @@ public class PdfSignatureController(IPdfDigitalSignatureService signatureService
|
||||
Location = request.Location,
|
||||
Email = request.Email,
|
||||
Phone = request.Phone,
|
||||
CertificationLevel = PdfSignatureCertificationLevel.FormFillingAndAnnotations
|
||||
CertificationLevel = PdfSignatureCertificationLevel.FormFillingAndAnnotations,
|
||||
VisualSignature = new PdfVisualSignatureOptionsDto(
|
||||
ImageBytes: signatureImageBuffer.ToArray(),
|
||||
PageNumber: request.Signature.PageNumber,
|
||||
Left: request.Signature.Left,
|
||||
Bottom: request.Signature.Bottom,
|
||||
Width: request.Signature.Width,
|
||||
Height: request.Signature.Height,
|
||||
ShowLabels: request.Signature.ShowLabels)
|
||||
};
|
||||
|
||||
await using var input = file.OpenReadStream();
|
||||
await using var output = new MemoryStream();
|
||||
await using var input = request.File.OpenReadStream();
|
||||
var output = new MemoryStream();
|
||||
await signatureService.SignPdfAsync(input, output, signOptions, cancel);
|
||||
output.Position = 0;
|
||||
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
|
||||
var fileName = Path.GetFileNameWithoutExtension(request.File.FileName);
|
||||
return File(output, "application/pdf", $"{fileName}-signed.pdf");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("is-signed")]
|
||||
[Consumes("multipart/form-data")]
|
||||
public async Task<IActionResult> IsSigned([FromForm] CheckPdfSignatureForm request, CancellationToken cancel)
|
||||
{
|
||||
var file = request.File;
|
||||
|
||||
if (file is null || file.Length == 0)
|
||||
return BadRequest("PDF file is required.");
|
||||
|
||||
if (!file.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
return BadRequest("Only PDF files are supported.");
|
||||
|
||||
await using var input = file.OpenReadStream();
|
||||
await using var input = request.File.OpenReadStream();
|
||||
var result = await signatureService.CheckPdfSignatureAsync(input, cancel);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user