Compare commits
201 Commits
feat/annot
...
web-multi-
| Author | SHA1 | Date | |
|---|---|---|---|
| 352618a745 | |||
| 8cf6484786 | |||
| 7345b8f877 | |||
| dc6a2027d6 | |||
| 8f94317e80 | |||
| f175e39de2 | |||
| 36794cb98b | |||
| fc8f9486c0 | |||
| 566dae8e2e | |||
| 9763ff05cf | |||
| 83f571b226 | |||
| 95ea4db0a0 | |||
| a2e68d275f | |||
| 41cf52fd41 | |||
| 171ab508c5 | |||
| 924e39253a | |||
| aba68faa4d | |||
| f1ceaab70a | |||
| f855c60be4 | |||
| 8f9ca082e5 | |||
| deec1b1df5 | |||
| a982f48ef9 | |||
| 297ab458c7 | |||
| 0e270e3182 | |||
| bcf55f7906 | |||
| 489b2d0917 | |||
| 63fbdc3bd5 | |||
| aaf1f75aa7 | |||
| cdca639e4f | |||
| ab57dd4cee | |||
| 745e9c7bfe | |||
| 670c8ed87c | |||
| 91eb5d1e64 | |||
| 9f59a17f63 | |||
| 2a0f7f99d6 | |||
| ec674b6e80 | |||
| 10f23170fd | |||
| 0ec823ec9e | |||
| 06884fe809 | |||
| c2d5bd65aa | |||
| cfcd43b0ed | |||
| f41199c389 | |||
| 03e3e0eaf4 | |||
| c8ca1ef22a | |||
| d31916eab8 | |||
| ee7c92ff5b | |||
| 89db852705 | |||
| c674a450d8 | |||
| 910a870ddf | |||
| e2afbc5a62 | |||
| 0fb94decdd | |||
| 2c81583831 | |||
| 47eade57a3 | |||
| d094fe14da | |||
| 0dc356726b | |||
| b227eb4051 | |||
| de36e29743 | |||
| 6291712291 | |||
| 73527a97d7 | |||
| ff094ebfe1 | |||
| 1c948fcbf8 | |||
| eba40acd4d | |||
| 5cb3465e12 | |||
| 2c43fdbaed | |||
| eb96842122 | |||
| a8cb8f935c | |||
| 387456659d | |||
| 17e3a67fe5 | |||
| 632723de5a | |||
| 6611b92fdb | |||
| 5baa28bac8 | |||
| c965975f82 | |||
| d480dd3a36 | |||
| ae7f0b80f3 | |||
| ef7c9c2b97 | |||
| 27f0aae8e0 | |||
| 1b10162c85 | |||
| bd0426dbee | |||
| b1551537c8 | |||
| 95b2ab5aed | |||
| ebed51b46a | |||
| 0d2425c9cf | |||
| c6c8747d23 | |||
| eb345a0e4d | |||
| 1b95b9d7e0 | |||
| d99193979f | |||
| 8742ea6025 | |||
| 2b8edc697a | |||
| 7c88d4ed4b | |||
| a6be907307 | |||
| 2fcea78574 | |||
| e8e428f935 | |||
| 9450ed3486 | |||
| 583a07c646 | |||
| 51ad4fbc2c | |||
| 50ac7570ea | |||
| 5465996563 | |||
| 1b840f4ae3 | |||
| 3923a3b403 | |||
| ada621ac46 | |||
| abbe6a26a9 | |||
| 3066dac541 | |||
| b1aa6d6639 | |||
| 31fe1c34f2 | |||
| d7644bfe07 | |||
| 4759b16a85 | |||
| cfdfb43631 | |||
| 6254bb6e3f | |||
| f995fa9fc3 | |||
| c2fefe798d | |||
| 849a282ec5 | |||
| 6b23dcdba7 | |||
| a60d0f63e2 | |||
| 2481059b49 | |||
| 6334097d5e | |||
| 9baa126c8c | |||
| 1ef46013cd | |||
| 72dffd1043 | |||
| eda30472b9 | |||
| 75846573da | |||
| f59c0d90ad | |||
| cf40449112 | |||
| a59d4836d4 | |||
| f475cf4ea9 | |||
| d39018ca39 | |||
| b49482137f | |||
| bd40404d97 | |||
| 6f16921a79 | |||
| 1afc95f9c6 | |||
| 6aed820196 | |||
| e17c4d02f8 | |||
| 8187924a8c | |||
| 1bf530f7e7 | |||
| 9cadc8e901 | |||
| 1d4ad13532 | |||
| 03a8154b1c | |||
| 20b8acd3fc | |||
| a3afeb175f | |||
| 114555c843 | |||
| f294ef2fde | |||
| 02ad819da9 | |||
| 041d98ca78 | |||
| afea2fb5ea | |||
| beeb9e4e75 | |||
| 30d13b1ffb | |||
| 814df63306 | |||
| 830d1af44a | |||
| 94018d2a36 | |||
| cf5a724bf2 | |||
| 172f2e27d7 | |||
| d350e2ae48 | |||
| 2779452d72 | |||
| 5ebc6c6739 | |||
| 891593755e | |||
| b20260674e | |||
| 7e5ff6bcb2 | |||
| 6eed9b1e31 | |||
| d4b1a4921c | |||
| f078bafdde | |||
| 786a3e128d | |||
| ff3a146636 | |||
| 40b2cad598 | |||
| 5c675be0ed | |||
| 58164be640 | |||
| a639377195 | |||
| e3d6e87ee5 | |||
| 2795b91386 | |||
| ca248c3aa6 | |||
| 383634fca6 | |||
| 75097afa06 | |||
| 77975c0644 | |||
| 5707213edd | |||
| ad54ba9dc4 | |||
| 1f233153cf | |||
| 513ec007eb | |||
| 1305714da2 | |||
| 1e90cda393 | |||
| 5a5cbcb14d | |||
| a35f06070a | |||
| 2606066103 | |||
| 7495e062a9 | |||
| 293044bec3 | |||
| e0ff976d21 | |||
| bec45ab1f1 | |||
| fecd054a5c | |||
| 32b488c50f | |||
| 9cfdd16970 | |||
| 4da5848253 | |||
| 88da210ba2 | |||
| fc23ba840e | |||
| 140d271b28 | |||
| a3b12a6957 | |||
| 16bdc7820d | |||
| 06e32b99ea | |||
| c7c78f96a6 | |||
| 5c232e61f2 | |||
| 24c9321c0f | |||
| c75c2b1dd5 | |||
| 8445757f34 | |||
| b088eb089f | |||
| 1f745ae79c |
118
EnvelopeGenerator.API/Controllers/AnnotationController.cs
Normal file
118
EnvelopeGenerator.API/Controllers/AnnotationController.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Application.Histories.Queries;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.API.Extensions;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Manages annotations and signature lifecycle for envelopes.
|
||||
/// </summary>
|
||||
[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<AnnotationController> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="AnnotationController"/>.
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public AnnotationController(
|
||||
ILogger<AnnotationController> logger,
|
||||
IEnvelopeHistoryService envelopeHistoryService,
|
||||
IEnvelopeReceiverService envelopeReceiverService,
|
||||
IMediator mediator)
|
||||
{
|
||||
_historyService = envelopeHistoryService;
|
||||
_envelopeReceiverService = envelopeReceiverService;
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates or updates annotations for the authenticated envelope receiver.
|
||||
/// </summary>
|
||||
/// <param name="psPdfKitAnnotation">Annotation payload.</param>
|
||||
/// <param name="cancel">Cancellation token.</param>
|
||||
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||
[HttpPost]
|
||||
[Obsolete("PSPDF Kit will no longer be used.")]
|
||||
public async Task<IActionResult> CreateOrUpdate([FromBody] PsPdfKitAnnotation? psPdfKitAnnotation = null, CancellationToken cancel = default)
|
||||
{
|
||||
var signature = User.GetReceiverSignatureOfReceiver();
|
||||
var uuid = User.GetEnvelopeUuidOfReceiver();
|
||||
|
||||
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 docSignedNotification = await _mediator
|
||||
.ReadEnvelopeReceiverAsync(uuid, signature, cancel)
|
||||
.ToDocSignedNotification(psPdfKitAnnotation)
|
||||
?? throw new NotFoundException("Envelope receiver is not found.");
|
||||
|
||||
await _mediator.PublishSafely(docSignedNotification, cancel);
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rejects the document for the current receiver.
|
||||
/// </summary>
|
||||
/// <param name="reason">Optional rejection reason.</param>
|
||||
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||
[HttpPost("reject")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> Reject([FromBody] string? reason = null)
|
||||
{
|
||||
var signature = User.GetReceiverSignatureOfReceiver();
|
||||
var uuid = User.GetEnvelopeUuidOfReceiver();
|
||||
var mail = User.GetReceiverMailOfReceiver();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
76
EnvelopeGenerator.API/Controllers/AuthController.cs
Normal file
76
EnvelopeGenerator.API/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Controller verantwortlich für die Benutzer-Authentifizierung, einschließlich Anmelden, Abmelden und Überprüfung des Authentifizierungsstatus.
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public partial class AuthController(IOptions<AuthTokenKeys> authTokenKeyOptions, IAuthorizationService authService) : ControllerBase, IAuthController
|
||||
{
|
||||
private readonly AuthTokenKeys authTokenKeys = authTokenKeyOptions.Value;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IAuthorizationService AuthService { get; } = authService;
|
||||
|
||||
/// <summary>
|
||||
/// Entfernt das Authentifizierungs-Cookie des Benutzers (AuthCookie)
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Gibt eine HTTP 200 oder 401.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// POST /api/auth/logout
|
||||
///
|
||||
/// </remarks>
|
||||
/// <response code="200">Erfolgreich gelöscht, wenn der Benutzer ein berechtigtes Cookie hat.</response>
|
||||
/// <response code="401">Wenn es kein zugelassenes Cookie gibt, wird „nicht zugelassen“ zurückgegeben.</response>
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[Authorize(Policy = AuthPolicy.SenderOrReceiver)]
|
||||
[HttpPost("logout")]
|
||||
public async Task<IActionResult> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prüft, ob der Benutzer ein autorisiertes Token hat.
|
||||
/// </summary>
|
||||
/// <returns>Wenn ein autorisiertes Token vorhanden ist HTTP 200 asynchron 401</returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// GET /api/auth
|
||||
///
|
||||
/// </remarks>
|
||||
/// <response code="200">Wenn es einen autorisierten Cookie gibt.</response>
|
||||
/// <response code="401">Wenn kein Cookie vorhanden ist oder nicht autorisierte.</response>
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[HttpGet("check")]
|
||||
[Authorize]
|
||||
public IActionResult Check(string? role = null)
|
||||
=> role is not null && !User.IsInRole(role)
|
||||
? Unauthorized()
|
||||
: Ok();
|
||||
}
|
||||
30
EnvelopeGenerator.API/Controllers/ConfigController.cs
Normal file
30
EnvelopeGenerator.API/Controllers/ConfigController.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Exposes configuration data required by the client applications.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of <see cref="ConfigController"/>.
|
||||
/// </remarks>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ConfigController(IOptionsMonitor<AnnotationParams> annotationParamsOptions) : ControllerBase
|
||||
{
|
||||
private readonly AnnotationParams _annotationParams = annotationParamsOptions.CurrentValue;
|
||||
|
||||
/// <summary>
|
||||
/// Returns annotation configuration that was previously rendered by MVC.
|
||||
/// </summary>
|
||||
[HttpGet("Annotations")]
|
||||
[Obsolete("PSPDF Kit will no longer be used.")]
|
||||
public IActionResult GetAnnotationParams()
|
||||
{
|
||||
return Ok(_annotationParams.AnnotationJSObject);
|
||||
}
|
||||
}
|
||||
63
EnvelopeGenerator.API/Controllers/DocumentController.cs
Normal file
63
EnvelopeGenerator.API/Controllers/DocumentController.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to envelope documents for authenticated receivers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="DocumentController"/> class.
|
||||
/// </remarks>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DocumentController(IMediator mediator, IAuthorizationService authService) : ControllerBase, IAuthController
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IAuthorizationService AuthService => authService;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the document bytes receiver.
|
||||
/// </summary>
|
||||
/// <param name="query">Encoded envelope key.</param>
|
||||
/// <param name="cancel">Cancellation token.</param>
|
||||
[HttpGet]
|
||||
[Authorize(Policy = AuthPolicy.SenderOrReceiver)]
|
||||
public async Task<IActionResult> 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.GetEnvelopeIdOfReceiver();
|
||||
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();
|
||||
}
|
||||
}
|
||||
69
EnvelopeGenerator.API/Controllers/EmailTemplateController.cs
Normal file
69
EnvelopeGenerator.API/Controllers/EmailTemplateController.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for managing temp templates.
|
||||
/// Steuerung zur Verwaltung von E-Mail-Vorlagen.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initialisiert eine neue Instanz der <see cref="EmailTemplateController"/>-Klasse.
|
||||
/// </remarks>
|
||||
/// <param name="mediator">
|
||||
/// Die Mediator-Instanz, die zum Senden von Befehlen und Abfragen verwendet wird.
|
||||
/// </param>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Policy = AuthPolicy.Sender)]
|
||||
public class EmailTemplateController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Ruft E-Mail-Vorlagen basierend auf der angegebenen Abfrage ab.
|
||||
/// Gibt alles zurück, wenn keine Id- oder Typ-Informationen eingegeben wurden.
|
||||
/// </summary>
|
||||
/// <param name="emailTemplate">Die Abfrageparameter zum Abrufen von E-Mail-Vorlagen.</param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns>Gibt HTTP-Antwort zurück</returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
/// GET /api/EmailTemplate?emailTemplateId=123
|
||||
/// </remarks>
|
||||
/// <response code="200">Wenn die E-Mail-Vorlagen erfolgreich abgerufen werden.</response>
|
||||
/// <response code="400">Wenn die Abfrageparameter ungültig sind.</response>
|
||||
/// <response code="401">Wenn der Benutzer nicht authentifiziert ist.</response>
|
||||
/// <response code="404">Wenn die gesuchte Abfrage nicht gefunden wird.</response>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get([FromQuery] ReadEmailTemplateQuery emailTemplate, CancellationToken cancel)
|
||||
{
|
||||
var result = await mediator.Send(emailTemplate, cancel);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="update"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <response code="200">Wenn die E-Mail-Vorlage erfolgreich aktualisiert oder zurückgesetzt wird.</response>
|
||||
/// <response code="400">Wenn die Abfrage ohne einen String gesendet wird.</response>
|
||||
/// <response code="401">Wenn der Benutzer nicht authentifiziert ist.</response>
|
||||
/// <response code="404">Wenn die gesuchte Abfrage nicht gefunden wird.</response>
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> Update([FromBody] UpdateEmailTemplateCommand update, CancellationToken cancel)
|
||||
{
|
||||
await mediator.Send(update, cancel);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
111
EnvelopeGenerator.API/Controllers/EnvelopeController.cs
Normal file
111
EnvelopeGenerator.API/Controllers/EnvelopeController.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Dieser Controller stellt Endpunkte für die Verwaltung von Umschlägen bereit.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class EnvelopeController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<EnvelopeController> _logger;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt eine neue Instanz des EnvelopeControllers.
|
||||
/// </summary>
|
||||
/// <param name="logger">Der Logger, der für das Protokollieren von Informationen verwendet wird.</param>
|
||||
/// <param name="mediator"></param>
|
||||
public EnvelopeController(ILogger<EnvelopeController> logger, IMediator mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ruft eine Liste von Umschlägen basierend auf dem Benutzer und den angegebenen Statusfiltern ab.
|
||||
/// </summary>
|
||||
/// <param name="envelope"></param>
|
||||
/// <returns>Eine IActionResult-Instanz, die die abgerufenen Umschläge oder einen Fehlerstatus enthält.</returns>
|
||||
/// <response code="200">Die Anfrage war erfolgreich, und die Umschläge werden zurückgegeben.</response>
|
||||
/// <response code="400">Die Anfrage war fehlerhaft oder unvollständig.</response>
|
||||
/// <response code="401">Der Benutzer ist nicht authentifiziert.</response>
|
||||
/// <response code="403">Der Benutzer hat keine Berechtigung, auf die Ressource zuzugreifen.</response>
|
||||
/// <response code="500">Ein unerwarteter Fehler ist aufgetreten.</response>
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync([FromQuery] ReadEnvelopeQuery envelope)
|
||||
{
|
||||
var result = await _mediator.Send(envelope.Authorize(User.GetId()));
|
||||
return result.Any() ? Ok(result) : NotFound();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ruft das Ergebnis eines Dokuments basierend auf der ID ab.
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="view">Gibt an, ob das Dokument inline angezeigt werden soll (true) oder als Download bereitgestellt wird (false).</param>
|
||||
/// <returns>Eine IActionResult-Instanz, die das Dokument oder einen Fehlerstatus enthält.</returns>
|
||||
/// <response code="200">Das Dokument wurde erfolgreich abgerufen.</response>
|
||||
/// <response code="404">Das Dokument wurde nicht gefunden oder ist nicht verfügbar.</response>
|
||||
/// <response code="500">Ein unerwarteter Fehler ist aufgetreten.</response>
|
||||
[HttpGet("doc-result")]
|
||||
public async Task<IActionResult> 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");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
[Authorize]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateAsync([FromBody] CreateEnvelopeCommand command)
|
||||
{
|
||||
var res = await _mediator.Send(command.Authorize(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);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,21 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.GeneratorAPI.Models;
|
||||
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 System.Reflection.Metadata;
|
||||
using EnvelopeGenerator.Domain;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.SQL;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
using EnvelopeGenerator.API.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
namespace EnvelopeGenerator.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller für die Verwaltung von Umschlagempfängern.
|
||||
@@ -33,38 +29,19 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
public class EnvelopeReceiverController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<EnvelopeReceiverController> _logger;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeReceiverService _erService;
|
||||
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
private readonly IEnvelopeExecutor _envelopeExecutor;
|
||||
|
||||
private readonly IEnvelopeReceiverExecutor _erExecutor;
|
||||
|
||||
private readonly IDocumentExecutor _documentExecutor;
|
||||
|
||||
private readonly string _cnnStr;
|
||||
|
||||
/// <summary>
|
||||
/// Konstruktor für den EnvelopeReceiverController.
|
||||
/// </summary>
|
||||
/// <param name="logger">Logger-Instanz zur Protokollierung von Informationen und Fehlern.</param>
|
||||
/// <param name="envelopeReceiverService">Service zur Verwaltung von Umschlagempfängern.</param>
|
||||
/// <param name="mediator">Mediator-Instanz zur Verarbeitung von Befehlen und Abfragen.</param>
|
||||
/// <param name="mapper"></param>
|
||||
/// <param name="envelopeExecutor"></param>
|
||||
/// <param name="erExecutor"></param>
|
||||
/// <param name="documentExecutor"></param>
|
||||
/// <param name="csOpt"></param>
|
||||
[Obsolete("Use MediatR")]
|
||||
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IEnvelopeReceiverService envelopeReceiverService, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor, IDocumentExecutor documentExecutor, IOptions<ConnectionString> csOpt)
|
||||
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor, IDocumentExecutor documentExecutor, IOptions<ConnectionString> csOpt)
|
||||
{
|
||||
_logger = logger;
|
||||
_erService = envelopeReceiverService;
|
||||
_mediator = mediator;
|
||||
_mapper = mapper;
|
||||
_envelopeExecutor = envelopeExecutor;
|
||||
@@ -87,32 +64,13 @@ public class EnvelopeReceiverController : ControllerBase
|
||||
/// <response code="500">Ein unerwarteter Fehler ist aufgetreten.</response>
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> GetEnvelopeReceiver([FromQuery] ReadEnvelopeReceiverQuery envelopeReceiver)
|
||||
{
|
||||
var username = User.GetUsernameOrDefault();
|
||||
envelopeReceiver = envelopeReceiver with { Username = User.GetUsername() };
|
||||
|
||||
if (username is null)
|
||||
{
|
||||
_logger.LogError(@"Envelope Receiver dto cannot be sent because username claim is null. Potential authentication and authorization error. The value of other claims are [id: {id}], [username: {username}], [name: {name}], [prename: {prename}], [email: {email}].",
|
||||
User.GetId(), User.GetUsernameOrDefault(), User.GetNameOrDefault(), User.GetPrenameOrDefault(), User.GetEmailOrDefault());
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
var result = await _mediator.Send(envelopeReceiver);
|
||||
|
||||
return await _erService.ReadByUsernameAsync(
|
||||
username: username,
|
||||
min_status: envelopeReceiver.Envelope.Status?.Min,
|
||||
max_status: envelopeReceiver.Envelope.Status?.Max,
|
||||
envelopeQuery: envelopeReceiver.Envelope,
|
||||
receiverQuery: envelopeReceiver.Receiver,
|
||||
ignore_statuses: envelopeReceiver.Envelope.Status?.Ignore ?? Array.Empty<EnvelopeStatus>())
|
||||
.ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, msg);
|
||||
});
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -129,25 +87,17 @@ public class EnvelopeReceiverController : ControllerBase
|
||||
/// <response code="500">Ein unerwarteter Fehler ist aufgetreten.</response>
|
||||
[Authorize]
|
||||
[HttpGet("salute")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> GetReceiverName([FromQuery] ReadReceiverNameQuery receiver)
|
||||
{
|
||||
return await _erService.ReadLastUsedReceiverNameByMailAsync(receiver.EmailAddress, receiver.Id, receiver.Signature).ThenAsync(
|
||||
Success: res => res is null ? NotFound() : Ok(res),
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
if (ntc.HasFlag(Flag.NotFound))
|
||||
return NotFound();
|
||||
|
||||
_logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
var name = await _mediator.Send(receiver);
|
||||
return name is null ? NotFound() : Ok(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Datenübertragungsobjekt mit Informationen zu Umschlägen, Empfängern und Unterschriften.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns>HTTP-Antwort</returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
@@ -183,13 +133,10 @@ public class EnvelopeReceiverController : ControllerBase
|
||||
/// <response code="500">Es handelt sich um einen unerwarteten Fehler. Die Protokolle sollten überprüft werden.</response>
|
||||
[Authorize]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateAsync([FromBody] CreateEnvelopeReceiverCommand request)
|
||||
public async Task<IActionResult> CreateAsync([FromBody] CreateEnvelopeReceiverCommand request, CancellationToken cancel)
|
||||
{
|
||||
CancellationToken cancel = default;
|
||||
int userId = User.GetId();
|
||||
|
||||
#region Create Envelope
|
||||
var envelope = await _envelopeExecutor.CreateEnvelopeAsync(userId, request.Title, request.Message, request.TFAEnabled, cancel);
|
||||
var envelope = await _envelopeExecutor.CreateEnvelopeAsync(User.GetId(), request.Title, request.Message, request.TFAEnabled, cancel);
|
||||
#endregion
|
||||
|
||||
#region Add receivers
|
||||
@@ -270,18 +217,14 @@ public class EnvelopeReceiverController : ControllerBase
|
||||
using (SqlConnection conn = new(_cnnStr))
|
||||
{
|
||||
conn.Open();
|
||||
var formattedSQL_hist = string.Format(sql_hist, envelope.Uuid.ToSqlParam(), 1003.ToSqlParam(), userId.ToSqlParam());
|
||||
using (SqlCommand cmd = new SqlCommand(formattedSQL_hist, conn))
|
||||
{
|
||||
cmd.CommandType = CommandType.Text;
|
||||
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);
|
||||
}
|
||||
}
|
||||
using SqlDataReader reader = cmd.ExecuteReader();
|
||||
if (reader.Read())
|
||||
{
|
||||
bool outSuccess = reader.GetBoolean(0);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
39
EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs
Normal file
39
EnvelopeGenerator.API/Controllers/EnvelopeTypeController.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Application.EnvelopeTypes.Queries;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EnvelopeTypeController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<EnvelopeTypeController> _logger;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="mediator"></param>
|
||||
public EnvelopeTypeController(ILogger<EnvelopeTypeController> logger, IMediator mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAllAsync()
|
||||
{
|
||||
var result = await _mediator.Send(new ReadEnvelopeTypesQuery());
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using EnvelopeGenerator.Application.Histories.Queries;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
namespace EnvelopeGenerator.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Dieser Controller stellt Endpunkte für den Zugriff auf die Umschlaghistorie bereit.
|
||||
@@ -113,6 +113,6 @@ public class HistoryController : ControllerBase
|
||||
public async Task<IActionResult> GetAllAsync([FromQuery] ReadHistoryQuery historyQuery, CancellationToken cancel)
|
||||
{
|
||||
var history = await _mediator.Send(historyQuery, cancel).ThrowIfEmpty(Exceptions.NotFound);
|
||||
return Ok((historyQuery.OnlyLast ?? false) ? history.MaxBy(h => h.AddedWhen) : history);
|
||||
return Ok((historyQuery.OnlyLast) ? history.MaxBy(h => h.AddedWhen) : history);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace EnvelopeGenerator.API.Controllers.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IAuthController
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
IAuthorizationService AuthService { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
ClaimsPrincipal User { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class AuthControllerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="policyName"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<bool> IsUserInPolicyAsync(this IAuthController controller, string policyName)
|
||||
{
|
||||
var result = await controller.AuthService.AuthorizeAsync(controller.User, policyName);
|
||||
return result.Succeeded;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using DigitalData.Core.API;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.CommonServices;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
namespace EnvelopeGenerator.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller für die Verwaltung der Lokalisierung und Spracheinstellungen.
|
||||
@@ -19,7 +19,7 @@ public class LocalizationController : ControllerBase
|
||||
private static readonly Guid L_KEY = Guid.NewGuid();
|
||||
|
||||
private readonly ILogger<LocalizationController> _logger;
|
||||
private readonly IStringLocalizer<Model> _mLocalizer;
|
||||
private readonly IStringLocalizer<Resource> _mLocalizer;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
@@ -34,7 +34,7 @@ public class LocalizationController : ControllerBase
|
||||
ILogger<LocalizationController> logger,
|
||||
IStringLocalizer<Resource> localizer,
|
||||
IMemoryCache memoryCache,
|
||||
IStringLocalizer<Model> _modelLocalizer)
|
||||
IStringLocalizer<Resource> _modelLocalizer)
|
||||
{
|
||||
_logger = logger;
|
||||
_localizer = localizer;
|
||||
91
EnvelopeGenerator.API/Controllers/ReadOnlyController.cs
Normal file
91
EnvelopeGenerator.API/Controllers/ReadOnlyController.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Manages read-only envelope sharing flows.
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ReadOnlyController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<ReadOnlyController> _logger;
|
||||
private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
|
||||
private readonly IEnvelopeMailService _mailService;
|
||||
private readonly IEnvelopeHistoryService _historyService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReadOnlyController"/> class.
|
||||
/// </summary>
|
||||
public ReadOnlyController(ILogger<ReadOnlyController> logger, IEnvelopeReceiverReadOnlyService readOnlyService, IEnvelopeMailService mailService, IEnvelopeHistoryService historyService)
|
||||
{
|
||||
_logger = logger;
|
||||
_readOnlyService = readOnlyService;
|
||||
_mailService = mailService;
|
||||
_historyService = historyService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new read-only receiver for the current envelope.
|
||||
/// </summary>
|
||||
/// <param name="createDto">Creation payload.</param>
|
||||
[HttpPost]
|
||||
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> CreateAsync([FromBody] EnvelopeReceiverReadOnlyCreateDto createDto)
|
||||
{
|
||||
var authReceiverMail = User.GetReceiverMailOfReceiver();
|
||||
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.GetEnvelopeIdOfReceiver();
|
||||
|
||||
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<int, IActionResult>(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);
|
||||
});
|
||||
}
|
||||
}
|
||||
47
EnvelopeGenerator.API/Controllers/ReceiverController.cs
Normal file
47
EnvelopeGenerator.API/Controllers/ReceiverController.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Application.Receivers.Queries;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller für die Verwaltung von Empfängern.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Dieser Controller bietet Endpunkte für das Abrufen von Empfängern basierend auf E-Mail-Adresse oder Signatur.
|
||||
/// </remarks>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ReceiverController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
/// <summary>
|
||||
/// Initialisiert eine neue Instanz des <see cref="ReceiverController"/>-Controllers.
|
||||
/// </summary>
|
||||
/// <param name="mediator">Mediator für Anfragen.</param>
|
||||
public ReceiverController(IMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ruft eine Liste von Empfängern ab, basierend auf den angegebenen Abfrageparametern.
|
||||
/// </summary>
|
||||
/// <param name="receiver">Die Abfrageparameter, einschließlich E-Mail-Adresse und Signatur.</param>
|
||||
/// <returns>Eine Liste von Empfängern oder ein Fehlerstatus.</returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> 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);
|
||||
}
|
||||
}
|
||||
129
EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs
Normal file
129
EnvelopeGenerator.API/Controllers/TfaRegistrationController.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Exposes endpoints for registering and managing two-factor authentication for envelope receivers.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/tfa")]
|
||||
public class TfaRegistrationController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<TfaRegistrationController> _logger;
|
||||
private readonly IEnvelopeReceiverService _envelopeReceiverService;
|
||||
private readonly IAuthenticator _authenticator;
|
||||
private readonly IReceiverService _receiverService;
|
||||
private readonly TFARegParams _parameters;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TfaRegistrationController"/> class.
|
||||
/// </summary>
|
||||
public TfaRegistrationController(
|
||||
ILogger<TfaRegistrationController> logger,
|
||||
IEnvelopeReceiverService envelopeReceiverService,
|
||||
IAuthenticator authenticator,
|
||||
IReceiverService receiverService,
|
||||
IOptions<TFARegParams> tfaRegParamsOptions,
|
||||
IStringLocalizer<Resource> localizer)
|
||||
{
|
||||
_logger = logger;
|
||||
_envelopeReceiverService = envelopeReceiverService;
|
||||
_authenticator = authenticator;
|
||||
_receiverService = receiverService;
|
||||
_parameters = tfaRegParamsOptions.Value;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates registration metadata (QR code and deadline) for a receiver.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">Encoded envelope receiver id.</param>
|
||||
[Authorize]
|
||||
[HttpGet("{envelopeReceiverId}")]
|
||||
public async Task<IActionResult> 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() });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs out the envelope receiver from cookie authentication.
|
||||
/// </summary>
|
||||
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||
[HttpPost("auth/logout")]
|
||||
public async Task<IActionResult> 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() });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using EnvelopeGenerator.API.Models;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace EnvelopeGenerator.API.Documentation;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class AuthProxyDocumentFilter : IDocumentFilter
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="swaggerDoc"></param>
|
||||
/// <param name="context"></param>
|
||||
public void Apply(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
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
17
EnvelopeGenerator.API/EnvelopeClaimTypes.cs
Normal file
17
EnvelopeGenerator.API/EnvelopeClaimTypes.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace EnvelopeGenerator.API;
|
||||
|
||||
/// <summary>
|
||||
/// Provides custom claim types for envelope-related information.
|
||||
/// </summary>
|
||||
public static class EnvelopeClaimTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Claim type for the title of an envelope.
|
||||
/// </summary>
|
||||
public static readonly string Title = $"Envelope{nameof(Title)}";
|
||||
|
||||
/// <summary>
|
||||
/// Claim type for the ID of an envelope.
|
||||
/// </summary>
|
||||
public static readonly string Id = $"Envelope{nameof(Id)}";
|
||||
}
|
||||
@@ -17,6 +17,17 @@
|
||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ClientApp\**" />
|
||||
<Content Remove="ClientApp\**" />
|
||||
<EmbeddedResource Remove="ClientApp\**" />
|
||||
<None Remove="ClientApp\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="yarp.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.Scalar" Version="1.1.8" />
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.7" />
|
||||
@@ -28,6 +39,7 @@
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction" Version="3.2.0" />
|
||||
<PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
||||
@@ -49,41 +61,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ClientApp\" />
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.CommonServices\EnvelopeGenerator.CommonServices.vbproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-35PBLQEP.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-IUSOII6E.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\favicon.ico">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\index.html">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\login\index.html">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\main-ZN7C4PGY.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\polyfills-N6LQB2YD.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\styles-S5ZWIC2V.css">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
101
EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs
Normal file
101
EnvelopeGenerator.API/Extensions/ReceiverClaimExtensions.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
|
||||
namespace EnvelopeGenerator.API.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides helper methods for working with envelope-specific authentication claims.
|
||||
/// </summary>
|
||||
public static class ReceiverClaimExtensions
|
||||
{
|
||||
private static string GetRequiredClaimOfReceiver(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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated envelope UUID from the claims.
|
||||
/// </summary>
|
||||
public static string GetEnvelopeUuidOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.NameIdentifier);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated receiver signature from the claims.
|
||||
/// </summary>
|
||||
public static string GetReceiverSignatureOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Hash);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated receiver display name from the claims.
|
||||
/// </summary>
|
||||
public static string GetReceiverNameOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated receiver email address from the claims.
|
||||
/// </summary>
|
||||
public static string GetReceiverMailOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Email);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated envelope title from the claims.
|
||||
/// </summary>
|
||||
public static string GetEnvelopeTitleOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Title);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated envelope identifier from the claims.
|
||||
/// </summary>
|
||||
public static int GetEnvelopeIdOfReceiver(this ClaimsPrincipal user)
|
||||
{
|
||||
var envIdStr = user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Id);
|
||||
if (!int.TryParse(envIdStr, out var envId))
|
||||
{
|
||||
throw new InvalidOperationException($"Claim '{EnvelopeClaimTypes.Id}' is not a valid integer.");
|
||||
}
|
||||
|
||||
return envId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs in an envelope receiver using cookie authentication and attaches envelope claims.
|
||||
/// </summary>
|
||||
/// <param name="context">The current HTTP context.</param>
|
||||
/// <param name="envelopeReceiver">Envelope receiver DTO to extract claims from.</param>
|
||||
/// <param name="receiverRole">Role to attach to the authentication ticket.</param>
|
||||
public static async Task SignInEnvelopeAsync(this HttpContext context, EnvelopeReceiverDto envelopeReceiver, string receiverRole)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.NameIdentifier, envelopeReceiver.Envelope!.Uuid),
|
||||
new(ClaimTypes.Hash, envelopeReceiver.Receiver!.Signature),
|
||||
new(ClaimTypes.Name, envelopeReceiver.Name ?? string.Empty),
|
||||
new(ClaimTypes.Email, envelopeReceiver.Receiver.EmailAddress),
|
||||
new(EnvelopeClaimTypes.Title, envelopeReceiver.Envelope.Title),
|
||||
new(EnvelopeClaimTypes.Id, envelopeReceiver.Envelope.Id.ToString()),
|
||||
new(ClaimTypes.Role, receiverRole)
|
||||
};
|
||||
|
||||
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
var authProperties = new AuthenticationProperties
|
||||
{
|
||||
AllowRefresh = false,
|
||||
IsPersistent = false
|
||||
};
|
||||
|
||||
await context.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(claimsIdentity),
|
||||
authProperties);
|
||||
}
|
||||
}
|
||||
95
EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs
Normal file
95
EnvelopeGenerator.API/Extensions/SenderClaimExtensions.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace EnvelopeGenerator.API.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for extracting user information from a <see cref="ClaimsPrincipal"/>.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user's ID from the claims. Throws an exception if the ID is missing or invalid.
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="ClaimsPrincipal"/> representing the user.</param>
|
||||
/// <returns>The user's ID as an integer.</returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the user ID claim is missing or invalid.</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the username from the claims.
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="ClaimsPrincipal"/> representing the user.</param>
|
||||
/// <returns>The username as a string.</returns>
|
||||
public static string GetUsername(this ClaimsPrincipal user)
|
||||
=> user.GetRequiredClaimOfSender(ClaimTypes.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user's surname (last name) from the claims.
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="ClaimsPrincipal"/> representing the user.</param>
|
||||
/// <returns>The surname as a string.</returns>
|
||||
public static string GetName(this ClaimsPrincipal user)
|
||||
=> user.GetRequiredClaimOfSender(ClaimTypes.Surname);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user's given name (first name) from the claims.
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="ClaimsPrincipal"/> representing the user.</param>
|
||||
/// <returns>The given name as a string.</returns>
|
||||
public static string GetPrename(this ClaimsPrincipal user)
|
||||
=> user.GetRequiredClaimOfSender(ClaimTypes.GivenName);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user's email address from the claims.
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="ClaimsPrincipal"/> representing the user.</param>
|
||||
/// <returns>The email address as a string.</returns>
|
||||
public static string GetEmail(this ClaimsPrincipal user)
|
||||
=> user.GetRequiredClaimOfSender(ClaimTypes.Email);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Middleware;
|
||||
namespace EnvelopeGenerator.API.Middleware;
|
||||
|
||||
using DigitalData.Core.Exceptions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
14
EnvelopeGenerator.API/Models/Auth.cs
Normal file
14
EnvelopeGenerator.API/Models/Auth.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Models;
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the keys and default values used for authentication token handling
|
||||
@@ -24,5 +24,5 @@ public class AuthTokenKeys
|
||||
/// <summary>
|
||||
/// Gets the expected audience value for the authentication token.
|
||||
/// </summary>
|
||||
public string Audience { get; init; } = "sign-flow-gen.digitaldata.works";
|
||||
public string Audience { get; init; } = "sign-flow.digitaldata.works";
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Models;
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
60
EnvelopeGenerator.API/Models/ContactLink.cs
Normal file
60
EnvelopeGenerator.API/Models/ContactLink.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace EnvelopeGenerator.API.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hyperlink for contact purposes with various HTML attributes.
|
||||
/// </summary>
|
||||
public class ContactLink
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the label of the hyperlink.
|
||||
/// </summary>
|
||||
public string Label { get; init; } = "Contact";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL that the hyperlink points to.
|
||||
/// </summary>
|
||||
public string Href { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target where the hyperlink should open.
|
||||
/// Commonly used values are "_blank", "_self", "_parent", "_top".
|
||||
/// </summary>
|
||||
public string Target { get; set; } = "_blank";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relationship of the linked URL as space-separated link types.
|
||||
/// Examples include "nofollow", "noopener", "noreferrer".
|
||||
/// </summary>
|
||||
public string Rel { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public string Download { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the language of the linked resource. Useful when linking to
|
||||
/// content in another language.
|
||||
/// </summary>
|
||||
public string HrefLang { get; set; } = "en";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MIME type of the linked URL. Helps browsers to handle
|
||||
/// the type correctly when the link is clicked.
|
||||
/// </summary>
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets additional information about the hyperlink, typically viewed
|
||||
/// as a tooltip when the mouse hovers over the link.
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an identifier for the hyperlink, unique within the HTML document.
|
||||
/// </summary>
|
||||
public string Id { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
17
EnvelopeGenerator.API/Models/Culture.cs
Normal file
17
EnvelopeGenerator.API/Models/Culture.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
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; }
|
||||
}
|
||||
12
EnvelopeGenerator.API/Models/Cultures.cs
Normal file
12
EnvelopeGenerator.API/Models/Cultures.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
public class Cultures : List<Culture>
|
||||
{
|
||||
public IEnumerable<string> Languages => this.Select(c => c.Language);
|
||||
|
||||
public IEnumerable<string> 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();
|
||||
}
|
||||
6
EnvelopeGenerator.API/Models/CustomImages.cs
Normal file
6
EnvelopeGenerator.API/Models/CustomImages.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
public class CustomImages : Dictionary<string, Image>
|
||||
{
|
||||
public new Image this[string key] => TryGetValue(key, out var img) && img is not null ? img : new();
|
||||
}
|
||||
10
EnvelopeGenerator.API/Models/ErrorViewModel.cs
Normal file
10
EnvelopeGenerator.API/Models/ErrorViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
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";
|
||||
}
|
||||
10
EnvelopeGenerator.API/Models/Image.cs
Normal file
10
EnvelopeGenerator.API/Models/Image.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
public class Image
|
||||
{
|
||||
public string Src { get; init; } = string.Empty;
|
||||
|
||||
public Dictionary<string, string> Classes { get; init; } = new();
|
||||
|
||||
public string GetClassIn(string page) => Classes.TryGetValue(page, out var cls) && cls is not null ? cls : string.Empty;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Models;
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Repräsentiert ein Login-Modell mit erforderlichem Passwort und optionaler ID und Benutzername.
|
||||
6
EnvelopeGenerator.API/Models/MainViewModel.cs
Normal file
6
EnvelopeGenerator.API/Models/MainViewModel.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
public class MainViewModel
|
||||
{
|
||||
public string? Title { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
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<Annotation> _annots = new List<Annotation>();
|
||||
|
||||
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<Annotation> 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<string, IAnnotation> 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<Dictionary<string, IAnnotation>> _AnnotationJSObjectInitor;
|
||||
|
||||
public Dictionary<string, IAnnotation> AnnotationJSObject => _AnnotationJSObjectInitor.Value;
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<IAnnotation> 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;
|
||||
}
|
||||
}
|
||||
10
EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs
Normal file
10
EnvelopeGenerator.API/Models/PsPdfKitAnnotation/Color.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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; }
|
||||
}
|
||||
17
EnvelopeGenerator.API/Models/TFARegParams.cs
Normal file
17
EnvelopeGenerator.API/Models/TFARegParams.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace EnvelopeGenerator.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the parameters for two-factor authentication (2FA) registration.
|
||||
/// </summary>
|
||||
public class TFARegParams
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum allowed time for completing the registration process.
|
||||
/// </summary>
|
||||
public TimeSpan TimeLimit { get; init; } = new(0, 30, 0);
|
||||
|
||||
/// <summary>
|
||||
/// The deadline for registration, calculated as the current time plus the <see cref="TimeLimit"/>.
|
||||
/// </summary>
|
||||
public DateTime Deadline => DateTime.Now.AddTicks(TimeLimit.Ticks);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -11,11 +12,11 @@ using DigitalData.UserManager.DependencyInjection;
|
||||
using EnvelopeGenerator.Application;
|
||||
using DigitalData.Auth.Client;
|
||||
using DigitalData.Core.Abstractions;
|
||||
using EnvelopeGenerator.GeneratorAPI.Models;
|
||||
using EnvelopeGenerator.API.Models;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DigitalData.Core.Abstractions.Security.Extensions;
|
||||
using EnvelopeGenerator.GeneratorAPI.Middleware;
|
||||
using EnvelopeGenerator.API.Middleware;
|
||||
using NLog.Web;
|
||||
using NLog;
|
||||
|
||||
@@ -26,6 +27,8 @@ 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())
|
||||
@@ -39,6 +42,8 @@ try
|
||||
var deferredProvider = new DeferredServiceProvider();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
|
||||
|
||||
// CORS Policy
|
||||
var allowedOrigins = config.GetSection("AllowedOrigins").Get<string[]>() ??
|
||||
@@ -89,7 +94,7 @@ try
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
@@ -102,6 +107,8 @@ try
|
||||
{
|
||||
options.IncludeXmlComments(xmlFile);
|
||||
}
|
||||
|
||||
options.DocumentFilter<EnvelopeGenerator.API.Documentation.AuthProxyDocumentFilter>();
|
||||
});
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
@@ -170,6 +177,16 @@ try
|
||||
options.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.AddPolicy(AuthPolicy.SenderOrReceiver, policy =>
|
||||
policy.RequireRole(Role.Sender, Role.Receiver.Full))
|
||||
.AddPolicy(AuthPolicy.Sender, policy =>
|
||||
policy.RequireRole(Role.Sender))
|
||||
.AddPolicy(AuthPolicy.Receiver, policy =>
|
||||
policy.RequireRole(Role.Receiver.Full))
|
||||
.AddPolicy(AuthPolicy.ReceiverTFA, policy =>
|
||||
policy.RequireRole(Role.Receiver.TFA));
|
||||
|
||||
// User manager
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
builder.Services.AddUserManager<EGDbContext>();
|
||||
@@ -241,6 +258,7 @@ try
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapReverseProxy();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@@ -6,11 +6,11 @@
|
||||
}
|
||||
},
|
||||
"AuthClientParams": {
|
||||
"Url": "https://localhost:7192/auth-hub",
|
||||
"Url": "http://172.24.12.39:9090/auth-hub",
|
||||
"PublicKeys": [
|
||||
{
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "sign-flow-gen.digitaldata.works"
|
||||
"Audience": "sign-flow.digitaldata.works"
|
||||
}
|
||||
],
|
||||
"RetryDelay": "00:00:05"
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"AllowedOrigins": [ "http://localhost:4200" ],
|
||||
"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;"
|
||||
@@ -24,11 +24,11 @@
|
||||
}
|
||||
},
|
||||
"AuthClientParams": {
|
||||
"Url": "https://localhost:7192/auth-hub",
|
||||
"Url": "http://172.24.12.39:9090/auth-hub",
|
||||
"PublicKeys": [
|
||||
{
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "sign-flow-gen.digitaldata.works"
|
||||
"Audience": "sign-flow.digitaldata.works"
|
||||
}
|
||||
],
|
||||
"RetryDelay": "00:00:05"
|
||||
@@ -37,7 +37,7 @@
|
||||
"Cookie": "AuthToken",
|
||||
"QueryString": "AuthToken",
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "work-flow.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.
|
||||
25
EnvelopeGenerator.API/yarp.json
Normal file
25
EnvelopeGenerator.API/yarp.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"ReverseProxy": {
|
||||
"Routes": {
|
||||
"auth-login": {
|
||||
"ClusterId": "auth-hub",
|
||||
"Match": {
|
||||
"Path": "/api/auth",
|
||||
"Methods": [ "POST" ]
|
||||
},
|
||||
"Transforms": [
|
||||
{ "PathSet": "/api/auth/sign-flow" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"Clusters": {
|
||||
"auth-hub": {
|
||||
"Destinations": {
|
||||
"primary": {
|
||||
"Address": "http://172.24.12.39:9090"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class CreateCommandHandler<TCommand, TEntity> : IRequestHandler<TCommand, TEntity>
|
||||
where TCommand : class, IRequest<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<TEntity> Repository;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public CreateCommandHandler(IRepository<TEntity> repository)
|
||||
{
|
||||
Repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task<TEntity> Handle(TCommand request, CancellationToken cancel) => Repository.CreateAsync(request, cancel);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TUpdateDto"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public abstract record UpdateCommand<TUpdateDto, TEntity> : IRequest where TUpdateDto : class where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TUpdateDto Update { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract Expression<Func<TEntity, bool>> BuildQueryExpression();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand"></typeparam>
|
||||
/// <typeparam name="TUpdateDto"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class UpdateCommandHandler<TCommand, TUpdateDto, TEntity> : IRequestHandler<TCommand>
|
||||
where TUpdateDto : class
|
||||
where TEntity : class
|
||||
where TCommand : UpdateCommand<TUpdateDto, TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<TEntity> Repository;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public UpdateCommandHandler(IRepository<TEntity> repository)
|
||||
{
|
||||
Repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(TCommand request, CancellationToken cancel)
|
||||
=> Repository.UpdateAsync(request.Update, request.BuildQueryExpression(), cancel);
|
||||
}
|
||||
@@ -1,31 +1,42 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record EmailTemplateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EmailTemplateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int Id{ get; init; }
|
||||
public int Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Body { get; set; }
|
||||
/// <summary>
|
||||
/// Das Datum und die Uhrzeit, wann die Vorlage hinzugefügt wurde.
|
||||
/// </summary>
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Subject { get; set; }
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// Der Inhalt (Body) der E-Mail-Vorlage. Kann null sein.
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Betreff der E-Mail-Vorlage. Kann null sein.
|
||||
/// </summary>
|
||||
public string? Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Sprachcode der E-Mail-Vorlage.
|
||||
/// </summary>
|
||||
public string LangCode { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Das Datum und die Uhrzeit, wann die Vorlage zuletzt geändert wurde. Kann null sein.
|
||||
/// </summary>
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
};
|
||||
@@ -74,6 +74,11 @@ public record EnvelopeDto
|
||||
/// </summary>
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool ReadOnly => EnvelopeTypeId == 2;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
@@ -28,8 +28,8 @@ public class MappingProfile : Profile
|
||||
CreateMap<EmailTemplate, EmailTemplateDto>();
|
||||
CreateMap<Envelope, EnvelopeDto>();
|
||||
CreateMap<Document, DocumentDto>();
|
||||
CreateMap<Domain.Entities.History, HistoryDto>();
|
||||
CreateMap<Domain.Entities.History, HistoryCreateDto>();
|
||||
CreateMap<Domain.Entities.History, HistoryDto>().ForMember(dest => dest.ActionDate, opt => opt.MapFrom(src => src.ChangedWhen));
|
||||
CreateMap<Domain.Entities.History, HistoryCreateDto>().ForMember(dest => dest.ActionDate, opt => opt.MapFrom(src => src.ChangedWhen));
|
||||
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverSecretDto>();
|
||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||
@@ -44,15 +44,15 @@ public class MappingProfile : Profile
|
||||
CreateMap<EmailTemplateDto, EmailTemplate>();
|
||||
CreateMap<EnvelopeDto, Envelope>();
|
||||
CreateMap<DocumentDto, Document>();
|
||||
CreateMap<HistoryDto, Domain.Entities.History>();
|
||||
CreateMap<HistoryCreateDto, Domain.Entities.History>();
|
||||
CreateMap<HistoryDto, Domain.Entities.History>().ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(src => src.ActionDate));
|
||||
CreateMap<HistoryCreateDto, Domain.Entities.History>().ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(src => src.ActionDate));
|
||||
CreateMap<EnvelopeReceiverDto, Domain.Entities.EnvelopeReceiver>();
|
||||
CreateMap<EnvelopeTypeDto, EnvelopeType>();
|
||||
CreateMap<ReceiverDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
CreateMap<AnnotationCreateDto, ElementAnnotation>()
|
||||
.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
|
||||
.MapAddedWhen();
|
||||
|
||||
// Messaging mappings
|
||||
// for GTX messaging
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for applying auditing timestamps during AutoMapper mappings.
|
||||
/// </summary>
|
||||
public static class AutoMapperAuditingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps <see cref="IHasAddedWhen.AddedWhen"/> to the current UTC time.
|
||||
/// </summary>
|
||||
public static IMappingExpression<TSource, TDestination> MapAddedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
|
||||
where TDestination : IHasAddedWhen
|
||||
=> expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
|
||||
|
||||
/// <summary>
|
||||
/// Maps <see cref="IHasChangedWhen.ChangedWhen"/> to the current UTC time.
|
||||
/// </summary>
|
||||
public static IMappingExpression<TSource, TDestination> MapChangedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
|
||||
where TDestination : IHasChangedWhen
|
||||
=> expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
|
||||
}
|
||||
@@ -3,8 +3,19 @@ using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="envelopeReceiverId"></param>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
@@ -18,6 +29,15 @@ namespace EnvelopeGenerator.Application.Common.Extensions
|
||||
logger.Log(LogLevel.Error, exception, sb.AppendLine(exception.Message).ToString(), args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="uuid"></param>
|
||||
/// <param name="signature"></param>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void LogEnvelopeError(this ILogger logger, string? uuid, string? signature = null, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
|
||||
@@ -34,6 +54,11 @@ namespace EnvelopeGenerator.Application.Common.Extensions
|
||||
logger.Log(LogLevel.Error, exception, sb.ToString(), args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverTuple"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
|
||||
{
|
||||
return $"UUID is {envelopeReceiverTuple.UUID} and signature is {envelopeReceiverTuple.Signature}";
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
/// <summary>
|
||||
/// Extension methods for tasks
|
||||
/// </summary>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static class TaskExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -17,6 +18,7 @@ public static class TaskExtensions
|
||||
/// <param name="factory">Exception provider</param>
|
||||
/// <returns>The awaited result if not <c>null</c>.</returns>
|
||||
/// <exception>Thrown if the result is <c>null</c>.</exception>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<T> ThrowIfNull<T, TException>(this Task<T?> task, Func<TException> factory) where TException : Exception
|
||||
{
|
||||
var result = await task;
|
||||
@@ -33,6 +35,7 @@ public static class TaskExtensions
|
||||
/// <param name="factory">Exception provider</param>
|
||||
/// <returns>The awaited collection if it is not <c>null</c> or empty.</returns>
|
||||
/// <exception cref="NotFoundException">Thrown if the result is <c>null</c> or empty.</exception>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<IEnumerable<T>> ThrowIfEmpty<T, TException>(this Task<IEnumerable<T>> task, Func<TException> factory) where TException : Exception
|
||||
{
|
||||
var result = await task;
|
||||
@@ -47,11 +50,33 @@ public static class TaskExtensions
|
||||
/// <param name="task"></param>
|
||||
/// <param name="act"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<I> Then<T, I>(this Task<T> task, Func<T, I> act)
|
||||
{
|
||||
var res = await task;
|
||||
return act(res);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static Task<T?> FirstOrDefaultAsync<T>(this Task<IEnumerable<T>> task) => task.Then(t => t.FirstOrDefault());
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TException"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<T> FirstAsync<T, TException>(this Task<IEnumerable<T>> task, Func<TException> factory)
|
||||
where TException : Exception
|
||||
=> task.Then(t => t.FirstOrDefault() ?? throw factory());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,11 +93,13 @@ public static class Exceptions
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static BadRequestException BadRequest() => new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static ForbiddenException Forbidden() => new();
|
||||
}
|
||||
@@ -2,16 +2,42 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class XSSExtensions
|
||||
{
|
||||
public static class XSSExtensions
|
||||
{
|
||||
public static string? TryEncode(this string? value, UrlEncoder encoder) => value is null ? value : encoder.Encode(value);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoder"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TryEncode(this string? value, UrlEncoder encoder) => value is null ? value : encoder.Encode(value);
|
||||
|
||||
public static string? TryEncode(this LocalizedString? value, UrlEncoder encoder) => value is null ? null : encoder.Encode(value);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoder"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TryEncode(this LocalizedString? value, UrlEncoder encoder) => value is null ? null : encoder.Encode(value);
|
||||
|
||||
public static string? TrySanitize(this string? html, HtmlSanitizer sanitizer) => html is null ? html : sanitizer.Sanitize(html);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="html"></param>
|
||||
/// <param name="sanitizer"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TrySanitize(this string? html, HtmlSanitizer sanitizer) => html is null ? html : sanitizer.Sanitize(html);
|
||||
|
||||
public static string? TrySanitize(this LocalizedString? html, HtmlSanitizer sanitizer) => html is null ? null : sanitizer.Sanitize(html);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="html"></param>
|
||||
/// <param name="sanitizer"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TrySanitize(this LocalizedString? html, HtmlSanitizer sanitizer) => html is null ? null : sanitizer.Sanitize(html);
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeRece
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public PsPdfKitAnnotation PsPdfKitAnnotation { get; init; } = null!;
|
||||
public PsPdfKitAnnotation? PsPdfKitAnnotation { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -59,7 +59,7 @@ public static class DocSignedNotificationExtensions
|
||||
/// <param name="dtoTask"></param>
|
||||
/// <param name="psPdfKitAnnotation"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, PsPdfKitAnnotation psPdfKitAnnotation)
|
||||
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, PsPdfKitAnnotation? psPdfKitAnnotation)
|
||||
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation } : null;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,6 +29,9 @@ public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||
=> _repo.CreateAsync(notification.PsPdfKitAnnotation.Structured, cancel);
|
||||
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||
{
|
||||
if (notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot)
|
||||
await _repo.CreateAsync(annot.Structured, cancel);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
/// </summary>
|
||||
public class DocStatusHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
private const string BlankAnnotationJson = "{}";
|
||||
|
||||
private readonly ISender _sender;
|
||||
|
||||
/// <summary>
|
||||
@@ -33,7 +35,9 @@ public class DocStatusHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
Envelope = new() { Id = notification.EnvelopeId },
|
||||
Receiver = new() { Id = notification.ReceiverId},
|
||||
Value = JsonSerializer.Serialize(notification.PsPdfKitAnnotation.Instant, Format.Json.ForAnnotations)
|
||||
Value = notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot
|
||||
? JsonSerializer.Serialize(annot.Instant, Format.Json.ForAnnotations)
|
||||
: BlankAnnotationJson
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,31 @@
|
||||
namespace EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Commands;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record CreateDocStatusCommand : ModifyDocStatusCommandBase
|
||||
public record CreateDocStatusCommand : ModifyDocStatusCommandBase, IRequest<DocumentStatus>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets timestamp when this record was added. Returns the StatusChangedWhen value.
|
||||
/// </summary>
|
||||
public DateTime AddedWhen => StatusChangedWhen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class CreateDocStatusCommandHandler : CreateCommandHandler<CreateDocStatusCommand, DocumentStatus>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public CreateDocStatusCommandHandler(IRepository<DocumentStatus> repository) : base(repository)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
@@ -16,10 +17,12 @@ public class MappingProfile : Profile
|
||||
{
|
||||
CreateMap<CreateDocStatusCommand, DocumentStatus>()
|
||||
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
|
||||
.ForMember(dest => dest.Receiver, opt => opt.Ignore())
|
||||
.MapAddedWhen();
|
||||
|
||||
CreateMap<UpdateDocStatusCommand, DocumentStatus>()
|
||||
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
|
||||
.ForMember(dest => dest.Receiver, opt => opt.Ignore())
|
||||
.MapChangedWhen();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using DigitalData.Core.Exceptions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Documents.Queries;
|
||||
|
||||
@@ -12,14 +13,14 @@ namespace EnvelopeGenerator.Application.Documents.Queries;
|
||||
/// </summary>
|
||||
/// <param name="Id">The unique identifier of the document. Optional.</param>
|
||||
/// <param name="EnvelopeId">The identifier of the envelope associated with the document. Optional.</param>
|
||||
public record ReadDocumentQuery(int? Id = null, int? EnvelopeId = null) : IRequest<DocumentDto?>
|
||||
public record ReadDocumentQuery(int? Id = null, int? EnvelopeId = null) : IRequest<DocumentDto>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles queries for reading <see cref="Document"/> data based on either the document ID or the envelope ID.
|
||||
/// </summary>
|
||||
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, DocumentDto?>
|
||||
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, DocumentDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// TempRepo for accessing <see cref="Document"/> entities.
|
||||
@@ -50,20 +51,19 @@ public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, Docum
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when neither <see cref="ReadDocumentQuery.Id"/> nor <see cref="ReadDocumentQuery.EnvelopeId"/> is provided.
|
||||
/// </exception>
|
||||
public async Task<DocumentDto?> Handle(ReadDocumentQuery query, CancellationToken cancel)
|
||||
public async Task<DocumentDto> Handle(ReadDocumentQuery query, CancellationToken cancel)
|
||||
{
|
||||
if (query.Id is not null)
|
||||
{
|
||||
var doc = await _repo.ReadOnly().Where(d => d.Id == query.Id).FirstOrDefaultAsync(cancel);
|
||||
var doc = await _repo.Query.Where(d => d.Id == query.Id).FirstOrDefaultAsync(cancel);
|
||||
return _mapper.Map<DocumentDto>(doc);
|
||||
}
|
||||
else if (query.EnvelopeId is not null)
|
||||
{
|
||||
var doc = await _repo.ReadOnly().Where(d => d.EnvelopeId == query.EnvelopeId).FirstOrDefaultAsync(cancel);
|
||||
var doc = await _repo.Query.Where(d => d.EnvelopeId == query.EnvelopeId).FirstOrDefaultAsync(cancel);
|
||||
return _mapper.Map<DocumentDto>(doc);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Invalid {nameof(ReadDocumentQuery)}: either {nameof(query.Id)} or {nameof(query.EnvelopeId)} must be provided.");
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using EnvelopeGenerator.Domain;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Reset;
|
||||
|
||||
/// <summary>
|
||||
/// Ein Befehl zum Zurücksetzen einer E-Mail-Vorlage auf die Standardwerte.
|
||||
/// Erbt von <see cref="EmailTemplateQuery"/> und ermöglicht die Angabe einer optionalen ID und eines Typs der E-Mail-Vorlage.<br/><br/>
|
||||
/// Beispiele:<br/>
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.<br/>
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.<br/>
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.<br/>
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.<br/>
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.<br/>
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.<br/>
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.<br/>
|
||||
/// 7 - DocumentRejected_ADM (Für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 8 - DocumentRejected_REC (Für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 9 - DocumentRejected_REC_2 (Für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.<br/>
|
||||
/// </summary>
|
||||
public record ResetEmailTemplateCommand : EmailTemplateQuery, IRequest
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="orginal"></param>
|
||||
public ResetEmailTemplateCommand(EmailTemplateQuery? orginal = null) : base(orginal ?? new())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="Id">Die optionale ID der E-Mail-Vorlage, die zurückgesetzt werden soll.</param>
|
||||
/// <param name="Type">Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional).</param>
|
||||
public ResetEmailTemplateCommand(int? Id = null, EmailTemplateType? Type = null) : base(Id, Type)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -1,11 +1,38 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Reset;
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Ein Befehl zum Zurücksetzen einer E-Mail-Vorlage auf die Standardwerte.
|
||||
/// Erbt von <see cref="IEmailTemplateQuery"/> und ermöglicht die Angabe einer optionalen ID und eines Typs der E-Mail-Vorlage.<br/><br/>
|
||||
/// </summary>
|
||||
public record ResetEmailTemplateCommand : IEmailTemplateQuery, IRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung der E-Mail-Vorlage (optional).
|
||||
/// </summary>
|
||||
public int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional). Beispiele:<br/>
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.<br/>
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.<br/>
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.<br/>
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.<br/>
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.<br/>
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.<br/>
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.<br/>
|
||||
/// 7 - DocumentRejected_ADM (für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 8 - DocumentRejected_REC (für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 9 - DocumentRejected_REC_2 (für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
|
||||
/// </summary>
|
||||
public EmailTemplateType? Type { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -41,7 +68,7 @@ public class ResetEmailTemplateCommandHandler : IRequestHandler<ResetEmailTempla
|
||||
foreach (var temp in temps)
|
||||
{
|
||||
var def = Defaults.Where(t => t.Name == temp.Name).FirstOrDefault();
|
||||
if(def is not null)
|
||||
if (def is not null)
|
||||
await _repository.UpdateAsync(def, t => t.Id == temp.Id, cancel);
|
||||
}
|
||||
}
|
||||
@@ -113,4 +140,4 @@ public class ResetEmailTemplateCommandHandler : IRequestHandler<ResetEmailTempla
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using MediatR;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Update;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Befehl zum Aktualisieren einer E-Mail-Vorlage.
|
||||
/// </summary>
|
||||
/// <param name="Body">
|
||||
/// (Optional)Der neue Inhalt des E-Mail-Textkörpers. Wenn null, bleibt der vorhandene Inhalt unverändert.
|
||||
/// </param>
|
||||
/// <param name="Subject">
|
||||
/// (Optional) Der neue Betreff der E-Mail. Wenn null, bleibt der vorhandene Betreff unverändert.
|
||||
/// </param>
|
||||
public record UpdateEmailTemplateCommand(string? Body = null, string? Subject = null) : IRequest
|
||||
{
|
||||
/// <param>
|
||||
/// Die Abfrage, die die E-Mail-Vorlage darstellt, die aktualisiert werden soll.
|
||||
/// </param>
|
||||
[JsonIgnore]
|
||||
public EmailTemplateQuery? EmailTemplateQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public DateTime ChangedWhen { get; init; } = DateTime.Now;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Update;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UpdateEmailTemplateCommandHandler : IRequestHandler<UpdateEmailTemplateCommand>
|
||||
{
|
||||
private readonly IRepository<EmailTemplate> _repository;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public UpdateEmailTemplateCommandHandler(IRepository<EmailTemplate> repository, IMapper mapper)
|
||||
{
|
||||
_repository = repository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <exception cref="NotFoundException"></exception>
|
||||
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
|
||||
public async Task Handle(UpdateEmailTemplateCommand request, CancellationToken cancel)
|
||||
{
|
||||
EmailTemplateDto? tempDto;
|
||||
|
||||
if (request.EmailTemplateQuery?.Id is int id)
|
||||
{
|
||||
var temp = await _repository.ReadOnly().Where(t => t.Id == id).FirstOrDefaultAsync(cancel);
|
||||
tempDto = _mapper.Map<EmailTemplateDto>(temp);
|
||||
}
|
||||
else if (request!.EmailTemplateQuery!.Type is EmailTemplateType type)
|
||||
{
|
||||
var temp = await _repository.ReadOnly().Where(t => t.Name == type.ToString()).FirstOrDefaultAsync(cancel);
|
||||
tempDto = _mapper.Map<EmailTemplateDto>(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Both id and type is null. Id: " + request.EmailTemplateQuery.Id +". Type: " + request.EmailTemplateQuery.Type.ToString());
|
||||
}
|
||||
|
||||
if (tempDto == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (request.Body is not null)
|
||||
tempDto.Body = request.Body;
|
||||
|
||||
if (request.Subject is not null)
|
||||
tempDto.Subject = request.Subject;
|
||||
|
||||
await _repository.UpdateAsync(tempDto, t => t.Id == tempDto.Id, cancel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Commands;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="Body"></param>
|
||||
/// <param name="Subject"></param>
|
||||
public record EmailTemplateUpdateDto(string Body, string Subject);
|
||||
|
||||
/// <summary>
|
||||
/// Befehl zum Aktualisieren einer E-Mail-Vorlage.
|
||||
/// </summary>
|
||||
public record UpdateEmailTemplateCommand : UpdateCommand<EmailTemplateUpdateDto, EmailTemplate>, IEmailTemplateQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung der E-Mail-Vorlage (optional).
|
||||
/// </summary>
|
||||
public int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional). Beispiele:<br/>
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.<br/>
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.<br/>
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.<br/>
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.<br/>
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.<br/>
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.<br/>
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.<br/>
|
||||
/// 7 - DocumentRejected_ADM (für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 8 - DocumentRejected_REC (für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 9 - DocumentRejected_REC_2 (für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
|
||||
/// </summary>
|
||||
public EmailTemplateType? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Expression<Func<EmailTemplate, bool>> BuildQueryExpression()
|
||||
=> Id is int id
|
||||
? temp => temp.Id == id
|
||||
: temp => temp!.Name == Type.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UpdateEmailTemplateCommandHandler : UpdateCommandHandler<UpdateEmailTemplateCommand, EmailTemplateUpdateDto, EmailTemplate>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public UpdateEmailTemplateCommandHandler(IRepository<EmailTemplate> repository) : base(repository)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates;
|
||||
|
||||
/// <summary>
|
||||
/// Repräsentiert eine Abfrage für E-Mail-Vorlagen, die für Absender und Empfänger von Umschlägen verwendet werden.
|
||||
/// Die Standardkultur ist "de-DE".
|
||||
/// </summary>
|
||||
/// <param name="Id">Die eindeutige Kennung der E-Mail-Vorlage (optional).</param>
|
||||
/// <param name="Type">Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional). Beispiele:
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.
|
||||
/// 7 - DocumentRejected_ADM (Für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.
|
||||
/// 8 - DocumentRejected_REC (Für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.
|
||||
/// 9 - DocumentRejected_REC_2 (Für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
|
||||
/// </param>
|
||||
public record EmailTemplateQuery(int? Id = null, EmailTemplateType? Type = null)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates;
|
||||
|
||||
/// <summary>
|
||||
/// Stellt eine Schnittstelle für Abfragen von E-Mail-Vorlagen dar, die für Absender und Empfänger von Umschlägen verwendet werden.
|
||||
/// Die Standardkultur ist "de-DE".
|
||||
/// </summary>
|
||||
public interface IEmailTemplateQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung der E-Mail-Vorlage (optional).
|
||||
/// </summary>
|
||||
int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional). Beispiele:<br/>
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.<br/>
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.<br/>
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.<br/>
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.<br/>
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.<br/>
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.<br/>
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.<br/>
|
||||
/// 7 - DocumentRejected_ADM (für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 8 - DocumentRejected_REC (für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 9 - DocumentRejected_REC_2 (für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
|
||||
/// </summary>
|
||||
EmailTemplateType? Type { get; set; }
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.EmailTemplates.Commands;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
///
|
||||
/// </summary>
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
///
|
||||
/// </summary>
|
||||
public MappingProfile()
|
||||
{
|
||||
CreateMap<EmailTemplate, ReadEmailTemplateResponse>();
|
||||
CreateMap<EmailTemplate, EmailTemplateDto>();
|
||||
|
||||
CreateMap<EmailTemplateUpdateDto, EmailTemplate>()
|
||||
.MapChangedWhen();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stellt eine Abfrage dar, um eine E-Mail-Vorlage zu lesen.
|
||||
/// Diese Klasse erbt von <see cref="EmailTemplateQuery"/>.
|
||||
/// </summary>
|
||||
public record ReadEmailTemplateQuery : EmailTemplateQuery, IRequest<ReadEmailTemplateResponse?>
|
||||
{
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQuery, ReadEmailTemplateResponse?>
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
|
||||
private readonly IEmailTemplateRepository _repository;
|
||||
|
||||
/// <summary>
|
||||
/// Initialisiert eine neue Instanz der <see cref="EmailTemplateController"/>-Klasse.
|
||||
/// </summary>
|
||||
/// <param name="mapper">
|
||||
/// <param name="repository">
|
||||
/// Die AutoMapper-Instanz, die zum Zuordnen von Objekten verwendet wird.
|
||||
/// </param>
|
||||
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
|
||||
public ReadEmailTemplateQueryHandler(IMapper mapper, IEmailTemplateRepository repository)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
[Obsolete("Use IRepository")]
|
||||
public async Task<ReadEmailTemplateResponse?> Handle(ReadEmailTemplateQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var temp = request.Id is int id
|
||||
? await _repository.ReadByIdAsync(id)
|
||||
: request.Type is EmailTemplateType type
|
||||
? await _repository.ReadByNameAsync(type)
|
||||
: throw new InvalidOperationException("Either a valid integer ID or a valid EmailTemplateType must be provided in the request.");
|
||||
|
||||
var res = _mapper.Map<ReadEmailTemplateResponse>(temp);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
|
||||
|
||||
/// <summary>
|
||||
/// Stellt die Antwort für eine Abfrage von E-Mail-Vorlagen bereit.
|
||||
/// </summary>
|
||||
public class ReadEmailTemplateResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung der E-Mail-Vorlage.
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name des Typs
|
||||
/// </summary>
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Das Datum und die Uhrzeit, wann die Vorlage hinzugefügt wurde.
|
||||
/// </summary>
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Inhalt (Body) der E-Mail-Vorlage. Kann null sein.
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Betreff der E-Mail-Vorlage. Kann null sein.
|
||||
/// </summary>
|
||||
public string? Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Das Datum und die Uhrzeit, wann die Vorlage zuletzt geändert wurde. Kann null sein.
|
||||
/// </summary>
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using AutoMapper;
|
||||
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 DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EmailTemplates.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// Stellt eine Abfrage dar, um eine E-Mail-Vorlage zu lesen.
|
||||
/// Diese Klasse erbt von <see cref="IEmailTemplateQuery"/>.
|
||||
/// </summary>
|
||||
public record ReadEmailTemplateQuery : IEmailTemplateQuery, IRequest<IEnumerable<EmailTemplateDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung der E-Mail-Vorlage (optional).
|
||||
/// </summary>
|
||||
public int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Typ der E-Mail-Vorlage, z. B. <see cref="EmailTemplateType"/> (optional). Beispiele:<br/>
|
||||
/// 0 - DocumentReceived: Benachrichtigung über den Empfang eines Dokuments.<br/>
|
||||
/// 1 - DocumentSigned: Benachrichtigung über die Unterzeichnung eines Dokuments.<br/>
|
||||
/// 2 - DocumentDeleted: Benachrichtigung über das Löschen eines Dokuments.<br/>
|
||||
/// 3 - DocumentCompleted: Benachrichtigung über den Abschluss eines Dokuments.<br/>
|
||||
/// 4 - DocumentAccessCodeReceived: Benachrichtigung über den Erhalt eines Zugangscodes.<br/>
|
||||
/// 5 - DocumentShared: Benachrichtigung über das Teilen eines Dokuments.<br/>
|
||||
/// 6 - TotpSecret: Benachrichtigung über ein TOTP-Geheimnis.<br/>
|
||||
/// 7 - DocumentRejected_ADM (für den Absender): Mail an den Absender, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 8 - DocumentRejected_REC (für den ablehnenden Empfänger): Mail an den ablehnenden Empfänger, wenn das Dokument abgelehnt wird.<br/>
|
||||
/// 9 - DocumentRejected_REC_2 (für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
|
||||
/// </summary>
|
||||
public EmailTemplateType? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? LangCode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class ReadEmailTemplateQueryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="langCode"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<EmailTemplateDto?> ReadEmailTemplateAsync(this ISender sender, int id, string langCode, CancellationToken cancel = default)
|
||||
{
|
||||
var result = await sender.Send(new ReadEmailTemplateQuery { Id = id, LangCode = langCode }, cancel);
|
||||
return result.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="langCode"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<EmailTemplateDto?> ReadEmailTemplateAsync(this ISender sender, EmailTemplateType type, string langCode, CancellationToken cancel = default)
|
||||
{
|
||||
var result = await sender.Send(new ReadEmailTemplateQuery { Type = type, LangCode = langCode }, cancel);
|
||||
return result.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQuery, IEnumerable<EmailTemplateDto>>
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
private readonly IRepository<EmailTemplate> _repo;
|
||||
|
||||
/// <summary>
|
||||
/// Initialisiert eine neue Instanz der <see cref="EmailTemplateController"/>-Klasse.
|
||||
/// </summary>
|
||||
/// <param name="mapper">
|
||||
/// <param name="repo">
|
||||
/// Die AutoMapper-Instanz, die zum Zuordnen von Objekten verwendet wird.
|
||||
/// </param>
|
||||
public ReadEmailTemplateQueryHandler(IMapper mapper, IRepository<EmailTemplate> repo)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<IEnumerable<EmailTemplateDto>> Handle(ReadEmailTemplateQuery request, CancellationToken cancel)
|
||||
{
|
||||
var query = _repo.Query;
|
||||
|
||||
if (request.Id is int id)
|
||||
query = query.Where(temp => temp.Id == id);
|
||||
|
||||
if (request.Type is EmailTemplateType type)
|
||||
query = query.Where(temp => temp.Name == type.ToString());
|
||||
|
||||
if (request.LangCode is string langCode)
|
||||
query = query.Where(temp => temp.LangCode == langCode);
|
||||
|
||||
var entity = await query.ToListAsync(cancel);
|
||||
|
||||
return _mapper.Map<IEnumerable<EmailTemplateDto>>(entity);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.4.0" />
|
||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
||||
<PackageReference Include="DigitalData.Core.Client" Version="2.1.0" />
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||
@@ -63,6 +63,9 @@
|
||||
<LastGenOutput>Model.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Resource.fr-FR.resx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Resource.de-DE.resx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using AutoMapper;
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
@@ -47,7 +47,13 @@ namespace EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
/// Die Antwort enthält Details wie den Include, die Zuordnung zwischen Umschlag und Empfänger
|
||||
/// sowie zusätzliche Metadaten.
|
||||
/// </remarks>
|
||||
public record ReadEnvelopeReceiverQuery : EnvelopeReceiverQueryBase<ReadEnvelopeQuery, ReadReceiverQuery>, IRequest<IEnumerable<EnvelopeReceiverDto>>;
|
||||
public record ReadEnvelopeReceiverQuery : EnvelopeReceiverQueryBase<ReadEnvelopeQuery, ReadReceiverQuery>, IRequest<IEnumerable<EnvelopeReceiverDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Optionaler Benutzernamefilter, um Ergebnisse auf Umschläge eines bestimmten Besitzers einzuschränken.
|
||||
/// </summary>
|
||||
public string? Username { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -61,10 +67,11 @@ public static class Extensions
|
||||
/// <param name="key"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<EnvelopeReceiverDto?> ReadEnvelopeReceiverAsync(this IMediator mediator, string key, CancellationToken cancel = default)
|
||||
public static async Task<EnvelopeReceiverDto?> ReadEnvelopeReceiverAsync(this IMediator mediator, string key, CancellationToken cancel = default)
|
||||
{
|
||||
var q = new ReadEnvelopeReceiverQuery() { Key = key };
|
||||
return mediator.Send(q, cancel).Then(envRcvs => envRcvs.FirstOrDefault());
|
||||
var envRcvs = await mediator.Send(q, cancel);
|
||||
return envRcvs.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,80 +82,82 @@ public static class Extensions
|
||||
/// <param name="signature"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<EnvelopeReceiverDto?> ReadEnvelopeReceiverAsync(this IMediator mediator, string uuid, string signature, CancellationToken cancel = default)
|
||||
public static async Task<EnvelopeReceiverDto?> ReadEnvelopeReceiverAsync(this IMediator mediator, string uuid, string signature, CancellationToken cancel = default)
|
||||
{
|
||||
var q = new ReadEnvelopeReceiverQuery();
|
||||
q.Envelope.Uuid = uuid;
|
||||
q.Receiver.Signature = signature;
|
||||
return mediator.Send(q, cancel).Then(envRcvs => envRcvs.FirstOrDefault());
|
||||
var envRcvs = await mediator.Send(q, cancel);
|
||||
return envRcvs.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadEnvelopeReceiverQueryHandler : IRequestHandler<ReadEnvelopeReceiverQuery, IEnumerable<EnvelopeReceiverDto>>
|
||||
{
|
||||
private readonly IRepository<EnvelopeReceiver> _repo;
|
||||
|
||||
private readonly IRepository<Receiver> _rcvRepo;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Verarbeitet <see cref="ReadEnvelopeReceiverQuery"/> und liefert passende <see cref="EnvelopeReceiverDto"/>-Ergebnisse.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiver"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public ReadEnvelopeReceiverQueryHandler(IRepository<EnvelopeReceiver> envelopeReceiver, IRepository<Receiver> rcvRepo, IMapper mapper)
|
||||
public class ReadEnvelopeReceiverQueryHandler : IRequestHandler<ReadEnvelopeReceiverQuery, IEnumerable<EnvelopeReceiverDto>>
|
||||
{
|
||||
_repo = envelopeReceiver;
|
||||
_mapper = mapper;
|
||||
_rcvRepo = rcvRepo;
|
||||
}
|
||||
private readonly IRepository<EnvelopeReceiver> _repo;
|
||||
private readonly IRepository<Receiver> _rcvRepo;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public async Task<IEnumerable<EnvelopeReceiverDto>> Handle(ReadEnvelopeReceiverQuery request, CancellationToken cancel)
|
||||
{
|
||||
var q = _repo.ReadOnly().Where(request, notnull: false);
|
||||
|
||||
if (request.Envelope.Status is not null)
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiver"></param>
|
||||
/// <param name="rcvRepo"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public ReadEnvelopeReceiverQueryHandler(IRepository<EnvelopeReceiver> envelopeReceiver, IRepository<Receiver> rcvRepo, IMapper mapper)
|
||||
{
|
||||
var status = request.Envelope.Status;
|
||||
if (status.Min is not null)
|
||||
q = q.Where(er => er.Envelope!.Status >= status.Min);
|
||||
|
||||
if (status.Max is not null)
|
||||
q = q.Where(er => er.Envelope!.Status <= status.Max);
|
||||
|
||||
if (status.Include?.Length > 0)
|
||||
q = q.Where(er => status.Include.Contains(er.Envelope!.Status));
|
||||
|
||||
if (status.Ignore is not null)
|
||||
q = q.Where(er => !status.Ignore.Contains(er.Envelope!.Status));
|
||||
_repo = envelopeReceiver;
|
||||
_mapper = mapper;
|
||||
_rcvRepo = rcvRepo;
|
||||
}
|
||||
|
||||
var envRcvs = await q
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.Documents!).ThenInclude(d => d.Elements)
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.Histories)
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.User)
|
||||
.Include(er => er.Receiver)
|
||||
.ToListAsync(cancel);
|
||||
|
||||
if (request.Receiver.HasAnyCriteria && envRcvs.Any())
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public async Task<IEnumerable<EnvelopeReceiverDto>> Handle(ReadEnvelopeReceiverQuery request, CancellationToken cancel)
|
||||
{
|
||||
var receiver = await _rcvRepo.ReadOnly().Where(request.Receiver).FirstAsync(cancel);
|
||||
var q = _repo.Query.Where(request, notnull: false);
|
||||
|
||||
foreach (var envRcv in envRcvs)
|
||||
envRcv.Envelope?.Documents?.First().Elements.RemoveAll(s => s.ReceiverId != receiver.Id);
|
||||
if (request.Username is string username)
|
||||
q = q.Where(er => er.Envelope!.User.Username == username);
|
||||
|
||||
if (request.Envelope.Status is not null)
|
||||
{
|
||||
var status = request.Envelope.Status;
|
||||
if (status.Min is not null)
|
||||
q = q.Where(er => er.Envelope!.Status >= status.Min);
|
||||
|
||||
if (status.Max is not null)
|
||||
q = q.Where(er => er.Envelope!.Status <= status.Max);
|
||||
|
||||
if (status.Include?.Length > 0)
|
||||
q = q.Where(er => status.Include.Contains(er.Envelope!.Status));
|
||||
|
||||
if (status.Ignore is not null)
|
||||
q = q.Where(er => !status.Ignore.Contains(er.Envelope!.Status));
|
||||
}
|
||||
|
||||
var envRcvs = await q
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.Documents!).ThenInclude(d => d.Elements)
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.Histories)
|
||||
.Include(er => er.Envelope).ThenInclude(e => e!.User)
|
||||
.Include(er => er.Receiver)
|
||||
.ToListAsync(cancel);
|
||||
|
||||
if (request.Receiver.HasAnyCriteria && envRcvs.Count != 0)
|
||||
{
|
||||
var receiver = await _rcvRepo.Query.Where(request.Receiver).FirstAsync(cancel);
|
||||
|
||||
foreach (var envRcv in envRcvs)
|
||||
envRcv.Envelope?.Documents?.FirstOrDefault()?.Elements?.RemoveAll(s => s.ReceiverId != receiver.Id);
|
||||
}
|
||||
|
||||
return _mapper.Map<List<EnvelopeReceiverDto>>(envRcvs);
|
||||
}
|
||||
|
||||
return _mapper.Map<List<EnvelopeReceiverDto>>(envRcvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,6 @@ public class ReceiverAlreadySignedQueryHandler : IRequestHandler<ReceiverAlready
|
||||
/// <returns></returns>
|
||||
public async Task<bool> Handle(ReceiverAlreadySignedQuery request, CancellationToken cancel = default)
|
||||
{
|
||||
return await _repo.ReadOnly().Where(request).Where(h => h.Status == EnvelopeStatus.DocumentSigned).AnyAsync(cancel);
|
||||
return await _repo.Query.Where(request).Where(h => h.Status == EnvelopeStatus.DocumentSigned).AnyAsync(cancel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using MediatR;
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EnvelopeTypes.Queries;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record ReadEnvelopeTypesQuery : IRequest<IEnumerable<EnvelopeTypeDto>>;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadEnvelopeTypesQueryHandler : IRequestHandler<ReadEnvelopeTypesQuery, IEnumerable<EnvelopeTypeDto>>
|
||||
{
|
||||
private readonly IRepository<EnvelopeType> _repository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public ReadEnvelopeTypesQueryHandler(IRepository<EnvelopeType> repository, IMapper mapper)
|
||||
{
|
||||
_repository = repository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<EnvelopeTypeDto>> Handle(ReadEnvelopeTypesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var types = await _repository.Query.ToListAsync(cancellationToken);
|
||||
return _mapper.Map<IEnumerable<EnvelopeTypeDto>>(types);
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,18 @@ public record CreateEnvelopeCommand : IRequest<EnvelopeDto?>
|
||||
/// <summary>
|
||||
/// ID des Absenders
|
||||
/// </summary>
|
||||
public int UserId { get; set; }
|
||||
internal int UserId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public bool Authorize(int userId)
|
||||
{
|
||||
UserId = userId;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines which component is used for envelope processing.
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// Repräsentiert eine Abfrage für Umschläge.
|
||||
/// </summary>
|
||||
public record ReadEnvelopeQuery : EnvelopeQueryBase, IRequest
|
||||
public record ReadEnvelopeQuery : EnvelopeQueryBase, IRequest<IEnumerable<EnvelopeDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Abfrage des Include des Umschlags
|
||||
/// </summary>
|
||||
public EnvelopeStatusQuery? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optionaler Benutzerfilter; wenn gesetzt, werden nur Umschläge des Benutzers geladen.
|
||||
/// </summary>
|
||||
public int? UserId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Setzt den Benutzerkontext für die Abfrage.
|
||||
/// </summary>
|
||||
public ReadEnvelopeQuery Authorize(int userId) => this with { UserId = userId };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,4 +80,62 @@ public record EnvelopeStatusQuery
|
||||
/// Eine Liste von Statuswerten, die ignoriert werden werden.
|
||||
/// </summary>
|
||||
public EnvelopeStatus[]? Ignore { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verarbeitet <see cref="ReadEnvelopeQuery"/> und liefert passende <see cref="EnvelopeDto"/>-Ergebnisse.
|
||||
/// </summary>
|
||||
public class ReadEnvelopeQueryHandler : IRequestHandler<ReadEnvelopeQuery, IEnumerable<EnvelopeDto>>
|
||||
{
|
||||
private readonly IRepository<Envelope> _repository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public ReadEnvelopeQueryHandler(IRepository<Envelope> repository, IMapper mapper)
|
||||
{
|
||||
_repository = repository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<EnvelopeDto>> Handle(ReadEnvelopeQuery request, CancellationToken cancel)
|
||||
{
|
||||
var query = _repository.Query;
|
||||
|
||||
if (request.UserId is int userId)
|
||||
query = query.Where(e => e.UserId == userId);
|
||||
|
||||
if (request.Id is int id)
|
||||
query = query.Where(e => e.Id == id);
|
||||
|
||||
if (request.Uuid is string uuid)
|
||||
query = query.Where(e => e.Uuid == uuid);
|
||||
|
||||
if (request.Status is { } status)
|
||||
{
|
||||
if (status.Min is not null)
|
||||
query = query.Where(e => e.Status >= status.Min);
|
||||
if (status.Max is not null)
|
||||
query = query.Where(e => e.Status <= status.Max);
|
||||
if (status.Include?.Length > 0)
|
||||
query = query.Where(e => status.Include.Contains(e.Status));
|
||||
if (status.Ignore?.Length > 0)
|
||||
query = query.Where(e => !status.Ignore.Contains(e.Status));
|
||||
}
|
||||
|
||||
var envelopes = await query
|
||||
.Include(e => e.Documents)
|
||||
.ToListAsync(cancel);
|
||||
|
||||
return _mapper.Map<IEnumerable<EnvelopeDto>>(envelopes);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using EnvelopeGenerator.Application.Receivers.Queries;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
|
||||
@@ -6,6 +10,54 @@ namespace EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
/// Eine Abfrage, um die zuletzt verwendete Anrede eines Empfängers zu ermitteln,
|
||||
/// damit diese für zukünftige Umschläge wiederverwendet werden kann.
|
||||
/// </summary>
|
||||
public record ReadReceiverNameQuery() : ReadReceiverQuery
|
||||
public record ReadReceiverNameQuery() : ReceiverQueryBase, IRequest<string?>;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadReceiverNameQueryHandler : IRequestHandler<ReadReceiverNameQuery, string?>
|
||||
{
|
||||
}
|
||||
private readonly IRepository<EnvelopeReceiver> _envelopeReceiverRepository;
|
||||
private readonly IRepository<Receiver> _receiverRepository;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverRepository"></param>
|
||||
/// <param name="receiverRepository"></param>
|
||||
public ReadReceiverNameQueryHandler(IRepository<EnvelopeReceiver> envelopeReceiverRepository, IRepository<Receiver> receiverRepository)
|
||||
{
|
||||
_envelopeReceiverRepository = envelopeReceiverRepository;
|
||||
_receiverRepository = receiverRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string?> Handle(ReadReceiverNameQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var receiverQuery = _receiverRepository.Query.AsNoTracking();
|
||||
|
||||
if (request.Id is int id)
|
||||
receiverQuery = receiverQuery.Where(r => r.Id == id);
|
||||
if (request.EmailAddress is string email)
|
||||
receiverQuery = receiverQuery.Where(r => r.EmailAddress == email);
|
||||
if (request.Signature is string signature)
|
||||
receiverQuery = receiverQuery.Where(r => r.Signature == signature);
|
||||
|
||||
var receiver = await receiverQuery.FirstOrDefaultAsync(cancellationToken);
|
||||
if (receiver is null)
|
||||
return null;
|
||||
|
||||
var erName = await _envelopeReceiverRepository.Query
|
||||
.Where(er => er.ReceiverId == receiver.Id)
|
||||
.OrderByDescending(er => er.AddedWhen)
|
||||
.Select(er => er.Name)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return erName;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class CreateHistoryCommandHandler : IRequestHandler<CreateHistoryCommand,
|
||||
if(request.UserReference is null)
|
||||
{
|
||||
var receivers = await _erRepo
|
||||
.ReadOnly()
|
||||
.Query
|
||||
.Where(request)
|
||||
.Include(er => er.Receiver)
|
||||
.ToListAsync(cancel);
|
||||
|
||||
@@ -67,6 +67,7 @@ public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverComman
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repo"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public CreateReceiverCommandHandler(IRepository<Receiver> repo, IMapper mapper)
|
||||
{
|
||||
_repo = repo;
|
||||
@@ -81,7 +82,7 @@ public class CreateReceiverCommandHandler : IRequestHandler<CreateReceiverComman
|
||||
/// <returns></returns>
|
||||
public async Task<(ReceiverDto Receiver, bool AlreadyExists)> Handle(CreateReceiverCommand request, CancellationToken cancel)
|
||||
{
|
||||
var receiver = await _repo.ReadOnly()
|
||||
var receiver = await _repo.Query
|
||||
.Where(r => r.EmailAddress == request.EmailAddress)
|
||||
.SingleOrDefaultAsync(cancel);
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using MediatR;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Receivers.Queries;
|
||||
|
||||
@@ -6,4 +12,53 @@ namespace EnvelopeGenerator.Application.Receivers.Queries;
|
||||
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
|
||||
/// um spezifische Informationen über einen Empfänger abzurufen.
|
||||
/// </summary>
|
||||
public record ReadReceiverQuery : ReceiverQueryBase;
|
||||
public record ReadReceiverQuery : ReceiverQueryBase, IRequest<IEnumerable<ReceiverDto>>;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReadReceiverQueryHandler : IRequestHandler<ReadReceiverQuery, IEnumerable<ReceiverDto>>
|
||||
{
|
||||
private readonly IRepository<Receiver> _repository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
/// <param name="mapper"></param>
|
||||
public ReadReceiverQueryHandler(IRepository<Receiver> repository, IMapper mapper)
|
||||
{
|
||||
_repository = repository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<ReceiverDto>> Handle(ReadReceiverQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _repository.Query;
|
||||
|
||||
if (request.Id is int id)
|
||||
{
|
||||
query = query.Where(r => r.Id == id);
|
||||
}
|
||||
|
||||
if (request.EmailAddress is string email)
|
||||
{
|
||||
query = query.Where(r => r.EmailAddress == email);
|
||||
}
|
||||
|
||||
if (request.Signature is string signature)
|
||||
{
|
||||
query = query.Where(r => r.Signature == signature);
|
||||
}
|
||||
|
||||
var receiver = await query.ToListAsync(cancellationToken);
|
||||
return _mapper.Map<IEnumerable<ReceiverDto>>(receiver);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,9 @@
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Zurück</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
|
||||
<value>Klicken Sie auf den</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
</data>
|
||||
@@ -144,6 +147,9 @@
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Dokument unterschrieben</value>
|
||||
</data>
|
||||
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
|
||||
<value>Der Zeitraum für die gemeinsame Nutzung von Dokumenten ist abgelaufen.</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>Englisch</value>
|
||||
</data>
|
||||
@@ -153,6 +159,9 @@
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Erstellt am {0} von {1}. Sie können den Absender über <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a></span> kontaktieren.</value>
|
||||
</data>
|
||||
<data name="Expired" xml:space="preserve">
|
||||
<value>Abgelaufen</value>
|
||||
</data>
|
||||
<data name="FiClass" xml:space="preserve">
|
||||
<value>fi-de</value>
|
||||
</data>
|
||||
@@ -165,6 +174,9 @@
|
||||
<data name="HomePageDescription" xml:space="preserve">
|
||||
<value>Das digitale Unterschriftenportal ist eine Plattform, die entwickelt wurde, um Ihre Dokumente sicher zu unterschreiben und zu verwalten. Mit seiner benutzerfreundlichen Oberfläche können Sie Ihre Dokumente schnell hochladen, die Unterschriftsprozesse verfolgen und Ihre digitalen Unterschriftenanwendungen einfach durchführen. Dieses Portal beschleunigt Ihren Arbeitsablauf mit rechtlich gültigen Unterschriften und erhöht gleichzeitig die Sicherheit Ihrer Dokumente.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Link" xml:space="preserve">
|
||||
<value>Link</value>
|
||||
</data>
|
||||
<data name="LocationWarning" xml:space="preserve">
|
||||
<value>Bitte überprüfen Sie die Standortinformationen. Wenn sie falsch sind, korrigieren Sie diese bitte.</value>
|
||||
</data>
|
||||
@@ -264,4 +276,175 @@
|
||||
<data name="WrongAccessCode" xml:space="preserve">
|
||||
<value>Ungültiger Zugangscode.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
|
||||
<value>um Ihre Authenticator-App einzurichten.</value>
|
||||
</data>
|
||||
<data name="DocumentSuccessfullySigned" xml:space="preserve">
|
||||
<value>Dokument erfolgreich signiert!</value>
|
||||
</data>
|
||||
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
|
||||
<value>Sie haben das Dokument signiert. Im Anschluss erhalten Sie eine schriftliche Bestätigung.</value>
|
||||
</data>
|
||||
<data name="Signatures" xml:space="preserve">
|
||||
<value>Unterschriften</value>
|
||||
</data>
|
||||
<data name="EnterRecipientToShareDocument" xml:space="preserve">
|
||||
<value>Geben Sie hier den Empfänger ein, mit welchem Sie das Dokument teilen wollen</value>
|
||||
</data>
|
||||
<data name="Email" xml:space="preserve">
|
||||
<value>E-Mail</value>
|
||||
</data>
|
||||
<data name="ValidUntil" xml:space="preserve">
|
||||
<value>Gültig bis</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
|
||||
<value>Falsche Email</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
|
||||
<value>Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com.</value>
|
||||
</data>
|
||||
<data name="ShrEnvSentTitle" xml:space="preserve">
|
||||
<value>Gesendet</value>
|
||||
</data>
|
||||
<data name="ShrEnvErrorTitle" xml:space="preserve">
|
||||
<value>Fehler</value>
|
||||
</data>
|
||||
<data name="InvalidDateTitle" xml:space="preserve">
|
||||
<value>Falsches Datum</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidDateText" xml:space="preserve">
|
||||
<value>Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com.</value>
|
||||
</data>
|
||||
<data name="UnexpectedErrorTitle" xml:space="preserve">
|
||||
<value>Unerwarteter Fehler</value>
|
||||
</data>
|
||||
<data name="ShrEnvOperationFailedText" xml:space="preserve">
|
||||
<value>Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team.</value>
|
||||
</data>
|
||||
<data name="PrivacyNotice" xml:space="preserve">
|
||||
<value>Datenschutzhinweis</value>
|
||||
</data>
|
||||
<data name="CookieConsentMessage" xml:space="preserve">
|
||||
<value>Wir verwenden technisch notwendige Session Cookies. Diese Cookies sind für den ordnungsgemäßen Betrieb dieser Webseite von nöten und können aus diesm Grund nicht abgewählt werden. Es findet keine Übermittlung an Dritte statt.</value>
|
||||
</data>
|
||||
<data name="Accept" xml:space="preserve">
|
||||
<value>Akzeptieren</value>
|
||||
</data>
|
||||
<data name="ConnectionValidityExpired" xml:space="preserve">
|
||||
<value>Die Gültigkeitsdauer der Verbindung ist abgelaufen.</value>
|
||||
</data>
|
||||
<data name="Creator" xml:space="preserve">
|
||||
<value>Ersteller</value>
|
||||
</data>
|
||||
<data name="Date" xml:space="preserve">
|
||||
<value>Datum</value>
|
||||
</data>
|
||||
<data name="DocumentProtected" xml:space="preserve">
|
||||
<value>Dokument geschützt</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Passwort</value>
|
||||
</data>
|
||||
<data name="Open" xml:space="preserve">
|
||||
<value>Öffnen</value>
|
||||
</data>
|
||||
<data name="TfaRegistration" xml:space="preserve">
|
||||
<value>2FA Registrierung</value>
|
||||
</data>
|
||||
<data name="Registration" xml:space="preserve">
|
||||
<value>Registrierung</value>
|
||||
</data>
|
||||
<data name="PageVisibleUntil" xml:space="preserve">
|
||||
<value>Diese Seite ist bis {0} sichtbar.</value>
|
||||
</data>
|
||||
<data name="Step1Download2faApplication" xml:space="preserve">
|
||||
<value>Schritt 1 - Download einer 2FA Applikation</value>
|
||||
</data>
|
||||
<data name="Download2faAppInstruction" xml:space="preserve">
|
||||
<value>Bitte nehmen Sie Ihr Smartphone zur Hand und laden eine Applikation herunter, die zur Zwei-Faktor-Authentifizierung (2FA) benutzt werden kann.</value>
|
||||
</data>
|
||||
<data name="Recommended2faApplications" xml:space="preserve">
|
||||
<value>Folgende Applikationen empfehlen wir</value>
|
||||
</data>
|
||||
<data name="Step2ScanQrCode" xml:space="preserve">
|
||||
<value>Schritt 2 - Scannen des QR-Codes</value>
|
||||
</data>
|
||||
<data name="ScanQrCodeInstruction" xml:space="preserve">
|
||||
<value>Sobald Sie eine Zwei-Faktor-Authentifizierung App installiert haben, können Sie fortfahren und innerhalb der Applikation die Option zum Scannen eines QR-Codes suchen und bestätigen. Im Anschluss, sobald die Kamera freigegeben wurde, können Sie den QR-Code von uns scannen.</value>
|
||||
</data>
|
||||
<data name="Step3VerifyTheCode" xml:space="preserve">
|
||||
<value>Schritt 3 - Verifizierung des Codes</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionMain" xml:space="preserve">
|
||||
<value>Sie können nun in der Zwei-Faktor-Authentifizierung App einen Zahlencode zur Verifizierung des Vorganges ablesen. Bitte tragen Sie diesen Code in das unten aufgeführte Eingabefeld ein und Klicken auf</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
|
||||
<value>Senden</value>
|
||||
</data>
|
||||
<data name="CopyLink" xml:space="preserve">
|
||||
<value>Link kopieren</value>
|
||||
</data>
|
||||
<data name="CityFormatInvalid" xml:space="preserve">
|
||||
<value>Bitte überprüfen Sie die eingegebene Ortsangabe "{0}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.</value>
|
||||
</data>
|
||||
<data name="CopyLinkSuccess" xml:space="preserve">
|
||||
<value>Kopiert</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Abmelden</value>
|
||||
</data>
|
||||
<data name="ViewAllPages" xml:space="preserve">
|
||||
<value>Bitte sehen Sie sich alle Seiten an.</value>
|
||||
</data>
|
||||
<data name="Reset" xml:space="preserve">
|
||||
<value>Zurücksetzen</value>
|
||||
</data>
|
||||
<data name="ViewRemainingPages" xml:space="preserve">
|
||||
<value>Bitte sehen Sie sich die folgenden Seiten an: {0}</value>
|
||||
</data>
|
||||
<data name="City" xml:space="preserve">
|
||||
<value>Ort</value>
|
||||
</data>
|
||||
<data name="EnvelopeRejectedRedirect" xml:space="preserve">
|
||||
<value>Dokument wurde von einem Empfänger abgelehnt. Sie werden weitergeleitet...</value>
|
||||
</data>
|
||||
<data name="MissingSignatures" xml:space="preserve">
|
||||
<value>Es wurden nicht alle Signaturfelder ausgefüllt!</value>
|
||||
</data>
|
||||
<data name="ResetConfirmText" xml:space="preserve">
|
||||
<value>Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?</value>
|
||||
</data>
|
||||
<data name="EnvelopeSignError" xml:space="preserve">
|
||||
<value>Umschlag konnte nicht signiert werden!</value>
|
||||
</data>
|
||||
<data name="SignedBy" xml:space="preserve">
|
||||
<value>Signiert von</value>
|
||||
</data>
|
||||
<data name="Warning" xml:space="preserve">
|
||||
<value>Warnung</value>
|
||||
</data>
|
||||
<data name="Position" xml:space="preserve">
|
||||
<value>Position</value>
|
||||
</data>
|
||||
<data name="Share" xml:space="preserve">
|
||||
<value>Teilen</value>
|
||||
</data>
|
||||
<data name="CopyLinkFailure" xml:space="preserve">
|
||||
<value>Unerwarteter Fehler</value>
|
||||
</data>
|
||||
<data name="LocationFieldsRequired" xml:space="preserve">
|
||||
<value>Bitte füllen Sie alle Standortinformationen vollständig aus!</value>
|
||||
</data>
|
||||
<data name="ResetConfirmTitle" xml:space="preserve">
|
||||
<value>Sind Sie sicher?</value>
|
||||
</data>
|
||||
<data name="EnvelopeUnavailable" xml:space="preserve">
|
||||
<value>Umschlag ist nicht mehr verfügbar.</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>Erfolg</value>
|
||||
</data>
|
||||
<data name="DocumentReset" xml:space="preserve">
|
||||
<value>Dokument wurde zurückgesetzt.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -123,6 +123,9 @@
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
|
||||
<value>Click the</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Complete</value>
|
||||
</data>
|
||||
@@ -144,6 +147,9 @@
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Document signed</value>
|
||||
</data>
|
||||
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
|
||||
<value>The period for sharing documents has expired.</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>English</value>
|
||||
</data>
|
||||
@@ -153,6 +159,9 @@
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Created on {0} by {1}. You can contact the sender via <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a></span>.</value>
|
||||
</data>
|
||||
<data name="Expired" xml:space="preserve">
|
||||
<value>Expired</value>
|
||||
</data>
|
||||
<data name="FiClass" xml:space="preserve">
|
||||
<value>fi-us</value>
|
||||
</data>
|
||||
@@ -165,6 +174,9 @@
|
||||
<data name="HomePageDescription" xml:space="preserve">
|
||||
<value>The Digital Signature Portal is a platform developed for securely signing and managing your documents. With its user-friendly interface, you can quickly upload your documents, track the signing processes, and easily carry out your digital signature applications. This portal accelerates your workflow with legally valid signatures while enhancing the security of your documents.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Link" xml:space="preserve">
|
||||
<value>link</value>
|
||||
</data>
|
||||
<data name="LocationWarning" xml:space="preserve">
|
||||
<value>Please review the location information. If it is incorrect, kindly make the necessary corrections.</value>
|
||||
</data>
|
||||
@@ -264,4 +276,175 @@
|
||||
<data name="WrongAccessCode" xml:space="preserve">
|
||||
<value>Invalid access code.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
|
||||
<value>to set up your authenticator app.</value>
|
||||
</data>
|
||||
<data name="DocumentSuccessfullySigned" xml:space="preserve">
|
||||
<value>Document successfully signed!</value>
|
||||
</data>
|
||||
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
|
||||
<value>You have signed the document. Afterwards, you will receive a written confirmation.</value>
|
||||
</data>
|
||||
<data name="Signatures" xml:space="preserve">
|
||||
<value>Signatures</value>
|
||||
</data>
|
||||
<data name="EnterRecipientToShareDocument" xml:space="preserve">
|
||||
<value>Enter the recipient you want to share the document with</value>
|
||||
</data>
|
||||
<data name="Email" xml:space="preserve">
|
||||
<value>E-mail</value>
|
||||
</data>
|
||||
<data name="ValidUntil" xml:space="preserve">
|
||||
<value>Valid until</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
|
||||
<value>Invalid email</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
|
||||
<value>The email address is invalid. Please use the correct format, e.g., user@mail.com.</value>
|
||||
</data>
|
||||
<data name="ShrEnvSentTitle" xml:space="preserve">
|
||||
<value>Sent</value>
|
||||
</data>
|
||||
<data name="ShrEnvErrorTitle" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="InvalidDateTitle" xml:space="preserve">
|
||||
<value>Invalid date</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidDateText" xml:space="preserve">
|
||||
<value>The email address is invalid. Please use the correct format, e.g., user@mail.com.</value>
|
||||
</data>
|
||||
<data name="UnexpectedErrorTitle" xml:space="preserve">
|
||||
<value>Unexpected error</value>
|
||||
</data>
|
||||
<data name="ShrEnvOperationFailedText" xml:space="preserve">
|
||||
<value>The operation failed. Please contact the IT team.</value>
|
||||
</data>
|
||||
<data name="PrivacyNotice" xml:space="preserve">
|
||||
<value>Privacy notice</value>
|
||||
</data>
|
||||
<data name="CookieConsentMessage" xml:space="preserve">
|
||||
<value>We use technically necessary session cookies. These cookies are required for the proper operation of this website and therefore cannot be deselected. No data is transmitted to third parties.</value>
|
||||
</data>
|
||||
<data name="Accept" xml:space="preserve">
|
||||
<value>Accept</value>
|
||||
</data>
|
||||
<data name="ConnectionValidityExpired" xml:space="preserve">
|
||||
<value>The session has expired.</value>
|
||||
</data>
|
||||
<data name="Creator" xml:space="preserve">
|
||||
<value>Creator</value>
|
||||
</data>
|
||||
<data name="Date" xml:space="preserve">
|
||||
<value>Date</value>
|
||||
</data>
|
||||
<data name="DocumentProtected" xml:space="preserve">
|
||||
<value>Document protected</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="Open" xml:space="preserve">
|
||||
<value>Open</value>
|
||||
</data>
|
||||
<data name="TfaRegistration" xml:space="preserve">
|
||||
<value>2FA Registration</value>
|
||||
</data>
|
||||
<data name="Registration" xml:space="preserve">
|
||||
<value>Registration</value>
|
||||
</data>
|
||||
<data name="PageVisibleUntil" xml:space="preserve">
|
||||
<value>This page is visible until {0}.</value>
|
||||
</data>
|
||||
<data name="Step1Download2faApplication" xml:space="preserve">
|
||||
<value>Step 1 – Download a 2FA application</value>
|
||||
</data>
|
||||
<data name="Download2faAppInstruction" xml:space="preserve">
|
||||
<value>Please take your smartphone and download an application that can be used for two-factor authentication (2FA).</value>
|
||||
</data>
|
||||
<data name="Recommended2faApplications" xml:space="preserve">
|
||||
<value>We recommend the following applications</value>
|
||||
</data>
|
||||
<data name="Step2ScanQrCode" xml:space="preserve">
|
||||
<value>Step 2 – Scan the QR code</value>
|
||||
</data>
|
||||
<data name="ScanQrCodeInstruction" xml:space="preserve">
|
||||
<value>Once you have installed a two-factor authentication app, you can proceed and look for the option to scan a QR code within the application and confirm it. Then, once the camera is enabled, you can scan the QR code provided by us.</value>
|
||||
</data>
|
||||
<data name="Step3VerifyTheCode" xml:space="preserve">
|
||||
<value>Step 3 – Verify the code</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionMain" xml:space="preserve">
|
||||
<value>You can now read a numeric code in the two-factor authentication app to verify the process. Please enter this code in the input field below and click</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
|
||||
<value>Submit</value>
|
||||
</data>
|
||||
<data name="CopyLink" xml:space="preserve">
|
||||
<value>Copy link</value>
|
||||
</data>
|
||||
<data name="CityFormatInvalid" xml:space="preserve">
|
||||
<value>Please check the entered location "{0}" for proper formatting. Examples: Munich, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines, etc.</value>
|
||||
</data>
|
||||
<data name="CopyLinkSuccess" xml:space="preserve">
|
||||
<value>Copied</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Logout</value>
|
||||
</data>
|
||||
<data name="ViewAllPages" xml:space="preserve">
|
||||
<value>Please view all pages.</value>
|
||||
</data>
|
||||
<data name="Reset" xml:space="preserve">
|
||||
<value>Reset</value>
|
||||
</data>
|
||||
<data name="ViewRemainingPages" xml:space="preserve">
|
||||
<value>Please view the following pages: {0}</value>
|
||||
</data>
|
||||
<data name="City" xml:space="preserve">
|
||||
<value>City</value>
|
||||
</data>
|
||||
<data name="EnvelopeRejectedRedirect" xml:space="preserve">
|
||||
<value>The document was rejected by a recipient. You will be redirected...</value>
|
||||
</data>
|
||||
<data name="MissingSignatures" xml:space="preserve">
|
||||
<value>Not all signature fields have been completed!</value>
|
||||
</data>
|
||||
<data name="ResetConfirmText" xml:space="preserve">
|
||||
<value>Do you want to reset the document and all created signatures?</value>
|
||||
</data>
|
||||
<data name="EnvelopeSignError" xml:space="preserve">
|
||||
<value>The envelope could not be signed!</value>
|
||||
</data>
|
||||
<data name="SignedBy" xml:space="preserve">
|
||||
<value>Signed by</value>
|
||||
</data>
|
||||
<data name="Warning" xml:space="preserve">
|
||||
<value>Warning</value>
|
||||
</data>
|
||||
<data name="Position" xml:space="preserve">
|
||||
<value>Position</value>
|
||||
</data>
|
||||
<data name="Share" xml:space="preserve">
|
||||
<value>Share</value>
|
||||
</data>
|
||||
<data name="CopyLinkFailure" xml:space="preserve">
|
||||
<value>Unexpected error</value>
|
||||
</data>
|
||||
<data name="LocationFieldsRequired" xml:space="preserve">
|
||||
<value>Please complete all location information.</value>
|
||||
</data>
|
||||
<data name="ResetConfirmTitle" xml:space="preserve">
|
||||
<value>Are you sure?</value>
|
||||
</data>
|
||||
<data name="EnvelopeUnavailable" xml:space="preserve">
|
||||
<value>The envelope is no longer available.</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>Success</value>
|
||||
</data>
|
||||
<data name="DocumentReset" xml:space="preserve">
|
||||
<value>Document has been reset.</value>
|
||||
</data>
|
||||
</root>
|
||||
450
EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx
Normal file
450
EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx
Normal file
@@ -0,0 +1,450 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>et</value>
|
||||
</data>
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Retour</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
|
||||
<value>Cliquez sur</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Terminer</value>
|
||||
</data>
|
||||
<data name="Confirmation" xml:space="preserve">
|
||||
<value>Confirmation</value>
|
||||
</data>
|
||||
<data name="Culture" xml:space="preserve">
|
||||
<value>fr-FR</value>
|
||||
</data>
|
||||
<data name="de-DE" xml:space="preserve">
|
||||
<value>Allemand</value>
|
||||
</data>
|
||||
<data name="DocProtected" xml:space="preserve">
|
||||
<value>Document protégé</value>
|
||||
</data>
|
||||
<data name="DocRejected" xml:space="preserve">
|
||||
<value>Document rejeté</value>
|
||||
</data>
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Document signé</value>
|
||||
</data>
|
||||
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
|
||||
<value>La période de partage des documents a expiré.</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>Anglais</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo1" xml:space="preserve">
|
||||
<value>Vous devez signer le processus {0}. <span class="highlight highlight-envelope-info-1">Veuillez vérifier la page {1}</span>.</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Créé le {0} par {1}. Vous pouvez contacter l’expéditeur via <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Cher%20{4}%20{5},%0A%0A%0A">{6}</a></span>.</value>
|
||||
</data>
|
||||
<data name="Expired" xml:space="preserve">
|
||||
<value>Expiré</value>
|
||||
</data>
|
||||
<data name="FiClass" xml:space="preserve">
|
||||
<value>fi-fr</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Finaliser</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Bonjour</value>
|
||||
</data>
|
||||
<data name="HomePageDescription" xml:space="preserve">
|
||||
<value>Le Portail de Signature Numérique est une plateforme développée pour signer et gérer vos documents en toute sécurité. Grâce à son interface conviviale, vous pouvez rapidement téléverser vos documents, suivre les processus de signature et effectuer facilement vos démarches de signature numérique. Ce portail accélère votre flux de travail avec des signatures juridiquement valides tout en renforçant la sécurité de vos documents.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Link" xml:space="preserve">
|
||||
<value>lien</value>
|
||||
</data>
|
||||
<data name="LocationWarning" xml:space="preserve">
|
||||
<value>Veuillez vérifier les informations de localisation. Si elles sont incorrectes, veuillez effectuer les corrections nécessaires.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAccess" xml:space="preserve">
|
||||
<value>Nous allons maintenant vous envoyer un code d’accès à votre adresse e-mail enregistrée. Cela peut prendre quelques minutes !</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticator" xml:space="preserve">
|
||||
<value>Veuillez saisir le TOTP fourni dans votre application Authenticator.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticatorNew" xml:space="preserve">
|
||||
<value>Nous avons envoyé le code QR à votre adresse e-mail. Votre code QR est valide jusqu’au {0}. Vous pouvez l’utiliser pour toutes les enveloppes reçues à cette adresse e-mail.</value>
|
||||
</data>
|
||||
<data name="LockedBodySms" xml:space="preserve">
|
||||
<value>Nous venons d’envoyer le code d’accès par SMS au numéro de téléphone que vous avez fourni.</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAccess" xml:space="preserve">
|
||||
<value>Code d’accès</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAuthenticator" xml:space="preserve">
|
||||
<value>TOTP</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelSms" xml:space="preserve">
|
||||
<value>Code SMS</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAccess" xml:space="preserve">
|
||||
<value>Veuillez vérifier votre boîte de réception, y compris le dossier spam. Vous pouvez également demander à l’expéditeur <a class="mail-link" href="mailto:{0}?subject={1}&body={2}" target="_blank">{0}</a> de vous envoyer le code par un autre moyen.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAuthenticator" xml:space="preserve">
|
||||
<value>Le nouveau code QR n’est envoyé qu’une seule fois pour une période donnée et est enregistré dans votre application Authenticator une fois scanné. Il peut être utilisé pour toutes les enveloppes reçues à la même adresse e-mail jusqu’à son expiration. Si vous ne recevez pas l’e-mail contenant le code QR ou si vous le supprimez à la fois de l’e-mail et de l’application Authenticator, veuillez contacter l’expéditeur.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodySms" xml:space="preserve">
|
||||
<value>Vous pouvez demander à l’expéditeur de vérifier votre numéro de téléphone. Le numéro de téléphone doit être saisi avec l’indicatif. Sinon, vous pouvez demander la suppression de la protection à deux facteurs.</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAccess" xml:space="preserve">
|
||||
<value>Vous n’avez pas reçu de code d’accès ?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAuthenticator" xml:space="preserve">
|
||||
<value>Vous n’avez pas reçu de code QR ?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleSms" xml:space="preserve">
|
||||
<value>Vous n’avez pas reçu de SMS ?</value>
|
||||
</data>
|
||||
<data name="LockedTitleAccess" xml:space="preserve">
|
||||
<value>Le document nécessite un code d’accès</value>
|
||||
</data>
|
||||
<data name="LockedTitleAuthenticator" xml:space="preserve">
|
||||
<value>Authentification à 2 facteurs</value>
|
||||
</data>
|
||||
<data name="LockedTitleSms" xml:space="preserve">
|
||||
<value>Authentification à 2 facteurs</value>
|
||||
</data>
|
||||
<data name="Privacy" xml:space="preserve">
|
||||
<value>Confidentialité</value>
|
||||
</data>
|
||||
<data name="ReadOnlyMessage" xml:space="preserve">
|
||||
<value>Transféré par {0}. Valable jusqu’au {1}.</value>
|
||||
</data>
|
||||
<data name="Reject" xml:space="preserve">
|
||||
<value>Rejeter</value>
|
||||
</data>
|
||||
<data name="Rejection" xml:space="preserve">
|
||||
<value>Rejet</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1" xml:space="preserve">
|
||||
<value>Ce processus de signature a été rejeté !</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1_ext" xml:space="preserve">
|
||||
<value>Processus annulé !</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2" xml:space="preserve">
|
||||
<value>Vous pouvez contacter {0}, <a href="mailto:{1}?subject={2}&body=Cher%20{0},%0A%0A%0A">{1}</a> si nécessaire.</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2_ext" xml:space="preserve">
|
||||
<value>Le processus a été rejeté par l’une des parties concernées. Vous pouvez contacter {0}, <a href="mailto:{1}?subject={2}&body=Cher%20{0},%0A%0A%0A">{1}</a> si nécessaire.</value>
|
||||
</data>
|
||||
<data name="RejectionReasonQ" xml:space="preserve">
|
||||
<value>Veuillez indiquer une raison :</value>
|
||||
</data>
|
||||
<data name="SigAgree" xml:space="preserve">
|
||||
<value>En cliquant sur Finaliser, j’accepte que la signature affichée et soumise soit une représentation électronique de ma signature dans les cas où je l’utilise sur des documents, y compris des contrats juridiquement contraignants.</value>
|
||||
</data>
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Signer le document</value>
|
||||
</data>
|
||||
<data name="SigningProcessTitle" xml:space="preserve">
|
||||
<value>Titre du processus de signature</value>
|
||||
</data>
|
||||
<data name="UnexpectedError" xml:space="preserve">
|
||||
<value>Une erreur inattendue s’est produite.</value>
|
||||
</data>
|
||||
<data name="ViewDoc" xml:space="preserve">
|
||||
<value>Afficher le document</value>
|
||||
</data>
|
||||
<data name="WelcomeToTheESignPortal" xml:space="preserve">
|
||||
<value>Bienvenue sur le portail eSign</value>
|
||||
</data>
|
||||
<data name="WrongAccessCode" xml:space="preserve">
|
||||
<value>Code d’accès invalide.</value>
|
||||
</data>
|
||||
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
|
||||
<value>pour configurer votre application d'authentification.</value>
|
||||
</data>
|
||||
<data name="DocumentSuccessfullySigned" xml:space="preserve">
|
||||
<value>Document signé avec succès !</value>
|
||||
</data>
|
||||
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
|
||||
<value>Vous avez signé le document. Vous recevrez ensuite une confirmation écrite.</value>
|
||||
</data>
|
||||
<data name="Signatures" xml:space="preserve">
|
||||
<value>Signatures</value>
|
||||
</data>
|
||||
<data name="EnterRecipientToShareDocument" xml:space="preserve">
|
||||
<value>Saisissez ici le destinataire avec lequel vous souhaitez partager le document</value>
|
||||
</data>
|
||||
<data name="Email" xml:space="preserve">
|
||||
<value>E-mail</value>
|
||||
</data>
|
||||
<data name="ValidUntil" xml:space="preserve">
|
||||
<value>Valable jusqu'au</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
|
||||
<value>E-mail incorrect</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
|
||||
<value>L'adresse e-mail est invalide. Veuillez utiliser le format correct, par ex. : user@mail.com.</value>
|
||||
</data>
|
||||
<data name="ShrEnvSentTitle" xml:space="preserve">
|
||||
<value>Envoyé</value>
|
||||
</data>
|
||||
<data name="ShrEnvErrorTitle" xml:space="preserve">
|
||||
<value>Erreur</value>
|
||||
</data>
|
||||
<data name="InvalidDateTitle" xml:space="preserve">
|
||||
<value>Date invalide</value>
|
||||
</data>
|
||||
<data name="ShrEnvInvalidDateText" xml:space="preserve">
|
||||
<value>L'adresse e-mail est invalide. Veuillez utiliser le format correct, par ex. : user@mail.com.</value>
|
||||
</data>
|
||||
<data name="UnexpectedErrorTitle" xml:space="preserve">
|
||||
<value>Erreur inattendue</value>
|
||||
</data>
|
||||
<data name="ShrEnvOperationFailedText" xml:space="preserve">
|
||||
<value>L'opération a échoué. Veuillez contacter l'équipe informatique.</value>
|
||||
</data>
|
||||
<data name="PrivacyNotice" xml:space="preserve">
|
||||
<value>Avis de confidentialité</value>
|
||||
</data>
|
||||
<data name="CookieConsentMessage" xml:space="preserve">
|
||||
<value>Nous utilisons des cookies de session strictement nécessaires. Ces cookies sont indispensables au bon fonctionnement de ce site et ne peuvent donc pas être désactivés. Aucune donnée n'est transmise à des tiers.</value>
|
||||
</data>
|
||||
<data name="Accept" xml:space="preserve">
|
||||
<value>Accepter</value>
|
||||
</data>
|
||||
<data name="ConnectionValidityExpired" xml:space="preserve">
|
||||
<value>La durée de validité de la connexion est expirée.</value>
|
||||
</data>
|
||||
<data name="Creator" xml:space="preserve">
|
||||
<value>Créateur</value>
|
||||
</data>
|
||||
<data name="Date" xml:space="preserve">
|
||||
<value>Date</value>
|
||||
</data>
|
||||
<data name="DocumentProtected" xml:space="preserve">
|
||||
<value>Document protégé</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Mot de passe</value>
|
||||
</data>
|
||||
<data name="Open" xml:space="preserve">
|
||||
<value>Ouvrir</value>
|
||||
</data>
|
||||
<data name="TfaRegistration" xml:space="preserve">
|
||||
<value>Enregistrement 2FA</value>
|
||||
</data>
|
||||
<data name="Registration" xml:space="preserve">
|
||||
<value>Inscription</value>
|
||||
</data>
|
||||
<data name="PageVisibleUntil" xml:space="preserve">
|
||||
<value>Cette page est visible jusqu'au {0}.</value>
|
||||
</data>
|
||||
<data name="Step1Download2faApplication" xml:space="preserve">
|
||||
<value>Étape 1 – Téléchargez une application 2FA</value>
|
||||
</data>
|
||||
<data name="Download2faAppInstruction" xml:space="preserve">
|
||||
<value>Veuillez prendre votre smartphone et télécharger une application pouvant être utilisée pour l’authentification à deux facteurs (2FA).</value>
|
||||
</data>
|
||||
<data name="Recommended2faApplications" xml:space="preserve">
|
||||
<value>Nous recommandons les applications suivantes</value>
|
||||
</data>
|
||||
<data name="Step2ScanQrCode" xml:space="preserve">
|
||||
<value>Étape 2 – Scannez le code QR</value>
|
||||
</data>
|
||||
<data name="ScanQrCodeInstruction" xml:space="preserve">
|
||||
<value>Une fois que vous avez installé une application d’authentification à deux facteurs, vous pouvez continuer et chercher dans l’application l’option pour scanner un code QR et la confirmer. Ensuite, une fois la caméra activée, vous pourrez scanner le code QR fourni par nos soins.</value>
|
||||
</data>
|
||||
<data name="Step3VerifyTheCode" xml:space="preserve">
|
||||
<value>Étape 3 – Vérification du code</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionMain" xml:space="preserve">
|
||||
<value>Vous pouvez maintenant lire un code numérique dans l’application d’authentification à deux facteurs pour vérifier l’opération. Veuillez saisir ce code dans le champ ci-dessous et cliquer sur</value>
|
||||
</data>
|
||||
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
|
||||
<value>Envoyer</value>
|
||||
</data>
|
||||
<data name="CopyLink" xml:space="preserve">
|
||||
<value>Copier le lien</value>
|
||||
</data>
|
||||
<data name="CityFormatInvalid" xml:space="preserve">
|
||||
<value>Veuillez vérifier le lieu saisi "{0}" pour un format correct. Exemples : Munich, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines, etc.</value>
|
||||
</data>
|
||||
<data name="CopyLinkSuccess" xml:space="preserve">
|
||||
<value>Copié</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Déconnexion</value>
|
||||
</data>
|
||||
<data name="ViewAllPages" xml:space="preserve">
|
||||
<value>Veuillez consulter toutes les pages.</value>
|
||||
</data>
|
||||
<data name="Reset" xml:space="preserve">
|
||||
<value>Réinitialiser</value>
|
||||
</data>
|
||||
<data name="ViewRemainingPages" xml:space="preserve">
|
||||
<value>Veuillez consulter les pages suivantes : {0}</value>
|
||||
</data>
|
||||
<data name="City" xml:space="preserve">
|
||||
<value>Ville</value>
|
||||
</data>
|
||||
<data name="EnvelopeRejectedRedirect" xml:space="preserve">
|
||||
<value>Le document a été refusé par un destinataire. Vous allez être redirigé...</value>
|
||||
</data>
|
||||
<data name="MissingSignatures" xml:space="preserve">
|
||||
<value>Tous les champs de signature n'ont pas été remplis !</value>
|
||||
</data>
|
||||
<data name="ResetConfirmText" xml:space="preserve">
|
||||
<value>Voulez-vous réinitialiser le document et toutes les signatures créées ?</value>
|
||||
</data>
|
||||
<data name="EnvelopeSignError" xml:space="preserve">
|
||||
<value>Le pli n'a pas pu être signé !</value>
|
||||
</data>
|
||||
<data name="SignedBy" xml:space="preserve">
|
||||
<value>Signé par</value>
|
||||
</data>
|
||||
<data name="Warning" xml:space="preserve">
|
||||
<value>Avertissement</value>
|
||||
</data>
|
||||
<data name="Position" xml:space="preserve">
|
||||
<value>Position</value>
|
||||
</data>
|
||||
<data name="Share" xml:space="preserve">
|
||||
<value>Partager</value>
|
||||
</data>
|
||||
<data name="CopyLinkFailure" xml:space="preserve">
|
||||
<value>Erreur inattendue</value>
|
||||
</data>
|
||||
<data name="LocationFieldsRequired" xml:space="preserve">
|
||||
<value>Veuillez compléter toutes les informations de localisation.</value>
|
||||
</data>
|
||||
<data name="ResetConfirmTitle" xml:space="preserve">
|
||||
<value>Êtes-vous sûr ?</value>
|
||||
</data>
|
||||
<data name="EnvelopeUnavailable" xml:space="preserve">
|
||||
<value>Le pli n'est plus disponible.</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>Succès</value>
|
||||
</data>
|
||||
<data name="DocumentReset" xml:space="preserve">
|
||||
<value>Le document a été réinitialisé.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -4,7 +4,6 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Configurations;
|
||||
@@ -12,6 +11,7 @@ using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services;
|
||||
|
||||
@@ -21,170 +21,170 @@ namespace EnvelopeGenerator.Application.Services;
|
||||
[Obsolete("Use MediatR")]
|
||||
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
|
||||
{
|
||||
private readonly IEmailTemplateService _tempService;
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
private readonly DispatcherParams _dConfig;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Dictionary<string, string> _placeholders;
|
||||
private readonly IAuthenticator _authenticator;
|
||||
private readonly IEmailTemplateService _tempService;
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
private readonly DispatcherParams _dConfig;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Dictionary<string, string> _placeholders;
|
||||
private readonly ISender _sender;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
/// <param name="mapper"></param>
|
||||
/// <param name="tempService"></param>
|
||||
/// <param name="envelopeReceiverService"></param>
|
||||
/// <param name="dispatcherConfigOptions"></param>
|
||||
/// <param name="configService"></param>
|
||||
/// <param name="mailConfig"></param>
|
||||
/// <param name="authenticator"></param>
|
||||
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, IAuthenticator authenticator) : base(repository, mapper)
|
||||
{
|
||||
_tempService = tempService;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_dConfig = dispatcherConfigOptions.Value;
|
||||
_configService = configService;
|
||||
_placeholders = new Dictionary<string, string>(mailConfig.Value.Placeholders);
|
||||
_authenticator = authenticator;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
/// <param name="mapper"></param>
|
||||
/// <param name="tempService"></param>
|
||||
/// <param name="envelopeReceiverService"></param>
|
||||
/// <param name="dispatcherConfigOptions"></param>
|
||||
/// <param name="configService"></param>
|
||||
/// <param name="mailConfig"></param>
|
||||
/// <param name="sender"></param>
|
||||
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, ISender sender) : base(repository, mapper)
|
||||
{
|
||||
_tempService = tempService;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_dConfig = dispatcherConfigOptions.Value;
|
||||
_configService = configService;
|
||||
_placeholders = new Dictionary<string, string>(mailConfig.Value.Placeholders);
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
|
||||
{
|
||||
if (accessCode is not null)
|
||||
_placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
|
||||
|
||||
if(envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
|
||||
{
|
||||
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).ToEnvelopeKey();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
if (accessCode is not null)
|
||||
_placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
|
||||
|
||||
if (envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
|
||||
{
|
||||
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).ToEnvelopeKey();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
}
|
||||
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
|
||||
{
|
||||
if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null)
|
||||
{
|
||||
_placeholders["[NAME_RECEIVER]"] = await _envRcvService.ReadLastUsedReceiverNameByMailAsync(readOnlyDto.AddedWho).ThenAsync(res => res, (msg, ntc) => string.Empty) ?? string.Empty;
|
||||
var erReadOnlyId = (readOnlyDto.Id).ToEnvelopeKey();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erReadOnlyId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
}
|
||||
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="tempType"></param>
|
||||
/// <param name="optionalPlaceholders"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(tempType);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, DigitalData.Core.Abstraction.Application.DTO.Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
|
||||
{
|
||||
EmailAddress = dto.Receiver!.EmailAddress,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//email_type = envelope_status,
|
||||
//message = envelope_message,
|
||||
ReferenceId = dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto!.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int) EnvelopeStatus.MessageAccessCodeSent,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null)
|
||||
{
|
||||
_placeholders["[NAME_RECEIVER]"] = await _envRcvService.ReadLastUsedReceiverNameByMailAsync(readOnlyDto.AddedWho).ThenAsync(res => res, (msg, ntc) => string.Empty) ?? string.Empty;
|
||||
var erReadOnlyId = (readOnlyDto.Id).ToEnvelopeKey();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erReadOnlyId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
}
|
||||
|
||||
//get acccess code
|
||||
var acResult = await _envRcvService.ReadAccessCodeByIdAsync(envelopeId: dto.EnvelopeId, receiverId: dto.ReceiverId);
|
||||
if (acResult.IsFailed)
|
||||
return acResult.ToFail<int>().Notice(LogLevel.Error, "Therefore, access code cannot be sent");
|
||||
var accessCode = acResult.Data;
|
||||
|
||||
var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto);
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="tempType"></param>
|
||||
/// <param name="optionalPlaceholders"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(tempType);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
//TODO: remove the requirement to add the models using reflections
|
||||
return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders,
|
||||
dto, dto.Envelope.User!, dto.Envelope);
|
||||
}
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.Receiver!.EmailAddress,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//email_type = envelope_status,
|
||||
//message = envelope_message,
|
||||
ReferenceId = dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto!.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int)EnvelopeStatus.MessageAccessCodeSent,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="optionalPlaceholders"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(EmailTemplateType.DocumentShared);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{EmailTemplateType.DocumentShared}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
//get acccess code
|
||||
var acResult = await _envRcvService.ReadAccessCodeByIdAsync(envelopeId: dto.EnvelopeId, receiverId: dto.ReceiverId);
|
||||
if (acResult.IsFailed)
|
||||
return acResult.ToFail<int>().Notice(LogLevel.Error, "Therefore, access code cannot be sent");
|
||||
var accessCode = acResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.ReceiverMail,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//TODO: remove int casting when all
|
||||
ReferenceId = (int) dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int)EnvelopeStatus.EnvelopeShared,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto);
|
||||
|
||||
var placeholders = await CreatePlaceholders(readOnlyDto: dto);
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
//TODO: remove the requirement to add the models using reflections
|
||||
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders,
|
||||
dto, dto.Envelope.User!, dto.Envelope);
|
||||
}
|
||||
|
||||
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders, dto.Envelope);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="optionalPlaceholders"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(EmailTemplateType.DocumentShared);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{EmailTemplateType.DocumentShared}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.ReceiverMail,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//TODO: remove int casting when all
|
||||
ReferenceId = (int)dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int)EnvelopeStatus.EnvelopeShared,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
|
||||
var placeholders = await CreatePlaceholders(readOnlyDto: dto);
|
||||
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
|
||||
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders, dto.Envelope);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: EmailTemplateType.DocumentAccessCodeReceived);
|
||||
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: EmailTemplateType.DocumentAccessCodeReceived);
|
||||
}
|
||||
@@ -70,8 +70,8 @@
|
||||
<Reference Include="DigitalData.Controls.DocumentViewer, Version=1.9.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Controls.DocumentViewer.1.9.8\lib\net462\DigitalData.Controls.DocumentViewer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.6.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.6.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
||||
@@ -109,9 +109,6 @@
|
||||
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EnvelopeGenerator.CommonServices">
|
||||
<HintPath>..\EnvelopeGenerator.CommonServices\bin\Debug\EnvelopeGenerator.CommonServices.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FirebirdSql.Data.FirebirdClient, Version=7.5.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FirebirdSql.Data.FirebirdClient.7.5.0\lib\net452\FirebirdSql.Data.FirebirdClient.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -466,8 +463,12 @@
|
||||
<Project>{6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}</Project>
|
||||
<Name>EnvelopeGenerator.CommonServices</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.CommonServices\EnvelopeGenerator.CommonServices.vbproj">
|
||||
<Project>{6ea0c51f-c2b1-4462-8198-3de0b32b74f8}</Project>
|
||||
<Name>EnvelopeGenerator.CommonServices</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj">
|
||||
<Project>{4F32A98D-E6F0-4A09-BD97-1CF26107E837}</Project>
|
||||
<Project>{4f32a98d-e6f0-4a09-bd97-1cf26107e837}</Project>
|
||||
<Name>EnvelopeGenerator.Domain</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj">
|
||||
@@ -495,6 +496,9 @@
|
||||
<Content Include="MailLicense.xml" />
|
||||
<Content Include="README.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WCFMetadata Include="Connected Services\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
<Import Project="..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
||||
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Controls.DocumentViewer" version="1.9.8" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstraction.Application" version="1.4.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstraction.Application" version="1.6.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
||||
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
||||
|
||||
@@ -72,8 +72,8 @@
|
||||
<Reference Include="DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||
<Reference Include="DevExpress.XtraGauges.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.XtraReports.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.6.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.6.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
||||
|
||||
@@ -422,7 +422,7 @@ Namespace Jobs
|
||||
End Function
|
||||
|
||||
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData
|
||||
Dim oSql = $"SELECT T.GUID, T.ENVELOPE_UUID,T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T
|
||||
Dim oSql = $"SELECT T.GUID, T.ENVELOPE_UUID, T.ENVELOPE_TYPE, T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T
|
||||
JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID
|
||||
WHERE T.GUID = {pEnvelopeId}"
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSql)
|
||||
|
||||
@@ -37,6 +37,15 @@ Namespace Jobs.FinalizeDocument
|
||||
Public Function BurnAnnotsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String), envelopeId As Integer) As Byte()
|
||||
'read the elements of envelope with their annotations
|
||||
Using scope = Factory.Shared.ScopeFactory.CreateScope()
|
||||
|
||||
Dim envRepo = scope.ServiceProvider.Repository(Of Envelope)()
|
||||
Dim envelope = envRepo.Where(Function(env) env.Id = envelopeId).FirstOrDefault()
|
||||
If envelope Is Nothing Then
|
||||
Throw New BurnAnnotationException($"Envelope with Id {envelopeId} not found.")
|
||||
ElseIf envelope.ReadOnly Then
|
||||
Return pSourceBuffer
|
||||
End If
|
||||
|
||||
Dim sigRepo = scope.ServiceProvider.Repository(Of Signature)()
|
||||
Dim elements = sigRepo _
|
||||
.Where(Function(sig) sig.Document.EnvelopeId = envelopeId) _
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
||||
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstraction.Application" version="1.4.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstraction.Application" version="1.6.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" />
|
||||
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
||||
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
||||
|
||||
15
EnvelopeGenerator.Domain/Constants/AuthPolicy.cs
Normal file
15
EnvelopeGenerator.Domain/Constants/AuthPolicy.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace EnvelopeGenerator.Domain.Constants
|
||||
{
|
||||
public static class AuthPolicy
|
||||
{
|
||||
public const string SenderOrReceiver = nameof(SenderOrReceiver) + nameof(AuthPolicy);
|
||||
|
||||
public const string ReceiverOrReceiverTFA = nameof(ReceiverOrReceiverTFA) + nameof(AuthPolicy);
|
||||
|
||||
public const string Sender = nameof(Sender) + nameof(AuthPolicy);
|
||||
|
||||
public const string Receiver = nameof(Receiver) + nameof(AuthPolicy);
|
||||
|
||||
public const string ReceiverTFA = nameof(ReceiverTFA) + nameof(AuthPolicy);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace EnvelopeGenerator.Domain.Constants
|
||||
{
|
||||
public static class ReceiverRole
|
||||
{
|
||||
public const string PreAuth = "PreAuth";
|
||||
public const string FullyAuth = "FullyAuth";
|
||||
}
|
||||
}
|
||||
23
EnvelopeGenerator.Domain/Constants/Role.cs
Normal file
23
EnvelopeGenerator.Domain/Constants/Role.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Constants
|
||||
{
|
||||
public static class Role
|
||||
{
|
||||
[Obsolete("Use Receiver.TFA")]
|
||||
public const string ReceiverTFA = Receiver.TFA;
|
||||
|
||||
[Obsolete("Use Receiver.Full")]
|
||||
public const string ReceiverFull = Receiver.Full;
|
||||
|
||||
public static class Receiver
|
||||
{
|
||||
public const string TFA = "EGReceiverTFA";
|
||||
public const string Full = "EGReceiver";
|
||||
}
|
||||
|
||||
public const string Sender = "EGSender";
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,22 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_CONFIG", Schema = "dbo")]
|
||||
public class Config
|
||||
{
|
||||
[Column("SENDING_PROFILE", TypeName = "int")]
|
||||
[Required]
|
||||
public int SendingProfile { get; set; }
|
||||
[Table("TBSIG_CONFIG", Schema = "dbo")]
|
||||
public class Config
|
||||
{
|
||||
[Column("SENDING_PROFILE", TypeName = "int")]
|
||||
[Required]
|
||||
public int SendingProfile { get; set; }
|
||||
|
||||
[Column("SIGNATURE_HOST", TypeName = "nvarchar(128)")]
|
||||
[Required]
|
||||
public string SignatureHost { get; set; }
|
||||
[Column("SIGNATURE_HOST", TypeName = "nvarchar(128)")]
|
||||
[Required]
|
||||
public string SignatureHost { get; set; }
|
||||
|
||||
[Column("EXTERNAL_PROGRAM_NAME", TypeName = "nvarchar(30)")]
|
||||
public string ExternalProgramName { get; set; }
|
||||
[Column("EXTERNAL_PROGRAM_NAME", TypeName = "nvarchar(30)")]
|
||||
public string ExternalProgramName { get; set; }
|
||||
|
||||
[Column("EXPORT_PATH", TypeName = "nvarchar(256)")]
|
||||
public string ExportPath { get; set; }
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[Column("EXPORT_PATH", TypeName = "nvarchar(256)")]
|
||||
public string ExportPath { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
using System;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
#if NETFRAMEWORK
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,81 +11,77 @@ using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")]
|
||||
public class Document : IHasEnvelope
|
||||
{
|
||||
public Document()
|
||||
[Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")]
|
||||
public class Document : IHasEnvelope, IHasAddedWhen
|
||||
{
|
||||
public Document()
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
Elements = Enumerable.Empty<Signature>().ToList();
|
||||
Elements = Enumerable.Empty<Signature>().ToList();
|
||||
#endif
|
||||
}
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ENVELOPE_ID")]
|
||||
public int EnvelopeId { get; set; }
|
||||
#if NETFRAMEWORK
|
||||
= 0;
|
||||
#endif
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
[Column("BYTE_DATA", TypeName = "varbinary(max)")]
|
||||
public byte[]
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
ByteData { get; set; }
|
||||
|
||||
#region File
|
||||
[Column("FILENAME", TypeName = "nvarchar(256)")]
|
||||
public string Filename { get; set; }
|
||||
|
||||
[Column("FILEPATH", TypeName = "nvarchar(256)")]
|
||||
public string Filepath { get; set; }
|
||||
|
||||
[Column("FILENAME_ORIGINAL", TypeName = "nvarchar(256)")]
|
||||
public string
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
FileNameOriginal { get; set; }
|
||||
#endregion
|
||||
|
||||
public virtual List<Signature>
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Elements { get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public virtual Envelope
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Envelope { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public bool IsTempFile { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public Bitmap Thumbnail { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public int PageCount { get; set; }
|
||||
#endif
|
||||
}
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ENVELOPE_ID")]
|
||||
public int EnvelopeId { get; set; }
|
||||
#if NETFRAMEWORK
|
||||
= 0;
|
||||
#endif
|
||||
|
||||
[Column("BYTE_DATA", TypeName = "varbinary(max)")]
|
||||
public byte[]
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
ByteData { get; set; }
|
||||
|
||||
#region File
|
||||
[Column("FILENAME", TypeName = "nvarchar(256)")]
|
||||
public string Filename { get; set; }
|
||||
|
||||
[Column("FILEPATH", TypeName = "nvarchar(256)")]
|
||||
public string Filepath { get; set; }
|
||||
|
||||
[Column("FILENAME_ORIGINAL", TypeName = "nvarchar(256)")]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
FileNameOriginal { get; set; }
|
||||
#endregion
|
||||
|
||||
public virtual List<Signature>
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Elements { get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public virtual Envelope
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Envelope { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public bool IsTempFile { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public Bitmap Thumbnail { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public int PageCount { get; set; }
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,65 +1,62 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using DigitalData.Core.Abstractions.Interfaces;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
#endif
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")]
|
||||
public class DocumentStatus : IHasEnvelope, IHasReceiver, IEntity
|
||||
{
|
||||
public DocumentStatus()
|
||||
[Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")]
|
||||
public class DocumentStatus : IHasEnvelope, IHasReceiver, IEntity, IHasAddedWhen, IHasChangedWhen
|
||||
{
|
||||
// TODO: * check Form Application and remove default value
|
||||
public DocumentStatus()
|
||||
{
|
||||
// TODO: * check Form Application and remove default value
|
||||
#if NETFRAMEWORK
|
||||
Status = Constants.DocumentStatus.Created;
|
||||
Status = Constants.DocumentStatus.Created;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ENVELOPE_ID")]
|
||||
public int EnvelopeId { get; set; }
|
||||
[Required]
|
||||
[Column("ENVELOPE_ID")]
|
||||
public int EnvelopeId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("RECEIVER_ID")]
|
||||
public int ReceiverId { get; set; }
|
||||
[Required]
|
||||
[Column("RECEIVER_ID")]
|
||||
public int ReceiverId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("STATUS")]
|
||||
public Constants.DocumentStatus Status { get; set; }
|
||||
[Required]
|
||||
[Column("STATUS")]
|
||||
public Constants.DocumentStatus Status { get; set; }
|
||||
|
||||
[Column("VALUE", TypeName = "nvarchar(max)")]
|
||||
public string Value { get; set; }
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public virtual Envelope
|
||||
#if NET
|
||||
?
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[Column("VALUE", TypeName = "nvarchar(max)")]
|
||||
public string Value { get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public virtual Envelope
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Envelope { get; set; }
|
||||
Envelope { get; set; }
|
||||
|
||||
[ForeignKey("ReceiverId")]
|
||||
public virtual Receiver
|
||||
#if NET
|
||||
?
|
||||
[ForeignKey("ReceiverId")]
|
||||
public virtual Receiver
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Receiver { get; set; }
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,92 +1,85 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION")]
|
||||
public class ElementAnnotation
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
[Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION")]
|
||||
public class ElementAnnotation : IHasAddedWhen, IUpdateAuditable
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ELEMENT_ID", TypeName = "int")]
|
||||
public int ElementId { get; set; }
|
||||
[Required]
|
||||
[Column("ELEMENT_ID", TypeName = "int")]
|
||||
public int ElementId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("NAME", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string Name { get; set; }
|
||||
[Required]
|
||||
[Column("NAME", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("VALUE", TypeName = "nvarchar(max)")]
|
||||
public string Value { get; set; }
|
||||
[Required]
|
||||
[Column("VALUE", TypeName = "nvarchar(max)")]
|
||||
public string Value { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("TYPE", TypeName = "nvarchar(50)")]
|
||||
public string Type { get; set; }
|
||||
[Required]
|
||||
[Column("TYPE", TypeName = "nvarchar(50)")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[Column("POSITION_X", TypeName = "float")]
|
||||
public double
|
||||
#if NET
|
||||
?
|
||||
[Column("POSITION_X", TypeName = "float")]
|
||||
public double
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
X { get; set; }
|
||||
X { get; set; }
|
||||
|
||||
[Column("POSITION_Y", TypeName = "float")]
|
||||
public double
|
||||
#if NET
|
||||
?
|
||||
[Column("POSITION_Y", TypeName = "float")]
|
||||
public double
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Y { get; set; }
|
||||
Y { get; set; }
|
||||
|
||||
[Column("WIDTH", TypeName = "float")]
|
||||
public double
|
||||
#if NET
|
||||
?
|
||||
[Column("WIDTH", TypeName = "float")]
|
||||
public double
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Width { get; set; }
|
||||
Width { get; set; }
|
||||
|
||||
[Column("HEIGHT", TypeName = "float")]
|
||||
public double
|
||||
#if NET
|
||||
?
|
||||
[Column("HEIGHT", TypeName = "float")]
|
||||
public double
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Height { get; set; }
|
||||
Height { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||
[StringLength(100)]
|
||||
public string
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
ChangedWho { get; set; }
|
||||
ChangedWho { get; set; }
|
||||
|
||||
[ForeignKey("ElementId")]
|
||||
public virtual Signature
|
||||
#if NET
|
||||
?
|
||||
[ForeignKey("ElementId")]
|
||||
public virtual Signature
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Element { get; set; }
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
Element { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2,43 +2,40 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_EMAIL_TEMPLATE", Schema = "dbo")]
|
||||
public class EmailTemplate : IEntity
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
[Table("TBSIG_EMAIL_TEMPLATE", Schema = "dbo")]
|
||||
public class EmailTemplate : IEntity, IHasAddedWhen, IHasChangedWhen
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("NAME", TypeName = "nvarchar(64)")]
|
||||
public string Name { get; set; }
|
||||
[Column("NAME", TypeName = "nvarchar(64)")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("BODY", TypeName = "nvarchar(max)")]
|
||||
public string Body { get; set; }
|
||||
[Column("BODY", TypeName = "nvarchar(max)")]
|
||||
public string Body { get; set; }
|
||||
|
||||
[Column("SUBJECT", TypeName = "nvarchar(512)")]
|
||||
public string Subject { get; set; }
|
||||
[Column("SUBJECT", TypeName = "nvarchar(512)")]
|
||||
public string Subject { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
[DefaultValue("GETDATE()")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
[Required]
|
||||
[Column("LANG_CODE", TypeName = "varchar(5)")]
|
||||
public string LangCode { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime ChangedWhen { get; set; }
|
||||
}
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
[DefaultValue("GETDATE()")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,203 +1,205 @@
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using System;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
#if NET
|
||||
;
|
||||
#elif NETFRAMEWORK
|
||||
{
|
||||
#endif
|
||||
|
||||
[Table("TBSIG_ENVELOPE", Schema = "dbo")]
|
||||
public class Envelope
|
||||
{
|
||||
public Envelope()
|
||||
[Table("TBSIG_ENVELOPE", Schema = "dbo")]
|
||||
public class Envelope : IHasAddedWhen, IHasChangedWhen
|
||||
{
|
||||
// TODO: * Check the Form App and remove the default value
|
||||
public Envelope()
|
||||
{
|
||||
// TODO: * Check the Form App and remove the default value
|
||||
#if NETFRAMEWORK
|
||||
Id = 0;
|
||||
Status = EnvelopeStatus.EnvelopeCreated;
|
||||
Uuid = Guid.NewGuid().ToString();
|
||||
Message = My.Resources.Envelope.Please_read_and_sign_this_document;
|
||||
Title= string.Empty;
|
||||
Comment = string.Empty;
|
||||
Language = "de-DE";
|
||||
SendReminderEmails = false;
|
||||
FirstReminderDays = 0;
|
||||
ReminderIntervalDays = 0;
|
||||
CertificationType = (int)Constants.CertificationType.AdvancedElectronicSignature;
|
||||
UseAccessCode = false;
|
||||
Documents = Enumerable.Empty<Document>().ToList();
|
||||
Histories = Enumerable.Empty<History>().ToList();
|
||||
EnvelopeReceivers = Enumerable.Empty<EnvelopeReceiver>().ToList();
|
||||
Id = 0;
|
||||
Status = EnvelopeStatus.EnvelopeCreated;
|
||||
Uuid = Guid.NewGuid().ToString();
|
||||
Message = My.Resources.Envelope.Please_read_and_sign_this_document;
|
||||
Title = string.Empty;
|
||||
Comment = string.Empty;
|
||||
Language = "de-DE";
|
||||
SendReminderEmails = false;
|
||||
FirstReminderDays = 0;
|
||||
ReminderIntervalDays = 0;
|
||||
CertificationType = (int)Constants.CertificationType.AdvancedElectronicSignature;
|
||||
UseAccessCode = false;
|
||||
Documents = Enumerable.Empty<Document>().ToList();
|
||||
Histories = Enumerable.Empty<History>().ToList();
|
||||
EnvelopeReceivers = Enumerable.Empty<EnvelopeReceiver>().ToList();
|
||||
#endif
|
||||
}
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("USER_ID")]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("STATUS")]
|
||||
public EnvelopeStatus Status { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ENVELOPE_UUID", TypeName = "nvarchar(36)")]
|
||||
public string Uuid { get; set; }
|
||||
|
||||
[Column("MESSAGE", TypeName = "nvarchar(max)")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[Column("EXPIRES_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ExpiresWhen { get; set; }
|
||||
|
||||
[Column("EXPIRES_WARNING_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ExpiresWarningWhen { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[Column("TITLE", TypeName = "nvarchar(128)")]
|
||||
public string
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Title
|
||||
{ get; set; }
|
||||
|
||||
[Column("COMMENT", TypeName = "nvarchar(128)")]
|
||||
public string Comment { get; set; }
|
||||
|
||||
[Column("CONTRACT_TYPE")]
|
||||
public int? ContractType { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public string ContractTypeTranslated => My.Resources.Model.ResourceManager.GetString(ContractType.ToString());
|
||||
#endif
|
||||
|
||||
[Column("LANGUAGE", TypeName = "nvarchar(5)")]
|
||||
public string Language { get; set; }
|
||||
|
||||
[Column("SEND_REMINDER_EMAILS")]
|
||||
public bool SendReminderEmails { get; set; }
|
||||
|
||||
[Column("FIRST_REMINDER_DAYS")]
|
||||
public int? FirstReminderDays { get; set; }
|
||||
|
||||
[Column("REMINDER_INTERVAL_DAYS")]
|
||||
public int? ReminderIntervalDays { get; set; }
|
||||
|
||||
[Column("ENVELOPE_TYPE")]
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[NotMapped]
|
||||
public bool ReadOnly => EnvelopeTypeId == 2;
|
||||
|
||||
[Column("CERTIFICATION_TYPE")]
|
||||
public int? CertificationType { get; set; }
|
||||
|
||||
[Column("USE_ACCESS_CODE")]
|
||||
public bool UseAccessCode { get; set; }
|
||||
|
||||
[Column("FINAL_EMAIL_TO_CREATOR")]
|
||||
public int? FinalEmailToCreator { get; set; }
|
||||
|
||||
[Column("FINAL_EMAIL_TO_RECEIVERS")]
|
||||
public int? FinalEmailToReceivers { get; set; }
|
||||
|
||||
[Column("EXPIRES_WHEN_DAYS")]
|
||||
public int? ExpiresWhenDays { get; set; }
|
||||
|
||||
[Column("EXPIRES_WARNING_WHEN_DAYS")]
|
||||
public int? ExpiresWarningWhenDays { get; set; }
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public User User { get; set; }
|
||||
|
||||
[Column("TFA_ENABLED")]
|
||||
public bool TfaEnabled { get; set; }
|
||||
#if NETFRAMEWORK
|
||||
= false;
|
||||
#endif
|
||||
|
||||
[NotMapped]
|
||||
[Column("DOC_RESULT")]
|
||||
public byte[]
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
DocResult
|
||||
{ get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeTypeId")]
|
||||
public virtual EnvelopeType
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Type
|
||||
{ get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public string CURRENT_WORK_APP { get; set; } = "signFLOW GUI";
|
||||
|
||||
[NotMapped]
|
||||
public bool IsAlreadySent => Status > EnvelopeStatus.EnvelopeSaved;
|
||||
#endif
|
||||
|
||||
public List<Document>
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Documents
|
||||
{ get; set; }
|
||||
|
||||
public List<History>
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
Histories
|
||||
{ get; set; }
|
||||
|
||||
public List<EnvelopeReceiver>
|
||||
#if nullable
|
||||
?
|
||||
#endif
|
||||
EnvelopeReceivers
|
||||
{ get; set; }
|
||||
|
||||
//#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Validates whether the receiver and document data are complete.
|
||||
/// </summary>
|
||||
public List<string> ValidateReceiverDocumentData()
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
if (!Documents?.Any() ?? true)
|
||||
errors.Add(My.Resources.Envelope.Missing_Documents);
|
||||
|
||||
if (!EnvelopeReceivers?.Any() ?? true)
|
||||
errors.Add(My.Resources.Envelope.Missing_Receivers);
|
||||
|
||||
if (EnvelopeReceivers?.Any(r => !r.HasEmailAndName) ?? false)
|
||||
errors.Add(My.Resources.Envelope.Incomplete_Receivers);
|
||||
|
||||
return errors;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("USER_ID")]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("STATUS")]
|
||||
public EnvelopeStatus Status { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ENVELOPE_UUID", TypeName = "nvarchar(36)")]
|
||||
public string Uuid { get; set; }
|
||||
|
||||
[Column("MESSAGE", TypeName = "nvarchar(max)")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[Column("EXPIRES_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ExpiresWhen { get; set; }
|
||||
|
||||
[Column("EXPIRES_WARNING_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ExpiresWarningWhen { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
public DateTime AddedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[Column("TITLE", TypeName = "nvarchar(128)")]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Title { get; set; }
|
||||
|
||||
[Column("COMMENT", TypeName = "nvarchar(128)")]
|
||||
public string Comment { get; set; }
|
||||
|
||||
[Column("CONTRACT_TYPE")]
|
||||
public int? ContractType { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public string ContractTypeTranslated => My.Resources.Model.ResourceManager.GetString(ContractType.ToString());
|
||||
#endif
|
||||
|
||||
[Column("LANGUAGE", TypeName = "nvarchar(5)")]
|
||||
public string Language { get; set; }
|
||||
|
||||
[Column("SEND_REMINDER_EMAILS")]
|
||||
public bool SendReminderEmails { get; set; }
|
||||
|
||||
[Column("FIRST_REMINDER_DAYS")]
|
||||
public int? FirstReminderDays { get; set; }
|
||||
|
||||
[Column("REMINDER_INTERVAL_DAYS")]
|
||||
public int? ReminderIntervalDays { get; set; }
|
||||
|
||||
[Column("ENVELOPE_TYPE")]
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
[Column("CERTIFICATION_TYPE")]
|
||||
public int? CertificationType { get; set; }
|
||||
|
||||
[Column("USE_ACCESS_CODE")]
|
||||
public bool UseAccessCode { get; set; }
|
||||
|
||||
[Column("FINAL_EMAIL_TO_CREATOR")]
|
||||
public int? FinalEmailToCreator { get; set; }
|
||||
|
||||
[Column("FINAL_EMAIL_TO_RECEIVERS")]
|
||||
public int? FinalEmailToReceivers { get; set; }
|
||||
|
||||
[Column("EXPIRES_WHEN_DAYS")]
|
||||
public int? ExpiresWhenDays { get; set; }
|
||||
|
||||
[Column("EXPIRES_WARNING_WHEN_DAYS")]
|
||||
public int? ExpiresWarningWhenDays { get; set; }
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public User User { get; set; }
|
||||
|
||||
[Column("TFA_ENABLED")]
|
||||
public bool TfaEnabled { get; set; }
|
||||
#if NETFRAMEWORK
|
||||
= false;
|
||||
#endif
|
||||
|
||||
[NotMapped]
|
||||
[Column("DOC_RESULT")]
|
||||
public byte[]
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
DocResult
|
||||
{ get; set; }
|
||||
|
||||
[ForeignKey("EnvelopeTypeId")]
|
||||
public virtual EnvelopeType
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Type { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
public string CURRENT_WORK_APP { get; set; } = "signFLOW GUI";
|
||||
|
||||
[NotMapped]
|
||||
public bool IsAlreadySent => Status > EnvelopeStatus.EnvelopeSaved;
|
||||
#endif
|
||||
|
||||
public List<Document>
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Documents { get; set; }
|
||||
|
||||
public List<History>
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Histories { get; set; }
|
||||
|
||||
public List<EnvelopeReceiver>
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
EnvelopeReceivers { get; set; }
|
||||
|
||||
//#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Validates whether the receiver and document data are complete.
|
||||
/// </summary>
|
||||
public List<string> ValidateReceiverDocumentData()
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
if (!Documents?.Any() ?? true)
|
||||
errors.Add(My.Resources.Envelope.Missing_Documents);
|
||||
|
||||
if (!EnvelopeReceivers?.Any() ?? true)
|
||||
errors.Add(My.Resources.Envelope.Missing_Receivers);
|
||||
|
||||
if (EnvelopeReceivers?.Any(r => !r.HasEmailAndName) ?? false)
|
||||
errors.Add(My.Resources.Envelope.Incomplete_Receivers);
|
||||
|
||||
return errors;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user