Introduced `ESignParams` for configurable e-signature settings, including `ApplicationName` and `DefaultReason`. Updated `DocReceiverElementDto` and `PdfSignOptionsDto` to support new properties. Registered `ESignParams` in DI container. Refactored `SignPdfByElementCommand` to include new fields and improved error handling. Added `SignPdfByEnvelopeReceiverCommand` to enable signing documents for envelope receivers. Replaced DevExpress with PdfSharp for PDF rendering in `ReceiverSignedPage.razor`, improving layout and flexibility. Enhanced `PdfSignatureController` with a new endpoint for signing documents by envelope key. Added `DataIntegrityException` for better error handling. Updated `appsettings.json` with `ESignParams` configuration.
175 lines
4.8 KiB
C#
175 lines
4.8 KiB
C#
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
|
using EnvelopeGenerator.Domain.Constants;
|
|
using EnvelopeGenerator.Domain.Interfaces;
|
|
|
|
namespace EnvelopeGenerator.Application.Common.Dto;
|
|
|
|
// TODO: Add the “Reason” property and integrate with UI and the digital signature process.
|
|
/// <summary>
|
|
/// Data Transfer Object representing a positioned element assigned to a document receiver.
|
|
/// </summary>
|
|
public class DocReceiverElementDto : IDocReceiverElement, ISignatureInkPayload
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the unique identifier of the element.
|
|
/// </summary>
|
|
public int Id { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the identifier of the associated document.
|
|
/// </summary>
|
|
public int DocumentId { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public virtual DocumentDto? Document { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the identifier of the receiver.
|
|
/// </summary>
|
|
public int ReceiverId { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public virtual ReceiverDto? Receiver { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the type of the element.
|
|
/// </summary>
|
|
public int ElementType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the X coordinate of the element.
|
|
/// </summary>
|
|
public double X { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Y coordinate of the element.
|
|
/// </summary>
|
|
public double Y { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the width of the element.
|
|
/// </summary>
|
|
public double Width { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the height of the element.
|
|
/// </summary>
|
|
public double Height { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page number where the element appears.
|
|
/// </summary>
|
|
public int Page { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the element is required.
|
|
/// </summary>
|
|
public bool Required { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the tooltip text for the element.
|
|
/// </summary>
|
|
public string? Tooltip { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the element is read-only.
|
|
/// </summary>
|
|
public bool ReadOnly { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the annotation index for ordering or reference.
|
|
/// </summary>
|
|
public int AnnotationIndex { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the timestamp when the element was added.
|
|
/// </summary>
|
|
public DateTime AddedWhen { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the timestamp when the element was last changed, if applicable.
|
|
/// </summary>
|
|
public DateTime? ChangedWhen { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the top position of the element (in layout terms).
|
|
/// </summary>
|
|
public double Top => Y;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the left position of the element (in layout terms).
|
|
/// </summary>
|
|
public double Left => X;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public IEnumerable<AnnotationDto>? Annotations { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public SenderAppType SenderAppType { get; set; } = SenderAppType.LegacyFormApp;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string? FullName { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string? Position { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string? Place { get; set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public byte[]? Ink { get; set; }
|
|
|
|
/// <summary>
|
|
/// Returns the stored signature bytes as an image payload with detected MIME type.
|
|
/// </summary>
|
|
/// <exception cref="InvalidOperationException">Thrown when signature image bytes do not exist.</exception>
|
|
public (byte[] Bytes, string ContentType, string FileExtension) ToImage()
|
|
{
|
|
if (Ink is not { Length: > 0 })
|
|
throw new InvalidOperationException("Signature image (Ink) does not exist.");
|
|
|
|
if (HasPrefix(Ink, 0x89, 0x50, 0x4E, 0x47))
|
|
return (Ink, "image/png", ".png");
|
|
|
|
if (HasPrefix(Ink, 0xFF, 0xD8, 0xFF))
|
|
return (Ink, "image/jpeg", ".jpg");
|
|
|
|
if (HasPrefix(Ink, 0x52, 0x49, 0x46, 0x46) &&
|
|
Ink.Length >= 12 &&
|
|
Ink[8] == 0x57 && Ink[9] == 0x45 && Ink[10] == 0x42 && Ink[11] == 0x50)
|
|
return (Ink, "image/webp", ".webp");
|
|
|
|
return (Ink, "application/octet-stream", ".bin");
|
|
}
|
|
|
|
private static bool HasPrefix(byte[] data, params byte[] prefix)
|
|
{
|
|
if (data.Length < prefix.Length)
|
|
return false;
|
|
|
|
for (var i = 0; i < prefix.Length; i++)
|
|
{
|
|
if (data[i] != prefix[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|