From 0f53d0509e37a67fd91e892e9dee1a56a2d84570 Mon Sep 17 00:00:00 2001
From: TekH
Date: Mon, 28 Sep 2026 09:51:51 +0200
Subject: [PATCH 1/2] remove depr API
---
EnvelopeGenerator.API/AuthScheme.cs | 17 -
.../Controllers/AnnotationController.cs | 132 -------
.../Controllers/AuthController.cs | 117 ------
.../Controllers/CacheController.cs | 84 -----
.../Controllers/ConfigController.cs | 31 --
.../DocReceiverElementController.cs | 57 ---
.../Controllers/DocumentController.cs | 84 -----
.../Controllers/EmailTemplateController.cs | 69 ----
.../Controllers/EnvelopeController.cs | 111 ------
.../Controllers/EnvelopeReceiverController.cs | 281 --------------
.../Controllers/EnvelopeTypeController.cs | 39 --
.../Controllers/HistoryController.cs | 118 ------
.../Controllers/Interfaces/IAuthController.cs | 38 --
.../Controllers/LocalizationController.cs | 121 ------
.../Controllers/ReadOnlyController.cs | 91 -----
.../Controllers/ReceiverController.cs | 47 ---
.../Controllers/TfaRegistrationController.cs | 129 -------
.../Documentation/AuthProxyDocumentFilter.cs | 123 ------
.../EnvelopeGenerator.API.csproj | 84 -----
.../Extensions/ReceiverClaimExtensions.cs | 96 -----
.../Extensions/SenderClaimExtensions.cs | 95 -----
EnvelopeGenerator.API/Jenkinsfile | 10 -
.../Middleware/ExceptionHandlingMiddleware.cs | 84 -----
EnvelopeGenerator.API/Models/Auth.cs | 14 -
EnvelopeGenerator.API/Models/AuthTokenKeys.cs | 28 --
.../Models/ConnectionString.cs | 12 -
EnvelopeGenerator.API/Models/ContactLink.cs | 60 ---
EnvelopeGenerator.API/Models/Culture.cs | 17 -
EnvelopeGenerator.API/Models/Cultures.cs | 12 -
EnvelopeGenerator.API/Models/CustomImages.cs | 6 -
.../Models/EnvelopeReceiverLogin.cs | 7 -
.../Models/ErrorViewModel.cs | 10 -
EnvelopeGenerator.API/Models/Image.cs | 10 -
EnvelopeGenerator.API/Models/Login.cs | 13 -
EnvelopeGenerator.API/Models/MainViewModel.cs | 6 -
.../Models/PsPdfKitAnnotation/Annotation.cs | 93 -----
.../PsPdfKitAnnotation/AnnotationParams.cs | 80 ----
.../Models/PsPdfKitAnnotation/Background.cs | 58 ---
.../Models/PsPdfKitAnnotation/Color.cs | 10 -
.../Models/PsPdfKitAnnotation/Extensions.cs | 8 -
.../Models/PsPdfKitAnnotation/IAnnotation.cs | 22 --
EnvelopeGenerator.API/Models/TFARegParams.cs | 17 -
EnvelopeGenerator.API/Options/CacheOptions.cs | 18 -
EnvelopeGenerator.API/Program.cs | 355 ------------------
.../PublishProfiles/IISProfileNet8.pubxml | 20 -
.../Properties/launchSettings.json | 51 ---
.../appsettings.Development.json | 29 --
EnvelopeGenerator.API/appsettings.json | 256 -------------
EnvelopeGenerator.API/yarp.json | 185 ---------
EnvelopeGenerator.sln | 7 -
50 files changed, 3462 deletions(-)
delete mode 100644 EnvelopeGenerator.API/AuthScheme.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/AnnotationController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/AuthController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/CacheController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/ConfigController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/DocReceiverElementController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/DocumentController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/EmailTemplateController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/EnvelopeController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/EnvelopeReceiverController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/HistoryController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/Interfaces/IAuthController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/LocalizationController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/ReadOnlyController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/ReceiverController.cs
delete mode 100644 EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs
delete mode 100644 EnvelopeGenerator.API/Documentation/AuthProxyDocumentFilter.cs
delete mode 100644 EnvelopeGenerator.API/EnvelopeGenerator.API.csproj
delete mode 100644 EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs
delete mode 100644 EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs
delete mode 100644 EnvelopeGenerator.API/Jenkinsfile
delete mode 100644 EnvelopeGenerator.API/Middleware/ExceptionHandlingMiddleware.cs
delete mode 100644 EnvelopeGenerator.API/Models/Auth.cs
delete mode 100644 EnvelopeGenerator.API/Models/AuthTokenKeys.cs
delete mode 100644 EnvelopeGenerator.API/Models/ConnectionString.cs
delete mode 100644 EnvelopeGenerator.API/Models/ContactLink.cs
delete mode 100644 EnvelopeGenerator.API/Models/Culture.cs
delete mode 100644 EnvelopeGenerator.API/Models/Cultures.cs
delete mode 100644 EnvelopeGenerator.API/Models/CustomImages.cs
delete mode 100644 EnvelopeGenerator.API/Models/EnvelopeReceiverLogin.cs
delete mode 100644 EnvelopeGenerator.API/Models/ErrorViewModel.cs
delete mode 100644 EnvelopeGenerator.API/Models/Image.cs
delete mode 100644 EnvelopeGenerator.API/Models/Login.cs
delete mode 100644 EnvelopeGenerator.API/Models/MainViewModel.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Annotation.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/AnnotationParams.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Background.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Extensions.cs
delete mode 100644 EnvelopeGenerator.API/Models/PsPdfKitAnnotation/IAnnotation.cs
delete mode 100644 EnvelopeGenerator.API/Models/TFARegParams.cs
delete mode 100644 EnvelopeGenerator.API/Options/CacheOptions.cs
delete mode 100644 EnvelopeGenerator.API/Program.cs
delete mode 100644 EnvelopeGenerator.API/Properties/PublishProfiles/IISProfileNet8.pubxml
delete mode 100644 EnvelopeGenerator.API/Properties/launchSettings.json
delete mode 100644 EnvelopeGenerator.API/appsettings.Development.json
delete mode 100644 EnvelopeGenerator.API/appsettings.json
delete mode 100644 EnvelopeGenerator.API/yarp.json
diff --git a/EnvelopeGenerator.API/AuthScheme.cs b/EnvelopeGenerator.API/AuthScheme.cs
deleted file mode 100644
index 96e3b90d..00000000
--- a/EnvelopeGenerator.API/AuthScheme.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace EnvelopeGenerator.API;
-
-///
-///
-///
-public static class AuthScheme
-{
- ///
- /// Scheme name used for per-envelope receiver JWT authentication.
- ///
- public const string Receiver = "EnvelopeGenerator.API.ReceiverJWT";
-
- ///
- /// Scheme name used for per-envelope sender JWT authentication.
- ///
- public const string Sender = "EnvelopeGenerator.API.SenderJWT";
-}
diff --git a/EnvelopeGenerator.API/Controllers/AnnotationController.cs b/EnvelopeGenerator.API/Controllers/AnnotationController.cs
deleted file mode 100644
index e0698b84..00000000
--- a/EnvelopeGenerator.API/Controllers/AnnotationController.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using DigitalData.Core.Abstraction.Application.DTO;
-using DigitalData.Core.Exceptions;
-using EnvelopeGenerator.API.Extensions;
-using EnvelopeGenerator.Application.Common.Dto;
-using EnvelopeGenerator.Application.Common.Extensions;
-using EnvelopeGenerator.Application.Common.Interfaces.Services;
-using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
-using EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
-using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
-using EnvelopeGenerator.Application.Histories.Queries;
-using EnvelopeGenerator.Domain.Constants;
-using MediatR;
-using Microsoft.AspNetCore.Authentication;
-using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Manages annotations and signature lifecycle for envelopes.
-///
-[Authorize(Policy = AuthPolicy.Receiver)]
-[ApiController]
-[Route("api/[controller]")]
-public class AnnotationController : ControllerBase
-{
- [Obsolete("Use MediatR")]
- private readonly IEnvelopeHistoryService _historyService;
-
- [Obsolete("Use MediatR")]
- private readonly IEnvelopeReceiverService _envelopeReceiverService;
-
- private readonly IMediator _mediator;
-
- private readonly ILogger _logger;
-
- ///
- /// Initializes a new instance of .
- ///
- [Obsolete("Use MediatR")]
- public AnnotationController(
- ILogger logger,
- IEnvelopeHistoryService envelopeHistoryService,
- IEnvelopeReceiverService envelopeReceiverService,
- IMediator mediator)
- {
- _historyService = envelopeHistoryService;
- _envelopeReceiverService = envelopeReceiverService;
- _mediator = mediator;
- _logger = logger;
- }
-
- ///
- /// Creates or updates annotations for the authenticated envelope receiver.
- ///
- /// Annotation payload.
- /// Cancellation token.
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpPost]
- [Obsolete("PSPDF Kit will no longer be used.")]
- public async Task CreateOrUpdate([FromBody] PsPdfKitAnnotation? psPdfKitAnnotation = null, CancellationToken cancel = default)
- {
- var signature = User.ReceiverSignature();
- var uuid = User.EnvelopeUuid();
-
- var envelopeReceiver = await _mediator.ReadEnvelopeReceiverAsync(uuid, signature, cancel).ThrowIfNull(Exceptions.NotFound);
-
- if (!envelopeReceiver.Envelope!.ReadOnly && psPdfKitAnnotation is null)
- return BadRequest();
-
- if (await _mediator.IsSignedAsync(uuid, signature, cancel))
- return Problem(statusCode: StatusCodes.Status409Conflict);
- else if (await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel))
- return Problem(statusCode: StatusCodes.Status423Locked);
-
- var envelopeReceiverDto = await _mediator.ReadEnvelopeReceiverAsync(uuid, signature, cancel);
- var docSignedNotification = envelopeReceiverDto is not null
- ? new DocSignedNotification { EnvelopeReceiver = envelopeReceiverDto, PsPdfKitAnnotation = psPdfKitAnnotation }
- : throw new NotFoundException("Envelope receiver is not found.");
-
- try
- {
- await _mediator.Publish(docSignedNotification, cancel);
- }
- catch (Exception)
- {
- await _mediator.Publish(new RemoveSignatureNotification()
- {
- EnvelopeId = docSignedNotification.EnvelopeReceiver.EnvelopeId,
- ReceiverId = docSignedNotification.EnvelopeReceiver.ReceiverId
- }, cancel);
- throw;
- }
- await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
-
- return Ok();
- }
-
- ///
- /// Rejects the document for the current receiver.
- ///
- /// Optional rejection reason.
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpPost("reject")]
- [Obsolete("Use MediatR")]
- public async Task Reject([FromBody] string? reason = null)
- {
- var signature = User.ReceiverSignature();
- var uuid = User.EnvelopeUuid();
- var mail = User.ReceiverMail();
-
- var envRcvRes = await _envelopeReceiverService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature);
-
- if (envRcvRes.IsFailed)
- {
- _logger.LogNotice(envRcvRes.Notices);
- return Unauthorized("you are not authorized");
- }
-
- var histRes = await _historyService.RecordAsync(envRcvRes.Data.EnvelopeId, userReference: mail, EnvelopeStatus.DocumentRejected, comment: reason);
- if (histRes.IsSuccess)
- {
- await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
- return NoContent();
- }
-
- _logger.LogEnvelopeError(uuid: uuid, signature: signature, message: "Unexpected error happened in api/envelope/reject");
- _logger.LogNotice(histRes.Notices);
- return StatusCode(500, histRes.Messages);
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/AuthController.cs b/EnvelopeGenerator.API/Controllers/AuthController.cs
deleted file mode 100644
index 56e710d8..00000000
--- a/EnvelopeGenerator.API/Controllers/AuthController.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using DigitalData.Auth.Claims;
-using EnvelopeGenerator.API.Controllers.Interfaces;
-using EnvelopeGenerator.API.Models;
-using EnvelopeGenerator.Domain.Constants;
-using Microsoft.AspNetCore.Authentication;
-using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Options;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Controller verantwortlich für die Benutzer-Authentifizierung, einschließlich Anmelden, Abmelden und Überprüfung des Authentifizierungsstatus.
-///
-[Route("api/[controller]")]
-[ApiController]
-public partial class AuthController(IOptions authTokenKeyOptions, IAuthorizationService authService) : ControllerBase, IAuthController
-{
- private readonly AuthTokenKeys authTokenKeys = authTokenKeyOptions.Value;
-
- ///
- ///
- ///
- public IAuthorizationService AuthService { get; } = authService;
-
- ///
- /// Entfernt das Authentifizierungs-Cookie des Benutzers (AuthCookie)
- ///
- ///
- /// Gibt eine HTTP 200 oder 401.
- ///
- ///
- /// Sample request:
- ///
- /// POST /api/auth/logout
- ///
- ///
- /// Erfolgreich gelöscht, wenn der Benutzer ein berechtigtes Cookie hat.
- /// Wenn es kein zugelassenes Cookie gibt, wird „nicht zugelassen“ zurückgegeben.
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
- [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
- [Authorize(AuthenticationSchemes = AuthScheme.Sender)]
- [HttpPost("logout")]
- public async Task Logout()
- {
- if (await this.IsUserInPolicyAsync(AuthPolicy.Sender))
- Response.Cookies.Delete(authTokenKeys.Cookie);
- else if (await this.IsUserInPolicyAsync(AuthPolicy.ReceiverOrReceiverTFA))
- await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
- else
- return Unauthorized();
-
- return Ok();
- }
-
- ///
- /// Prüft, ob der Benutzer ein autorisiertes Token hat.
- ///
- /// Wenn ein autorisiertes Token vorhanden ist HTTP 200 asynchron 401
- ///
- /// Sample request:
- ///
- /// GET /api/auth
- ///
- ///
- /// Wenn es einen autorisierten Cookie gibt.
- /// Wenn kein Cookie vorhanden ist oder nicht autorisierte.
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
- [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
- [HttpGet("check")]
- [Authorize(AuthenticationSchemes = AuthScheme.Sender)]
- public IActionResult Check(string? role = null)
- => role is not null && !User.IsInRole(role)
- ? Unauthorized()
- : Ok();
-
- ///
- /// Checks whether the caller holds a valid per-envelope receiver token for the given envelope key.
- /// The request must carry a cookie named AuthTokenSignFLOWReceiver.{envelopeKey}.
- ///
- /// The unique envelope key extracted from the route.
- /// Valid per-envelope token found.
- /// Token is missing, expired or invalid.
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
- [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpGet("check/envelope/{envelopeKey}")]
- public IActionResult CheckEnvelopeReceiver([FromRoute] string envelopeKey) => Ok();
-
- ///
- /// Removes the per-envelope receiver cookie for the given envelope key.
- ///
- /// The unique envelope key whose cookie should be deleted.
- /// Cookie successfully deleted.
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
- [HttpPost("logout/envelope/{envelopeKey}")]
- public IActionResult LogoutEnvelopeReceiver([FromRoute] string envelopeKey)
- {
- var cookieName = CookieNames.GetEnvelopeReceiverCookieName(authTokenKeys.Cookie, envelopeKey);
- Response.Cookies.Delete(cookieName);
- return Ok();
- }
-
- ///
- /// Removes all per-envelope receiver cookies from the current request.
- ///
- /// All envelope receiver cookies successfully deleted.
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
- [HttpPost("logout/envelope")]
- public IActionResult LogoutAllEnvelopeReceivers()
- {
- foreach (var cookieName in Request.Cookies.Keys.Where(k => CookieNames.IsEnvelopeReceiverCookie(k, authTokenKeys.Cookie)))
- Response.Cookies.Delete(cookieName);
- return Ok();
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/CacheController.cs b/EnvelopeGenerator.API/Controllers/CacheController.cs
deleted file mode 100644
index 8379d4eb..00000000
--- a/EnvelopeGenerator.API/Controllers/CacheController.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.Options;
-using System.Text.Json;
-using EnvelopeGenerator.API.Options;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.API.Extensions;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Manages cached data for receivers using distributed cache.
-///
-[ApiController]
-[Route("api/[controller]")]
-[Authorize(Policy = AuthPolicy.Receiver)]
-public class CacheController(
- IDistributedCache cache,
- IOptions cacheOptions) : ControllerBase
-{
- private const string SignatureCacheKeyPrefix = "envelope-generator.receiver-ui.signature:";
-
- ///
- /// Stores a receiver's signature in cache for the specified envelope.
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpPost("SignatureCapture/{envelopeKey}")]
- public async Task SaveSignature(
- [FromRoute] string envelopeKey,
- [FromBody] SignatureCacheRequest request,
- CancellationToken cancel)
- {
- var cacheKey = $"{SignatureCacheKeyPrefix}{User.ReceiverSignature()}";
- var json = JsonSerializer.Serialize(request);
-
- var options = cacheOptions.Value.SignatureCacheExpiration.HasValue
- ? new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = cacheOptions.Value.SignatureCacheExpiration.Value }
- : null;
-
- await cache.SetStringAsync(cacheKey, json, options ?? new DistributedCacheEntryOptions(), cancel);
-
- return Ok();
- }
-
- ///
- /// Retrieves a cached signature for the specified envelope.
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpGet("SignatureCapture/{envelopeKey}")]
- public async Task GetSignature([FromRoute] string envelopeKey, CancellationToken cancel)
- {
- var cacheKey = $"{SignatureCacheKeyPrefix}{User.ReceiverSignature()}";
- var json = await cache.GetStringAsync(cacheKey, cancel);
-
- if (json is null)
- return NotFound();
-
- var signature = JsonSerializer.Deserialize(json);
- return Ok(signature);
- }
-
- ///
- /// Deletes a cached signature for the specified envelope.
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpDelete("SignatureCapture/{envelopeKey}")]
- public async Task DeleteSignature([FromRoute] string envelopeKey, CancellationToken cancel)
- {
- var cacheKey = $"{SignatureCacheKeyPrefix}{User.ReceiverSignature()}";
- await cache.RemoveAsync(cacheKey, cancel);
-
- return Ok();
- }
-}
-
-///
-/// Request model for caching signature data.
-///
-public sealed record SignatureCacheRequest(
- string DataUrl,
- string FullName,
- string Place,
- string? Position = null);
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/ConfigController.cs b/EnvelopeGenerator.API/Controllers/ConfigController.cs
deleted file mode 100644
index 117252a2..00000000
--- a/EnvelopeGenerator.API/Controllers/ConfigController.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-using EnvelopeGenerator.Domain.Constants;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Options;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Exposes configuration data required by the client applications.
-///
-///
-/// Initializes a new instance of .
-///
-[Route("api/[controller]")]
-[ApiController]
-[Authorize(Policy = AuthPolicy.SenderOrReceiver)]
-public class ConfigController(IOptionsMonitor annotationParamsOptions) : ControllerBase
-{
- private readonly AnnotationParams _annotationParams = annotationParamsOptions.CurrentValue;
-
- ///
- /// Returns annotation configuration that was previously rendered by MVC.
- ///
- [HttpGet("Annotations")]
- [Obsolete("PSPDF Kit will no longer be used.")]
- public IActionResult GetAnnotationParams()
- {
- return Ok(_annotationParams.AnnotationJSObject);
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/DocReceiverElementController.cs b/EnvelopeGenerator.API/Controllers/DocReceiverElementController.cs
deleted file mode 100644
index 6c234117..00000000
--- a/EnvelopeGenerator.API/Controllers/DocReceiverElementController.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using EnvelopeGenerator.API.Extensions;
-using EnvelopeGenerator.Application.Common.Dto;
-using EnvelopeGenerator.Application.Common.Extensions;
-using EnvelopeGenerator.Application.Documents.Queries;
-using EnvelopeGenerator.Domain.Constants;
-using MediatR;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-///
-///
-[Authorize(Policy = AuthPolicy.Receiver)]
-[ApiController]
-[Route("api/[controller]")]
-public class DocReceiverElementController : ControllerBase
-{
- private readonly IMediator _mediator;
-
- ///
- /// Initializes a new instance of .
- ///
- public DocReceiverElementController(IMediator mediator)
- {
- _mediator = mediator;
- }
-
- //TODO: update to use signature query
- ///
- ///
- ///
- ///
- ///
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpGet("{envelopeKey}")]
- public async Task Get(string envelopeKey, CancellationToken cancel)
- {
- int envelopeId = User.EnvelopeId();
-
- int receiverId = User.ReceiverId();
-
- var doc = await _mediator.Send(new ReadDocumentQuery() { EnvelopeId = envelopeId }, cancel);
-
- if (doc.Elements is not IEnumerable docSignatures)
- return NotFound("Document is empty.");
-
- var rcvSignatures = docSignatures.Where(s => s.ReceiverId == receiverId).ToList();
-
- if (rcvSignatures is null)
- return NotFound("No signatures found for the current receiver.");
- else
- return Ok(rcvSignatures);
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/DocumentController.cs b/EnvelopeGenerator.API/Controllers/DocumentController.cs
deleted file mode 100644
index f8468f81..00000000
--- a/EnvelopeGenerator.API/Controllers/DocumentController.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using DigitalData.Auth.Claims;
-using EnvelopeGenerator.API.Controllers.Interfaces;
-using EnvelopeGenerator.API.Extensions;
-using EnvelopeGenerator.Application.Documents.Queries;
-using EnvelopeGenerator.Domain.Constants;
-using MediatR;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Provides access to envelope documents for authenticated receivers.
-///
-///
-/// Initializes a new instance of the class.
-///
-[ApiController]
-[Route("api/[controller]")]
-public class DocumentController(IMediator mediator, IAuthorizationService authService, ILogger logger) : ControllerBase, IAuthController
-{
- ///
- ///
- ///
- public IAuthorizationService AuthService => authService;
-
- ///
- /// Returns the document bytes receiver.
- ///
- /// Encoded envelope key.
- /// Cancellation token.
- [HttpGet]
- [Authorize(Policy = AuthPolicy.SenderOrReceiver)]
- public async Task GetDocument(CancellationToken cancel, [FromQuery] ReadDocumentQuery? query = null)
- {
- // Sender: expects query with envelope key
- if (await this.IsUserInPolicyAsync(AuthPolicy.Sender))
- {
- if (query is null)
- return BadRequest("Missing document query.");
-
- var senderDoc = await mediator.Send(query, cancel);
- return senderDoc.ByteData is byte[] senderDocByte
- ? File(senderDocByte, "application/octet-stream")
- : NotFound("Document is empty.");
- }
-
- // Receiver: resolve envelope id from claims
- if (await this.IsUserInPolicyAsync(AuthPolicy.Receiver))
- {
- if (query is not null)
- return BadRequest("Query parameters are not allowed for receiver role.");
-
- var envelopeId = User.EnvelopeId();
- var receiverDoc = await mediator.Send(new ReadDocumentQuery { EnvelopeId = envelopeId }, cancel);
- return receiverDoc.ByteData is byte[] receiverDocByte
- ? File(receiverDocByte, "application/octet-stream")
- : NotFound("Document is empty.");
- }
-
- return Unauthorized();
- }
-
- ///
- /// Gets the document for the specified envelope key.
- ///
- ///
- ///
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpGet("{envelopeKey}")]
- public async Task GetDocumentOfReceiver(string envelopeKey, CancellationToken cancel)
- {
- int envelopeId = User.EnvelopeId();
-
- var senderDoc = await mediator.Send(new ReadDocumentQuery() { EnvelopeId = envelopeId }, cancel);
-
- if (senderDoc.ByteData is not byte[] senderDocByte)
- return NotFound("Document is empty.");
-
- Response.Headers.ContentDisposition = $"inline; filename=\"{envelopeKey}.pdf\"";
- return File(senderDocByte, "application/pdf");
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/EmailTemplateController.cs b/EnvelopeGenerator.API/Controllers/EmailTemplateController.cs
deleted file mode 100644
index be670e42..00000000
--- a/EnvelopeGenerator.API/Controllers/EmailTemplateController.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using AutoMapper;
-using EnvelopeGenerator.Application.EmailTemplates.Commands;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using MediatR;
-using EnvelopeGenerator.Application.Common.Dto;
-using DigitalData.Core.Abstraction.Application.Repository;
-using EnvelopeGenerator.Domain.Entities;
-using Microsoft.EntityFrameworkCore;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.Application.EmailTemplates.Queries;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Controller for managing temp templates.
-/// Steuerung zur Verwaltung von E-Mail-Vorlagen.
-///
-///
-/// Initialisiert eine neue Instanz der -Klasse.
-///
-///
-/// Die Mediator-Instanz, die zum Senden von Befehlen und Abfragen verwendet wird.
-///
-[Route("api/[controller]")]
-[ApiController]
-[Authorize(Policy = AuthPolicy.Sender)]
-public class EmailTemplateController(IMediator mediator) : ControllerBase
-{
- ///
- /// Ruft E-Mail-Vorlagen basierend auf der angegebenen Abfrage ab.
- /// Gibt alles zurück, wenn keine Id- oder Typ-Informationen eingegeben wurden.
- ///
- /// Die Abfrageparameter zum Abrufen von E-Mail-Vorlagen.
- ///
- /// Gibt HTTP-Antwort zurück
- ///
- /// Sample request:
- /// GET /api/EmailTemplate?emailTemplateId=123
- ///
- /// Wenn die E-Mail-Vorlagen erfolgreich abgerufen werden.
- /// Wenn die Abfrageparameter ungültig sind.
- /// Wenn der Benutzer nicht authentifiziert ist.
- /// Wenn die gesuchte Abfrage nicht gefunden wird.
- [HttpGet]
- public async Task Get([FromQuery] ReadEmailTemplateQuery emailTemplate, CancellationToken cancel)
- {
- var result = await mediator.Send(emailTemplate, cancel);
- return Ok(result);
- }
-
- ///
- /// Updates an temp template or resets it if no update command is provided.
- /// Aktualisiert eine E-Mail-Vorlage oder setzt sie zurück, wenn kein Aktualisierungsbefehl angegeben ist.
- ///
- ///
- ///
- ///
- /// Wenn die E-Mail-Vorlage erfolgreich aktualisiert oder zurückgesetzt wird.
- /// Wenn die Abfrage ohne einen String gesendet wird.
- /// Wenn der Benutzer nicht authentifiziert ist.
- /// Wenn die gesuchte Abfrage nicht gefunden wird.
- [HttpPut]
- public async Task Update([FromBody] UpdateEmailTemplateCommand update, CancellationToken cancel)
- {
- await mediator.Send(update, cancel);
- return Ok();
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/EnvelopeController.cs b/EnvelopeGenerator.API/Controllers/EnvelopeController.cs
deleted file mode 100644
index c1bb54d2..00000000
--- a/EnvelopeGenerator.API/Controllers/EnvelopeController.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using EnvelopeGenerator.API.Extensions;
-using EnvelopeGenerator.Application.Envelopes.Commands;
-using EnvelopeGenerator.Application.Envelopes.Queries;
-using MediatR;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Newtonsoft.Json;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Dieser Controller stellt Endpunkte für die Verwaltung von Umschlägen bereit.
-///
-///
-/// Die API ermöglicht das Abrufen und Verwalten von Umschlägen basierend auf Benutzerinformationen und Statusfiltern.
-///
-/// Mögliche Antworten:
-/// - 200 OK: Die Anfrage war erfolgreich, und die angeforderten Daten werden zurückgegeben.
-/// - 400 Bad Request: Die Anfrage war fehlerhaft oder unvollständig.
-/// - 401 Unauthorized: Der Benutzer ist nicht authentifiziert.
-/// - 403 Forbidden: Der Benutzer hat keine Berechtigung, auf die Ressource zuzugreifen.
-/// - 404 Not Found: Die angeforderte Ressource wurde nicht gefunden.
-/// - 500 Internal Server Error: Ein unerwarteter Fehler ist aufgetreten.
-///
-[Route("api/[controller]")]
-[ApiController]
-[Authorize]
-public class EnvelopeController : ControllerBase
-{
- private readonly ILogger _logger;
- private readonly IMediator _mediator;
-
- ///
- /// Erstellt eine neue Instanz des EnvelopeControllers.
- ///
- /// Der Logger, der für das Protokollieren von Informationen verwendet wird.
- ///
- public EnvelopeController(ILogger logger, IMediator mediator)
- {
- _logger = logger;
- _mediator = mediator;
- }
-
- ///
- /// Ruft eine Liste von Umschlägen basierend auf dem Benutzer und den angegebenen Statusfiltern ab.
- ///
- ///
- /// Eine IActionResult-Instanz, die die abgerufenen Umschläge oder einen Fehlerstatus enthält.
- /// Die Anfrage war erfolgreich, und die Umschläge werden zurückgegeben.
- /// Die Anfrage war fehlerhaft oder unvollständig.
- /// Der Benutzer ist nicht authentifiziert.
- /// Der Benutzer hat keine Berechtigung, auf die Ressource zuzugreifen.
- /// Ein unerwarteter Fehler ist aufgetreten.
- [Authorize(AuthenticationSchemes = AuthScheme.Sender)]
- [HttpGet]
- public async Task GetAsync([FromQuery] ReadEnvelopeQuery envelope)
- {
- var result = await _mediator.Send(envelope.Authorize(User.GetId()));
- return result.Any() ? Ok(result) : NotFound();
- }
-
- ///
- /// Ruft das Ergebnis eines Dokuments basierend auf der ID ab.
- ///
- ///
- /// Gibt an, ob das Dokument inline angezeigt werden soll (true) oder als Download bereitgestellt wird (false).
- /// Eine IActionResult-Instanz, die das Dokument oder einen Fehlerstatus enthält.
- /// Das Dokument wurde erfolgreich abgerufen.
- /// Das Dokument wurde nicht gefunden oder ist nicht verfügbar.
- /// Ein unerwarteter Fehler ist aufgetreten.
- [HttpGet("doc-result")]
- public async Task GetDocResultAsync([FromQuery] ReadEnvelopeQuery query, [FromQuery] bool view = false)
- {
- var envelopes = await _mediator.Send(query.Authorize(User.GetId()));
- var envelope = envelopes.FirstOrDefault();
-
- if (envelope is null)
- return NotFound("Envelope not available.");
- if (envelope.DocResult is null)
- return NotFound("The document has not been fully signed or the result has not yet been released.");
-
- if (view)
- {
- Response.Headers.Append("Content-Disposition", "inline; filename=\"" + envelope.Uuid + ".pdf\"");
- return File(envelope.DocResult, "application/pdf");
- }
-
- return File(envelope.DocResult, "application/pdf", $"{envelope.Uuid}.pdf");
- }
-
- ///
- ///
- ///
- ///
- ///
- [NonAction]
- [Authorize]
- [HttpPost]
- public async Task CreateAsync([FromBody] CreateEnvelopeCommand command)
- {
- var res = await _mediator.Send(command.WithAuth(User.GetId()));
-
- if (res is null)
- {
- _logger.LogError("Failed to create envelope. Envelope details: {EnvelopeDetails}", JsonConvert.SerializeObject(command));
- return StatusCode(StatusCodes.Status500InternalServerError);
- }
- else
- return Ok(res);
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/EnvelopeReceiverController.cs b/EnvelopeGenerator.API/Controllers/EnvelopeReceiverController.cs
deleted file mode 100644
index 55ee0f71..00000000
--- a/EnvelopeGenerator.API/Controllers/EnvelopeReceiverController.cs
+++ /dev/null
@@ -1,281 +0,0 @@
-using AutoMapper;
-using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
-using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
-using EnvelopeGenerator.Application.Envelopes.Queries;
-using EnvelopeGenerator.Domain.Entities;
-using EnvelopeGenerator.API.Models;
-using MediatR;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Data.SqlClient;
-using Microsoft.Extensions.Options;
-using System.Data;
-using EnvelopeGenerator.Application.Common.SQL;
-using EnvelopeGenerator.Application.Common.Dto.Receiver;
-using EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
-using EnvelopeGenerator.API.Extensions;
-using EnvelopeGenerator.Domain.Constants;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Controller für die Verwaltung von Umschlagempfängern.
-///
-///
-/// Dieser Controller bietet Endpunkte für das Abrufen und Verwalten von Umschlagempfängerdaten.
-///
-[Route("api/[controller]")]
-[Authorize]
-[ApiController]
-public class EnvelopeReceiverController : ControllerBase
-{
- private readonly ILogger _logger;
- private readonly IMediator _mediator;
- private readonly IMapper _mapper;
- private readonly IEnvelopeExecutor _envelopeExecutor;
- private readonly IEnvelopeReceiverExecutor _erExecutor;
- private readonly IDocumentExecutor _documentExecutor;
- private readonly string _cnnStr;
-
- ///
- /// Konstruktor für den EnvelopeReceiverController.
- ///
- public EnvelopeReceiverController(ILogger logger, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor, IDocumentExecutor documentExecutor, IOptions csOpt)
- {
- _logger = logger;
- _mediator = mediator;
- _mapper = mapper;
- _envelopeExecutor = envelopeExecutor;
- _erExecutor = erExecutor;
- _documentExecutor = documentExecutor;
- _cnnStr = csOpt.Value.Value;
- }
-
- ///
- /// Ruft eine Liste von Umschlagempfängern basierend auf den angegebenen Abfrageparametern ab.
- ///
- /// Die Abfrageparameter für die Filterung von Umschlagempfängern.
- /// Eine HTTP-Antwort mit der Liste der gefundenen Umschlagempfänger oder einem Fehlerstatus.
- ///
- /// Dieser Endpunkt ermöglicht es, Umschlagempfänger basierend auf dem Benutzernamen und optionalen Statusfiltern abzurufen.
- /// Wenn der Benutzername nicht ermittelt werden kann, wird ein Serverfehler zurückgegeben.
- ///
- /// Die Liste der Umschlagempfänger wurde erfolgreich abgerufen.
- /// Wenn kein autorisierter Token vorhanden ist
- /// Ein unerwarteter Fehler ist aufgetreten.
- [Authorize]
- [HttpGet]
- public async Task GetEnvelopeReceiver([FromQuery] ReadEnvelopeReceiverQuery envelopeReceiver)
- {
- envelopeReceiver = envelopeReceiver with { Username = User.GetUsername() };
-
- var result = await _mediator.Send(envelopeReceiver);
-
- return Ok(result);
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpGet("{envelopeKey}")]
- public async Task GetEnvelopeReceiverOfReceiver([FromRoute] string envelopeKey, CancellationToken cancel)
- {
- var er = await _mediator.Send(new ReadEnvelopeReceiverQuery()
- {
- Key = envelopeKey
- }, cancel);
-
- return Ok(er.SingleOrDefault());
- }
-
- ///
- /// Ruft den Namen des zuletzt verwendeten Empfängers basierend auf der angegebenen E-Mail-Adresse ab.
- ///
- /// Abfrage, bei der nur eine der Angaben ID, Signatur oder E-Mail-Adresse des Empfängers eingegeben werden muss.
- /// Eine HTTP-Antwort mit dem Namen des Empfängers oder einem Fehlerstatus.
- ///
- /// Dieser Endpunkt ermöglicht es, den Namen des zuletzt verwendeten Empfängers basierend auf der E-Mail-Adresse abzurufen.
- ///
- /// Der Name des Empfängers wurde erfolgreich abgerufen.
- /// Wenn kein autorisierter Token vorhanden ist
- /// Kein Empfänger gefunden.
- /// Ein unerwarteter Fehler ist aufgetreten.
- [Authorize]
- [HttpGet("salute")]
- public async Task GetReceiverName([FromQuery] ReadReceiverNameQuery receiver)
- {
- var name = await _mediator.Send(receiver);
- return name is null ? NotFound() : Ok(name);
- }
-
- ///
- /// Datenübertragungsobjekt mit Informationen zu Umschlägen, Empfängern und Unterschriften.
- ///
- ///
- ///
- /// HTTP-Antwort
- ///
- /// Sample request:
- ///
- /// POST /api/envelope
- /// {
- /// "title": "Vertragsdokument",
- /// "message": "Bitte unterschreiben Sie dieses Dokument.",
- /// "document": {
- /// "dataAsBase64": "dGVzdC1iYXNlNjQtZGF0YQ=="
- /// },
- /// "receivers": [
- /// {
- /// "emailAddress": "example@example.com",
- /// "signatures": [
- /// {
- /// "x": 100,
- /// "y": 200,
- /// "page": 1
- /// }
- /// ],
- /// "name": "Max Mustermann",
- /// "phoneNumber": "+49123456789"
- /// }
- /// ],
- /// "tfaEnabled": false
- /// }
- ///
- ///
- /// Envelope-Erstellung und Sendeprozessbefehl erfolgreich
- /// Wenn ein Fehler im HTTP-Body auftritt
- /// Wenn kein autorisierter Token vorhanden ist
- /// Es handelt sich um einen unerwarteten Fehler. Die Protokolle sollten überprüft werden.
- [Authorize]
- [HttpPost]
- public async Task CreateAsync([FromBody] CreateEnvelopeReceiverCommand request, CancellationToken cancel)
- {
- #region Create Envelope
- var envelope = await _envelopeExecutor.CreateEnvelopeAsync(User.GetId(), request.Title, request.Message, request.TFAEnabled, cancel);
- #endregion
-
- #region Add receivers
- List sentReceivers = new();
- List unsentReceivers = new();
-
- foreach (var receiver in request.Receivers)
- {
- var envelopeReceiver = await _erExecutor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel);
-
- if (envelopeReceiver is null)
- unsentReceivers.Add(receiver);
- else
- sentReceivers.Add(envelopeReceiver);
- }
-
- var res = _mapper.Map(envelope);
- res.UnsentReceivers = unsentReceivers;
- res.SentReceiver = _mapper.Map>(sentReceivers.Select(er => er.Receiver));
- #endregion
-
- #region Add document
- var document = await _documentExecutor.CreateDocumentAsync(request.Document.DataAsBase64, envelope.Uuid, cancel);
-
- if (document is null)
- return StatusCode(StatusCodes.Status500InternalServerError, "Document creation is failed.");
- #endregion
-
- #region Add document element
- // @DOC_ID, @RECEIVER_ID, @POSITION_X, @POSITION_Y, @PAGE
- string sql = @"
- DECLARE @OUT_SUCCESS bit;
-
- EXEC [dbo].[PRSIG_API_ADD_DOC_RECEIVER_ELEM]
- {0},
- {1},
- {2},
- {3},
- {4},
- @OUT_SUCCESS OUTPUT;
-
- SELECT @OUT_SUCCESS as [@OUT_SUCCESS];";
-
- foreach (var rcv in res.SentReceiver)
- foreach (var sign in request.Receivers.Where(r => r.EmailAddress == rcv.EmailAddress).FirstOrDefault()?.DocReceiverElements ?? Enumerable.Empty())
- {
- using SqlConnection conn = new(_cnnStr);
- conn.Open();
-
- var formattedSQL = string.Format(sql, document.Id.ToSqlParam(), rcv.Id.ToSqlParam(), sign.X.ToSqlParam(), sign.Y.ToSqlParam(), sign.Page.ToSqlParam());
-
- using SqlCommand cmd = new(formattedSQL, conn);
- cmd.CommandType = CommandType.Text;
-
- using SqlDataReader reader = cmd.ExecuteReader();
- if (reader.Read())
- {
- bool outSuccess = reader.GetBoolean(0);
- if (!outSuccess)
- _logger.LogWarning(
- "PRSIG_API_ADD_DOC_RECEIVER_ELEM returned OUT_SUCCESS=false. DOC_ID={DocId}, RECEIVER_ID={ReceiverId}, Page={Page}",
- document.Id, rcv.Id, sign.Page);
- }
- }
- #endregion
-
- #region Create history
- // ENV_UID, STATUS_ID, USER_ID,
- string sql_hist = @"
- DECLARE @OUT_SUCCESS bit;
-
- EXEC [dbo].[PRSIG_API_ADD_HISTORY_STATE]
- {0},
- {1},
- {2},
- @OUT_SUCCESS OUTPUT;
-
- SELECT @OUT_SUCCESS as [@OUT_SUCCESS];";
-
- using (SqlConnection conn = new(_cnnStr))
- {
- conn.Open();
- var formattedSQL_hist = string.Format(sql_hist, envelope.Uuid.ToSqlParam(), 1003.ToSqlParam(), User.GetId().ToSqlParam());
- using SqlCommand cmd = new(formattedSQL_hist, conn);
- cmd.CommandType = CommandType.Text;
-
- using SqlDataReader reader = cmd.ExecuteReader();
- if (reader.Read())
- {
- bool outSuccess = reader.GetBoolean(0);
- if (!outSuccess)
- _logger.LogWarning(
- "PRSIG_API_ADD_HISTORY_STATE returned OUT_SUCCESS=false. EnvelopeUuid={EnvelopeUuid}",
- envelope.Uuid);
- }
- }
- #endregion
-
- return Ok(res);
- }
-
- ///
- ///
- ///
- ///
- ///
- public static bool IsBase64String(string input)
- {
- if (string.IsNullOrWhiteSpace(input))
- return false;
-
- try
- {
- Convert.FromBase64String(input);
- return true;
- }
- catch (FormatException)
- {
- return false;
- }
- }
-
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs b/EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs
deleted file mode 100644
index e6fc6095..00000000
--- a/EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediatR;
-using EnvelopeGenerator.Application.EnvelopeTypes.Queries;
-using Microsoft.AspNetCore.Mvc;
-
-namespace EnvelopeGenerator.GeneratorAPI.Controllers;
-
-///
-///
-///
-[ApiExplorerSettings(IgnoreApi = true)]
-[Route("api/[controller]")]
-[ApiController]
-public class EnvelopeTypeController : ControllerBase
-{
- private readonly ILogger _logger;
- private readonly IMediator _mediator;
-
- ///
- ///
- ///
- ///
- ///
- public EnvelopeTypeController(ILogger logger, IMediator mediator)
- {
- _logger = logger;
- _mediator = mediator;
- }
-
- ///
- ///
- ///
- ///
- [HttpGet]
- public async Task GetAllAsync()
- {
- var result = await _mediator.Send(new ReadEnvelopeTypesQuery());
- return Ok(result);
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/HistoryController.cs b/EnvelopeGenerator.API/Controllers/HistoryController.cs
deleted file mode 100644
index 16418fa3..00000000
--- a/EnvelopeGenerator.API/Controllers/HistoryController.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using MediatR;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Caching.Memory;
-using EnvelopeGenerator.Application.Histories.Queries;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.Application.Common.Extensions;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Dieser Controller stellt Endpunkte für den Zugriff auf die Umschlaghistorie bereit.
-///
-[Route("api/[controller]")]
-[ApiController]
-[Authorize]
-public class HistoryController : ControllerBase
-{
- private readonly IMemoryCache _memoryCache;
-
- private readonly IMediator _mediator;
-
- ///
- /// Konstruktor für den HistoryController.
- ///
- ///
- ///
- public HistoryController(IMemoryCache memoryCache, IMediator mediator)
- {
- _memoryCache = memoryCache;
- _mediator = mediator;
- }
-
- ///
- /// Gibt alle möglichen Verweise auf alle möglichen Include in einem Verlaufsdatensatz zurück. (z. B. DocumentSigned bezieht sich auf Receiver.)
- /// Dies wird hinzugefügt, damit Client-Anwendungen sich selbst auf dem neuesten Stand halten können.
- /// 1 - Sender:
- /// Historische Datensätze über den Include der Empfänger. Diese haben Statuscodes, die mit 1* beginnen.
- /// 2 - Receiver:
- /// Historische Datensätze, die sich auf den Include des Absenders beziehen. Sie haben Statuscodes, die mit 2* beginnen.
- /// 3 - System:
- /// Historische Datensätze, die sich auf den allgemeinen Zustand des Umschlags beziehen. Diese haben Statuscodes, die mit 3* beginnen.
- /// 4 - Unknown:
- /// Ein unbekannter Datensatz weist auf einen möglichen Mangel oder eine Unstimmigkeit im Aktualisierungsprozess der Anwendung hin.
- ///
- ///
- ///
- [HttpGet("related")]
- [Authorize]
- public IActionResult GetReferenceTypes(ReferenceType? referenceType = null)
- {
- return referenceType is null
- ? Ok(_memoryCache.GetEnumAsDictionary("gen.api", ReferenceType.Unknown))
- : Ok(referenceType.ToString());
- }
-
- ///
- /// Gibt alle möglichen Include in einem Verlaufsdatensatz zurück.
- /// Dies wird hinzugefügt, damit Client-Anwendungen sich selbst auf dem neuesten Stand halten können.
- /// 1003: EnvelopeQueued
- /// 1006: EnvelopeCompletelySigned
- /// 1007: EnvelopeReportCreated
- /// 1008: EnvelopeArchived
- /// 1009: EnvelopeDeleted
- /// 10007: EnvelopeRejected
- /// 10009: EnvelopeWithdrawn
- /// 2001: AccessCodeRequested
- /// 2002: AccessCodeCorrect
- /// 2003: AccessCodeIncorrect
- /// 2004: DocumentOpened
- /// 2005: DocumentSigned
- /// 2006: DocumentForwarded
- /// 2007: DocumentRejected
- /// 2008: EnvelopeShared
- /// 2009: EnvelopeViewed
- /// 3001: MessageInvitationSent (Wird von Trigger verwendet)
- /// 3002: MessageAccessCodeSent
- /// 3003: MessageConfirmationSent
- /// 3004: MessageDeletionSent
- /// 3005: MessageCompletionSent
- ///
- ///
- /// Abfrageparameter, der angibt, auf welche Referenz sich der Include bezieht.
- /// 1 - Sender: Historische Datensätze, die sich auf den Include des Absenders beziehen. Sie haben Statuscodes, die mit 1* beginnen.
- /// 2 - Receiver: Historische Datensätze über den Include der Empfänger. Diese haben Statuscodes, die mit 2* beginnen.
- /// 3 - System: Diese werden durch Datenbank-Trigger aktualisiert und sind in den Tabellen EnvelopeHistory und EmailOut zu finden.Sie arbeiten
- /// integriert mit der Anwendung EmailProfiler, um E-Mails zu versenden und haben die Codes, die mit 3* beginnen.
- ///
- /// Gibt die HTTP-Antwort zurück.
- ///
- [HttpGet("status")]
- [Authorize]
- public IActionResult GetEnvelopeStatus([FromQuery] EnvelopeStatus? status = null)
- {
- return status is null
- ? Ok(_memoryCache.GetEnumAsDictionary("gen.api", Status.NonHist, Status.RelatedToFormApp))
- : Ok(status.ToString());
- }
-
- ///
- /// Ruft die gesamte Umschlaghistorie basierend auf den angegebenen Abfrageparametern ab.
- ///
- /// Die Abfrageparameter, die die Filterkriterien für die Umschlaghistorie definieren.
- ///
- /// Eine Liste von Historieneinträgen, die den angegebenen Kriterien entsprechen, oder nur der letzte Eintrag.
- /// Die Anfrage war erfolgreich, und die Umschlaghistorie wird zurückgegeben.
- /// Die Anfrage war ungültig oder unvollständig.
- /// Der Benutzer ist nicht authentifiziert.
- /// Der Benutzer hat keine Berechtigung, auf die Ressource zuzugreifen.
- /// Ein unerwarteter Fehler ist aufgetreten.
- [HttpGet]
- [Authorize]
- public async Task GetAllAsync([FromQuery] ReadHistoryQuery historyQuery, CancellationToken cancel)
- {
- var history = await _mediator.Send(historyQuery, cancel).ThrowIfEmpty(Exceptions.NotFound);
- return Ok((historyQuery.OnlyLast) ? history.MaxBy(h => h.AddedWhen) : history);
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/Interfaces/IAuthController.cs b/EnvelopeGenerator.API/Controllers/Interfaces/IAuthController.cs
deleted file mode 100644
index cf31d972..00000000
--- a/EnvelopeGenerator.API/Controllers/Interfaces/IAuthController.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System.Security.Claims;
-using Microsoft.AspNetCore.Authorization;
-
-namespace EnvelopeGenerator.API.Controllers.Interfaces;
-
-///
-///
-///
-public interface IAuthController
-{
- ///
- ///
- ///
- IAuthorizationService AuthService { get; }
-
- ///
- ///
- ///
- ClaimsPrincipal User { get; }
-}
-
-///
-///
-///
-public static class AuthControllerExtensions
-{
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task IsUserInPolicyAsync(this IAuthController controller, string policyName)
- {
- var result = await controller.AuthService.AuthorizeAsync(controller.User, policyName);
- return result.Succeeded;
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/LocalizationController.cs b/EnvelopeGenerator.API/Controllers/LocalizationController.cs
deleted file mode 100644
index e2e02de2..00000000
--- a/EnvelopeGenerator.API/Controllers/LocalizationController.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using DigitalData.Core.API;
-using EnvelopeGenerator.Application.Resources;
-using Microsoft.AspNetCore.Localization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Localization;
-using EnvelopeGenerator.Application.Resources;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Controller für die Verwaltung der Lokalisierung und Spracheinstellungen.
-///
-[ApiExplorerSettings(IgnoreApi = true)]
-[Route("api/[controller]")]
-[ApiController]
-public class LocalizationController : ControllerBase
-{
- private static readonly Guid L_KEY = Guid.NewGuid();
-
- private readonly ILogger _logger;
- private readonly IStringLocalizer _mLocalizer;
- private readonly IStringLocalizer _localizer;
- private readonly IMemoryCache _cache;
-
- ///
- /// Konstruktor für den .
- ///
- /// Logger für die Protokollierung.
- /// Lokalisierungsdienst für Ressourcen.
- /// Speicher-Cache für die Zwischenspeicherung von Daten.
- /// Lokalisierungsdienst für Modelle.
- public LocalizationController(
- ILogger logger,
- IStringLocalizer localizer,
- IMemoryCache memoryCache,
- IStringLocalizer _modelLocalizer)
- {
- _logger = logger;
- _localizer = localizer;
- _cache = memoryCache;
- _mLocalizer = _modelLocalizer;
- }
-
- ///
- /// Ruft alle lokalisierten Daten ab.
- ///
- /// Eine Liste aller lokalisierten Daten.
- [HttpGet]
- public IActionResult GetAll() => Ok(_cache.GetOrCreate(Language ?? string.Empty + L_KEY, _ => _mLocalizer.ToDictionary()));
-
- ///
- /// Ruft die aktuelle Sprache ab.
- ///
- /// Die aktuelle Sprache oder ein NotFound-Ergebnis, wenn keine Sprache gesetzt ist.
- [HttpGet("lang")]
- public IActionResult GetLanguage() => Language is null ? NotFound() : Ok(Language);
-
- ///
- /// Setzt die Sprache.
- ///
- /// Die zu setzende Sprache.
- /// Ein Ok-Ergebnis, wenn die Sprache erfolgreich gesetzt wurde, oder ein BadRequest-Ergebnis, wenn die Eingabe ungültig ist.
- [HttpPost("lang")]
- public IActionResult SetLanguage([FromQuery] string language)
- {
- if (string.IsNullOrEmpty(language))
- return BadRequest();
-
- Language = language;
- return Ok();
- }
-
- ///
- /// Löscht die aktuelle Sprache.
- ///
- /// Ein Ok-Ergebnis, wenn die Sprache erfolgreich gelöscht wurde.
- [HttpDelete("lang")]
- public IActionResult DeleteLanguage()
- {
- Language = null;
- return Ok();
- }
-
- ///
- /// Eigenschaft für die Verwaltung der aktuellen Sprache über Cookies.
- ///
- private string? Language
- {
- get
- {
- var cookieValue = Request.Cookies[CookieRequestCultureProvider.DefaultCookieName];
-
- if (string.IsNullOrEmpty(cookieValue))
- return null;
-
- var culture = CookieRequestCultureProvider.ParseCookieValue(cookieValue)?.Cultures[0];
- return culture?.Value ?? null;
- }
- set
- {
- if (value is null)
- Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);
- else
- {
- var cookieOptions = new CookieOptions()
- {
- Expires = DateTimeOffset.UtcNow.AddYears(1),
- Secure = false,
- SameSite = SameSiteMode.Strict,
- HttpOnly = true
- };
-
- Response.Cookies.Append(
- CookieRequestCultureProvider.DefaultCookieName,
- CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(value)),
- cookieOptions);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/ReadOnlyController.cs b/EnvelopeGenerator.API/Controllers/ReadOnlyController.cs
deleted file mode 100644
index db800c22..00000000
--- a/EnvelopeGenerator.API/Controllers/ReadOnlyController.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using DigitalData.Core.Abstraction.Application.DTO;
-using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
-using EnvelopeGenerator.Application.Common.Interfaces.Services;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.API.Extensions;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Newtonsoft.Json;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Manages read-only envelope sharing flows.
-///
-[Route("api/[controller]")]
-[ApiController]
-public class ReadOnlyController : ControllerBase
-{
- private readonly ILogger _logger;
- private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
- private readonly IEnvelopeMailService _mailService;
- private readonly IEnvelopeHistoryService _historyService;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ReadOnlyController(ILogger logger, IEnvelopeReceiverReadOnlyService readOnlyService, IEnvelopeMailService mailService, IEnvelopeHistoryService historyService)
- {
- _logger = logger;
- _readOnlyService = readOnlyService;
- _mailService = mailService;
- _historyService = historyService;
- }
-
- ///
- /// Creates a new read-only receiver for the current envelope.
- ///
- /// Creation payload.
- [HttpPost]
- [Authorize(Policy = AuthPolicy.Receiver)]
- [Obsolete("Use MediatR")]
- public async Task CreateAsync([FromBody] EnvelopeReceiverReadOnlyCreateDto createDto)
- {
- var authReceiverMail = User.ReceiverMail();
- if (authReceiverMail is null)
- {
- _logger.LogError("EmailAddress claim is not found in envelope-receiver-read-only creation process. Create DTO is:\n {dto}", JsonConvert.SerializeObject(createDto));
- return Unauthorized();
- }
-
- var envelopeId = User.EnvelopeId();
-
- createDto.AddedWho = authReceiverMail;
- createDto.EnvelopeId = envelopeId;
-
- var creationRes = await _readOnlyService.CreateAsync(createDto: createDto);
-
- if (creationRes.IsFailed)
- {
- _logger.LogNotice(creationRes);
- return StatusCode(StatusCodes.Status500InternalServerError);
- }
-
- var readRes = await _readOnlyService.ReadByIdAsync(creationRes.Data.Id);
- if (readRes.IsFailed)
- {
- _logger.LogNotice(creationRes);
- return StatusCode(StatusCodes.Status500InternalServerError);
- }
-
- var newReadOnly = readRes.Data;
-
- return await _mailService.SendAsync(newReadOnly).ThenAsync(SuccessAsync: async _ =>
- {
- var histRes = await _historyService.RecordAsync((int)createDto.EnvelopeId, createDto.AddedWho, EnvelopeStatus.EnvelopeShared);
- if (histRes.IsFailed)
- {
- _logger.LogError("Although the envelope was sent as read-only, the EnvelopeShared history could not be saved. Create DTO:\n{createDto}", JsonConvert.SerializeObject(createDto));
- _logger.LogNotice(histRes.Notices);
- }
-
- return Ok();
- },
-
- Fail: (msg, ntc) =>
- {
- _logger.LogNotice(ntc);
- return StatusCode(StatusCodes.Status500InternalServerError);
- });
- }
-}
diff --git a/EnvelopeGenerator.API/Controllers/ReceiverController.cs b/EnvelopeGenerator.API/Controllers/ReceiverController.cs
deleted file mode 100644
index 756b5eb3..00000000
--- a/EnvelopeGenerator.API/Controllers/ReceiverController.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using MediatR;
-using EnvelopeGenerator.Application.Receivers.Queries;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace EnvelopeGenerator.GeneratorAPI.Controllers;
-
-///
-/// Controller für die Verwaltung von Empfängern.
-///
-///
-/// Dieser Controller bietet Endpunkte für das Abrufen von Empfängern basierend auf E-Mail-Adresse oder Signatur.
-///
-[Route("api/[controller]")]
-[ApiController]
-[Authorize]
-public class ReceiverController : ControllerBase
-{
- private readonly IMediator _mediator;
-
- ///
- /// Initialisiert eine neue Instanz des -Controllers.
- ///
- /// Mediator für Anfragen.
- public ReceiverController(IMediator mediator)
- {
- _mediator = mediator;
- }
-
- ///
- /// Ruft eine Liste von Empfängern ab, basierend auf den angegebenen Abfrageparametern.
- ///
- /// Die Abfrageparameter, einschließlich E-Mail-Adresse und Signatur.
- /// Eine Liste von Empfängern oder ein Fehlerstatus.
- [HttpGet]
- public async Task Get([FromQuery] ReadReceiverQuery receiver)
- {
- if (!receiver.HasAnyCriteria)
- {
- var all = await _mediator.Send(new ReadReceiverQuery());
- return Ok(all);
- }
-
- var result = await _mediator.Send(receiver);
- return result is null ? NotFound() : Ok(result);
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs b/EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs
deleted file mode 100644
index f365c0df..00000000
--- a/EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using DigitalData.Core.Abstraction.Application.DTO;
-using EnvelopeGenerator.Application.Common.Extensions;
-using EnvelopeGenerator.Application.Common.Interfaces.Services;
-using EnvelopeGenerator.Application.Resources;
-using EnvelopeGenerator.Domain.Constants;
-using EnvelopeGenerator.API.Models;
-using Ganss.Xss;
-using Microsoft.AspNetCore.Authentication;
-using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Options;
-
-namespace EnvelopeGenerator.API.Controllers;
-
-///
-/// Exposes endpoints for registering and managing two-factor authentication for envelope receivers.
-///
-[ApiController]
-[Route("api/tfa")]
-public class TfaRegistrationController : ControllerBase
-{
- private readonly ILogger _logger;
- private readonly IEnvelopeReceiverService _envelopeReceiverService;
- private readonly IAuthenticator _authenticator;
- private readonly IReceiverService _receiverService;
- private readonly TFARegParams _parameters;
- private readonly IStringLocalizer _localizer;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public TfaRegistrationController(
- ILogger logger,
- IEnvelopeReceiverService envelopeReceiverService,
- IAuthenticator authenticator,
- IReceiverService receiverService,
- IOptions tfaRegParamsOptions,
- IStringLocalizer localizer)
- {
- _logger = logger;
- _envelopeReceiverService = envelopeReceiverService;
- _authenticator = authenticator;
- _receiverService = receiverService;
- _parameters = tfaRegParamsOptions.Value;
- _localizer = localizer;
- }
-
- ///
- /// Generates registration metadata (QR code and deadline) for a receiver.
- ///
- /// Encoded envelope receiver id.
- [Authorize]
- [HttpGet("{envelopeReceiverId}")]
- public async Task RegisterAsync(string envelopeReceiverId)
- {
- try
- {
- var (uuid, signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
-
- if (uuid is null || signature is null)
- {
- _logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer.WrongEnvelopeReceiverId());
- return Unauthorized(new { message = _localizer.WrongEnvelopeReceiverId() });
- }
-
- var secretResult = await _envelopeReceiverService.ReadWithSecretByUuidSignatureAsync(uuid: uuid, signature: signature);
- if (secretResult.IsFailed)
- {
- _logger.LogNotice(secretResult.Notices);
- return NotFound(new { message = _localizer.WrongEnvelopeReceiverId() });
- }
-
- var envelopeReceiver = secretResult.Data;
-
- if (!envelopeReceiver.Envelope!.TFAEnabled)
- return Unauthorized(new { message = _localizer.WrongAccessCode() });
-
- var receiver = envelopeReceiver.Receiver;
- receiver!.TotpSecretkey = _authenticator.GenerateTotpSecretKey();
- await _receiverService.UpdateAsync(receiver);
- var totpQr64 = _authenticator.GenerateTotpQrCode(userEmail: receiver.EmailAddress, secretKey: receiver.TotpSecretkey).ToBase64String();
-
- if (receiver.TfaRegDeadline is null)
- {
- receiver.TfaRegDeadline = _parameters.Deadline;
- await _receiverService.UpdateAsync(receiver);
- }
- else if (receiver.TfaRegDeadline <= DateTime.Now)
- {
- return StatusCode(StatusCodes.Status410Gone, new { message = _localizer.WrongAccessCode() });
- }
-
- return Ok(new
- {
- envelopeReceiver.EnvelopeId,
- envelopeReceiver.Envelope!.Uuid,
- envelopeReceiver.Receiver!.Signature,
- receiver.TfaRegDeadline,
- TotpQR64 = totpQr64
- });
- }
- catch (Exception ex)
- {
- _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex, message: _localizer.WrongEnvelopeReceiverId());
- return StatusCode(StatusCodes.Status500InternalServerError, new { message = _localizer.UnexpectedError() });
- }
- }
-
- ///
- /// Logs out the envelope receiver from cookie authentication.
- ///
- [Authorize(Policy = AuthPolicy.Receiver)]
- [HttpPost("auth/logout")]
- public async Task LogOutAsync()
- {
- try
- {
- await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
- return Ok();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "{message}", ex.Message);
- return StatusCode(StatusCodes.Status500InternalServerError, new { message = _localizer.UnexpectedError() });
- }
- }
-}
diff --git a/EnvelopeGenerator.API/Documentation/AuthProxyDocumentFilter.cs b/EnvelopeGenerator.API/Documentation/AuthProxyDocumentFilter.cs
deleted file mode 100644
index 8cb9c6c0..00000000
--- a/EnvelopeGenerator.API/Documentation/AuthProxyDocumentFilter.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using EnvelopeGenerator.API.Models;
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Models;
-using Swashbuckle.AspNetCore.SwaggerGen;
-
-namespace EnvelopeGenerator.API.Documentation;
-
-///
-///
-///
-public sealed class AuthProxyDocumentFilter : IDocumentFilter
-{
- ///
- ///
- ///
- ///
- ///
- public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
- {
- AddLoginOperation(swaggerDoc, context);
- AddEnvelopeReceiverLoginOperation(swaggerDoc, context);
- }
-
- private static void AddLoginOperation(OpenApiDocument swaggerDoc, DocumentFilterContext context)
- {
- const string path = "/api/auth";
-
- var loginSchema = context.SchemaGenerator.GenerateSchema(typeof(Login), context.SchemaRepository);
- var loginExample = new OpenApiObject
- {
- ["password"] = new OpenApiString(""),
- ["username"] = new OpenApiString("")
- };
-
- var operation = new OpenApiOperation
- {
- Summary = "Proxy login (auth-hub)",
- Description = "Proxies the request to the auth service. Add query parameter `cookie=true|false`.",
- Tags = [new() { Name = "Auth" }],
- Parameters =
- {
- new OpenApiParameter
- {
- Name = "cookie",
- In = ParameterLocation.Query,
- Required = false,
- Schema = new OpenApiSchema { Type = "boolean", Default = new OpenApiBoolean(true) },
- Example = new OpenApiBoolean(true),
- Description = "If true, auth service sets the auth cookie."
- }
- },
- RequestBody = new OpenApiRequestBody
- {
- Required = true,
- Content =
- {
- ["application/json"] = new OpenApiMediaType { Schema = loginSchema, Example = loginExample },
- ["multipart/form-data"] = new OpenApiMediaType { Schema = loginSchema, Example = loginExample }
- }
- },
- Responses =
- {
- ["200"] = new OpenApiResponse { Description = "OK (proxied response)" },
- ["401"] = new OpenApiResponse { Description = "Unauthorized" }
- }
- };
-
- swaggerDoc.Paths[path] = new OpenApiPathItem
- {
- Operations =
- {
- [OperationType.Post] = operation
- }
- };
- }
-
- private static void AddEnvelopeReceiverLoginOperation(OpenApiDocument swaggerDoc, DocumentFilterContext context)
- {
- const string path = "/api/Auth/envelope-receiver/{key}";
-
- var bodySchema = context.SchemaGenerator.GenerateSchema(typeof(EnvelopeReceiverLogin), context.SchemaRepository);
-
- var operation = new OpenApiOperation
- {
- Summary = "Envelope receiver login (auth-hub proxy)",
- Description = "Proxies the envelope receiver login to the auth service. " +
- "The `cookie` query parameter is always forwarded as `true` so the auth service sets the per-envelope cookie automatically.",
- Tags = [new() { Name = "Auth" }],
- Parameters =
- {
- new OpenApiParameter
- {
- Name = "key",
- In = ParameterLocation.Path,
- Required = true,
- Schema = new OpenApiSchema { Type = "string" },
- Description = "The unique envelope receiver key."
- }
- },
- RequestBody = new OpenApiRequestBody
- {
- Required = false,
- Content =
- {
- ["multipart/form-data"] = new OpenApiMediaType { Schema = bodySchema }
- }
- },
- Responses =
- {
- ["200"] = new OpenApiResponse { Description = "OK – per-envelope cookie set by auth service." },
- ["401"] = new OpenApiResponse { Description = "Unauthorized – invalid or missing access code." }
- }
- };
-
- swaggerDoc.Paths[path] = new OpenApiPathItem
- {
- Operations =
- {
- [OperationType.Post] = operation
- }
- };
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/EnvelopeGenerator.API.csproj b/EnvelopeGenerator.API/EnvelopeGenerator.API.csproj
deleted file mode 100644
index 96154a76..00000000
--- a/EnvelopeGenerator.API/EnvelopeGenerator.API.csproj
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
- net8.0
- enable
- enable
- true
- EnvelopeGenerator.GeneratorAPI
-
- Digital Data GmbH
- Digital Data GmbH
- EnvelopeGenerator.GeneratorAPI
- 1.4.0
- 1.4.0
- 1.4.0
- Copyright © 2025 Digital Data GmbH. All rights reserved.
- bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs b/EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs
deleted file mode 100644
index d851c1de..00000000
--- a/EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using DigitalData.Auth.Claims;
-using Microsoft.IdentityModel.JsonWebTokens;
-using System.Security.Claims;
-
-namespace EnvelopeGenerator.API.Extensions;
-
-///
-/// Provides helper methods for working with envelope-specific authentication claims.
-///
-public static class ReceiverClaimExtensions
-{
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- private static string GetRequiredClaimValue(this ClaimsPrincipal user, string claimType)
- {
- var value = user.FindFirstValue(claimType);
- if (value is not null)
- {
- return value;
- }
-
- var identity = user.Identity;
- var principalName = identity?.Name ?? "(anonymous)";
- var authType = identity?.AuthenticationType ?? "(none)";
- var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"));
- var message = $"Required claim '{claimType}' is missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
- throw new InvalidOperationException(message);
- }
-
- private static string GetRequiredClaimValue(this ClaimsPrincipal user, params string[] claimTypes)
- {
- foreach (var claimType in claimTypes.Where(t => !string.IsNullOrWhiteSpace(t)).Distinct())
- {
- var value = user.FindFirstValue(claimType);
- if (!string.IsNullOrWhiteSpace(value))
- return value;
- }
-
- var identity = user.Identity;
- var principalName = identity?.Name ?? "(anonymous)";
- var authType = identity?.AuthenticationType ?? "(none)";
- var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"));
- var message = $"Required claim(s) '{string.Join("', '", claimTypes)}' are missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
- throw new InvalidOperationException(message);
- }
-
- ///
- /// Gets the authenticated envelope UUID from the claims.
- ///
- public static string EnvelopeUuid(this ClaimsPrincipal user)
- => user.GetRequiredClaimValue(EnvelopeClaimNames.EnvelopeUuid);
-
- ///
- /// Gets the authenticated receiver signature from the claims.
- ///
- public static string ReceiverSignature(this ClaimsPrincipal user)
- => user.GetRequiredClaimValue(EnvelopeClaimNames.ReceiverSignature);
-
- ///
- /// Gets the authenticated receiver email address from the claims.
- ///
- public static string ReceiverMail(this ClaimsPrincipal user)
- => user.GetRequiredClaimValue(JwtRegisteredClaimNames.Email);
-
- ///
- /// Gets the authenticated envelope identifier from the claims.
- ///
- public static int EnvelopeId(this ClaimsPrincipal user)
- {
- var envIdStr = user.GetRequiredClaimValue(EnvelopeClaimNames.EnvelopeId);
- if (int.TryParse(envIdStr, out var envId))
- return envId;
- else
- throw new InvalidOperationException($"Claim '{EnvelopeClaimNames.EnvelopeId}' is not a valid integer.");
- }
-
- ///
- /// Gets the authenticated receiver identifier from the claims.
- ///
- ///
- ///
- ///
- public static int ReceiverId(this ClaimsPrincipal user)
- {
- var rcvIdStr = user.GetRequiredClaimValue(EnvelopeClaimNames.ReceiverId);
- if (int.TryParse(rcvIdStr, out var rcvId))
- return rcvId;
- else
- throw new InvalidOperationException($"Claim '{EnvelopeClaimNames.ReceiverId}' is not a valid integer.");
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs b/EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs
deleted file mode 100644
index 262968ed..00000000
--- a/EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System.Security.Claims;
-
-namespace EnvelopeGenerator.API.Extensions
-{
- ///
- /// Provides extension methods for extracting user information from a .
- ///
- public static class SenderClaimExtensions
- {
- private static string GetRequiredClaimOfSender(this ClaimsPrincipal user, string claimType)
- {
- var value = user.FindFirstValue(claimType);
- if (value is not null)
- {
- return value;
- }
-
- var identity = user.Identity;
- var principalName = identity?.Name ?? "(anonymous)";
- var authType = identity?.AuthenticationType ?? "(none)";
- var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"));
- var message = $"Required claim '{claimType}' is missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
- throw new InvalidOperationException(message);
- }
-
- private static string GetRequiredClaimOfSender(this ClaimsPrincipal user, params string[] claimTypes)
- {
- string? value = null;
-
- foreach (var claimType in claimTypes)
- {
- value = user.FindFirstValue(claimType);
- if (value is not null)
- return value;
- }
-
- var identity = user.Identity;
- var principalName = identity?.Name ?? "(anonymous)";
- var authType = identity?.AuthenticationType ?? "(none)";
- var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"));
- var message = $"Required claim among [{string.Join(", ", claimTypes)}] is missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
- throw new InvalidOperationException(message);
- }
-
- ///
- /// Retrieves the user's ID from the claims. Throws an exception if the ID is missing or invalid.
- ///
- /// The representing the user.
- /// The user's ID as an integer.
- /// Thrown if the user ID claim is missing or invalid.
- public static int GetId(this ClaimsPrincipal user)
- {
- var idValue = user.GetRequiredClaimOfSender(ClaimTypes.NameIdentifier, "sub");
-
- if (!int.TryParse(idValue, out var result))
- {
- throw new InvalidOperationException("User ID claim is missing or invalid. This may indicate a misconfigured or forged JWT token.");
- }
-
- return result;
- }
-
- ///
- /// Retrieves the username from the claims.
- ///
- /// The representing the user.
- /// The username as a string.
- public static string GetUsername(this ClaimsPrincipal user)
- => user.GetRequiredClaimOfSender(ClaimTypes.Name);
-
- ///
- /// Retrieves the user's surname (last name) from the claims.
- ///
- /// The representing the user.
- /// The surname as a string.
- public static string GetName(this ClaimsPrincipal user)
- => user.GetRequiredClaimOfSender(ClaimTypes.Surname);
-
- ///
- /// Retrieves the user's given name (first name) from the claims.
- ///
- /// The representing the user.
- /// The given name as a string.
- public static string GetPrename(this ClaimsPrincipal user)
- => user.GetRequiredClaimOfSender(ClaimTypes.GivenName);
-
- ///
- /// Retrieves the user's email address from the claims.
- ///
- /// The representing the user.
- /// The email address as a string.
- public static string GetEmail(this ClaimsPrincipal user)
- => user.GetRequiredClaimOfSender(ClaimTypes.Email);
- }
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Jenkinsfile b/EnvelopeGenerator.API/Jenkinsfile
deleted file mode 100644
index 3546ad67..00000000
--- a/EnvelopeGenerator.API/Jenkinsfile
+++ /dev/null
@@ -1,10 +0,0 @@
-pipeline {
- agent any
- stages {
- stage('Build') {
- steps {
- sh 'dotnet build'
- }
- }
- }
-}
diff --git a/EnvelopeGenerator.API/Middleware/ExceptionHandlingMiddleware.cs b/EnvelopeGenerator.API/Middleware/ExceptionHandlingMiddleware.cs
deleted file mode 100644
index 08d6c392..00000000
--- a/EnvelopeGenerator.API/Middleware/ExceptionHandlingMiddleware.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-namespace EnvelopeGenerator.API.Middleware;
-
-using DigitalData.Core.Exceptions;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using System.Net;
-using System.Text.Json;
-
-///
-/// Middleware for handling exceptions globally in the application.
-/// Captures exceptions thrown during the request pipeline execution,
-/// logs them, and returns an appropriate HTTP response with a JSON error message.
-///
-public class ExceptionHandlingMiddleware
-{
- private readonly RequestDelegate _next;
- private readonly ILogger _logger;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The next middleware in the request pipeline.
- /// The logger instance for logging exceptions.
- public ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger)
- {
- _next = next;
- _logger = logger;
- }
-
- ///
- /// Invokes the middleware to handle the HTTP request.
- ///
- /// The HTTP context of the current request.
- /// A task that represents the asynchronous operation.
- public async Task InvokeAsync(HttpContext context)
- {
- try
- {
- await _next(context); // Continue down the pipeline
- }
- catch (Exception ex)
- {
- await HandleExceptionAsync(context, ex, _logger);
- }
- }
-
- ///
- /// Handles exceptions by logging them and writing an appropriate JSON response.
- ///
- /// The HTTP context of the current request.
- /// The exception that occurred.
- /// The logger instance for logging the exception.
- /// A task that represents the asynchronous operation.
- private static async Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger)
- {
- context.Response.ContentType = "application/json";
-
- string message;
-
- switch (exception)
- {
- case BadRequestException badRequestEx:
- context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
- message = badRequestEx.Message;
- break;
-
- case NotFoundException notFoundEx:
- context.Response.StatusCode = (int)HttpStatusCode.NotFound;
- message = notFoundEx.Message;
- break;
-
- default:
- logger.LogError(exception, "Unhandled exception occurred.");
- context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
- message = "An unexpected error occurred.";
- break;
- }
-
- await context.Response.WriteAsync(JsonSerializer.Serialize(new
- {
- message
- }));
- }
-}
diff --git a/EnvelopeGenerator.API/Models/Auth.cs b/EnvelopeGenerator.API/Models/Auth.cs
deleted file mode 100644
index f08b6c95..00000000
--- a/EnvelopeGenerator.API/Models/Auth.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public record Auth(string? AccessCode = null, string? SmsCode = null, string? AuthenticatorCode = null, bool UserSelectSMS = default)
-{
- public bool HasAccessCode => AccessCode is not null;
-
- public bool HasSmsCode => SmsCode is not null;
-
- public bool HasAuthenticatorCode => AuthenticatorCode is not null;
-
- public bool HasMulti => new[] { HasAccessCode, HasSmsCode, HasAuthenticatorCode }.Count(state => state) > 1;
-
- public bool HasNone => !(HasAccessCode || HasSmsCode || HasAuthenticatorCode);
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/AuthTokenKeys.cs b/EnvelopeGenerator.API/Models/AuthTokenKeys.cs
deleted file mode 100644
index 1952e384..00000000
--- a/EnvelopeGenerator.API/Models/AuthTokenKeys.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-///
-/// Represents the keys and default values used for authentication token handling
-/// within the Envelope Generator API.
-///
-public class AuthTokenKeys
-{
- ///
- /// Gets the name of the cookie used to store the authentication token.
- ///
- public string Cookie { get; init; } = "AuthToken";
-
- ///
- /// Gets the name of the query string parameter used to pass the authentication token.
- ///
- public string QueryString { get; init; } = "AuthToken";
-
- ///
- /// Gets the expected issuer value for the authentication token.
- ///
- public string Issuer { get; init; } = "auth.digitaldata.works";
-
- ///
- /// Gets the expected audience value for the authentication token.
- ///
- public string Audience { get; init; } = "sign-flow.digitaldata.works";
-}
diff --git a/EnvelopeGenerator.API/Models/ConnectionString.cs b/EnvelopeGenerator.API/Models/ConnectionString.cs
deleted file mode 100644
index 90280671..00000000
--- a/EnvelopeGenerator.API/Models/ConnectionString.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-///
-///
-///
-public class ConnectionString
-{
- ///
- ///
- ///
- public string Value { get; set; } = string.Empty;
-}
diff --git a/EnvelopeGenerator.API/Models/ContactLink.cs b/EnvelopeGenerator.API/Models/ContactLink.cs
deleted file mode 100644
index 691dbc83..00000000
--- a/EnvelopeGenerator.API/Models/ContactLink.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-namespace EnvelopeGenerator.API.Models
-{
- ///
- /// Represents a hyperlink for contact purposes with various HTML attributes.
- ///
- public class ContactLink
- {
- ///
- /// Gets or sets the label of the hyperlink.
- ///
- public string Label { get; init; } = "Contact";
-
- ///
- /// Gets or sets the URL that the hyperlink points to.
- ///
- public string Href { get; set; } = string.Empty;
-
- ///
- /// Gets or sets the target where the hyperlink should open.
- /// Commonly used values are "_blank", "_self", "_parent", "_top".
- ///
- public string Target { get; set; } = "_blank";
-
- ///
- /// Gets or sets the relationship of the linked URL as space-separated link types.
- /// Examples include "nofollow", "noopener", "noreferrer".
- ///
- public string Rel { get; set; } = string.Empty;
-
- ///
- /// Gets or sets the filename that should be downloaded when clicking the hyperlink.
- /// This attribute will only have an effect if the href attribute is set.
- ///
- public string Download { get; set; } = string.Empty;
-
- ///
- /// Gets or sets the language of the linked resource. Useful when linking to
- /// content in another language.
- ///
- public string HrefLang { get; set; } = "en";
-
- ///
- /// Gets or sets the MIME type of the linked URL. Helps browsers to handle
- /// the type correctly when the link is clicked.
- ///
- public string Type { get; set; } = string.Empty;
-
- ///
- /// Gets or sets additional information about the hyperlink, typically viewed
- /// as a tooltip when the mouse hovers over the link.
- ///
- public string Title { get; set; } = string.Empty;
-
- ///
- /// Gets or sets an identifier for the hyperlink, unique within the HTML document.
- ///
- public string Id { get; set; } = string.Empty;
- }
-
-}
diff --git a/EnvelopeGenerator.API/Models/Culture.cs b/EnvelopeGenerator.API/Models/Culture.cs
deleted file mode 100644
index b1386088..00000000
--- a/EnvelopeGenerator.API/Models/Culture.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Globalization;
-
-namespace EnvelopeGenerator.API.Models;
-
-public class Culture
-{
- private string _language = string.Empty;
- public string Language { get => _language;
- init {
- _language = value;
- Info = new(value);
- }
- }
- public string FIClass { get; init; } = string.Empty;
-
- public CultureInfo? Info { get; init; }
-}
diff --git a/EnvelopeGenerator.API/Models/Cultures.cs b/EnvelopeGenerator.API/Models/Cultures.cs
deleted file mode 100644
index 7b293c13..00000000
--- a/EnvelopeGenerator.API/Models/Cultures.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public class Cultures : List
-{
- public IEnumerable Languages => this.Select(c => c.Language);
-
- public IEnumerable FIClasses => this.Select(c => c.FIClass);
-
- public Culture Default => this.First();
-
- public Culture? this[string? language] => language is null ? null : this.Where(c => c.Language == language).FirstOrDefault();
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/CustomImages.cs b/EnvelopeGenerator.API/Models/CustomImages.cs
deleted file mode 100644
index fd212acd..00000000
--- a/EnvelopeGenerator.API/Models/CustomImages.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public class CustomImages : Dictionary
-{
- public new Image this[string key] => TryGetValue(key, out var img) && img is not null ? img : new();
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/EnvelopeReceiverLogin.cs b/EnvelopeGenerator.API/Models/EnvelopeReceiverLogin.cs
deleted file mode 100644
index fa53ec61..00000000
--- a/EnvelopeGenerator.API/Models/EnvelopeReceiverLogin.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-///
-/// Request body for the envelope-receiver login endpoint.
-///
-/// The access code sent to the receiver.
-public record EnvelopeReceiverLogin(string? AccessCode = null);
diff --git a/EnvelopeGenerator.API/Models/ErrorViewModel.cs b/EnvelopeGenerator.API/Models/ErrorViewModel.cs
deleted file mode 100644
index b09ffded..00000000
--- a/EnvelopeGenerator.API/Models/ErrorViewModel.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public class ErrorViewModel
-{
- public string Title { get; init; } = "404";
-
- public string Subtitle { get; init; } = "Hmmm...";
-
- public string Body { get; init; } = "It looks like one of the developers fell asleep";
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/Image.cs b/EnvelopeGenerator.API/Models/Image.cs
deleted file mode 100644
index d7abd148..00000000
--- a/EnvelopeGenerator.API/Models/Image.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public class Image
-{
- public string Src { get; init; } = string.Empty;
-
- public Dictionary Classes { get; init; } = new();
-
- public string GetClassIn(string page) => Classes.TryGetValue(page, out var cls) && cls is not null ? cls : string.Empty;
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/Login.cs b/EnvelopeGenerator.API/Models/Login.cs
deleted file mode 100644
index 926b1811..00000000
--- a/EnvelopeGenerator.API/Models/Login.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace EnvelopeGenerator.API.Models;
-
-///
-/// Repräsentiert ein Login-Modell mit erforderlichem Passwort und optionaler ID und Benutzername.
-///
-/// Das erforderliche Passwort für das Login.
-/// Die optionale ID des Benutzers.
-/// Der optionale Benutzername.
-public record Login([Required] string Password, int? UserId = null, string? Username = null)
-{
-}
diff --git a/EnvelopeGenerator.API/Models/MainViewModel.cs b/EnvelopeGenerator.API/Models/MainViewModel.cs
deleted file mode 100644
index d49d323b..00000000
--- a/EnvelopeGenerator.API/Models/MainViewModel.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-public class MainViewModel
-{
- public string? Title { get; init; }
-}
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Annotation.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Annotation.cs
deleted file mode 100644
index 5dbb1aed..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Annotation.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-using System.Text.Json.Serialization;
-
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-public record Annotation : IAnnotation
-{
- public required string Name { get; init; }
-
- #region Bound Annotation
- [JsonIgnore]
- public string? HorBoundAnnotName { get; init; }
-
- [JsonIgnore]
- public string? VerBoundAnnotName { get; init; }
- #endregion
-
- #region Layout
- [JsonIgnore]
- public double? MarginLeft { get; set; }
-
- [JsonIgnore]
- public double MarginLeftRatio { get; init; } = 1;
-
- [JsonIgnore]
- public double? MarginTop { get; set; }
-
- [JsonIgnore]
- public double MarginTopRatio { get; init; } = 1;
-
- public double? Width { get; set; }
-
- [JsonIgnore]
- public double WidthRatio { get; init; } = 1;
-
- public double? Height { get; set; }
-
- [JsonIgnore]
- public double HeightRatio { get; init; } = 1;
- #endregion
-
- #region Position
- public double Left => (MarginLeft ?? 0) + (HorBoundAnnot?.HorBoundary ?? 0);
-
- public double Top => (MarginTop ?? 0) + (VerBoundAnnot?.VerBoundary ?? 0);
- #endregion
-
- #region Boundary
- [JsonIgnore]
- public double HorBoundary => Left + (Width ?? 0);
-
- [JsonIgnore]
- public double VerBoundary => Top + (Height ?? 0);
- #endregion
-
- #region BoundAnnot
- [JsonIgnore]
- public Annotation? HorBoundAnnot { get; set; }
-
- [JsonIgnore]
- public Annotation? VerBoundAnnot { get; set; }
- #endregion
-
- public Color? BackgroundColor { get; init; }
-
- #region Border
- public Color? BorderColor { get; init; }
-
- public string? BorderStyle { get; init; }
-
- public int? BorderWidth { get; set; }
- #endregion
-
- [JsonIgnore]
- internal Annotation Default
- {
- set
- {
- // To set null value, annotation must have null (0) value but null must has non-null value
- if (MarginLeft == null && value.MarginLeft != null)
- MarginLeft = value.MarginLeft * MarginLeftRatio;
-
- if (MarginTop == null && value.MarginTop != null)
- MarginTop = value.MarginTop * MarginTopRatio;
-
- if (Width == null && value.Width != null)
- Width = value.Width * WidthRatio;
-
- if (Height == null && value.Height != null)
- Height = value.Height * HeightRatio;
- }
- }
-};
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/AnnotationParams.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/AnnotationParams.cs
deleted file mode 100644
index 019d872e..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/AnnotationParams.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-using System.Text.Json.Serialization;
-
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-public class AnnotationParams
-{
- public AnnotationParams()
- {
- _AnnotationJSObjectInitor = new(CreateAnnotationJSObject);
- }
-
- public Background? Background { get; init; }
-
- #region Annotation
- [JsonIgnore]
- public Annotation? DefaultAnnotation { get; init; }
-
- private readonly List _annots = new List();
-
- public bool TryGet(string name, out Annotation annotation)
- {
-#pragma warning disable CS8601 // Possible null reference assignment.
- annotation = _annots.FirstOrDefault(a => a.Name == name);
-#pragma warning restore CS8601 // Possible null reference assignment.
- return annotation is not null;
- }
-
- public required IEnumerable Annotations
- {
- get => _annots;
- init
- {
- _annots = value.ToList();
-
- if (DefaultAnnotation is not null)
- foreach (var annot in _annots)
- annot.Default = DefaultAnnotation;
-
- for (int i = 0; i < _annots.Count; i++)
- {
- #region set bound annotations
- // horizontal
- if (_annots[i].HorBoundAnnotName is string horBoundAnnotName)
- if (TryGet(horBoundAnnotName, out var horBoundAnnot))
- _annots[i].HorBoundAnnot = horBoundAnnot;
- else
- throw new InvalidOperationException($"{horBoundAnnotName} added as bound anotation. However, it is not defined.");
-
- // vertical
- if (_annots[i].VerBoundAnnotName is string verBoundAnnotName)
- if (TryGet(verBoundAnnotName, out var verBoundAnnot))
- _annots[i].VerBoundAnnot = verBoundAnnot;
- else
- throw new InvalidOperationException($"{verBoundAnnotName} added as bound anotation. However, it is not defined.");
- #endregion
- }
- }
- }
- #endregion
-
- #region AnnotationJSObject
- private Dictionary CreateAnnotationJSObject()
- {
- var dict = _annots.ToDictionary(a => a.Name.ToLower(), a => a as IAnnotation);
-
- if (Background is not null)
- {
- Background.Locate(_annots);
- dict.Add(Background.Name.ToLower(), Background);
- }
-
- return dict;
- }
-
- private readonly Lazy> _AnnotationJSObjectInitor;
-
- public Dictionary AnnotationJSObject => _AnnotationJSObjectInitor.Value;
- #endregion
-}
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Background.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Background.cs
deleted file mode 100644
index 19298196..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Background.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-///
-/// The Background is an annotation for the PSPDF Kit. However, it has no function.
-/// It is only the first annotation as a background for other annotations.
-///
-public record Background : IAnnotation
-{
- [JsonIgnore]
- public double Margin { get; init; }
-
- public string Name { get; } = "Background";
-
- public double? Width { get; set; }
-
- public double? Height { get; set; }
-
- public double Left { get; set; }
-
- public double Top { get; set; }
-
- public Color? BackgroundColor { get; init; }
-
- #region Border
- public Color? BorderColor { get; init; }
-
- public string? BorderStyle { get; init; }
-
- public int? BorderWidth { get; set; }
- #endregion
-
- public void Locate(IEnumerable annotations)
- {
- // set Top
- if (annotations.MinBy(a => a.Top)?.Top is double minTop)
- Top = minTop;
-
- // set Left
- if (annotations.MinBy(a => a.Left)?.Left is double minLeft)
- Left = minLeft;
-
- // set Width
- if(annotations.MaxBy(a => a.GetRight())?.GetRight() is double maxRight)
- Width = maxRight - Left;
-
- // set Height
- if (annotations.MaxBy(a => a.GetBottom())?.GetBottom() is double maxBottom)
- Height = maxBottom - Top;
-
- // add margins
- Top -= Margin;
- Left -= Margin;
- Width += Margin * 2;
- Height += Margin * 2;
- }
-}
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs
deleted file mode 100644
index 0d3d4056..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-public record Color
-{
- public int R { get; init; } = 0;
-
- public int G { get; init; } = 0;
-
- public int B { get; init; } = 0;
-}
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Extensions.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Extensions.cs
deleted file mode 100644
index 1cc508fd..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Extensions.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-public static class Extensions
-{
- public static double GetRight(this IAnnotation annotation) => annotation.Left + annotation?.Width ?? 0;
-
- public static double GetBottom(this IAnnotation annotation) => annotation.Top + annotation?.Height ?? 0;
-}
diff --git a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/IAnnotation.cs b/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/IAnnotation.cs
deleted file mode 100644
index 735bf573..00000000
--- a/EnvelopeGenerator.API/Models/PsPdfKitAnnotation/IAnnotation.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
-
-public interface IAnnotation
-{
- string Name { get; }
-
- double? Width { get; }
-
- double? Height { get; }
-
- double Left { get; }
-
- double Top { get; }
-
- Color? BackgroundColor { get; }
-
- Color? BorderColor { get; }
-
- string? BorderStyle { get; }
-
- int? BorderWidth { get; }
-}
diff --git a/EnvelopeGenerator.API/Models/TFARegParams.cs b/EnvelopeGenerator.API/Models/TFARegParams.cs
deleted file mode 100644
index ff363fdf..00000000
--- a/EnvelopeGenerator.API/Models/TFARegParams.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace EnvelopeGenerator.API.Models;
-
-///
-/// Represents the parameters for two-factor authentication (2FA) registration.
-///
-public class TFARegParams
-{
- ///
- /// The maximum allowed time for completing the registration process.
- ///
- public TimeSpan TimeLimit { get; init; } = new(0, 30, 0);
-
- ///
- /// The deadline for registration, calculated as the current time plus the .
- ///
- public DateTime Deadline => DateTime.Now.AddTicks(TimeLimit.Ticks);
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Options/CacheOptions.cs b/EnvelopeGenerator.API/Options/CacheOptions.cs
deleted file mode 100644
index c39da3d7..00000000
--- a/EnvelopeGenerator.API/Options/CacheOptions.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace EnvelopeGenerator.API.Options;
-
-///
-/// Configuration options for distributed caching.
-///
-public sealed class CacheOptions
-{
- ///
- /// Configuration section name in appsettings.json.
- ///
- public const string SectionName = "Cache";
-
- ///
- /// Signature cache expiration time.
- /// If null, signatures will not expire automatically.
- ///
- public TimeSpan? SignatureCacheExpiration { get; set; }
-}
diff --git a/EnvelopeGenerator.API/Program.cs b/EnvelopeGenerator.API/Program.cs
deleted file mode 100644
index 8e0b570e..00000000
--- a/EnvelopeGenerator.API/Program.cs
+++ /dev/null
@@ -1,355 +0,0 @@
-using DigitalData.Core.API;
-using DigitalData.Core.Application;
-using EnvelopeGenerator.Infrastructure;
-using EnvelopeGenerator.Domain.Constants;
-using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.Localization;
-using Microsoft.EntityFrameworkCore;
-using System.Globalization;
-using Scalar.AspNetCore;
-using Microsoft.OpenApi.Models;
-using DigitalData.UserManager.DependencyInjection;
-using EnvelopeGenerator.Application;
-using DigitalData.Auth.Client;
-using DigitalData.Core.Abstractions;
-using EnvelopeGenerator.API.Models;
-using Microsoft.IdentityModel.Tokens;
-using DigitalData.Core.Abstractions.Security.Extensions;
-using EnvelopeGenerator.API.Middleware;
-using EnvelopeGenerator.API.Options;
-using NLog.Web;
-using NLog;
-using DigitalData.Auth.Claims;
-using EnvelopeGenerator.API;
-using Microsoft.AspNetCore.Authentication.JwtBearer;
-
-var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
-logger.Info("Logging initialized!");
-
-try
-{
- var builder = WebApplication.CreateBuilder(args);
-
- builder.Configuration.AddJsonFile("yarp.json", optional: true, reloadOnChange: true);
-
- builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
-
- if (!builder.Environment.IsDevelopment())
- {
- builder.Logging.ClearProviders();
- builder.Host.UseNLog();
- }
-
- var config = builder.Configuration;
-
- var deferredProvider = new DeferredServiceProvider();
-
- builder.Services.AddControllers()
- .AddJsonOptions(options =>
- {
- options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
- });
- builder.Services.AddHttpClient();
- builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
-
- // CORS Policy
- var allowedOrigins = config.GetSection("AllowedOrigins").Get() ??
- throw new InvalidOperationException("AllowedOrigins section is missing in the configuration.");
- builder.Services.AddCors(options =>
- {
- options.AddPolicy("AllowSpecificOriginsPolicy", builder =>
- {
- builder.WithOrigins(allowedOrigins)
- .SetIsOriginAllowedToAllowWildcardSubdomains()
- .AllowAnyMethod()
- .AllowAnyHeader()
- .AllowCredentials();
- });
- });
-
- // Swagger
- builder.Services.AddEndpointsApiExplorer();
- builder.Services.AddSwaggerGen(options =>
- {
- options.SwaggerDoc("v1", new OpenApiInfo
- {
- Version = "v1",
- Title = "signFLOW Absender-API",
- Description = "Eine API zur Verwaltung der Erstellung, des Versands und der Nachverfolgung von Umschlägen in der signFLOW-Anwendung.",
- Contact = new OpenApiContact
- {
- Name = "Digital Data GmbH",
- Url = new Uri("https://digitaldata.works/digitale-signatur#kontakt"),
- Email = "info-flow@digitaldata.works"
- },
- });
-
- options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
- {
- Name = "Authorization",
- Type = SecuritySchemeType.Http,
- Scheme = "bearer",
- BearerFormat = "JWT",
- In = ParameterLocation.Header,
- Description = "JWT-Autorisierungs-Header unter Verwendung des Bearer-Schemas.",
- });
-
- options.AddSecurityRequirement(new OpenApiSecurityRequirement
- {
- {
- new OpenApiSecurityScheme
- {
- Reference = new OpenApiReference
- {
- Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
- Id = "Bearer"
- }
- },
- Array.Empty()
- }
- });
-
- var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
- foreach (var xmlFile in xmlFiles)
- {
- options.IncludeXmlComments(xmlFile);
- }
-
- options.DocumentFilter();
- });
-#if NET9_0_OR_GREATER
- builder.Services.AddOpenApi();
-#endif
-
- //Add EF Core dbcontext
- var useDbMigration = Environment.GetEnvironmentVariable("MIGRATION_TEST_MODE") == true.ToString() || config.GetValue("UseDbMigration");
- var cnnStrName = useDbMigration ? "DbMigrationTest" : "Default";
- var connStr = config.GetConnectionString(cnnStrName)
- ?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration.");
-
- builder.Services.Configure(cs => cs.Value = connStr);
-
- builder.Services.AddDbContext(options => options.UseSqlServer(connStr));
-
- builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams"));
-
- var authTokenKeys = config.GetOrDefault();
-
- builder.Services.AddAuthentication(options =>
- {
- options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
- options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
- })
- .AddJwtBearer(AuthScheme.Sender, opt =>
- {
- opt.TokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
- {
- var clientParams = deferredProvider.GetOptions();
- var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
- return [publicKey.SecurityKey];
- },
- ValidateIssuer = true,
- ValidIssuer = authTokenKeys.Issuer,
- ValidateAudience = true,
- ValidAudience = authTokenKeys.Audience,
- };
-
- opt.Events = new JwtBearerEvents
- {
- OnMessageReceived = context =>
- {
- // if there is no token read related cookie or query string
- if (context.Token is null) // if there is no token
- {
- if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null)
- context.Token = cookieToken;
- else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken))
- context.Token = queryStrToken;
- }
- return Task.CompletedTask;
- }
- };
- })
- // Per-envelope receiver scheme: reads the JWT from the cookie named
- // AuthTokenSignFLOWReceiver.{envelope_key} where envelope_key is the
- // last path segment of the request URL.
- // This enables simultaneous authentication for multiple envelopes
- // within the same browser session.
- .AddJwtBearer(AuthScheme.Receiver, opt =>
- {
- opt.TokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
- {
- var clientParams = deferredProvider.GetOptions();
- var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
- return [publicKey.SecurityKey];
- },
- ValidateIssuer = true,
- ValidIssuer = authTokenKeys.Issuer,
- ValidateAudience = true,
- ValidAudience = authTokenKeys.Audience,
- };
-
- opt.Events = new JwtBearerEvents
- {
- OnMessageReceived = context =>
- {
- var paths = context.Request.Path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
-
- // Derive the envelope key from the last route segment: /{envelope_key}
- var envelopeKey = paths?.LastOrDefault();
-
- if (envelopeKey is not null)
- {
- var cookieName = CookieNames.GetEnvelopeReceiverCookieName(authTokenKeys.Cookie, envelopeKey);
- if (context.Request.Cookies.TryGetValue(cookieName, out var cookieToken) && cookieToken is not null)
- context.Token = cookieToken;
- }
-
- return Task.CompletedTask;
- },
- OnTokenValidated = context =>
- {
- var paths = context.Request.Path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
- var envelopeKey = paths?.LastOrDefault();
-
- var sub = context.Principal?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
- ?? context.Principal?.FindFirst("sub")?.Value;
-
- if (envelopeKey is null || sub != envelopeKey)
- context.Fail("Envelope key in the path does not match the token subject.");
-
- return Task.CompletedTask;
- }
- };
- });
-
- // Authentication
- builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
- .AddCookie(options =>
- {
- options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
- options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only
- options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites
- options.LoginPath = "/api/auth/login";
- options.LogoutPath = "/api/auth/logout";
- options.SlidingExpiration = true;
- });
-
- builder.Services.AddAuthorizationBuilder()
- .AddPolicy(AuthPolicy.SenderOrReceiver, policy => policy
- .RequireRole(Role.Sender, Role.Receiver.Full)
- .AddAuthenticationSchemes(AuthScheme.Sender, AuthScheme.Receiver))
- .AddPolicy(AuthPolicy.Sender, policy => policy
- .RequireRole(Role.Sender)
- .AddAuthenticationSchemes(AuthScheme.Sender))
- .AddPolicy(AuthPolicy.Receiver, policy => policy
- .AddAuthenticationSchemes(AuthScheme.Receiver)
- .RequireAuthenticatedUser()
- .RequireRole(Role.Receiver.Full, "receiver"))
- .AddPolicy(AuthPolicy.ReceiverTFA, policy => policy.RequireRole(Role.Receiver.TFA));
-
- // User manager
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services.AddUserManager();
-#pragma warning restore CS0618 // Type or member is obsolete
-
- // LDAP
- builder.ConfigureBySection();
- builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
-
- // Localizer
- builder.Services.AddCookieBasedLocalizer();
-
- // Cache options
- builder.Services.Configure(config.GetSection(CacheOptions.SectionName));
-
- // Distributed Cache - SQL Server
- builder.Services.AddDistributedSqlServerCache(options =>
- {
- config.GetSection("Cache:SqlServer").Bind(options);
-
- if (string.IsNullOrWhiteSpace(options.ConnectionString))
- {
- options.ConnectionString = connStr;
- }
- });
-
- // Envelope generator serives
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services
- .AddEnvelopeGeneratorInfrastructureServices(opt =>
- {
- opt.AddDbTriggerParams(config);
- opt.AddDbContext((provider, options) =>
- {
- var logger = provider.GetRequiredService>();
- options.UseSqlServer(connStr)
- .LogTo(log => logger.LogInformation("{log}", log), Microsoft.Extensions.Logging.LogLevel.Trace)
- .EnableSensitiveDataLogging()
- .EnableDetailedErrors();
- });
- opt.AddSQLExecutor(executor => executor.ConnectionString = connStr);
- })
- .AddEnvelopeGeneratorServices(config);
-#pragma warning restore CS0618 // Type or member is obsolete
-
- var app = builder.Build();
-
- deferredProvider.Factory = () => app.Services;
-
- app.UseMiddleware();
-
-#if NET9_0_OR_GREATER
- app.MapOpenApi();
-#endif
-
- // Configure the HTTP request pipeline.
- if (app.Environment.IsDevelopment() || (app.IsDevOrDiP() && config.GetValue("UseSwagger")))
- {
- app.UseSwagger();
- app.UseSwaggerUI();
- app.MapScalarApiReference();
- }
-
- // Set CORS policy
- app.UseCors("AllowSpecificOriginsPolicy");
-
- // Localizer
- string[] supportedCultureNames = ["de-DE", "en-US"];
- IList list = [.. supportedCultureNames.Select(cn => new CultureInfo(cn))];
- var cultureInfo = list.FirstOrDefault() ?? throw new InvalidOperationException("There is no supported culture.");
- var requestLocalizationOptions = new RequestLocalizationOptions
- {
- SupportedCultures = list,
- SupportedUICultures = list
- };
- requestLocalizationOptions.RequestCultureProviders.Add(new QueryStringRequestCultureProvider());
- app.UseRequestLocalization(requestLocalizationOptions);
-
-
- app.UseHttpsRedirection();
-
- app.UseDefaultFiles();
- app.UseStaticFiles();
-
- app.UseAuthentication();
- app.UseAuthorization();
-
- app.MapControllers();
-
- // Catch-all YARP proxy — only forward requests that are not swagger/scalar/openapi paths.
- app.MapReverseProxy();
-
- app.Run();
-}
-catch (Exception ex)
-{
- logger.Error(ex, "Stopped program because of exception");
- throw;
-}
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Properties/PublishProfiles/IISProfileNet8.pubxml b/EnvelopeGenerator.API/Properties/PublishProfiles/IISProfileNet8.pubxml
deleted file mode 100644
index 039b567b..00000000
--- a/EnvelopeGenerator.API/Properties/PublishProfiles/IISProfileNet8.pubxml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- Package
- Release
- Any CPU
-
- true
- false
- 5e0e17c0-ff5a-4246-bf87-1add85376a27
- M:\App&Service\0 DD - Smart UP\signFLOW\PreRelease\API\net8\$(Version)\EnvelopeGenerator.API.zip
- true
- EnvelopeGenerator
- <_TargetId>IISWebDeployPackage
- net8.0
-
-
\ No newline at end of file
diff --git a/EnvelopeGenerator.API/Properties/launchSettings.json b/EnvelopeGenerator.API/Properties/launchSettings.json
deleted file mode 100644
index 365fa0b2..00000000
--- a/EnvelopeGenerator.API/Properties/launchSettings.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/launchsettings.json",
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:4176",
- "sslPort": 44300
- }
- },
- "profiles": {
- "http": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": true,
- "launchUrl": "swagger",
- "applicationUrl": "http://localhost:5131",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "https": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": true,
- "launchUrl": "sender",
- "applicationUrl": "https://localhost:8088;http://localhost:5131",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "angular": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": true,
- "launchUrl": "",
- "applicationUrl": "https://localhost:7174;http://localhost:5131",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "launchUrl": "swagger",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
-}
diff --git a/EnvelopeGenerator.API/appsettings.Development.json b/EnvelopeGenerator.API/appsettings.Development.json
deleted file mode 100644
index dce89096..00000000
--- a/EnvelopeGenerator.API/appsettings.Development.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-"Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
-},
-"ReverseProxy": {
- "Clusters": {
- "receiver-ui": {
- "Destinations": {
- "primary": {
- "Address": "https://localhost:52936"
- }
- }
- }
- }
-},
- "AuthClientParams": {
- "Url": "http://172.24.12.39:9090/auth-hub",
- "PublicKeys": [
- {
- "Issuer": "auth.digitaldata.works",
- "Audience": "sign-flow.digitaldata.works"
- }
- ],
- "RetryDelay": "00:00:05"
- }
-}
diff --git a/EnvelopeGenerator.API/appsettings.json b/EnvelopeGenerator.API/appsettings.json
deleted file mode 100644
index a3907871..00000000
--- a/EnvelopeGenerator.API/appsettings.json
+++ /dev/null
@@ -1,256 +0,0 @@
-{
- "UseSwagger": true,
- "UseDbMigration": false,
- "DiPMode": true,
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- },
- "AllowedHosts": "*",
- "AllowedOrigins": [ "http://localhost:4200", "http://172.24.12.39:9090", "https://localhost:8088", "http://localhost:5131", "http://localhost:7192" ],
- "ConnectionStrings": {
- "Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;",
- "DbMigrationTest": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM_DATA_MIGR_TEST;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
- },
- "DirectorySearchOptions": {
- "ServerName": "DD-VMP01-DC01",
- "Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works",
- "UserCacheExpirationDays": 1,
- "CustomSearchFilters": {
- "User": "(&(objectClass=user)(sAMAccountName=*))",
- "Group": "(&(objectClass=group)(samAccountName=*))"
- }
- },
- "AuthClientParams": {
- "Url": "http://172.24.12.39:9090/auth-hub",
- "PublicKeys": [
- {
- "Issuer": "auth.digitaldata.works",
- "Audience": "sign-flow.digitaldata.works"
- }
- ],
- "RetryDelay": "00:00:05"
- },
- "AuthTokenKeys": {
- "Cookie": "AuthToken",
- "QueryString": "AuthToken",
- "Issuer": "auth.digitaldata.works",
- "Audience": "sign-flow.digitaldata.works"
- },
- "PSPDFKitLicenseKey": "SXCtGGY9XA-31OGUXQK-r7c6AkdLGPm2ljuyDr1qu0kkhLvydg-Do-fxpNUF4Rq3fS_xAnZRNFRHbXpE6sQ2BMcCSVTcXVJO6tPviexjpiT-HnrDEySlUERJnnvh-tmeOWprxS6BySPnSILkmaVQtUfOIUS-cUbvvEYHTvQBKbSF8di4XHQFyfv49ihr51axm3NVV3AXwh2EiKL5C5XdqBZ4sQ4O7vXBjM2zvxdPxlxdcNYmiU83uAzw7B83O_jubPzya4CdUHh_YH7Nlp2gP56MeG1Sw2JhMtfG3Rj14Sg4ctaeL9p6AEWca5dDjJ2li5tFIV2fQSsw6A_cowLu0gtMm5i8IfJXeIcQbMC2-0wGv1oe9hZYJvFMdzhTM_FiejM0agemxt3lJyzuyP8zbBSOgp7Si6A85krLWPZptyZBTG7pp7IHboUHfPMxCXqi-zMsqewOJtQBE2mjntU-lPryKnssOpMPfswwQX7QSkJYV5EMqNmEhQX6mEkp2wcqFzMC7bJQew1aO4pOpvChUaMvb1vgRek0HxLag0nwQYX2YrYGh7F_xXJs-8HNwJe8H0-eW4x4faayCgM5rB5772CCCsD9ThZcvXFrjNHHLGJ8WuBUFm6LArvSfFQdii_7j-_sqHMpeKZt26NFgivj1A==",
- "Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value.
- "default-src 'self'",
- "script-src 'self' 'nonce-{0}' 'unsafe-eval'",
- "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com:*",
- "img-src 'self' data: https: blob:",
- "font-src 'self' https://fonts.gstatic.com:*",
- "connect-src 'self' https://nominatim.openstreetmap.org:* http://localhost:* https://localhost:* ws://localhost:* wss://localhost:* blob:",
- "frame-src 'self'",
- "media-src 'self'",
- "object-src 'self'"
- ],
- "NLog": {
- "throwConfigExceptions": true,
- "variables": {
- "logDirectory": "E:\\LogFiles\\Digital Data\\signFlow",
- "logFileNamePrefix": "${shortdate}-ECM.EnvelopeGenerator.Web"
- },
- "targets": {
- "infoLogs": {
- "type": "File",
- "fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log",
- "maxArchiveDays": 30
- },
- "errorLogs": {
- "type": "File",
- "fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log",
- "maxArchiveDays": 30
- },
- "criticalLogs": {
- "type": "File",
- "fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log",
- "maxArchiveDays": 30
- }
- },
- // Trace, Debug, Info, Warn, Error and *Fatal*
- "rules": [
- {
- "logger": "*",
- "minLevel": "Info",
- "maxLevel": "Warn",
- "writeTo": "infoLogs"
- },
- {
- "logger": "*",
- "level": "Error",
- "writeTo": "errorLogs"
- },
- {
- "logger": "*",
- "level": "Fatal",
- "writeTo": "criticalLogs"
- }
- ]
- },
- "ContactLink": {
- "Label": "Kontakt",
- "Href": "https://digitaldata.works/",
- "HrefLang": "de",
- "Target": "_blank",
- "Title": "Digital Data GmbH"
- },
- /* Resx naming format is -> Resource.language.resx (eg: Resource.de_DE.resx).
- To add a new language, first you should write the required resx file.
- first is the default culture name. */
- "Cultures": [
- {
- "Language": "de-DE",
- "FIClass": "fi-de"
- },
- {
- "Language": "en-US",
- "FIClass": "fi-us"
- }
- ],
- "DisableMultiLanguage": false,
- "Regexes": [
- {
- "Pattern": "/^\\p{L}+(?:([\\ \\-\\']|(\\.\\ ))\\p{L}+)*$/u",
- "Name": "City",
- "Platforms": [ ".NET" ]
- },
- {
- "Pattern": "/^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$/",
- "Name": "City",
- "Platforms": [ "javascript" ]
- }
- ],
- "CustomImages": {
- "App": {
- "Src": "/img/DD_signFLOW_LOGO.png",
- "Classes": {
- "Main": "signFlow-logo"
- }
- },
- "Company": {
- "Src": "/img/digital_data.svg",
- "Classes": {
- "Show": "dd-show-logo",
- "Locked": "dd-locked-logo"
- }
- }
- },
- "DispatcherParams": {
- "SendingProfile": 1,
- "AddedWho": "DDEnvelopGenerator",
- "ReminderTypeId": 202377,
- "EmailAttmt1": ""
- },
- "MailParams": {
- "Placeholders": {
- "[NAME_PORTAL]": "signFlow",
- "[SIGNATURE_TYPE]": "signieren",
- "[REASON]": ""
- }
- },
- "GtxMessagingParams": {
- "Uri": "https://rest.gtx-messaging.net",
- "Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json",
- "Headers": {},
- "QueryParams": {
- "from": "signFlow"
- }
- },
- "TFARegParams": {
- "TimeLimit": "00:30:00"
- },
- "DbTriggerParams": {
- "Envelope": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ],
- "EnvelopeHistory": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ],
- "EmailOut": [ "TBEMLP_EMAIL_OUT_AFT_INS", "TBEMLP_EMAIL_OUT_AFT_UPD" ],
- "EnvelopeReceiverReadOnly": [ "TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD" ],
- "Receiver": [],
- "EmailTemplate": [ "TBSIG_EMAIL_TEMPLATE_AFT_UPD" ]
- },
- "Cache": {
- "SignatureCacheExpiration": null,
- "SqlServer": {
- "ConnectionString": null,
- "SchemaName": "dbo",
- "TableName": "TBDD_CACHE"
- }
- },
- "MainPageTitle": null,
- "AnnotationParams": {
- "Background": {
- "Margin": 0.20,
- "BackgroundColor": {
- "R": 222,
- "G": 220,
- "B": 215
- },
- "BorderColor": {
- "R": 204,
- "G": 202,
- "B": 198
- },
- "BorderStyle": "underline",
- "BorderWidth": 4
- },
- "DefaultAnnotation": {
- "Width": 1,
- "Height": 0.5,
- "MarginTop": 1
- },
- "Annotations": [
- {
- "Name": "Signature",
- "MarginTop": 0
- },
- {
- "Name": "PositionLabel",
- "VerBoundAnnotName": "Signature",
- "WidthRatio": 1.2,
- "HeightRatio": 0.5,
- "MarginTopRatio": 0.22
- },
- {
- "Name": "Position",
- "VerBoundAnnotName": "PositionLabel",
- "WidthRatio": 1.2,
- "HeightRatio": 0.5,
- "MarginTopRatio": -0.05
- },
- {
- "Name": "CityLabel",
- "VerBoundAnnotName": "Position",
- "WidthRatio": 1.2,
- "HeightRatio": 0.5,
- "MarginTopRatio": 0.05
- },
- {
- "Name": "City",
- "VerBoundAnnotName": "CityLabel",
- "WidthRatio": 1.2,
- "HeightRatio": 0.5,
- "MarginTopRatio": -0.05
- },
- {
- "Name": "DateLabel",
- "VerBoundAnnotName": "City",
- "WidthRatio": 1.55,
- "HeightRatio": 0.5,
- "MarginTopRatio": 0.05
- },
- {
- "Name": "Date",
- "VerBoundAnnotName": "DateLabel",
- "WidthRatio": 1.55,
- "HeightRatio": 0.5,
- "MarginTopRatio": -0.1
- }
- ]
- }
-}
diff --git a/EnvelopeGenerator.API/yarp.json b/EnvelopeGenerator.API/yarp.json
deleted file mode 100644
index aba392dd..00000000
--- a/EnvelopeGenerator.API/yarp.json
+++ /dev/null
@@ -1,185 +0,0 @@
-{
-"ReverseProxy": {
- "Routes": {
- "receiver-ui-root": {
- "ClusterId": "receiver-ui",
- "Order": 300,
- "Match": {
- "Path": "/",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- { "PathSet": "/index.html" }
- ]
- },
- "receiver-ui-sender": {
- "ClusterId": "receiver-ui",
- "Order": 100,
- "Match": {
- "Path": "/sender/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- { "PathSet": "/index.html" }
- ]
- },
- "receiver-ui-envelope": {
- "ClusterId": "receiver-ui",
- "Order": 100,
- "Match": {
- "Path": "/envelope/{EnvelopeKey}",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- { "PathSet": "/index.html" }
- ]
- },
- "receiver-ui-envelope-dxreportviewer": {
- "ClusterId": "receiver-ui",
- "Order": 90,
- "Match": {
- "Path": "/envelope/{EnvelopeKey}/DxReportViewer",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- { "PathSet": "/index.html" }
- ]
- },
- "receiver-ui-blazor-framework": {
- "ClusterId": "receiver-ui",
- "Order": 50,
- "Match": {
- "Path": "/_framework/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-blazor-content": {
- "ClusterId": "receiver-ui",
- "Order": 50,
- "Match": {
- "Path": "/_content/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-static-css": {
- "ClusterId": "receiver-ui",
- "Order": 200,
- "Match": {
- "Path": "/css/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- {
- "ResponseHeader": "Cache-Control",
- "Set": "no-cache, no-store, must-revalidate",
- "When": "Always"
- }
- ]
- },
- "receiver-ui-static-js": {
- "ClusterId": "receiver-ui",
- "Order": 200,
- "Match": {
- "Path": "/js/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- },
- "Transforms": [
- {
- "ResponseHeader": "Cache-Control",
- "Set": "no-cache, no-store, must-revalidate",
- "When": "Always"
- }
- ]
- },
- "receiver-ui-fake-data": {
- "ClusterId": "receiver-ui",
- "Order": 200,
- "Match": {
- "Path": "/fake-data/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-appsettings": {
- "ClusterId": "receiver-ui",
- "Order": 50,
- "Match": {
- "Path": "/appsettings.json",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-appsettings-dev": {
- "ClusterId": "receiver-ui",
- "Order": 50,
- "Match": {
- "Path": "/appsettings.Development.json",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-styles": {
- "ClusterId": "receiver-ui",
- "Order": 50,
- "Match": {
- "Path": "/EnvelopeGenerator.ReceiverUI.styles.css",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-fonts": {
- "ClusterId": "receiver-ui",
- "Order": 200,
- "Match": {
- "Path": "/fonts/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "receiver-ui-images": {
- "ClusterId": "receiver-ui",
- "Order": 200,
- "Match": {
- "Path": "/images/{**catch-all}",
- "Methods": [ "GET", "HEAD" ]
- }
- },
- "auth-login": {
- "ClusterId": "auth-hub",
- "Match": {
- "Path": "/api/auth",
- "Methods": [ "POST" ]
- },
- "Transforms": [
- { "PathSet": "/api/auth/sign-flow" }
- ]
- },
- "auth-envelope-receiver-login": {
- "ClusterId": "auth-hub",
- "Match": {
- "Path": "/api/Auth/envelope-receiver/{key}",
- "Methods": [ "POST" ]
- },
- "Transforms": [
- { "PathPattern": "/api/auth/envelope-receiver/{key}" },
- {
- "QueryValueParameter": "cookie",
- "Set": "true"
- }
- ]
- }
- },
- "Clusters": {
- "receiver-ui": {
- "Destinations": {
- "primary": {
- "Address": "https://localhost:52936"
- }
- }
- },
- "auth-hub": {
- "Destinations": {
- "primary": {
- "Address": "http://172.24.12.39:9090"
- }
- }
- }
- }
- }
-}
-
diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln
index 4b7867c0..cca97ec9 100644
--- a/EnvelopeGenerator.sln
+++ b/EnvelopeGenerator.sln
@@ -36,8 +36,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.PdfEditor
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Tests", "EnvelopeGenerator.Tests\EnvelopeGenerator.Tests.csproj", "{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.API", "EnvelopeGenerator.API\EnvelopeGenerator.API.csproj", "{EC768913-6270-14F4-1DD3-69C87A659462}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.DependencyInjection", "EnvelopeGenerator.DependencyInjection\EnvelopeGenerator.DependencyInjection.csproj", "{5DCCF9A1-C03F-90E6-87D3-E96DB25250C2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvelopeGenerator.Server", "EnvelopeGenerator.Server", "{BF1700D5-592E-4FFA-84E8-5480E289A1F0}"
@@ -95,10 +93,6 @@ Global
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.Build.0 = Release|Any CPU
- {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.Build.0 = Release|Any CPU
{5DCCF9A1-C03F-90E6-87D3-E96DB25250C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DCCF9A1-C03F-90E6-87D3-E96DB25250C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DCCF9A1-C03F-90E6-87D3-E96DB25250C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -136,7 +130,6 @@ Global
{6D56C01F-D6CB-4D8A-BD3D-4FD34326998C} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8} = {0CBC2432-A561-4440-89BC-671B66A24146}
- {EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{5DCCF9A1-C03F-90E6-87D3-E96DB25250C2} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{BF1700D5-592E-4FFA-84E8-5480E289A1F0} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{4E6C54DA-576D-0955-2564-9EC890BB8279} = {BF1700D5-592E-4FFA-84E8-5480E289A1F0}
From 380a5f4c0cdcd33796d16fb505e938bb1d30dfac Mon Sep 17 00:00:00 2001
From: TekH
Date: Mon, 28 Sep 2026 12:21:44 +0200
Subject: [PATCH 2/2] Add signature submission feature and pipeline updates
Introduced a new feature for submitting signatures, including
backend and frontend changes. Added `SignatureSubmitDto` and
`SubmitAsync` in `SignatureService` to handle signature data
submission. Implemented a new `Submit` endpoint in
`SignatureController` to validate and process signature payloads.
Updated pipeline behaviors to include `SaveSignatureBehavior`
and adjusted the execution order. Enhanced query logic in
`EnvelopeReceiverResolutionBehavior` and `SaveSignatureBehavior`
to align with the updated data model.
Refactored `EGDbContext` to improve trigger handling and logging.
Updated `ReceiverSignedPage.razor` to integrate `SignatureService`
and handle submission errors gracefully. Adjusted application
URLs in `launchSettings.json` and added new database triggers
in `appsettings.json`.
---
.../Common/Dto/Signature.cs | 4 +-
.../DependencyInjection.cs | 11 +++--
.../EnvelopeReceiverResolutionBehavior.cs | 6 ++-
.../Behaviors/SaveSignatureBehavior.cs | 4 +-
.../EGDbContext.cs | 24 ++++++---
.../Models/SignatureSubmitDto.cs | 10 ++++
.../Services/SignatureService.cs | 29 +++++++++++
.../Components/Pages/ReceiverSignedPage.razor | 42 +++++++++++++++-
.../Controllers/SignatureController.cs | 49 ++++++++++++++++++-
.../Properties/launchSettings.json | 2 +-
.../EnvelopeGenerator.Server/appsettings.json | 2 +
11 files changed, 162 insertions(+), 21 deletions(-)
create mode 100644 EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Models/SignatureSubmitDto.cs
diff --git a/EnvelopeGenerator.Application/Common/Dto/Signature.cs b/EnvelopeGenerator.Application/Common/Dto/Signature.cs
index 9a934934..71af71eb 100644
--- a/EnvelopeGenerator.Application/Common/Dto/Signature.cs
+++ b/EnvelopeGenerator.Application/Common/Dto/Signature.cs
@@ -49,7 +49,7 @@ public sealed record Signature
public string? Position
{
get => _position;
- init => _position = string.IsNullOrWhiteSpace(value) ? value : null;
+ init => _position = string.IsNullOrWhiteSpace(value) ? null : value;
}
///
@@ -62,4 +62,4 @@ public sealed record Signature
/// Example: "Berlin" ? rendered as "Berlin, 26.01.2025"
///
public required string Place { get; init; }
-}
\ No newline at end of file
+}
diff --git a/EnvelopeGenerator.Application/DependencyInjection.cs b/EnvelopeGenerator.Application/DependencyInjection.cs
index 23715f65..bf41d504 100644
--- a/EnvelopeGenerator.Application/DependencyInjection.cs
+++ b/EnvelopeGenerator.Application/DependencyInjection.cs
@@ -65,18 +65,21 @@ public static class DependencyInjection
cfg.AddBehavior, EnvelopeReceiverResolutionBehavior>();
// 1. AnnotationBehavior - Saves annotations (executes second)
+ cfg.AddBehavior, SaveSignatureBehavior>();
+
+ // 2. AnnotationBehavior - Saves annotations for legacy web flow
cfg.AddBehavior, AnnotationBehavior>();
- // 2. DocStatusBehavior - Creates document status (executes third)
+ // 3. DocStatusBehavior - Creates document status
cfg.AddBehavior, DocStatusBehavior>();
- // 3. HistoryBehavior - Records history (executes fourth)
+ // 4. HistoryBehavior - Records history
cfg.AddBehavior, HistoryBehavior>();
- // 4. SendSignedMailBehavior - Sends notification email (executes LAST, only if all previous succeed)
+ // 5. SendSignedMailBehavior - Sends notification email (executes LAST)
cfg.AddBehavior, SendSignedMailBehavior>();
});
return services;
}
-}
\ No newline at end of file
+}
diff --git a/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/EnvelopeReceiverResolutionBehavior.cs b/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/EnvelopeReceiverResolutionBehavior.cs
index 8eeb1669..5a1946d4 100644
--- a/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/EnvelopeReceiverResolutionBehavior.cs
+++ b/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/EnvelopeReceiverResolutionBehavior.cs
@@ -43,7 +43,11 @@ public class EnvelopeReceiverResolutionBehavior : IPipelineBehavior x.Envelope)
+ .Include(x => x.Receiver)
+ .SingleOrDefaultAsync(cancellationToken)
?? throw new NotFoundException("EnvelopeReceiver not found");
request.SetEnvelopeReceiver(_mapper.Map(er));
diff --git a/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/SaveSignatureBehavior.cs b/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/SaveSignatureBehavior.cs
index e4aecec0..f1207ae3 100644
--- a/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/SaveSignatureBehavior.cs
+++ b/EnvelopeGenerator.Application/DocReceiverElements/Behaviors/SaveSignatureBehavior.cs
@@ -50,8 +50,8 @@ public class SaveSignatureBehavior : IPipelineBehavior
throw new BadRequestException($"Signatures are required for saving signature behavior.");
var elements = await _elementRepo
- .Where(e => e.Document.EnvelopeId == request.Envelope.Id)
- .Where(e => e.ReceiverId == request.Receiver.Id)
+ .Where(e => e.Document.EnvelopeId == request.EnvelopeReceiver.EnvelopeId)
+ .Where(e => e.ReceiverId == request.EnvelopeReceiver.ReceiverId)
.ToListAsync(cancel);
foreach (var element in elements)
diff --git a/EnvelopeGenerator.Infrastructure/EGDbContext.cs b/EnvelopeGenerator.Infrastructure/EGDbContext.cs
index 2b6bdee0..b66f856f 100644
--- a/EnvelopeGenerator.Infrastructure/EGDbContext.cs
+++ b/EnvelopeGenerator.Infrastructure/EGDbContext.cs
@@ -204,16 +204,24 @@ public abstract class EGDbContextBase : DbContext
#region Trigger
// Configure entities to handle database triggers
- void AddTrigger() where T : class => _triggers
- .Where(t => t.Key == typeof(T).Name)
- .SelectMany(t => t.Value)
- .ForEach(tName =>
+ void AddTrigger() where T : class
+ {
+ var entityName = typeof(T).Name;
+
+ var configuredTriggerNames = _triggers
+ .Where(t => t.Key == entityName)
+ .SelectMany(t => t.Value)
+ .Distinct()
+ .ToList();
+
+ foreach (var triggerName in configuredTriggerNames)
{
#if NET
- modelBuilder.Entity().ToTable(tb => tb.HasTrigger(tName));
+ modelBuilder.Entity().ToTable(tb => tb.HasTrigger(triggerName));
#endif
- _logger?.LogInformation("Trigger '{triggerName}' has been added to the '{entityName}' entity.", tName, typeof(T).Name);
- });
+ _logger?.LogInformation("Trigger '{triggerName}' has been added to the '{entityName}' entity.", triggerName, entityName);
+ }
+ }
// TODO: call add trigger methods with attributes and reflection
AddTrigger();
@@ -243,4 +251,4 @@ public abstract class EGDbContextBase : DbContext
#if NETFRAMEWORK
}
-#endif
\ No newline at end of file
+#endif
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Models/SignatureSubmitDto.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Models/SignatureSubmitDto.cs
new file mode 100644
index 00000000..78d32317
--- /dev/null
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Models/SignatureSubmitDto.cs
@@ -0,0 +1,10 @@
+namespace EnvelopeGenerator.Server.Client.Models;
+
+public sealed record SignatureSubmitDto
+{
+ public required int Id { get; init; }
+ public required string DataUrl { get; init; }
+ public required string FullName { get; init; }
+ public string? Position { get; init; }
+ public required string Place { get; init; }
+}
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureService.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureService.cs
index a8f76d22..7b64dffb 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureService.cs
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureService.cs
@@ -1,6 +1,7 @@
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
+using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Server.Client.Models;
namespace EnvelopeGenerator.Server.Client.Services;
@@ -21,4 +22,32 @@ public class SignatureService(IHttpClientFactory httpClientFactory)
var result = await response.Content.ReadFromJsonAsync>(_jsonOptions, cancel);
return result ?? [];
}
+
+ public async Task SubmitAsync(string envelopeKey, IEnumerable signatures, CancellationToken cancel = default)
+ {
+ using var http = httpClientFactory.CreateClient("EnvelopeGenerator.Server");
+
+ var payload = signatures
+ .Select(signature => new Signature
+ {
+ Id = signature.Id,
+ DataUrl = signature.DataUrl,
+ FullName = signature.FullName,
+ Position = signature.Position,
+ Place = signature.Place
+ })
+ .ToList();
+
+ var response = await http.PostAsJsonAsync(
+ $"/api/Signature/submit/{Uri.EscapeDataString(envelopeKey)}",
+ payload,
+ cancel);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var body = await response.Content.ReadAsStringAsync(cancel);
+ throw new HttpRequestException(
+ $"Failed to submit signature for envelope {envelopeKey}: {(int)response.StatusCode} {response.StatusCode} - {body}");
+ }
+ }
}
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/ReceiverSignedPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/ReceiverSignedPage.razor
index 0a26cc4b..63119a0c 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/ReceiverSignedPage.razor
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/ReceiverSignedPage.razor
@@ -12,6 +12,7 @@
@inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService
@inject EnvelopeGenerator.Server.Services.EnvelopeReceiverAuthorizationService ReceiverAuthorizationService
@inject EnvelopeGenerator.Server.Services.EnvelopeReceiverPageDataService PageDataService
+@inject SignatureService SignatureService
@inject AppVersionService AppVersion
@inject IMemoryCache MemoryCache
@inject ILogger Logger
@@ -122,6 +123,12 @@
+ @if (!string.IsNullOrWhiteSpace(_submitErrorMessage))
+ {
+
+ @_submitErrorMessage
+
+ }
@@ -161,17 +168,48 @@
// ----- Submit / logout state -----
bool _isLoggingOut = false;
bool _submitConfirmVisible = false;
+ string? _submitErrorMessage;
void OpenSubmitConfirmPopup() => _submitConfirmVisible = true;
async Task SubmitAndLogoutAsync()
{
if (_isLoggingOut) return;
+
+ if (string.IsNullOrWhiteSpace(EnvelopeKey) || _sig is null)
+ return;
+
_isLoggingOut = true;
_submitConfirmVisible = false;
+ _submitErrorMessage = null;
await InvokeAsync(StateHasChanged);
- await AuthService.LogoutEnvelopeReceiverAsync(EnvelopeKey!);
- Navigation.NavigateTo("/", forceLoad: true);
+
+ try
+ {
+ if (_signatures.Count == 0)
+ throw new InvalidOperationException("No signature fields found for receiver.");
+
+ var payload = _signatures.Select(field => new SignatureSubmitDto
+ {
+ Id = field.Id,
+ DataUrl = _sig.DataUrl,
+ FullName = _sig.FullName,
+ Position = string.IsNullOrWhiteSpace(_sig.Position) ? null : _sig.Position,
+ Place = _sig.Place
+ }).ToList();
+
+ await SignatureService.SubmitAsync(EnvelopeKey, payload);
+
+ await AuthService.LogoutEnvelopeReceiverAsync(EnvelopeKey);
+ Navigation.NavigateTo("/", forceLoad: true);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "Failed to finalize signature for {EnvelopeKey}", EnvelopeKey);
+ _submitErrorMessage = "Die Unterschrift konnte nicht abgeschlossen werden. Bitte versuchen Sie es erneut.";
+ _isLoggingOut = false;
+ await InvokeAsync(StateHasChanged);
+ }
}
protected override async Task OnInitializedAsync()
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/SignatureController.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/SignatureController.cs
index 2c951983..9e9a33cd 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/SignatureController.cs
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/SignatureController.cs
@@ -1,7 +1,10 @@
using EnvelopeGenerator.Server.Extensions;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Extensions;
+using EnvelopeGenerator.Application.DocReceiverElements.Commands;
using EnvelopeGenerator.Application.Documents.Queries;
+using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
+using EnvelopeGenerator.Application.Histories.Queries;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@@ -18,13 +21,15 @@ namespace EnvelopeGenerator.Server.Controllers;
public class SignatureController : ControllerBase
{
private readonly IMediator _mediator;
+ private readonly ILogger _logger;
///
/// Initializes a new instance of .
///
- public SignatureController(IMediator mediator)
+ public SignatureController(IMediator mediator, ILogger logger)
{
_mediator = mediator;
+ _logger = logger;
}
//TODO: update to use signature query
@@ -54,4 +59,46 @@ public class SignatureController : ControllerBase
else
return Ok(rcvSignatures);
}
+
+ ///
+ /// Finalizes the receiver signing flow and persists signature data to TBSIG_DOCUMENT_RECEIVER_ELEMENT.
+ /// Also triggers status/history/mail side effects through SigningCommand pipeline.
+ ///
+ [Authorize(Policy = AuthPolicy.Receiver)]
+ [HttpPost("submit/{envelopeKey}")]
+ public async Task Submit(
+ [FromRoute] string envelopeKey,
+ [FromBody] IEnumerable? signatures,
+ CancellationToken cancel)
+ {
+ if (signatures is null)
+ return BadRequest("Signature payload is required.");
+
+ var uuid = User.EnvelopeUuid();
+ var receiverSignature = User.ReceiverSignature();
+
+ if (await _mediator.IsSignedAsync(uuid, receiverSignature, cancel))
+ return Problem(statusCode: StatusCodes.Status409Conflict);
+
+ if (await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel))
+ return Problem(statusCode: StatusCodes.Status423Locked);
+
+ try
+ {
+ await _mediator.Send(new SigningCommand
+ {
+ Envelope = new() { Uuid = uuid },
+ Receiver = new() { Signature = receiverSignature },
+ ReceiverAppType = ReceiverAppType.ReceiverUI,
+ Signatures = signatures.ToList()
+ }, cancel);
+
+ return Ok();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to submit signatures for envelope {EnvelopeKey}", envelopeKey);
+ throw;
+ }
+ }
}
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Properties/launchSettings.json b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Properties/launchSettings.json
index 39f160ad..64b21d1a 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Properties/launchSettings.json
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Properties/launchSettings.json
@@ -13,7 +13,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
- "applicationUrl": "https://localhost:8088;http://localhost:5131",
+ "applicationUrl": "https://localhost:8089;http://localhost:5132",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json
index 9dadd643..060188ee 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json
@@ -185,8 +185,10 @@
"TimeLimit": "00:30:00"
},
"DbTriggerParams": {
+ "DocReceiverElement": [ "TBSIG_DOCUMENT_RECEIVER_ELEMENT_AFT_INS", "TBSIG_DOCUMENT_RECEIVER_ELEMENT_AFT_UPD" ],
"Envelope": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ],
"EnvelopeHistory": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ],
+ "History": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ],
"EmailOut": [ "TBEMLP_EMAIL_OUT_AFT_INS", "TBEMLP_EMAIL_OUT_AFT_UPD" ],
"EnvelopeReceiverReadOnly": [ "TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD" ],
"Receiver": [],