Compare commits

...

91 Commits

Author SHA1 Message Date
8db72037e0 refactor(form): vbproj aktualisieren, um mit .net 8 zu konfigurieren.
- Verwandte Referenzen für net 9 hinzufügen.
 - Backup-XML-Datei für altes vbproj erstellen.
2025-09-10 13:27:48 +02:00
6b89b9bbf2 refactor(ModifyDocStatusCommandBase): add EnvelopeId and ReceiverId properties 2025-09-09 23:15:19 +02:00
83ff3da795 fix(ReceiverAlreadySignedQuery) 2025-09-09 21:57:59 +02:00
5bb3341f43 refactor(JsonSerializerSettings): set Ignore ReferenceLoopHandling 2025-09-09 20:39:21 +02:00
7568274c77 refactor(ReceiverSecretDto): remove 2025-09-09 20:32:35 +02:00
c59b179a8f merge with EnvelopeReceiverBasicDto 2025-09-09 20:05:34 +02:00
248c5bce5a refactor(Common.Model): rename as Common.Query 2025-09-09 19:39:50 +02:00
c76a772768 fix references 2025-09-09 19:23:04 +02:00
3ba7bfd15a refactor(EnvelopeHistoryDto): rename HostoryDto 2025-09-09 19:01:20 +02:00
e8f2c868b1 refactor(EnvelopeHistory): rename as History 2025-09-09 18:58:58 +02:00
ae669d05e7 refactor(EnvelopeDocument): rename as Document 2025-09-09 18:56:55 +02:00
fbbc05814f refactor(DocumentReceiverElementDto): rename as SignatureDto 2025-09-09 18:56:18 +02:00
ec57906290 refactor(EnvelopeDocumentDto): rename as DocumentDto 2025-09-09 18:52:58 +02:00
fbfc20705d refactor(Extensions): move to common 2025-09-09 18:26:06 +02:00
895eb8977e refactor(Notifications): move to Common 2025-09-09 18:24:42 +02:00
428f45bff1 refactor(Model): move to Common 2025-09-09 18:22:31 +02:00
9339f24bf1 refacor(EnvelopeFlag): move to Common 2025-09-09 18:21:24 +02:00
390cbf9db5 refactor(Dto): move to common 2025-09-09 18:18:47 +02:00
570a192438 refactor(Configurations): move to common 2025-09-09 18:17:39 +02:00
c8a0264ed8 refactor(SQL): move to common 2025-09-09 18:17:00 +02:00
207bc8bcbd convert csrfToken to get method 2025-09-09 18:11:14 +02:00
1ac2a476d2 refactor(DocumentReceiverElementDto): remove Top and Left-properties 2025-09-09 16:55:34 +02:00
Developer 02
41f5d9f1e4 refactor: make CreateShowEnvelopeView and SignInEnvelopeAsync generic method 2025-09-09 14:08:20 +02:00
2ae6dda27e refactor(EnvelopeMailService): remove SendTFAQrCodeAsync method 2025-09-08 17:41:34 +02:00
e5a25c5893 refactor(EnvelopeReceiverDto): add option to make Receiver property generic 2025-09-08 17:32:00 +02:00
7d0648ede4 Um den Receiver in ReceiverSecretDto umwandeln zu können, fügen Sie ein Mapping-Profil hinzu. 2025-09-08 17:25:40 +02:00
bb6ca82289 feat(ReceiverSecretDto): ReceiverDto wurde so hinzugefügt, dass es vererbt wird.
- Die Eigenschaft TotpSecretkey wurde aus ReceiverDto entfernt.
 - Die Eigenschaft TotpSecretkey wurde zu ReceiverSecretDto hinzugefügt.
2025-09-08 17:23:20 +02:00
ed7068fe71 refactor(ReceiverReadDto): rename as ReceiverDto 2025-09-08 17:19:38 +02:00
876c5def56 fix(Extensions): update to add suffix 2025-09-08 16:53:44 +02:00
40697435ff fix(EnvelopeDto): convert type of Status-property to EnvelopeStatus 2025-09-08 16:20:16 +02:00
b43399ad01 fix(EGDbContext): add Envelope-property to Envelope-History relation definition on model builder 2025-09-08 16:16:22 +02:00
f41f26b810 refactor(DocumentReceiverElement): make AddedWhen nullable and add ChangedWho-property 2025-09-08 15:00:02 +02:00
442b7f7451 refactor(EGDbContext): split to regions 2025-09-08 13:03:12 +02:00
beada59593 refactor(HomeController): update EnvelopeLocked to use _mediator 2025-09-08 12:58:29 +02:00
b78aff102a remove then-calback method implementation on EnvelopeLocked-endpoint. 2025-09-08 11:55:08 +02:00
67f068ef38 refactor(Envelope): rename Receivers property as EnvelopeReceivers 2025-09-08 11:48:54 +02:00
122df4bd62 chore: remove DevExpress.Data.v21.2 and GdPicture.NET.14 2025-09-08 11:32:53 +02:00
741ebc8975 minify js 2025-09-05 15:01:29 +02:00
ada76d5030 refactor(HomeController): add SetLanguage and GetLanguages endpoints 2025-09-05 14:42:04 +02:00
845d06fc4c refactor(HomeController): add HttpGet-attribute to Error404 (fallback) endpoint 2025-09-05 14:32:22 +02:00
59105caffc fix(pdf-burner): Korrektur des Versatzes von Siegelbildern für Tintenunterschriften
- Hinzufügen des Parameters „yOffset“ zu „AddImageAnnotation“, um die Position der Siegel anzupassen.
- Aktualisierung von „AddInstantJSONAnnotationToPDF“, um den Versatz für das erste Unterschriftssiegel anzuwenden.
- Stellt sicher, dass Tintenunterschriftssiegel in PDF-Dateien korrekt dargestellt werden, ohne andere Anmerkungen zu beeinträchtigen.
2025-09-05 13:25:25 +02:00
fa8d2f5f62 feat(pdfburner): Berechnung für Anmerkungsindex innerhalb der Signaturgruppe hinzufügen 2025-09-05 11:26:09 +02:00
dbf42e13d9 feat(pdfburner): Berechnung des Signaturindexes bei der Anmerkungsverarbeitung hinzugefügt
- Variablen `annotCountPerSign`, `annotIndex` und `calcSignIndex` eingeführt
- Berechnung von `signIndex` während der Anmerkungsiteration hinzugefügt
- Bestehende Logik für Bild-, Tinten- und Widget-Anmerkungen beibehalten
2025-09-05 11:01:36 +02:00
e48a86e21c feat: add EnvelopeKeyRedirController to redirect /EnvelopeKey/{*path} to /Envelope/{*path} 2025-09-04 23:44:01 +02:00
1e6c9ed40e refactor(HomeController): ranme EnvelopeKey route as Envelope 2025-09-04 23:38:11 +02:00
1d605e9da3 fix(EnvelopeController): remove envelopeKey route parameter 2025-09-04 23:17:24 +02:00
77070a8cfc convert csrfToken constan variable 2025-09-04 23:07:32 +02:00
c479ea4179 remove README.md from static files 2025-09-04 19:10:31 +02:00
369d101d7b refactor(network): Netzwerkklasse entfernen und Methoden statisch machen.
- Unnötige Funktionen entfernen.
2025-09-04 19:09:21 +02:00
86eb687296 remove npm components of bootstrap-icons 2025-09-04 19:01:41 +02:00
aa8f46a303 remove old envelope srrvice dependencies 2025-09-04 18:56:02 +02:00
2c825d2fe3 update post Envelope to handle without object 2025-09-04 18:45:00 +02:00
1e1517f88a refactor(EnvelopeController): remove EnvelopeOldService 2025-09-04 18:01:01 +02:00
124523ad88 configure attributes 2025-09-04 17:46:16 +02:00
9c48b230b4 convert PlaceHolders-property to CreatePlaceHolders callback-method 2025-09-04 17:01:40 +02:00
95fe1aefcf merge placeholders dictionary 2025-09-04 16:45:56 +02:00
1b7a42fd7e remove cancelation token from ConfigEmailOut 2025-09-04 16:41:26 +02:00
73da768ed3 update ConfigEmailOut to add notifications 2025-09-04 09:28:13 +02:00
f20243d02c update to configure email out 2025-09-03 18:39:33 +02:00
c1c30caeec init EmailOut 2025-09-03 17:55:50 +02:00
5ccd1fee26 init SendMailHandler to read tempalte and replace placeholders 2025-09-03 17:46:24 +02:00
954d665ac3 remove unnecessary references 2025-09-03 16:58:07 +02:00
bb85437cc4 arrange folder structure of notification 2025-09-03 16:57:25 +02:00
763f022a5e add history handler 2025-09-03 16:42:32 +02:00
f87f8a1d17 refactor(DocSignedNotificationStatusHandler): rename as DocSignedNotificationAnnotationHandler 2025-09-03 16:31:14 +02:00
fb5d2110bd add DocSignedNotificationStatusHandler and implement the natification into EnveloepControler 2025-09-03 16:24:51 +02:00
aafed0f4f4 init DocSignedNotificationStatusHandler 2025-09-03 15:47:37 +02:00
a433654f86 refactor(DocSignedNotification): Aktualisierung, um von EnvelopeReceiverDto zu erben.
- Erweiterungsmethoden für die Zuordnung hinzufügen.
2025-09-03 15:38:41 +02:00
b599ada864 add DocSignedNotification 2025-09-03 15:17:03 +02:00
6b00ab6a45 refactor(SaveDocStatusCommand): update to return DocumentStatusDto. 2025-09-03 13:03:09 +02:00
6ab85f25eb refactor(SignDocBehavior): add to handle the events after document status updateted 2025-09-03 12:49:16 +02:00
fa46dd1fa8 feat(Format): create to centrilize the formats.
- Add json serializer settings for diagnostics and implement to DocumentController
2025-09-03 11:06:47 +02:00
e623680c3f refactor(DocumentController): migrate from legacy service to MediatR pattern
- Replace obsolete DocumentController implementation using EnvelopeOldService and direct dependencies
- Migrate to MediatR-based query handling via ReadEnvelopeReceiverAsync
- Remove obsolete constructors and actions marked for deprecation
- Add proper error handling with NotFoundException for missing envelope or document data
- Improve logging with structured JSON output for diagnostics
- Update base class from BaseController to ControllerBase and add ApiController attribute
- Rename action to GetDocument and apply explicit HttpGet routing
- Use IMediator for clean separation of concerns and alignment with CQRS pattern
2025-09-03 10:51:34 +02:00
f6e34c6d91 refactor(HistoryTests): Verbesserung von HistoryTests mit realistischen Daten und konsistenter Struktur
- Verwendung tatsächlicher Umschlag- und Empfängerdaten anstelle von magischen Zahlen
- Ersetzen von fest codierten EnvelopeId und UserReference durch dynamisch erstellte Entitäten
- Aktualisierung von ReadHistoryQuery zur Verwendung der Objektinitialisierungssyntax
- Fügen Sie CancellationToken zu Mediator.Send-Aufrufen hinzu, um Konsistenz zu gewährleisten
- Verwenden Sie EnvelopeHistoryDto explizit in der Assertion
- Verbessern Sie die Lesbarkeit und den Realismus des Tests, indem Sie vollständige Voraussetzungdaten einrichten
- Korrigieren Sie die Schreibweise im Kommentar: „EnvelopeReceiver” -> „envelope receiver”
2025-09-03 10:08:42 +02:00
fc443fb87f refactor(ReadHistoryQuery): Aktualisierung zur Verwendung von getter-initter. 2025-09-03 09:34:12 +02:00
1c9d0a6c47 refactor(MappingProfile): update to ignore Envelope, Sender and Receiver 2025-09-02 23:58:35 +02:00
23ec4fe322 remove re-read process 2025-09-02 23:14:16 +02:00
8ca0519dbc feat(history): CreateHistoryCommand wurde verbessert, um DTO zurückzugeben und den Empfänger zu validieren.
- Der Rückgabetyp des Handlers wurde von „long?“ zu „EnvelopeHistoryDto?“ geändert.
 - AutoMapper-Integration für die Zuordnung von EnvelopeHistory zu DTO hinzugefügt.
 - IRepository<EnvelopeReceiver> zur Validierung der Benutzerreferenz eingeführt.
 - Validierung implementiert, um sicherzustellen, dass genau ein Empfänger gefunden wird.
 - BadRequestException-Behandlung für fehlende oder mehrere Empfänger hinzugefügt.
2025-09-02 23:11:41 +02:00
c67bac3e16 test(history): Aktualisieren Sie HistoryTests, um die Erstellung von Umschlägen auf Repository-Basis zu verwenden. 2025-09-02 18:48:18 +02:00
6cdd1db7a9 feat(Fake): add extension method to Fake to create Envelope 2025-09-02 15:25:59 +02:00
a87a524271 feat(MappingProfile): UUID-Generierung beim Zuordnen von CreateEnvelopeCommand zu Envelope hinzufügen 2025-09-02 12:19:06 +02:00
ddb2439b29 add mapping profile to convert CreateEnvelopeCommand to Envelope 2025-09-01 17:30:38 +02:00
d48514bbad refactor(Extensions): update CreateEnvelopeCommand to make UseSQLExecutor false 2025-09-01 17:27:14 +02:00
00077a647a feat(envelopes): add support for SQLExecutor or repository when creating envelopes
- Refactored `CreateEnvelopeCommandHandler` to resolve dependencies via `IServiceProvider`
- Added `IRepository<Envelope>` to allow repository-based envelope creation
- Updated handler logic to choose between `IEnvelopeExecutor` and repository based on `UseSQLExecutor` flag
2025-09-01 17:23:40 +02:00
ee7eb08e75 refactor(CreateEnvelopeCommand): add UseSQLExecutor-property 2025-09-01 17:07:16 +02:00
6a34b65825 rename as ToEnvelopeKey 2025-09-01 15:43:13 +02:00
20d312a84e update to create key by EncodeEnvelopeReceiverId 2025-09-01 15:42:33 +02:00
87c5e7e4de feat(HistoryTests): add create receiver logic 2025-09-01 15:27:32 +02:00
bb93b980b4 refactor(HistoryTests): create and implement TestBase 2025-09-01 15:19:52 +02:00
950ae5a418 Update HistoryTests with new commands and setup changes
- Added new using directives for additional namespaces.
- Replaced `_host.AddSampleReceivers()` with `_host.AddSamples()` in the Setup method.
- Introduced `createEnvelopeCmd` in the test method to create an envelope before executing the history command.
2025-09-01 15:06:10 +02:00
582cc1eb13 Refactor CreateHistoryCommand and update tests
- Simplified `CreateHistoryCommand` method by removing generic type parameters.
- Updated `using` directives in `HistoryTests` to include necessary constants.
- Revised test method to utilize `Fake.Provider.CreateHistoryCommand` for improved maintainability.
2025-09-01 14:52:49 +02:00
233 changed files with 2417 additions and 4441 deletions

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
///

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
///

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
///
@@ -23,5 +23,5 @@ public class DispatcherParams
/// <summary>
/// Default value is string.Empty
/// </summary>
public string EmailAttmt1 { get; init; } = string.Empty;
public string? EmailAttmt1 { get; init; } = null;
}

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Client.Interface;
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
/// https://www.gtx-messaging.com/en/api-docs/sms-rest-api/

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
///

View File

@@ -1,7 +1,7 @@
using OtpNet;
using System.Globalization;
namespace EnvelopeGenerator.Application.Configurations;
namespace EnvelopeGenerator.Application.Common.Configurations;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Data Transfer Object representing configuration settings.

View File

@@ -1,12 +1,12 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Data Transfer Object representing a document within an envelope, including optional binary data and form elements.
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public class EnvelopeDocumentDto
public class DocumentDto
{
/// <summary>
/// Gets or sets the unique identifier of the document.
@@ -31,5 +31,5 @@ public class EnvelopeDocumentDto
/// <summary>
/// Gets or sets the collection of elements associated with the document for receiver interactions, if any.
/// </summary>
public IEnumerable<DocumentReceiverElementDto>? Elements { get; set; }
public IEnumerable<SignatureDto>? Elements { get; set; }
}

View File

@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using EnvelopeGenerator.Domain.Constants;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Data Transfer Object representing the status of a document for a specific receiver.
@@ -26,7 +27,7 @@ public class DocumentStatusDto
/// <summary>
/// Gets or sets the current status code.
/// </summary>
public int Status { get; set; }
public EnvelopeStatus Status { get; set; }
/// <summary>
/// Gets or sets the timestamp when the status was changed.

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto
namespace EnvelopeGenerator.Application.Common.Dto
{
/// <summary>
///

View File

@@ -1,10 +1,10 @@
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
using DigitalData.UserManager.Application.DTOs.User;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
///
@@ -25,7 +25,7 @@ public record EnvelopeDto
/// <summary>
///
/// </summary>
public required EnvelopeStatusQuery Status { get; set; }
public required EnvelopeStatus Status { get; set; }
/// <summary>
/// Default value is string.Empty
@@ -117,5 +117,5 @@ public record EnvelopeDto
/// <summary>
///
/// </summary>
public IEnumerable<EnvelopeDocumentDto>? Documents { get; set; }
public IEnumerable<DocumentDto>? Documents { get; set; }
}

View File

@@ -1,14 +1,25 @@
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
/// <summary>
///
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public record EnvelopeReceiverBasicDto
public record EnvelopeReceiverDto
{
/// <summary>
///
/// </summary>
public EnvelopeDto? Envelope { get; set; }
/// <summary>
///
/// </summary>
public ReceiverDto? Receiver { get; set; }
/// <summary>
///
/// </summary>

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
/// <summary>
///

View File

@@ -2,7 +2,7 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
/// <summary>
///

View File

@@ -1,7 +1,8 @@
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
/// <summary>
/// Represents a read-only Data Transfer Object (DTO) for an envelope receiver.
@@ -59,5 +60,5 @@ public class EnvelopeReceiverReadOnlyDto
/// <summary>
/// Gets or inits the associated receiver details.
/// </summary>
public ReceiverReadDto? Receiver { get; set; }
public ReceiverDto? Receiver { get; set; }
}

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
/// <summary>
/// Data Transfer Object for updating a read-only envelope receiver.

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Data Transfer Object representing a type of envelope with its configuration settings.

View File

@@ -1,11 +1,9 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeHistory;
namespace EnvelopeGenerator.Application.Common.Dto.History;
/// <summary>
/// Data Transfer Object for creating a new envelope history record.
/// </summary>
public class EnvelopeHistoryCreateDto
public class HistoryCreateDto
{
/// <summary>
/// Gets or sets the identifier of the envelope.

View File

@@ -1,13 +1,13 @@
using DigitalData.UserManager.Application.DTOs.User;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Dto.EnvelopeHistory;
namespace EnvelopeGenerator.Application.Common.Dto.History;
/// <summary>
/// Data Transfer Object representing the history of an envelope, including status, sender, receiver, and related metadata.
/// </summary>
public record EnvelopeHistoryDto
public record HistoryDto
{
/// <summary>
/// Unique identifier for the envelope history entry.
@@ -62,7 +62,7 @@ public record EnvelopeHistoryDto
/// <summary>
/// Information about the receiver associated with this history entry.
/// </summary>
public ReceiverReadDto? Receiver { get; set; }
public ReceiverDto? Receiver { get; set; }
/// <summary>
/// Optional comment related to this history entry.

View File

@@ -1,14 +1,13 @@
using AutoMapper;
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Dto.Messaging;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Application.Receivers.Commands;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Represents the AutoMapper profile configuration for mapping between
@@ -24,32 +23,31 @@ public class MappingProfile : Profile
{
// Entity to DTO mappings
CreateMap<Config, ConfigDto>();
CreateMap<DocumentReceiverElement, DocumentReceiverElementDto>();
CreateMap<Signature, SignatureDto>();
CreateMap<DocumentStatus, DocumentStatusDto>();
CreateMap<EmailTemplate, EmailTemplateDto>();
CreateMap<Envelope, EnvelopeDto>();
CreateMap<EnvelopeDocument, EnvelopeDocumentDto>();
CreateMap<Domain.Entities.EnvelopeHistory, EnvelopeHistoryDto>();
CreateMap<Domain.Entities.EnvelopeHistory, EnvelopeHistoryCreateDto>();
CreateMap<Document, DocumentDto>();
CreateMap<Domain.Entities.History, HistoryDto>();
CreateMap<Domain.Entities.History, HistoryCreateDto>();
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverDto>();
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverSecretDto>();
CreateMap<EnvelopeType, EnvelopeTypeDto>();
CreateMap<Domain.Entities.Receiver, ReceiverReadDto>();
CreateMap<Domain.Entities.Receiver, ReceiverDto>();
CreateMap<Domain.Entities.EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
// DTO to Entity mappings
CreateMap<ConfigDto, Config>();
CreateMap<DocumentReceiverElementDto, DocumentReceiverElement>();
CreateMap<SignatureDto, Signature>();
CreateMap<DocumentStatusDto, DocumentStatus>();
CreateMap<EmailTemplateDto, EmailTemplate>();
CreateMap<EnvelopeDto, Envelope>();
CreateMap<EnvelopeDocumentDto, EnvelopeDocument>();
CreateMap<EnvelopeHistoryDto, Domain.Entities.EnvelopeHistory>();
CreateMap<EnvelopeHistoryCreateDto, Domain.Entities.EnvelopeHistory>();
CreateMap<DocumentDto, Document>();
CreateMap<HistoryDto, Domain.Entities.History>();
CreateMap<HistoryCreateDto, Domain.Entities.History>();
CreateMap<EnvelopeReceiverDto, Domain.Entities.EnvelopeReceiver>();
CreateMap<EnvelopeTypeDto, EnvelopeType>();
CreateMap<ReceiverReadDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverBasicDto>();
CreateMap<ReceiverDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.Messaging;
namespace EnvelopeGenerator.Application.Common.Dto.Messaging;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.Messaging;
namespace EnvelopeGenerator.Application.Common.Dto.Messaging;
/// <summary>
///

View File

@@ -1,14 +1,14 @@
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Application.Dto.Receiver;
namespace EnvelopeGenerator.Application.Common.Dto.Receiver;
/// <summary>
///
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public class ReceiverReadDto
public class ReceiverDto
{
/// <summary>
///
@@ -25,6 +25,12 @@ public class ReceiverReadDto
/// </summary>
public required string Signature { get; set; }
/// <summary>
///
/// </summary>
[JsonIgnore]
public string? TotpSecretkey { get; set; }
/// <summary>
///
/// </summary>
@@ -34,18 +40,13 @@ public class ReceiverReadDto
///
/// </summary>
[JsonIgnore]
public IEnumerable<EnvelopeReceiverBasicDto>? EnvelopeReceivers { get; set; }
public IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers { get; set; }
/// <summary>
///
/// </summary>
public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name;
/// <summary>
///
/// </summary>
public string? TotpSecretkey { get; set; } = null;
/// <summary>
///
/// </summary>

View File

@@ -1,12 +1,12 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto;
namespace EnvelopeGenerator.Application.Common.Dto;
/// <summary>
/// Data Transfer Object representing a positioned element assigned to a document receiver.
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public class DocumentReceiverElementDto
public class SignatureDto
{
/// <summary>
/// Gets or sets the unique identifier of the element.
@@ -86,10 +86,10 @@ public class DocumentReceiverElementDto
/// <summary>
/// Gets or sets the top position of the element (in layout terms).
/// </summary>
public double Top { get; set; }
public double Top => Y;
/// <summary>
/// Gets or sets the left position of the element (in layout terms).
/// </summary>
public double Left { get; set; }
public double Left => X;
}

View File

@@ -0,0 +1,27 @@
namespace EnvelopeGenerator.Application.Common;
/// <summary>
///
/// </summary>
public enum EnvelopeFlag
{
/// <summary>
///
/// </summary>
EnvelopeOrReceiverNonexists,
/// <summary>
///
/// </summary>
NonDecodableEnvelopeReceiverId,
/// <summary>
///
/// </summary>
WrongEnvelopeReceiverId,
/// <summary>
///
/// </summary>
AccessCodeNull
}

View File

@@ -1,6 +1,6 @@
using Microsoft.Extensions.Caching.Distributed;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///

View File

@@ -1,7 +1,7 @@
using EnvelopeGenerator.Domain.Constants;
using System.Text;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///
@@ -58,8 +58,8 @@ public static class DecodingExtensions
}
// Ensure no invalid padding scenarios exist
if (input.EndsWith("==") && (input.Length % 4 == 0) ||
input.EndsWith("=") && (input.Length % 4 == 3))
if (input.EndsWith("==") && input.Length % 4 == 0 ||
input.EndsWith("=") && input.Length % 4 == 3)
{
return true;
}
@@ -157,7 +157,7 @@ public static class DecodingExtensions
return null;
}
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
string decodedString = Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
if (parts.Length > 2)

View File

@@ -0,0 +1,38 @@
using System.Text;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
/// </summary>
public static class EncodingExtensions
{
/// <summary>
///
/// </summary>
/// <param name="readOnlyId"></param>
/// <returns></returns>
public static string ToEnvelopeKey(this long readOnlyId)
{
//The random number is used as a salt to increase security but it is not saved in the database.
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string ToEnvelopeKey(this (string envelopeUuid, string receiverSignature) input)
{
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
}

View File

@@ -1,7 +1,7 @@
using Microsoft.Extensions.Logging;
using System.Text;
namespace EnvelopeGenerator.Application.Extensions
namespace EnvelopeGenerator.Application.Common.Extensions
{
public static class LoggerExtensions
{

View File

@@ -1,6 +1,6 @@
using EnvelopeGenerator.Application.Dto.Messaging;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
/// Provides extension methods for common mapping and conversion operations.

View File

@@ -1,11 +1,24 @@
using Microsoft.Extensions.Caching.Memory;
using EnvelopeGenerator.Application.Common.Extensions;
using Microsoft.Extensions.Caching.Memory;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///
/// </summary>
public static class MemoryCacheExtensions
{
private static readonly Guid BaseId = Guid.NewGuid();
/// <summary>
///
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <param name="memoryCache"></param>
/// <param name="key"></param>
/// <param name="ignores"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public static IDictionary<string, int> GetEnumAsDictionary<TEnum>(this IMemoryCache memoryCache, string key = "", params object[] ignores)
where TEnum : Enum
=> memoryCache.GetOrCreate(BaseId + typeof(TEnum).FullName + key, _ =>

View File

@@ -1,8 +1,10 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Domain.Interfaces;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///
@@ -33,6 +35,28 @@ public static class QueryExtensions
return root;
}
/// <summary>
///
/// </summary>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<Envelope> Where(this IQueryable<Envelope> root, EnvelopeQueryBase query, bool notnull = true)
{
if (query.Id is not null)
root = root.Where(e => e.Id == query.Id);
else if (query.Uuid is not null)
root = root.Where(e => e.Uuid == query.Uuid);
else if (notnull)
throw new BadRequestException(
"Either Envelope Id or Envelope Uuid must be provided in the query."
);
return root;
}
/// <summary>
///
/// </summary>
@@ -59,6 +83,30 @@ public static class QueryExtensions
return root;
}
/// <summary>
///
/// </summary>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<Receiver> Where(this IQueryable<Receiver> root, ReceiverQueryBase query, bool notnull = true)
{
if (query.Id is not null)
root = root.Where(e => e.Id == query.Id);
else if (query.EmailAddress is not null)
root = root.Where(e => e.EmailAddress == query.EmailAddress);
else if (query.Signature is not null)
root = root.Where(e => e.Signature == query.Signature);
else if (notnull)
throw new BadRequestException(
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
);
return root;
}
/// <summary>
///
/// </summary>

View File

@@ -1,6 +1,6 @@
using OtpNet;
namespace EnvelopeGenerator.Application.Extensions
namespace EnvelopeGenerator.Application.Common.Extensions
{
public static class StringExtension
{

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Exceptions;
namespace EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
/// Extension methods for tasks

View File

@@ -2,7 +2,7 @@
using Microsoft.Extensions.Localization;
using System.Text.Encodings.Web;
namespace EnvelopeGenerator.Application.Extensions
namespace EnvelopeGenerator.Application.Common.Extensions
{
public static class XSSExtensions
{

View File

@@ -0,0 +1,55 @@
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
using Newtonsoft.Json;
using System.Dynamic;
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned;
/// <summary>
///
/// </summary>
/// <param name="Original"></param>
public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeReceiverDto(Original), INotification, ISendMailNotification
{
/// <summary>
///
/// </summary>
public required ExpandoObject Annotations { get; init; }
/// <summary>
///
/// </summary>
public EmailTemplateType TemplateType => EmailTemplateType.DocumentSigned;
/// <summary>
///
/// </summary>
public string EmailAddress => Receiver?.EmailAddress
?? throw new InvalidOperationException($"Receiver is null." +
$"DocSignedNotification:\n{JsonConvert.SerializeObject(this, Format.Json.ForDiagnostics)}");
}
/// <summary>
///
/// </summary>
public static class DocSignedNotificationExtensions
{
/// <summary>
/// Converts an <see cref="EnvelopeReceiverDto"/> to a <see cref="DocSignedNotification"/>.
/// </summary>
/// <param name="dto">The DTO to convert.</param>
/// <param name="annotations"></param>
/// <returns>A new <see cref="DocSignedNotification"/> instance.</returns>
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, ExpandoObject annotations)
=> new(dto) { Annotations = annotations };
/// <summary>
/// Asynchronously converts a <see cref="Task{EnvelopeReceiverDto}"/> to a <see cref="DocSignedNotification"/>.
/// </summary>
/// <param name="dtoTask">The task that returns the DTO to convert.</param>
/// <param name="annotations"></param>
/// <returns>A task that represents the asynchronous conversion operation.</returns>
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, ExpandoObject annotations)
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { Annotations = annotations } : null;
}

View File

@@ -0,0 +1,40 @@
using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
using EnvelopeGenerator.Application.DocStatus.Commands;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
using Newtonsoft.Json;
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
/// <summary>
///
/// </summary>
public class AnnotationHandler : INotificationHandler<DocSignedNotification>
{
private readonly ISender _sender;
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
public AnnotationHandler(ISender sender)
{
_sender = sender;
}
/// <summary>
///
/// </summary>
/// <param name="notification"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
{
await _sender.Send(new SaveDocStatusCommand()
{
Envelope = new() { Id = notification.EnvelopeId },
Receiver = new() { Id = notification.ReceiverId},
Value = JsonConvert.SerializeObject(notification.Annotations, Format.Json.ForAnnotations)
}, cancel);
}
}

View File

@@ -0,0 +1,45 @@
using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
using EnvelopeGenerator.Application.Histories.Commands;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
using Newtonsoft.Json;
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
/// <summary>
///
/// </summary>
public class HistoryHandler : INotificationHandler<DocSignedNotification>
{
private readonly ISender _sender;
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
public HistoryHandler(ISender sender)
{
_sender = sender;
}
/// <summary>
///
/// </summary>
/// <param name="notification"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
{
if(notification.Receiver is null)
if (notification.Receiver is null)
throw new InvalidOperationException($"Receiver information is missing in the notification. DocSignedNotification:\n {JsonConvert.SerializeObject(notification, Format.Json.ForDiagnostics)}");
await _sender.Send(new CreateHistoryCommand()
{
EnvelopeId = notification.EnvelopeId,
UserReference = notification.Receiver.EmailAddress,
Status = EnvelopeStatus.DocumentSigned,
Comment = JsonConvert.SerializeObject(notification.Annotations, Format.Json.ForAnnotations)
}, cancel);
}
}

View File

@@ -0,0 +1,50 @@
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.Extensions.Options;
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
/// <summary>
///
/// </summary>
public class SendSignedMailHandler : SendMailHandler<DocSignedNotification>
{
/// <summary>
///
/// </summary>
/// <param name="tempRepo"></param>
/// <param name="emailOutRepo"></param>
/// <param name="mailParamsOptions"></param>
/// <param name="dispatcherParamsOptions"></param>
public SendSignedMailHandler(IRepository<EmailTemplate> tempRepo, IRepository<EmailOut> emailOutRepo, IOptions<MailParams> mailParamsOptions, IOptions<DispatcherParams> dispatcherParamsOptions) : base(tempRepo, emailOutRepo, mailParamsOptions, dispatcherParamsOptions)
{
}
/// <summary>
///
/// </summary>
/// <param name="notification"></param>
/// <param name="emailOut"></param>
protected override void ConfigureEmailOut(DocSignedNotification notification, EmailOut emailOut)
{
emailOut.ReferenceString = notification.EmailAddress;
emailOut.ReferenceId = notification.ReceiverId;
}
/// <summary>
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
protected override Dictionary<string, string> CreatePlaceHolders(DocSignedNotification notification)
{
var placeHolders = new Dictionary<string, string>()
{
{ "[NAME_RECEIVER]", notification.Name ?? string.Empty },
{ "[DOCUMENT_TITLE]", notification.Envelope?.Title ?? string.Empty },
};
return placeHolders;
}
}

View File

@@ -0,0 +1,152 @@
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace EnvelopeGenerator.Application.Common.Notifications;
/// <summary>
///
/// </summary>
public interface ISendMailNotification : INotification
{
/// <summary>
///
/// </summary>
public EmailTemplateType TemplateType { get; }
/// <summary>
///
/// </summary>
public string EmailAddress { get; }
}
/// <summary>
///
/// </summary>
public abstract class SendMailHandler<TNotification> : INotificationHandler<TNotification>
where TNotification : ISendMailNotification
{
/// <summary>
///
/// </summary>
protected readonly IRepository<EmailTemplate> TempRepo;
/// <summary>
///
/// </summary>
protected readonly IRepository<EmailOut> EmailOutRepo;
/// <summary>
///
/// </summary>
protected abstract Dictionary<string, string> CreatePlaceHolders(TNotification notification);
/// <summary>
///{ "[MESSAGE]", notification.Message },<br/>
///{ "[DOCUMENT_ACCESS_CODE]", notification.ReceiverAccessCode },<br/>
///{ "[REASON]", pReason }<br/>
///{ "[NAME_SENDER]", notification.Envelope.User?.FullName},<br/>
///{ "[NAME_PORTAL]", DispatcherParams. },<br/>
///{ "[SIGNATURE_TYPE]", "signieren" },<br/>
///{ "[LINK_TO_DOCUMENT]", notification.SignatureLink },<br/>
///{ "[LINK_TO_DOCUMENT_TEXT]", $"{notification.SignatureLink.Truncate(40)}.." },
/// </summary>
protected readonly MailParams MailParams;
/// <summary>
///
/// </summary>
protected readonly DispatcherParams DispatcherParams;
/// <summary>
///
/// </summary>
/// <param name="notification"></param>
/// <param name="emailOut"></param>
protected abstract void ConfigureEmailOut(TNotification notification, EmailOut emailOut);
/// <summary>
///
/// </summary>
/// <param name="tempRepo"></param>
/// <param name="emailOutRepo"></param>
/// <param name="mailParamsOptions"></param>
/// <param name="dispatcherParamsOptions"></param>
protected SendMailHandler(IRepository<EmailTemplate> tempRepo, IRepository<EmailOut> emailOutRepo, IOptions<MailParams> mailParamsOptions, IOptions<DispatcherParams> dispatcherParamsOptions)
{
TempRepo = tempRepo;
EmailOutRepo = emailOutRepo;
MailParams = mailParamsOptions.Value;
DispatcherParams = dispatcherParamsOptions.Value;
}
/// <summary>
///
/// </summary>
/// <param name="notification"></param>
/// <param name="cancel"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public virtual async Task Handle(TNotification notification, CancellationToken cancel)
{
var placeHolders = CreatePlaceHolders(notification);
var temp = await TempRepo
.ReadOnly()
.SingleOrDefaultAsync(x => x.Name == notification.TemplateType.ToString(), cancel)
?? throw new InvalidOperationException($"Receiver information is missing in the notification." +
$"{typeof(TNotification)}:\n {JsonConvert.SerializeObject(notification, Format.Json.ForDiagnostics)}");
temp.Subject = ReplacePlaceHolders(temp.Subject, placeHolders, MailParams.Placeholders);
temp.Body = ReplacePlaceHolders(temp.Body, placeHolders, MailParams.Placeholders);
var emailOut = new EmailOut
{
EmailAddress = notification.EmailAddress,
EmailBody = TextToHtml(temp.Body),
EmailSubj = temp.Subject,
AddedWhen = DateTime.UtcNow,
AddedWho = DispatcherParams.AddedWho,
SendingProfile = DispatcherParams.SendingProfile,
ReminderTypeId = DispatcherParams.ReminderTypeId,
EmailAttmt1 = DispatcherParams.EmailAttmt1,
WfId = (int)EnvelopeStatus.MessageConfirmationSent,
};
ConfigureEmailOut(notification, emailOut);
await EmailOutRepo.CreateAsync(emailOut, cancel);
}
private static string ReplacePlaceHolders(string text, params Dictionary<string, string>[] placeHoldersList)
{
foreach (var placeHolders in placeHoldersList)
foreach (var ph in placeHolders)
text = text.Replace(ph.Key, ph.Value);
return text;
}
private static string TextToHtml(string input)
{
if (string.IsNullOrEmpty(input)) return "";
// HTML encoding special characters
string encoded = System.Net.WebUtility.HtmlEncode(input);
// Convert tabs to &nbsp; (4 non-breaking spaces)
encoded = encoded.Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
// Convert line breaks to <br />
encoded = encoded.Replace("\r\n", "<br />"); // Windows
encoded = encoded.Replace("\r", "<br />"); // Mac old
encoded = encoded.Replace("\n", "<br />"); // Unix/Linux
return encoded;
}
}

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Model;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
@@ -8,10 +8,10 @@ public record EnvelopeQueryBase
/// <summary>
/// Die eindeutige Kennung des Umschlags.
/// </summary>
public virtual int? Id { get; init; }
public virtual int? Id { get; set; }
/// <summary>
/// Die universell eindeutige Kennung des Umschlags.
/// </summary>
public virtual string? Uuid { get; init; }
public virtual string? Uuid { get; set; }
}

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.Model;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
///

View File

@@ -1,7 +1,7 @@
using AutoMapper;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Model;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
///

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Model;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
@@ -9,12 +9,12 @@ public record ReceiverQueryBase
/// <summary>
/// ID des Empfängers
/// </summary>
public virtual int? Id { get; init; }
public virtual int? Id { get; set; }
/// <summary>
/// E-Mail Adresse des Empfängers
/// </summary>
public virtual string? EmailAddress { get; init; }
public virtual string? EmailAddress { get; set; }
/// <summary>
/// Eindeutige Signatur des Empfängers

View File

@@ -3,12 +3,12 @@ using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.SQL;
namespace EnvelopeGenerator.Application.Common.SQL;
/// <summary>
///
/// </summary>
public class DocumentCreateReadSQL : ISQL<EnvelopeDocument>
public class DocumentCreateReadSQL : ISQL<Document>
{
/// <summary>
/// Base64, OUT_UID

View File

@@ -3,7 +3,7 @@ using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using EnvelopeGenerator.Domain.Entities;
using System.Data;
namespace EnvelopeGenerator.Application.SQL;
namespace EnvelopeGenerator.Application.Common.SQL;
/// <summary>
///

View File

@@ -2,7 +2,7 @@
using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.SQL;
namespace EnvelopeGenerator.Application.Common.SQL;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using System.Globalization;
namespace EnvelopeGenerator.Application.SQL;
namespace EnvelopeGenerator.Application.Common.SQL;
/// <summary>
/// Extension method for converting objects to SQL parameter strings.

View File

@@ -1,13 +1,12 @@
using EnvelopeGenerator.Application.Configurations;
using DigitalData.Core.Client;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using DigitalData.Core.Client;
using QRCoder;
using EnvelopeGenerator.Application.Interfaces.Services;
using System.Reflection;
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
namespace EnvelopeGenerator.Application;
@@ -58,7 +57,6 @@ public static class DependencyInjection
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
cfg.RegisterServicesFromAssembly(typeof(CreateEnvelopeReceiverCommandHandler).Assembly);
});
return services;

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
@@ -8,6 +8,21 @@ namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// </summary>
public record ModifyDocStatusCommandBase : EnvelopeReceiverQueryBase
{
/// <summary>
///
/// </summary>
public int? EnvelopeId => Envelope.Id;
/// <summary>
///
/// </summary>
public int? ReceiverId => Receiver.Id;
/// <summary>
///
/// </summary>
public override ReceiverQueryBase Receiver { get => base.Receiver; set => base.Receiver = value; }
/// <summary>
/// Gets the current status code.
/// </summary>

View File

@@ -2,7 +2,9 @@
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Application.Extensions;
using AutoMapper;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
@@ -10,45 +12,34 @@ namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// Represents a command to save the status of a document, either by creating a new status or updating an existing one based on the provided envelope and receiver identifiers.
/// It returns the identifier of the saved document status.
/// </summary>
public record SaveDocStatusCommand : ModifyDocStatusCommandBase, IRequest<int?>;
public record SaveDocStatusCommand : ModifyDocStatusCommandBase, IRequest<DocumentStatusDto?>;
/// <summary>
///
/// </summary>
public static class Extensions
public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand, DocumentStatusDto?>
{
/// <summary>
///
/// </summary>
/// <param name="mediator"></param>
/// <param name="uuid"></param>
/// <param name="signature"></param>
/// <param name="value"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public static Task<int?> SignDocAsync(this IMediator mediator, string uuid, string signature, string value, CancellationToken cancel = default)
=> mediator.Send(new SaveDocStatusCommand()
{
Envelope = new() { Uuid = uuid },
Receiver = new() { Signature = signature },
Value = value
}, cancel);
}
private readonly IMapper _mapper;
/// <summary>
///
/// </summary>
public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand, int?>
{
private readonly IRepository<DocumentStatus> _repo;
private readonly IRepository<Envelope> _envRepo;
private readonly IRepository<Receiver> _rcvRepo;
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="repo"></param>
public SaveDocStatusCommandHandler(IRepository<DocumentStatus> repo)
/// <param name="rcvRepo"></param>
/// <param name="envRepo"></param>
public SaveDocStatusCommandHandler(IMapper mapper, IRepository<DocumentStatus> repo, IRepository<Receiver> rcvRepo, IRepository<Envelope> envRepo)
{
_mapper = mapper;
_repo = repo;
_rcvRepo = rcvRepo;
_envRepo = envRepo;
}
/// <summary>
@@ -57,11 +48,17 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
/// <param name="request"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task<int?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
public async Task<DocumentStatusDto?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
{
// ceck if exists
bool isExists = await _repo.ReadOnly().Where(request).AnyAsync(cancel);
var env = await _envRepo.ReadOnly().Where(request.Envelope).FirstAsync(cancel);
var rcv = await _rcvRepo.ReadOnly().Where(request.Receiver).FirstAsync(cancel);
request.Envelope.Id = env.Id;
request.Receiver.Id = rcv.Id;
if (isExists)
{
var uReq = request.To<UpdateDocStatusCommand>();
@@ -74,6 +71,7 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
}
var docStatus = await _repo.ReadOnly().Where(request).SingleOrDefaultAsync(cancel);
return docStatus?.Id;
return _mapper.Map<DocumentStatusDto>(docStatus);
}
}

View File

@@ -14,7 +14,12 @@ public class MappingProfile : Profile
/// </summary>
public MappingProfile()
{
CreateMap<CreateDocStatusCommand, DocumentStatus>();
CreateMap<UpdateDocStatusCommand, DocumentStatus>();
CreateMap<CreateDocStatusCommand, DocumentStatus>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
CreateMap<UpdateDocStatusCommand, DocumentStatus>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
}
}
}

View File

@@ -1,9 +1,9 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Dto;
using MediatR;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Documents.Queries;
@@ -12,55 +12,55 @@ namespace EnvelopeGenerator.Application.Documents.Queries;
/// </summary>
/// <param name="Id">The unique identifier of the document. Optional.</param>
/// <param name="EnvelopeId">The identifier of the envelope associated with the document. Optional.</param>
public record ReadDocumentQuery(int? Id = null, int? EnvelopeId = null) : IRequest<EnvelopeDocumentDto?>
public record ReadDocumentQuery(int? Id = null, int? EnvelopeId = null) : IRequest<DocumentDto?>
{
}
/// <summary>
/// Handles queries for reading <see cref="EnvelopeDocument"/> data based on either the document ID or the envelope ID.
/// Handles queries for reading <see cref="Document"/> data based on either the document ID or the envelope ID.
/// </summary>
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, EnvelopeDocumentDto?>
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, DocumentDto?>
{
/// <summary>
/// Repository for accessing <see cref="EnvelopeDocument"/> entities.
/// TempRepo for accessing <see cref="Document"/> entities.
/// </summary>
private readonly IRepository<EnvelopeDocument> _repo;
private readonly IRepository<Document> _repo;
private readonly IMapper _mapper;
/// <summary>
/// Initializes a new instance of the <see cref="ReadDocumentQueryHandler"/> class.
/// </summary>
/// <param name="envelopeDocumentRepository">The repository used to access <see cref="EnvelopeDocument"/> entities.</param>
/// <param name="envelopeDocumentRepository">The repository used to access <see cref="Document"/> entities.</param>
/// <param name="mapper"></param>
public ReadDocumentQueryHandler(IRepository<EnvelopeDocument> envelopeDocumentRepository, IMapper mapper)
public ReadDocumentQueryHandler(IRepository<Document> envelopeDocumentRepository, IMapper mapper)
{
_repo = envelopeDocumentRepository;
_mapper = mapper;
}
/// <summary>
/// Handles the <see cref="ReadDocumentQuery"/> and returns a <see cref="EnvelopeDocumentDto"/> based on the provided identifiers.
/// Handles the <see cref="ReadDocumentQuery"/> and returns a <see cref="DocumentDto"/> based on the provided identifiers.
/// </summary>
/// <param name="query">The query containing the document ID or envelope ID to search for.</param>
/// <param name="cancel">A token to monitor for cancellation requests.</param>
/// <returns>
/// A <see cref="EnvelopeDocumentDto"/> if a matching document is found; otherwise, <c>null</c>.
/// A <see cref="DocumentDto"/> if a matching document is found; otherwise, <c>null</c>.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Thrown when neither <see cref="ReadDocumentQuery.Id"/> nor <see cref="ReadDocumentQuery.EnvelopeId"/> is provided.
/// </exception>
public async Task<EnvelopeDocumentDto?> Handle(ReadDocumentQuery query, CancellationToken cancel)
public async Task<DocumentDto?> Handle(ReadDocumentQuery query, CancellationToken cancel)
{
if (query.Id is not null)
{
var doc = await _repo.ReadOnly().Where(d => d.Id == query.Id).FirstOrDefaultAsync(cancel);
return _mapper.Map<EnvelopeDocumentDto>(doc);
return _mapper.Map<DocumentDto>(doc);
}
else if (query.EnvelopeId is not null)
{
var doc = await _repo.ReadOnly().Where(d => d.EnvelopeId == query.EnvelopeId).FirstOrDefaultAsync(cancel);
return _mapper.Map<EnvelopeDocumentDto>(doc);
return _mapper.Map<DocumentDto>(doc);
}
throw new InvalidOperationException(

View File

@@ -1,22 +0,0 @@
using EnvelopeGenerator.Application.Dto.Receiver;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
/// <summary>
///
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto()
{
/// <summary>
///
/// </summary>
public EnvelopeDto? Envelope { get; set; }
/// <summary>
///
/// </summary>
public ReceiverReadDto? Receiver { get; set; }
}

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;

View File

@@ -1,11 +1,11 @@
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Dto;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Update;

View File

@@ -1,10 +0,0 @@
namespace EnvelopeGenerator.Application
{
public enum EnvelopeFlag
{
EnvelopeOrReceiverNonexists,
NonDecodableEnvelopeReceiverId,
WrongEnvelopeReceiverId,
AccessCodeNull
}
}

View File

@@ -1,8 +1,8 @@
using AutoMapper;
using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
@@ -59,7 +59,7 @@ public class CreateEnvelopeReceiverCommandHandler : IRequestHandler<CreateEnvelo
var res = _mapper.Map<CreateEnvelopeReceiverResponse>(envelope);
res.UnsentReceivers = unsentRecipients;
res.SentReceiver = _mapper.Map<IEnumerable<ReceiverReadDto>>(sentRecipients);
res.SentReceiver = _mapper.Map<IEnumerable<ReceiverDto>>(sentRecipients);
return res;
}
}

View File

@@ -1,5 +1,5 @@
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
@@ -11,7 +11,7 @@ public record CreateEnvelopeReceiverResponse : EnvelopeDto
/// <summary>
///
/// </summary>
public IEnumerable<ReceiverReadDto> SentReceiver { get; set; } = new List<ReceiverReadDto>();
public IEnumerable<ReceiverDto> SentReceiver { get; set; } = new List<ReceiverDto>();
/// <summary>
///

View File

@@ -1,5 +1,5 @@
using AutoMapper;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Application.Envelopes.Commands;
using EnvelopeGenerator.Domain.Entities;
@@ -15,6 +15,6 @@ public class MappingProfile : Profile
/// </summary>
public MappingProfile()
{
CreateMap<Receiver, ReceiverReadDto>();
CreateMap<Receiver, ReceiverDto>();
}
}

View File

@@ -1,14 +1,14 @@
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Application.Receivers.Queries;
using MediatR;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
@@ -66,6 +66,22 @@ public static class Extensions
var q = new ReadEnvelopeReceiverQuery() { Key = key };
return mediator.Send(q, cancel).Then(envRcvs => envRcvs.FirstOrDefault());
}
/// <summary>
///
/// </summary>
/// <param name="mediator"></param>
/// <param name="uuid"></param>
/// <param name="signature"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public static Task<EnvelopeReceiverDto?> ReadEnvelopeReceiverAsync(this IMediator mediator, string uuid, string signature, CancellationToken cancel = default)
{
var q = new ReadEnvelopeReceiverQuery();
q.Envelope.Uuid = uuid;
q.Receiver.Signature = signature;
return mediator.Send(q, cancel).Then(envRcvs => envRcvs.FirstOrDefault());
}
}
/// <summary>
@@ -97,7 +113,7 @@ public class ReadEnvelopeReceiverQueryHandler : IRequestHandler<ReadEnvelopeRece
/// <exception cref="BadRequestException"></exception>
public async Task<IEnumerable<EnvelopeReceiverDto>> Handle(ReadEnvelopeReceiverQuery request, CancellationToken cancel)
{
var q = _repo.Read().Where(request, notnull: false);
var q = _repo.ReadOnly().Where(request, notnull: false);
if (request.Envelope.Status is not null)
{
@@ -115,12 +131,13 @@ public class ReadEnvelopeReceiverQueryHandler : IRequestHandler<ReadEnvelopeRece
q = q.Where(er => !status.Ignore.Contains(er.Envelope!.Status));
}
var envRcvs = await q.Include(er => er.Envelope).ThenInclude(e => e!.Documents).ThenInclude(d => d.Elements)
.Include(er => er.Envelope).ThenInclude(e => e!.History)
var envRcvs = await q
.Include(er => er.Envelope).ThenInclude(e => e!.Documents!).ThenInclude(d => d.Elements)
.Include(er => er.Envelope).ThenInclude(e => e!.Histories)
.Include(er => er.Envelope).ThenInclude(e => e!.User)
.Include(er => er.Receiver)
.ToListAsync(cancel);
return _mapper.Map<IEnumerable<EnvelopeReceiverDto>>(envRcvs);
return _mapper.Map<List<EnvelopeReceiverDto>>(envRcvs);
}
}
}

View File

@@ -1,10 +1,10 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Application.Common.Extensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Query;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
@@ -49,13 +49,13 @@ public static class ReceiverAlreadySignedQueryExtensions
/// </summary>
public class ReceiverAlreadySignedQueryHandler : IRequestHandler<ReceiverAlreadySignedQuery, bool>
{
private readonly IRepository<EnvelopeReceiver> _repo;
private readonly IRepository<History> _repo;
/// <summary>
///
/// </summary>
/// <param name="repo"></param>
public ReceiverAlreadySignedQueryHandler(IRepository<EnvelopeReceiver> repo)
public ReceiverAlreadySignedQueryHandler(IRepository<History> repo)
{
_repo = repo;
}
@@ -68,10 +68,6 @@ public class ReceiverAlreadySignedQueryHandler : IRequestHandler<ReceiverAlready
/// <returns></returns>
public async Task<bool> Handle(ReceiverAlreadySignedQuery request, CancellationToken cancel = default)
{
return await _repo.Read()
.Where(er => er.Envelope!.Uuid == request.Envelope.Uuid)
.Where(er => er.Receiver!.Signature == request.Receiver.Signature)
.Where(er => er.Envelope!.History.Any(hist => hist.Status == EnvelopeStatus.DocumentSigned))
.AnyAsync(cancel);
return await _repo.ReadOnly().Where(request).Where(h => h.Status == EnvelopeStatus.DocumentSigned).AnyAsync(cancel);
}
}

View File

@@ -1,6 +1,10 @@
using EnvelopeGenerator.Application.Dto;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using MediatR;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Application.Envelopes.Commands;
@@ -30,4 +34,14 @@ public record CreateEnvelopeCommand : IRequest<EnvelopeDto?>
/// ID des Absenders
/// </summary>
public int UserId { get; set; }
/// <summary>
/// Determines which component is used for envelope processing.
/// When <c>true</c>, processing is delegated to <see cref="IEnvelopeExecutor"/>;
/// when <c>false</c>, <see cref="IRepository{Envelope}"/> is used instead.
/// Note: <see cref="IRepository{Envelope}"/> should only be used in testing scenarios.
/// </summary>
[JsonIgnore]
[NotMapped]
public bool UseSQLExecutor { get; set; } = true;
}

View File

@@ -1,7 +1,10 @@
using AutoMapper;
using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using EnvelopeGenerator.Application.Dto;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Envelopes.Commands;
@@ -10,18 +13,22 @@ namespace EnvelopeGenerator.Application.Envelopes.Commands;
/// </summary>
public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeCommand, EnvelopeDto?>
{
private readonly IEnvelopeExecutor _envelopeExecutor;
private readonly IServiceProvider _provider;
private IEnvelopeExecutor Executor => _provider.GetRequiredService<IEnvelopeExecutor>();
private IRepository<Envelope> Repository => _provider.GetRequiredService<IRepository<Envelope>>();
private readonly IMapper _mapper;
/// <summary>
///
/// </summary>
/// <param name="envelopeExecutor"></param>
/// <param name="provider"></param>
/// <param name="mapper"></param>
public CreateEnvelopeCommandHandler(IEnvelopeExecutor envelopeExecutor, IMapper mapper)
public CreateEnvelopeCommandHandler(IServiceProvider provider, IMapper mapper)
{
_envelopeExecutor = envelopeExecutor;
_provider = provider;
_mapper = mapper;
}
@@ -29,12 +36,14 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
///
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task<EnvelopeDto?> Handle(CreateEnvelopeCommand request, CancellationToken cancellationToken)
public async Task<EnvelopeDto?> Handle(CreateEnvelopeCommand request, CancellationToken cancel)
{
var envelope = await _envelopeExecutor.CreateEnvelopeAsync(request.UserId, request.Title, request.Message, request.TFAEnabled, cancellationToken);
var envelope = request.UseSQLExecutor
? await Executor.CreateEnvelopeAsync(request.UserId, request.Title, request.Message, request.TFAEnabled, cancel)
: await Repository.CreateAsync(request, cancel);
return _mapper.Map<EnvelopeDto>(envelope);
}
}
}

View File

@@ -1,5 +1,6 @@
using AutoMapper;
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
using EnvelopeGenerator.Application.Envelopes.Commands;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Envelopes;
@@ -15,5 +16,7 @@ public class MappingProfile : Profile
public MappingProfile()
{
CreateMap<Envelope, CreateEnvelopeReceiverResponse>();
CreateMap<CreateEnvelopeCommand, Envelope>()
.ForMember(dest => dest.Uuid, opt => opt.MapFrom(_ => Guid.NewGuid().ToString()));
}
}

View File

@@ -1,6 +1,6 @@
using MediatR;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Query;
namespace EnvelopeGenerator.Application.Envelopes.Queries;

View File

@@ -1,30 +0,0 @@
using Microsoft.Extensions.Logging;
using System.Text;
namespace EnvelopeGenerator.Application.Extensions
{
/// <summary>
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
/// </summary>
public static class EncodingExtensions
{
public static string EncodeEnvelopeReceiverId(this long readOnlyId)
{
//The random number is used as a salt to increase security but it is not saved in the database.
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
{
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
string base64String = Convert.ToBase64String(bytes);
return base64String;
}
}
}

View File

@@ -1,17 +1,20 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Model;
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Histories.Commands;
/// <summary>
///
/// </summary>
public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest<long?>
public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest<HistoryDto?>
{
/// <summary>
///
@@ -47,17 +50,25 @@ public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest<long?>
/// <summary>
///
/// </summary>
public class CreateHistoryCommandHandler : IRequestHandler<CreateHistoryCommand, long?>
public class CreateHistoryCommandHandler : IRequestHandler<CreateHistoryCommand, HistoryDto?>
{
private readonly IRepository<EnvelopeHistory> _repo;
private readonly IRepository<History> _repo;
private readonly IRepository<EnvelopeReceiver> _erRepo;
private readonly IMapper _mapper;
/// <summary>
///
/// </summary>
/// <param name="repo"></param>
public CreateHistoryCommandHandler(IRepository<EnvelopeHistory> repo)
/// <param name="erRepo"></param>
/// <param name="mapper"></param>
public CreateHistoryCommandHandler(IRepository<History> repo, IRepository<EnvelopeReceiver> erRepo, IMapper mapper)
{
_repo = repo;
_erRepo = erRepo;
_mapper = mapper;
}
/// <summary>
@@ -66,26 +77,32 @@ public class CreateHistoryCommandHandler : IRequestHandler<CreateHistoryCommand,
/// <param name="request"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task<long?> Handle(CreateHistoryCommand request, CancellationToken cancel)
public async Task<HistoryDto?> Handle(CreateHistoryCommand request, CancellationToken cancel)
{
if(request.UserReference is null)
{
var receivers = await _erRepo
.ReadOnly()
.Where(request)
.Include(er => er.Receiver)
.ToListAsync(cancel);
if (receivers.Count != 1)
throw new BadRequestException(
receivers.Count > 1
? "Multiple receivers found for the given envelope and receiver criteria."
: "No receiver found for the given envelope and receiver criteria."
);
var receiver = receivers.Single().Receiver
?? throw new BadRequestException("No receiver found for the given envelope and receiver criteria.");
request.UserReference = receiver.EmailAddress;
}
// create entitiy
await _repo.CreateAsync(request, cancel);
// check if created
var query = _repo.ReadOnly();
query = request.EnvelopeId is null
? query.Where(request.Envelope)
: query.Where(h => h.EnvelopeId == request.EnvelopeId);
query = request.UserReference is null
? query.Where(request.Receiver)
: query.Where(h => h.UserReference == request.UserReference);
var record = await query
.Where(h => h.ActionDate == request.ActionDate)
.SingleOrDefaultAsync(cancel);
return record?.Id;
var hist = await _repo.CreateAsync(request, cancel);
return _mapper.Map<HistoryDto>(hist);
}
}

View File

@@ -14,6 +14,9 @@ public class MappingProfile: Profile
/// </summary>
public MappingProfile()
{
CreateMap<CreateHistoryCommand, EnvelopeHistory>();
CreateMap<CreateHistoryCommand, History>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Sender, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
}
}
}

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
using System.ComponentModel.DataAnnotations;
@@ -9,11 +9,21 @@ namespace EnvelopeGenerator.Application.Histories.Queries;
/// <summary>
/// Repräsentiert eine Abfrage für die Verlaufshistorie eines Umschlags.
/// </summary>
/// <param name="EnvelopeId">Die eindeutige Kennung des Umschlags.</param>
/// <param name="Status">Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.</param>
/// <param name="OnlyLast">Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.</param>
public record ReadHistoryQuery(
public record ReadHistoryQuery : IRequest<IEnumerable<HistoryDto>>
{
/// <summary>
/// Die eindeutige Kennung des Umschlags.
/// </summary>
[Required]
int EnvelopeId,
EnvelopeStatus? Status = null,
bool? OnlyLast = true) : IRequest<IEnumerable<EnvelopeHistoryDto>>;
public int EnvelopeId { get; init; }
/// <summary>
/// Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.
/// </summary>
public EnvelopeStatus? Status { get; init; }
/// <summary>
/// Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.
/// </summary>
public bool? OnlyLast { get; init; } = true;
}

View File

@@ -1,7 +1,7 @@
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
@@ -11,9 +11,9 @@ namespace EnvelopeGenerator.Application.Histories.Queries;
/// <summary>
///
/// </summary>
public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumerable<EnvelopeHistoryDto>>
public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumerable<HistoryDto>>
{
private readonly IRepository<EnvelopeHistory> _repo;
private readonly IRepository<History> _repo;
private readonly IMapper _mapper;
@@ -22,7 +22,7 @@ public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumer
/// </summary>
/// <param name="repo"></param>
/// <param name="mapper"></param>
public ReadHistoryQueryHandler(IRepository<EnvelopeHistory> repo, IMapper mapper)
public ReadHistoryQueryHandler(IRepository<History> repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
@@ -35,13 +35,13 @@ public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumer
/// <param name="cancel"></param>
/// <returns></returns>
/// <exception cref="NotFoundException"></exception>
public async Task<IEnumerable<EnvelopeHistoryDto>> Handle(ReadHistoryQuery request, CancellationToken cancel = default)
public async Task<IEnumerable<HistoryDto>> Handle(ReadHistoryQuery request, CancellationToken cancel = default)
{
var query = _repo.ReadOnly().Where(h => h.EnvelopeId == request.EnvelopeId);
if (request.Status is not null)
query = query.Where(h => h.Status == request.Status);
var hists = await query.ToListAsync(cancel);
return _mapper.Map<IEnumerable<EnvelopeHistoryDto>>(hists);
return _mapper.Map<List<HistoryDto>>(hists);
}
}

View File

@@ -6,6 +6,6 @@ namespace EnvelopeGenerator.Application.Interfaces.Repositories;
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IDocumentReceiverElementRepository : ICRUDRepository<DocumentReceiverElement, int>
public interface IDocumentReceiverElementRepository : ICRUDRepository<Signature, int>
{
}

View File

@@ -7,6 +7,6 @@ namespace EnvelopeGenerator.Application.Interfaces.Repositories;
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IEnvelopeDocumentRepository : ICRUDRepository<EnvelopeDocument, int>
public interface IEnvelopeDocumentRepository : ICRUDRepository<Document, int>
{
}

View File

@@ -8,7 +8,7 @@ namespace EnvelopeGenerator.Application.Interfaces.Repositories;
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IEnvelopeHistoryRepository : ICRUDRepository<EnvelopeHistory, long>
public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
{
/// <summary>
///
@@ -28,5 +28,5 @@ public interface IEnvelopeHistoryRepository : ICRUDRepository<EnvelopeHistory, l
/// <param name="withSender"></param>
/// <param name="withReceiver"></param>
/// <returns></returns>
Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
Task<IEnumerable<History>> ReadAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
}

View File

@@ -14,5 +14,5 @@ public interface IDocumentExecutor
/// <param name="envelope_uuid"></param>
/// <param name="cancellation"></param>
/// <returns></returns>
Task<EnvelopeDocument> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
Task<Document> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
}

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
@@ -8,6 +8,6 @@ namespace EnvelopeGenerator.Application.Interfaces.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IDocumentReceiverElementService : IBasicCRUDService<DocumentReceiverElementDto, DocumentReceiverElement, int>
public interface IDocumentReceiverElementService : IBasicCRUDService<SignatureDto, Signature, int>
{
}

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
@@ -8,6 +8,6 @@ namespace EnvelopeGenerator.Application.Interfaces.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IEnvelopeDocumentService : IBasicCRUDService<EnvelopeDocumentDto, EnvelopeDocument, int>
public interface IEnvelopeDocumentService : IBasicCRUDService<DocumentDto, Document, int>
{
}

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
@@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Application.Interfaces.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistory, long>
public interface IEnvelopeHistoryService : ICRUDService<HistoryCreateDto, HistoryDto, History, long>
{
/// <summary>
///
@@ -56,7 +56,7 @@ public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto
/// <param name="withSender"></param>
/// <param name="withReceiver"></param>
/// <returns></returns>
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
Task<IEnumerable<HistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
/// <summary>
///
@@ -64,14 +64,14 @@ public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto
/// <param name="envelopeId"></param>
/// <param name="userReference"></param>
/// <returns></returns>
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
Task<IEnumerable<HistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
/// <summary>
///
/// </summary>
/// <param name="envelopeId"></param>
/// <returns></returns>
Task<IEnumerable<ReceiverReadDto>> ReadRejectingReceivers(int envelopeId);
Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId);
/// <summary>
///

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.DTO;
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Interfaces.Services;
@@ -35,11 +35,4 @@ public interface IEnvelopeMailService : IEmailOutService
/// <param name="envelopeReceiverDto"></param>
/// <returns></returns>
Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
/// <summary>
///
/// </summary>
/// <param name="envelopeReceiverDto"></param>
/// <returns></returns>
Task<DataResult<int>> SendTFAQrCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
}

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,8 +1,8 @@
using CommandDotNet;
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Dto.Messaging;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
using EnvelopeGenerator.Application.Envelopes;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Application.Receivers.Queries;

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;

View File

@@ -1,5 +1,5 @@
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Dto.Messaging;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,5 +1,5 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Application.Receivers.Commands;
using EnvelopeGenerator.Domain.Entities;
@@ -10,7 +10,7 @@ namespace EnvelopeGenerator.Application.Interfaces.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IReceiverService : ICRUDService<CreateReceiverCommand, ReceiverReadDto, Receiver, int>
public interface IReceiverService : ICRUDService<CreateReceiverCommand, ReceiverDto, Receiver, int>
{
/// <summary>
///
@@ -18,7 +18,7 @@ public interface IReceiverService : ICRUDService<CreateReceiverCommand, Receiver
/// <param name="emailAddress"></param>
/// <param name="signature"></param>
/// <returns></returns>
Task<DataResult<ReceiverReadDto>> ReadByAsync(string? emailAddress = null, string? signature = null);
Task<DataResult<ReceiverDto>> ReadByAsync(string? emailAddress = null, string? signature = null);
/// <summary>
///

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Application.Dto.Messaging;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
namespace EnvelopeGenerator.Application.Interfaces.Services;

View File

@@ -1,4 +1,6 @@
using DigitalData.Core.Abstraction.Application.Repository;
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -13,7 +15,7 @@ namespace EnvelopeGenerator.Application.Receivers.Commands;
///
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public record CreateReceiverCommand : IRequest<(int Id, bool AlreadyExists)>
public record CreateReceiverCommand : IRequest<(ReceiverDto Receiver, bool AlreadyExists)>
{
/// <summary>
///
@@ -52,20 +54,23 @@ public record CreateReceiverCommand : IRequest<(int Id, bool AlreadyExists)>
/// <summary>
///
/// </summary>
public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverCommand, (int Id, bool AlreadyExists)>
public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverCommand, (ReceiverDto Receiver, bool AlreadyExists)>
{
/// <summary>
///
/// </summary>
private readonly IRepository<Receiver> _repo;
private readonly IMapper _mapper;
/// <summary>
///
/// </summary>
/// <param name="repo"></param>
public CreateReceiverCommandHandler(IRepository<Receiver> repo)
public CreateReceiverCommandHandler(IRepository<Receiver> repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
}
/// <summary>
@@ -74,7 +79,7 @@ public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverComman
/// <param name="request"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task<(int Id, bool AlreadyExists)> Handle(CreateReceiverCommand request, CancellationToken cancel)
public async Task<(ReceiverDto Receiver, bool AlreadyExists)> Handle(CreateReceiverCommand request, CancellationToken cancel)
{
var receiver = await _repo.ReadOnly()
.Where(r => r.EmailAddress == request.EmailAddress)
@@ -85,6 +90,7 @@ public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverComman
if (!alreadyExists)
receiver = await _repo.CreateAsync(request, cancel);
return (receiver!.Id, alreadyExists);
var receiverDto = _mapper.Map<ReceiverDto>(receiver);
return (receiverDto, alreadyExists);
}
}

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Application.Common.Query;
namespace EnvelopeGenerator.Application.Receivers.Queries;

View File

@@ -1,5 +1,4 @@
using Microsoft.Extensions.Localization;
using System.Runtime.CompilerServices;
namespace EnvelopeGenerator.Application.Resources;
@@ -328,39 +327,39 @@ public static class Extensions
///
/// </summary>
/// <param name="localizer"></param>
/// <param name="arg0"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public static string LockedTitle(this IStringLocalizer localizer, object? arg0) => string.Format(localizer[nameof(Privacy)].Value, arg0);
public static string LockedTitle(this IStringLocalizer localizer, string suffix) => localizer[nameof(LockedTitle) + suffix].Value;
/// <summary>
///
/// </summary>
/// <param name="localizer"></param>
/// <param name="arg0"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public static string LockedBody(this IStringLocalizer localizer, object? arg0) => string.Format(localizer[nameof(LockedBody)].Value, arg0);
public static string LockedBody(this IStringLocalizer localizer, string suffix) => localizer[nameof(LockedBody) + suffix].Value;
/// <summary>
///
/// </summary>
/// <param name="localizer"></param>
/// <param name="arg0"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public static string LockedCodeLabel(this IStringLocalizer localizer, object? arg0) => string.Format(localizer[nameof(LockedCodeLabel)].Value, arg0);
public static string LockedCodeLabel(this IStringLocalizer localizer, string suffix) => localizer[nameof(LockedCodeLabel) + suffix].Value;
/// <summary>
///
/// </summary>
/// <param name="localizer"></param>
/// <param name="arg0"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public static string LockedFooterTitle(this IStringLocalizer localizer, object? arg0) => string.Format(localizer[nameof(LockedFooterTitle)].Value, arg0);
public static string LockedFooterTitle(this IStringLocalizer localizer, string suffix) => localizer[nameof(LockedFooterTitle) + suffix].Value;
/// <summary>
///
/// </summary>
/// <param name="localizer"></param>
/// <param name="arg0"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public static string LockedFooterBody(this IStringLocalizer localizer, object? arg0) => string.Format(localizer[nameof(LockedFooterBody)].Value, arg0);
public static string LockedFooterBody(this IStringLocalizer localizer, string suffix) => localizer[nameof(LockedFooterBody) + suffix].Value;
}

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Application.Configurations;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Application.Interfaces.Services;
using Microsoft.Extensions.Options;
using OtpNet;

View File

@@ -2,11 +2,11 @@
using DigitalData.Core.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Services;

View File

@@ -1,9 +1,9 @@
using AutoMapper;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Services;
@@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Application.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public class DocumentReceiverElementService : BasicCRUDService<IDocumentReceiverElementRepository, DocumentReceiverElementDto, DocumentReceiverElement, int>, IDocumentReceiverElementService
public class DocumentReceiverElementService : BasicCRUDService<IDocumentReceiverElementRepository, SignatureDto, Signature, int>, IDocumentReceiverElementService
{
/// <summary>
///

View File

@@ -1,9 +1,9 @@
using AutoMapper;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Services;

View File

@@ -1,12 +1,12 @@
using AutoMapper;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using DigitalData.Core.Abstraction.Application.DTO;
using Microsoft.Extensions.Logging;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Services;

View File

@@ -1,9 +1,9 @@
using AutoMapper;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Dto;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.Services;
@@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Application.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public class EnvelopeDocumentService : BasicCRUDService<IEnvelopeDocumentRepository, EnvelopeDocumentDto, EnvelopeDocument, int>, IEnvelopeDocumentService
public class EnvelopeDocumentService : BasicCRUDService<IEnvelopeDocumentRepository, DocumentDto, Document, int>, IEnvelopeDocumentService
{
/// <summary>
///

View File

@@ -2,11 +2,11 @@
using DigitalData.Core.Application;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
using EnvelopeGenerator.Application.Dto.Receiver;
using EnvelopeGenerator.Application.Interfaces.Services;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Dto.History;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
namespace EnvelopeGenerator.Application.Services;
@@ -14,7 +14,7 @@ namespace EnvelopeGenerator.Application.Services;
///
/// </summary>
[Obsolete("Use MediatR")]
public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistory, long>, IEnvelopeHistoryService
public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, HistoryCreateDto, HistoryDto, History, long>, IEnvelopeHistoryService
{
/// <summary>
///
@@ -94,9 +94,9 @@ public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, En
/// <param name="withSender"></param>
/// <param name="withReceiver"></param>
/// <returns></returns>
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false)
public async Task<IEnumerable<HistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false)
{
var histDTOs = _mapper.Map<IEnumerable<EnvelopeHistoryDto>>(
var histDTOs = _mapper.Map<IEnumerable<HistoryDto>>(
await _repository.ReadAsync(
envelopeId: envelopeId,
userReference: userReference,
@@ -112,7 +112,7 @@ public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, En
/// <param name="envelopeId"></param>
/// <param name="userReference"></param>
/// <returns></returns>
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) =>
public async Task<IEnumerable<HistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) =>
await ReadAsync(envelopeId: envelopeId, userReference: userReference, status: EnvelopeStatus.DocumentRejected, withReceiver:true);
//TODO: use IQueryable in repository to incerease the performance
@@ -121,11 +121,11 @@ public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, En
/// </summary>
/// <param name="envelopeId"></param>
/// <returns></returns>
public async Task<IEnumerable<ReceiverReadDto>> ReadRejectingReceivers(int envelopeId)
public async Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId)
{
var envelopes = await ReadRejectedAsync(envelopeId);
return envelopes is null
? Enumerable.Empty<ReceiverReadDto>()
? Enumerable.Empty<ReceiverDto>()
: envelopes
.Where(eh => eh?.Receiver != null)
.Select(eh => eh.Receiver!);

View File

@@ -2,16 +2,16 @@
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Application.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Configurations;
using Newtonsoft.Json;
using EnvelopeGenerator.Application.Interfaces.Services;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.Services;
@@ -56,7 +56,7 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
if(envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
{
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).EncodeEnvelopeReceiverId();
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).ToEnvelopeKey();
var sigHost = await _configService.ReadDefaultSignatureHost();
var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}";
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
@@ -71,7 +71,7 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null)
{
_placeholders["[NAME_RECEIVER]"] = await _envRcvService.ReadLastUsedReceiverNameByMailAsync(readOnlyDto.AddedWho).ThenAsync(res => res, (msg, ntc) => string.Empty) ?? string.Empty;
var erReadOnlyId = (readOnlyDto.Id).EncodeEnvelopeReceiverId();
var erReadOnlyId = (readOnlyDto.Id).ToEnvelopeKey();
var sigHost = await _configService.ReadDefaultSignatureHost();
var linkToDoc = $"{sigHost}/EnvelopeKey/{erReadOnlyId}";
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
@@ -181,31 +181,10 @@ public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Di
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders, dto.Envelope);
}
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: EmailTemplateType.DocumentAccessCodeReceived);
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public Task<DataResult<int>> SendTFAQrCodeAsync(EnvelopeReceiverDto dto)
{
// Check if receiver or secret key is null
if (dto.Receiver is null)
throw new ArgumentNullException(nameof(dto), $"TFA Qr Code cannot sent. Receiver information is missing. Envelope receiver dto is {JsonConvert.SerializeObject(dto)}");
if (dto.Receiver.TotpSecretkey is null)
throw new ArgumentNullException(nameof(dto), $"TFA Qr Code cannot sent. Receiver.TotpSecretKey is null. Envelope receiver dto is {JsonConvert.SerializeObject(dto)}");
var totp_qr_64 = _authenticator.GenerateTotpQrCode(userEmail: dto.Receiver.EmailAddress, secretKey: dto.Receiver.TotpSecretkey).ToBase64String();
return SendAsync(dto, EmailTemplateType.TotpSecret, new()
{
{"[TFA_QR_CODE]", totp_qr_64 },
});
}
}

Some files were not shown because too many files have changed in this diff Show More