From 0b9abc8fc1cfa7cae5b334fb161b6083af086cdb Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 13 May 2026 22:40:43 +0200 Subject: [PATCH] Add client-side DTOs for envelopes and authentication Introduced EnvelopeDtos.cs and ReceiverAuthDtos.cs under EnvelopeGenerator.ReceiverUI.Web.Client.Api.Models. These files define client-side DTOs that mirror server-side models, exposing only the fields required by the receiver UI. EnvelopeDtos.cs covers envelopes, documents, receivers, and signature elements, while ReceiverAuthDtos.cs handles authentication responses and requests. All DTOs are documented and structured for camelCase JSON serialization, improving maintainability and clarity for API interactions in the receiver UI. --- .../Api/Models/EnvelopeDtos.cs | 126 ++++++++++++++++++ .../Api/Models/ReceiverAuthDtos.cs | 53 ++++++++ 2 files changed, 179 insertions(+) create mode 100644 receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/EnvelopeDtos.cs create mode 100644 receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/ReceiverAuthDtos.cs diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/EnvelopeDtos.cs b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/EnvelopeDtos.cs new file mode 100644 index 00000000..23d64f06 --- /dev/null +++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/EnvelopeDtos.cs @@ -0,0 +1,126 @@ +namespace EnvelopeGenerator.ReceiverUI.Web.Client.Api.Models; + +/// +/// Client-side DTOs for envelope display. These mirror the server-side +/// EnvelopeReceiverDto / EnvelopeDto / DocumentDto used by the existing +/// API endpoints, but expose only the fields the receiver UI actually needs. +/// JSON serialization is camelCase by default (System.Text.Json). +/// +public class EnvelopeReceiverDto +{ + public long EnvelopeId { get; set; } + public long ReceiverId { get; set; } + public string? Name { get; set; } + public bool HasPhoneNumber { get; set; } + public EnvelopeDto? Envelope { get; set; } + public ReceiverDto? Receiver { get; set; } +} + +public class EnvelopeDto +{ + public long Id { get; set; } + public string? Uuid { get; set; } + public string? Title { get; set; } + public string? Message { get; set; } + public bool ReadOnly { get; set; } + public bool UseAccessCode { get; set; } + public bool TFAEnabled { get; set; } + public DateTime AddedWhen { get; set; } + public SenderUserDto? User { get; set; } + public List? Documents { get; set; } +} + +public class SenderUserDto +{ + public string? Email { get; set; } + public string? Prename { get; set; } + public string? Name { get; set; } +} + +public class ReceiverDto +{ + public long Id { get; set; } + public string? EmailAddress { get; set; } + public string? Signature { get; set; } + public string? Prename { get; set; } + public string? Name { get; set; } +} + +public class DocumentDto +{ + public long Id { get; set; } + public string? Name { get; set; } + public List? Elements { get; set; } +} + +/// +/// Signature placement on a PDF document. Pixel/inch units follow the same +/// convention as the legacy PSPDFKit pipeline. +/// +public class DocumentElementDto +{ + public int Id { get; set; } + public int Page { get; set; } + public double Left { get; set; } + public double Top { get; set; } +} + +/// +/// Body for POST /api/readonly (share read-only link with another e-mail). +/// +public class ReadOnlyShareRequest +{ + public string ReceiverMail { get; set; } = string.Empty; + public DateTime DateValid { get; set; } +} + +/// +/// Returned by GET /api/annotation/elements. Each item describes a +/// signature placeholder the authenticated receiver must sign on the +/// current envelope. Coordinates are in PDF points relative to the page. +/// +public class SignatureElementDto +{ + public int Id { get; set; } + public int Page { get; set; } + public double X { get; set; } + public double Y { get; set; } + public double Width { get; set; } + public double Height { get; set; } + public bool Required { get; set; } + public string? Tooltip { get; set; } +} + +/// +/// Body of POST /api/annotation/blazor — mirrors the API-side +/// BlazorSignaturePayload. +/// +public class BlazorSignaturePayload +{ + public List Signatures { get; set; } = new(); +} + +public class BlazorSignatureEntry +{ + public int ElementId { get; set; } + /// Image as data URL (e.g. data:image/png;base64,...). + public string SignatureDataUrl { get; set; } = string.Empty; + public string? Position { get; set; } + public string? City { get; set; } + public DateTime SignedAt { get; set; } +} + +/// +/// Response of GET /api/tfa/{envelopeReceiverId}. The API serializes +/// the anonymous type in TfaRegistrationController.RegisterAsync; the +/// shape mirrored here is the camelCased JSON that crosses the wire. +/// +public class TfaRegistrationResponse +{ + public int EnvelopeId { get; set; } + public string? Uuid { get; set; } + public string? Signature { get; set; } + public DateTime? TfaRegDeadline { get; set; } + /// Base64-encoded PNG suitable for data:image/png;base64,.... + public string? TotpQR64 { get; set; } +} diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/ReceiverAuthDtos.cs b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/ReceiverAuthDtos.cs new file mode 100644 index 00000000..7bb2ae93 --- /dev/null +++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Api/Models/ReceiverAuthDtos.cs @@ -0,0 +1,53 @@ +namespace EnvelopeGenerator.ReceiverUI.Web.Client.Api.Models; + +/// +/// Mirrors EnvelopeGenerator.API.Models.ReceiverAuthResponse. +/// The Status string determines which fields are relevant. +/// Possible values: +/// requires_access_code, requires_tfa, show_document, +/// already_signed, rejected, not_found, expired, error. +/// +public class ReceiverAuthResponse +{ + public string Status { get; set; } = string.Empty; + public string? Title { get; set; } + public string? Message { get; set; } + public string? SenderEmail { get; set; } + public string? ReceiverName { get; set; } + public bool TfaEnabled { get; set; } + public bool HasPhoneNumber { get; set; } + public bool ReadOnly { get; set; } + + /// "sms" or "authenticator" when Status == "requires_tfa". + public string? TfaType { get; set; } + public DateTime? TfaExpiration { get; set; } + public string? ErrorMessage { get; set; } +} + +public class AccessCodeRequest +{ + public string AccessCode { get; set; } = string.Empty; + public bool PreferSms { get; set; } +} + +public class TfaCodeRequest +{ + public string Code { get; set; } = string.Empty; + /// "sms" or "authenticator". + public string Type { get; set; } = "authenticator"; +} + +/// +/// Status strings returned by . +/// +public static class ReceiverAuthStatus +{ + public const string RequiresAccessCode = "requires_access_code"; + public const string RequiresTfa = "requires_tfa"; + public const string ShowDocument = "show_document"; + public const string AlreadySigned = "already_signed"; + public const string Rejected = "rejected"; + public const string NotFound = "not_found"; + public const string Expired = "expired"; + public const string Error = "error"; +}