From 2692fee6d226887f93ec23787e0878a95c1c5d7c Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 6 May 2025 16:11:02 +0200 Subject: [PATCH] Enhance envelope creation functionality and configuration - Updated DependencyInjection to include new command handler. - Modified CreateEnvelopeReceiverCommand for nullable responses. - Altered SQL command in EnvelopeReceiverAddReadSQL. - Refactored EnvelopeReceiverController with new dependencies and improved CreateAsync method. - Expanded appsettings.json with additional configuration settings. - Introduced new DTOs for signatures and receivers in CreateEnvelopeReceiverDtos. --- .../DependencyInjection.cs | 2 + .../Create/CreateEnvelopeReceiverCommand.cs | 41 +--- .../Create/CreateEnvelopeReceiverDtos.cs | 46 ++++ .../SQL/EnvelopeReceiverAddReadSQL.cs | 3 - .../Controllers/EnvelopeReceiverController.cs | 59 ++++- .../appsettings.json | 205 ++++++++++++++++++ 6 files changed, 306 insertions(+), 50 deletions(-) create mode 100644 EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverDtos.cs diff --git a/EnvelopeGenerator.Application/DependencyInjection.cs b/EnvelopeGenerator.Application/DependencyInjection.cs index 0d96155c..4e3904d1 100644 --- a/EnvelopeGenerator.Application/DependencyInjection.cs +++ b/EnvelopeGenerator.Application/DependencyInjection.cs @@ -7,6 +7,7 @@ using DigitalData.Core.Client; using QRCoder; using EnvelopeGenerator.Application.Contracts.Services; using System.Reflection; +using EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create; namespace EnvelopeGenerator.Application; @@ -58,6 +59,7 @@ public static class DependencyInjection services.AddMediatR(cfg => { cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); + cfg.RegisterServicesFromAssembly(typeof(CreateEnvelopeReceiverCommandHandler).Assembly); }); return services; diff --git a/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverCommand.cs b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverCommand.cs index 04711c4f..fb82abaf 100644 --- a/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverCommand.cs +++ b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverCommand.cs @@ -18,43 +18,4 @@ public record CreateEnvelopeReceiverCommand( [Required] DocumentCreateCommand Document, [Required] IEnumerable Receivers, bool TFAEnabled = false - ) : CreateEnvelopeCommand(Title, Message, TFAEnabled), IRequest; - -#region DTOs -/// -/// Signaturposition auf einem Dokument. -/// -/// X-Position -/// Y-Position -/// Seite, auf der sie sich befindet -public record Signature([Required] int X, [Required] int Y, [Required] int Page); - -/// -/// DTO für Empfänger, die erstellt oder abgerufen werden sollen. -/// Wenn nicht, wird sie erstellt und mit einer Signatur versehen. -/// -/// Unterschriften auf Dokumenten. -/// Der Name, mit dem der Empfänger angesprochen werden soll. Bei Null oder keinem Wert wird der zuletzt verwendete Name verwendet. -/// Sollte mit Vorwahl geschrieben werden -public record ReceiverGetOrCreateCommand([Required] IEnumerable Signatures, string? Salution = null, string? PhoneNumber = null) -{ - private string _emailAddress = string.Empty; - - /// - /// E-Mail-Adresse des Empfängers. - /// - [Required] - public required string EmailAddress { get => _emailAddress.ToLower(); init => _emailAddress = _emailAddress.ToLower(); } -}; - -/// -/// DTO zum Erstellen eines Dokuments. -/// -/// -/// Die Dokumentdaten im Byte-Array-Format. Wird verwendet, wenn das Dokument als Roh-Binärdaten bereitgestellt wird. -/// -/// -/// Die Dokumentdaten im Base64-String-Format. Wird verwendet, wenn das Dokument als Base64-codierter String bereitgestellt wird. -/// -public record DocumentCreateCommand(byte[]? DataAsByte = null, string? DataAsBase64 = null); -#endregion \ No newline at end of file + ) : CreateEnvelopeCommand(Title, Message, TFAEnabled), IRequest; \ No newline at end of file diff --git a/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverDtos.cs b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverDtos.cs new file mode 100644 index 00000000..b1b8908a --- /dev/null +++ b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/Create/CreateEnvelopeReceiverDtos.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create; + +#region DTOs +/// +/// Signaturposition auf einem Dokument. +/// +/// X-Position +/// Y-Position +/// Seite, auf der sie sich befindet +public record Signature([Required] int X, [Required] int Y, [Required] int Page); + +/// +/// DTO für Empfänger, die erstellt oder abgerufen werden sollen. +/// Wenn nicht, wird sie erstellt und mit einer Signatur versehen. +/// +/// Unterschriften auf Dokumenten. +/// Der Name, mit dem der Empfänger angesprochen werden soll. Bei Null oder keinem Wert wird der zuletzt verwendete Name verwendet. +/// Sollte mit Vorwahl geschrieben werden +public record ReceiverGetOrCreateCommand([Required] IEnumerable Signatures, string? Salution = null, string? PhoneNumber = null) +{ + private string? _emailAddress = "h.tek@digitaldata.works"; + + /// + /// E-Mail-Adresse des Empfängers. + /// + public string? EmailAddress { get => _emailAddress?.ToLower(); init => _emailAddress = _emailAddress?.ToLower() ?? "h.tek@digitaldata.works"; } +}; + +/// +/// DTO zum Erstellen eines Dokuments. +/// +/// +/// Die Dokumentdaten im Byte-Array-Format. Wird verwendet, wenn das Dokument als Roh-Binärdaten bereitgestellt wird. +/// +/// +/// Die Dokumentdaten im Base64-String-Format. Wird verwendet, wenn das Dokument als Base64-codierter String bereitgestellt wird. +/// +public record DocumentCreateCommand(byte[]? DataAsByte = null, string? DataAsBase64 = null); +#endregion \ No newline at end of file diff --git a/EnvelopeGenerator.Application/SQL/EnvelopeReceiverAddReadSQL.cs b/EnvelopeGenerator.Application/SQL/EnvelopeReceiverAddReadSQL.cs index 0e3195c8..6ed0d9f3 100644 --- a/EnvelopeGenerator.Application/SQL/EnvelopeReceiverAddReadSQL.cs +++ b/EnvelopeGenerator.Application/SQL/EnvelopeReceiverAddReadSQL.cs @@ -14,12 +14,9 @@ public class EnvelopeReceiverAddReadSQL : ISQL /// public string Raw => @" USE [DD_ECM] - GO DECLARE @OUT_RECEIVER_ID int - DECLARE @ENV_UID varchar(36) = @ENV_UID - EXEC [dbo].[PRSIG_API_CREATE_RECEIVER] @ENV_UID = @ENV_UID, @EMAIL_ADRESS = @EMAIL_ADRESS , diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs index dd8e828a..bc4e77a9 100644 --- a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs @@ -1,11 +1,16 @@ -using DigitalData.Core.DTO; +using AutoMapper; +using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts.Services; +using EnvelopeGenerator.Application.Contracts.SQLExecutor; +using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create; using EnvelopeGenerator.Application.EnvelopeReceivers.Queries.Read; using EnvelopeGenerator.Application.Envelopes.Queries.ReceiverName; +using EnvelopeGenerator.Domain.Entities; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using System.Threading.Channels; namespace EnvelopeGenerator.GeneratorAPI.Controllers; @@ -26,17 +31,29 @@ public class EnvelopeReceiverController : ControllerBase private readonly IMediator _mediator; + private readonly IMapper _mapper; + + private readonly IEnvelopeExecutor _envelopeExecutor; + + private readonly IEnvelopeReceiverExecutor _erExecutor; + /// /// Konstruktor für den EnvelopeReceiverController. /// /// Logger-Instanz zur Protokollierung von Informationen und Fehlern. /// Service zur Verwaltung von Umschlagempfängern. /// Mediator-Instanz zur Verarbeitung von Befehlen und Abfragen. - public EnvelopeReceiverController(ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IMediator mediator) + /// + /// + /// + public EnvelopeReceiverController(ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor) { _logger = logger; _erService = envelopeReceiverService; _mediator = mediator; + _mapper = mapper; + _envelopeExecutor = envelopeExecutor; + _erExecutor = erExecutor; } /// @@ -120,8 +137,7 @@ public class EnvelopeReceiverController : ControllerBase /// /// Datenübertragungsobjekt mit Informationen zu Umschlägen, Empfängern und Unterschriften. /// - /// - /// Token to cancel the operation + /// /// HTTP-Antwort /// /// Sample request: @@ -157,9 +173,38 @@ public class EnvelopeReceiverController : ControllerBase /// Es handelt sich um einen unerwarteten Fehler. Die Protokolle sollten überprüft werden. [Authorize] [HttpPost] - public async Task CreateAsync([FromBody] CreateEnvelopeReceiverCommand createEnvelopeQuery, CancellationToken cancellationToken) + public async Task CreateAsync([FromBody] CreateEnvelopeReceiverCommand request) { - await _mediator.Send(createEnvelopeQuery, cancellationToken); - return Accepted(); + try + { + CancellationToken cancel = default; + int userId = User.GetId(); + + var envelope = await _envelopeExecutor.CreateEnvelopeAsync(userId, request.Title, request.Message, request.TFAEnabled, cancel); + + List sentRecipients = new(); + List unsentRecipients = new(); + + foreach (var receiver in request.Receivers) + { + var envelopeReceiver = await _erExecutor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel); + + if (envelopeReceiver is null) + unsentRecipients.Add(receiver); + else + sentRecipients.Add(envelopeReceiver); + } + + var res = _mapper.Map(envelope); + res.UnsentRecipients = unsentRecipients; + res.SentRecipients = _mapper.Map>(sentRecipients); + + return Ok(res); + } + catch (Exception ex) + { + _logger.LogError(ex, "{Message}", ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/appsettings.json b/EnvelopeGenerator.GeneratorAPI/appsettings.json index c03dbb20..739f29c5 100644 --- a/EnvelopeGenerator.GeneratorAPI/appsettings.json +++ b/EnvelopeGenerator.GeneratorAPI/appsettings.json @@ -36,5 +36,210 @@ "QueryString": "AuthToken", "Issuer": "auth.digitaldata.works", "Audience": "work-flow.digitaldata.works" + }, + "PSPDFKitLicenseKey": "SXCtGGY9XA-31OGUXQK-r7c6AkdLGPm2ljuyDr1qu0kkhLvydg-Do-fxpNUF4Rq3fS_xAnZRNFRHbXpE6sQ2BMcCSVTcXVJO6tPviexjpiT-HnrDEySlUERJnnvh-tmeOWprxS6BySPnSILkmaVQtUfOIUS-cUbvvEYHTvQBKbSF8di4XHQFyfv49ihr51axm3NVV3AXwh2EiKL5C5XdqBZ4sQ4O7vXBjM2zvxdPxlxdcNYmiU83uAzw7B83O_jubPzya4CdUHh_YH7Nlp2gP56MeG1Sw2JhMtfG3Rj14Sg4ctaeL9p6AEWca5dDjJ2li5tFIV2fQSsw6A_cowLu0gtMm5i8IfJXeIcQbMC2-0wGv1oe9hZYJvFMdzhTM_FiejM0agemxt3lJyzuyP8zbBSOgp7Si6A85krLWPZptyZBTG7pp7IHboUHfPMxCXqi-zMsqewOJtQBE2mjntU-lPryKnssOpMPfswwQX7QSkJYV5EMqNmEhQX6mEkp2wcqFzMC7bJQew1aO4pOpvChUaMvb1vgRek0HxLag0nwQYX2YrYGh7F_xXJs-8HNwJe8H0-eW4x4faayCgM5rB5772CCCsD9ThZcvXFrjNHHLGJ8WuBUFm6LArvSfFQdii_7j-_sqHMpeKZt26NFgivj1A==", + "Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value. + "default-src 'self'", + "script-src 'self' 'nonce-{0}' 'unsafe-eval'", + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com:*", + "img-src 'self' data: https: blob:", + "font-src 'self' https://fonts.gstatic.com:*", + "connect-src 'self' https://nominatim.openstreetmap.org:* http://localhost:* https://localhost:* ws://localhost:* wss://localhost:* blob:", + "frame-src 'self'", + "media-src 'self'", + "object-src 'self'" + ], + "NLog": { + "throwConfigExceptions": true, + "variables": { + "logDirectory": "E:\\LogFiles\\Digital Data\\signFlow", + "logFileNamePrefix": "${shortdate}-ECM.EnvelopeGenerator.Web" + }, + "targets": { + "infoLogs": { + "type": "File", + "fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log", + "maxArchiveDays": 30 + }, + "errorLogs": { + "type": "File", + "fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log", + "maxArchiveDays": 30 + }, + "criticalLogs": { + "type": "File", + "fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log", + "maxArchiveDays": 30 + } + }, + // Trace, Debug, Info, Warn, Error and *Fatal* + "rules": [ + { + "logger": "*", + "minLevel": "Info", + "maxLevel": "Warn", + "writeTo": "infoLogs" + }, + { + "logger": "*", + "level": "Error", + "writeTo": "errorLogs" + }, + { + "logger": "*", + "level": "Fatal", + "writeTo": "criticalLogs" + } + ] + }, + "ContactLink": { + "Label": "Kontakt", + "Href": "https://digitaldata.works/", + "HrefLang": "de", + "Target": "_blank", + "Title": "Digital Data GmbH" + }, + /* Resx naming format is -> Resource.language.resx (eg: Resource.de_DE.resx). + To add a new language, first you should write the required resx file. + first is the default culture name. */ + "Cultures": [ + { + "Language": "de-DE", + "FIClass": "fi-de" + }, + { + "Language": "en-US", + "FIClass": "fi-us" + } + ], + "DisableMultiLanguage": false, + "Regexes": [ + { + "Pattern": "/^\\p{L}+(?:([\\ \\-\\']|(\\.\\ ))\\p{L}+)*$/u", + "Name": "City", + "Platforms": [ ".NET" ] + }, + { + "Pattern": "/^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$/", + "Name": "City", + "Platforms": [ "javascript" ] + } + ], + "CustomImages": { + "App": { + "Src": "/img/DD_signFLOW_LOGO.png", + "Classes": { + "Main": "signFlow-logo" + } + }, + "Company": { + "Src": "/img/digital_data.svg", + "Classes": { + "Show": "dd-show-logo", + "Locked": "dd-locked-logo" + } + } + }, + "DispatcherParams": { + "SendingProfile": 1, + "AddedWho": "DDEnvelopGenerator", + "ReminderTypeId": 202377, + "EmailAttmt1": "" + }, + "MailParams": { + "Placeholders": { + "[NAME_PORTAL]": "signFlow", + "[SIGNATURE_TYPE]": "signieren", + "[REASON]": "" + } + }, + "GtxMessagingParams": { + "Uri": "https://rest.gtx-messaging.net", + "Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json", + "Headers": {}, + "QueryParams": { + "from": "signFlow" + } + }, + "TFARegParams": { + "TimeLimit": "00:30:00" + }, + "DbTriggerParams": { + "Envelope": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ], + "EnvelopeHistory": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ], + "EmailOut": [ "TBEMLP_EMAIL_OUT_AFT_INS", "TBEMLP_EMAIL_OUT_AFT_UPD" ], + "EnvelopeReceiverReadOnly": [ "TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD" ], + "Receiver": [] + }, + "MainPageTitle": null, + "AnnotationParams": { + "Background": { + "Margin": 0.20, + "BackgroundColor": { + "R": 222, + "G": 220, + "B": 215 + }, + "BorderColor": { + "R": 204, + "G": 202, + "B": 198 + }, + "BorderStyle": "underline", + "BorderWidth": 4 + }, + "DefaultAnnotation": { + "Width": 1, + "Height": 0.5, + "MarginTop": 1 + }, + "Annotations": [ + { + "Name": "Signature", + "MarginTop": 0 + }, + { + "Name": "PositionLabel", + "VerBoundAnnotName": "Signature", + "WidthRatio": 1.2, + "HeightRatio": 0.5, + "MarginTopRatio": 0.22 + }, + { + "Name": "Position", + "VerBoundAnnotName": "PositionLabel", + "WidthRatio": 1.2, + "HeightRatio": 0.5, + "MarginTopRatio": -0.05 + }, + { + "Name": "CityLabel", + "VerBoundAnnotName": "Position", + "WidthRatio": 1.2, + "HeightRatio": 0.5, + "MarginTopRatio": 0.05 + }, + { + "Name": "City", + "VerBoundAnnotName": "CityLabel", + "WidthRatio": 1.2, + "HeightRatio": 0.5, + "MarginTopRatio": -0.05 + }, + { + "Name": "DateLabel", + "VerBoundAnnotName": "City", + "WidthRatio": 1.55, + "HeightRatio": 0.5, + "MarginTopRatio": 0.05 + }, + { + "Name": "Date", + "VerBoundAnnotName": "DateLabel", + "WidthRatio": 1.55, + "HeightRatio": 0.5, + "MarginTopRatio": -0.1 + } + ] } }