Compare commits
5 Commits
701b26289b
...
261d1b3db9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
261d1b3db9 | ||
|
|
401d03aac2 | ||
|
|
7871bf72f6 | ||
|
|
7e07afa384 | ||
|
|
251420134a |
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
@@ -17,6 +17,7 @@
|
||||
<PackageReference Include="DigitalData.Core.Client" Version="2.0.3" />
|
||||
<PackageReference Include="DigitalData.Core.DTO" Version="2.0.0" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
||||
<PackageReference Include="MediatR" Version="11.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
||||
<PackageReference Include="Otp.NET" Version="1.4.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.6.0" />
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using MediatR;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
|
||||
|
||||
#region DTOs
|
||||
/// <summary>
|
||||
/// Signaturposition auf einem Dokument.
|
||||
/// </summary>
|
||||
/// <param name="X">X-Position</param>
|
||||
/// <param name="Y">Y-Position</param>
|
||||
/// <param name="Page">Seite, auf der sie sich befindet</param>
|
||||
public record Signature([Required] int X, [Required] int Y, [Required] int Page);
|
||||
|
||||
/// <summary>
|
||||
/// DTO für Empfänger, die erstellt oder abgerufen werden sollen.
|
||||
/// Wenn nicht, wird sie erstellt und mit einer Signatur versehen.
|
||||
/// </summary>
|
||||
/// <param name="Signatures">Unterschriften auf Dokumenten.</param>
|
||||
/// <param name="Name">Der Name, mit dem der Käufer angesprochen werden soll. Bei Null oder keinem Wert wird der zuletzt verwendete Name verwendet.</param>
|
||||
/// <param name="PhoneNumber">Sollte mit Vorwahl geschrieben werden</param>
|
||||
public record ReceiverGetOrCreateDto([Required] IEnumerable<Signature> Signatures, string? Name = null, string? PhoneNumber = null)
|
||||
{
|
||||
private string _emailAddress;
|
||||
|
||||
/// <summary>
|
||||
/// E-Mail-Adresse des Empfängers.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public required string EmailAddress { get => _emailAddress.ToLower(); init => _emailAddress.ToLower(); }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// DTO für die Erstellung eines Dokuments.
|
||||
/// </summary>
|
||||
public record DocumentCreateDto(byte[]? DataAsByte = null, string? DataAsBase64 = null);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Befehl zur Erstellung eines Umschlags.
|
||||
/// </summary>
|
||||
public record CreateEnvelopeCommand(
|
||||
[Required] string Title,
|
||||
[Required] string Message,
|
||||
[Required] DocumentCreateDto Document,
|
||||
[Required] IEnumerable<ReceiverGetOrCreateDto> Receivers,
|
||||
string Language = "de-DE",
|
||||
DateTime? ExpiresWhen = null,
|
||||
DateTime? ExpiresWarningWhen = null,
|
||||
int ContractType = (int)Common.Constants.ContractType.Contract,
|
||||
bool TFAEnabled = false
|
||||
) : IRequest;
|
||||
|
||||
/// <summary>
|
||||
/// Handler für den CreateEnvelopeCommand.
|
||||
/// </summary>
|
||||
public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeCommand>
|
||||
{
|
||||
public Task<Unit> Handle(CreateEnvelopeCommand request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -41,12 +41,22 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
/// <param name="login">Benutzeranmeldedaten (Benutzername und Passwort).</param>
|
||||
/// <param name="cookie">Wenn wahr, wird das JWT-Token auch als HTTP-Only-Cookie gesendet.</param>
|
||||
/// <returns>
|
||||
/// Gibt eine HTTP 200 OK-Antwort mit dem JWT-Token im Antwortkörper oder als HTTP-Only-Cookie zurück, wenn 'cookie' wahr ist.
|
||||
/// Gibt eine HTTP 200 oder 401.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// POST /api/auth?cookie=true
|
||||
/// {
|
||||
/// "username": "MaxMustermann",
|
||||
/// "password": "Geheim123!"
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <response code="200">Erfolgreiche Anmeldung. Gibt das JWT-Token im Antwortkörper oder als Cookie zurück, wenn 'cookie' wahr ist.</response>
|
||||
/// <response code="401">Unbefugt. Ungültiger Benutzername oder Passwort.</response>
|
||||
[ProducesResponseType(typeof(string), StatusCodes.Status200OK, "text/javascript")]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Login([FromBody] Login login, [FromQuery] bool cookie = false)
|
||||
@@ -112,12 +122,22 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
/// </summary>
|
||||
/// <param name="login">Benutzeranmeldedaten (Benutzername und Passwort).</param>
|
||||
/// <returns>
|
||||
/// Gibt eine HTTP 200 OK-Antwort als HTTP-Only-Cookie zurück.
|
||||
/// Gibt eine HTTP 200 oder 401.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// POST /api/auth/form
|
||||
/// {
|
||||
/// "username": "MaxMustermann",
|
||||
/// "password": "Geheim123!"
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <response code="200">Erfolgreiche Anmeldung. Gibt das JWT-Token im Antwortkörper oder als Cookie zurück, wenn 'cookie' wahr ist.</response>
|
||||
/// <response code="401">Unbefugt. Ungültiger Benutzername oder Passwort.</response>
|
||||
[ProducesResponseType(typeof(string), StatusCodes.Status200OK, "text/javascript")]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
[Route("form")]
|
||||
@@ -126,6 +146,22 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
return await Login(login, true);
|
||||
}
|
||||
|
||||
/// <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(string), StatusCodes.Status200OK, "text/javascript")]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[Authorize]
|
||||
[HttpPost("logout")]
|
||||
public async Task<IActionResult> Logout()
|
||||
@@ -142,8 +178,22 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
/// <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(string), StatusCodes.Status200OK, "text/javascript")]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public IActionResult IsAuthenticated() => Ok(User.Identity?.IsAuthenticated ?? false);
|
||||
public IActionResult IsAuthenticated() => Ok();
|
||||
}
|
||||
}
|
||||
@@ -3,50 +3,49 @@ using EnvelopeGenerator.Application.Contracts.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class EnvelopeController : ControllerBase
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class EnvelopeController : ControllerBase
|
||||
private readonly ILogger<EnvelopeController> _logger;
|
||||
private readonly IEnvelopeService _envelopeService;
|
||||
|
||||
public EnvelopeController(ILogger<EnvelopeController> logger, IEnvelopeService envelopeService)
|
||||
{
|
||||
private readonly ILogger<EnvelopeController> _logger;
|
||||
private readonly IEnvelopeService _envelopeService;
|
||||
_logger = logger;
|
||||
_envelopeService = envelopeService;
|
||||
}
|
||||
|
||||
public EnvelopeController(ILogger<EnvelopeController> logger, IEnvelopeService envelopeService)
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAsync(
|
||||
[FromQuery] int? min_status = null,
|
||||
[FromQuery] int? max_status = null,
|
||||
[FromQuery] params int[] ignore_statuses)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger = logger;
|
||||
_envelopeService = envelopeService;
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetCurrentAsync(
|
||||
[FromQuery] int? min_status = null,
|
||||
[FromQuery] int? max_status = null,
|
||||
[FromQuery] params int[] ignore_statuses)
|
||||
{
|
||||
try
|
||||
if (User.GetId() is int intId)
|
||||
return await _envelopeService.ReadByUserAsync(intId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
else
|
||||
{
|
||||
if (User.GetId() is int intId)
|
||||
return await _envelopeService.ReadByUserAsync(intId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
else
|
||||
{
|
||||
_logger.LogError("Despite successful authorization, the 'api/envelope' route encountered an issue: the user ID is not recognized as an integer. This may be due to the removal of the ID during the creation of the claims list.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
_logger.LogError("Despite successful authorization, the 'api/envelope' route encountered an issue: the user ID is not recognized as an integer. This may be due to the removal of the ID during the creation of the claims list.");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts.Services;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
|
||||
using EnvelopeGenerator.Common.My.Resources;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -12,12 +14,16 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
public class EnvelopeReceiverController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<EnvelopeReceiverController> _logger;
|
||||
|
||||
private readonly IEnvelopeReceiverService _erService;
|
||||
|
||||
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IEnvelopeReceiverService envelopeReceiverService)
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IEnvelopeReceiverService envelopeReceiverService, IMediator mediator)
|
||||
{
|
||||
_logger = logger;
|
||||
_erService = envelopeReceiverService;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -94,5 +100,55 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Datenübertragungsobjekt mit Informationen zu Umschlägen, Empfängern und Unterschriften.
|
||||
/// </summary>
|
||||
/// <param name="envelope"></param>
|
||||
/// <param name="cancellationToken">Token to cancel the operation</param>
|
||||
/// <returns>HTTP-Antwort</returns>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// POST /api/envelope
|
||||
/// {
|
||||
/// "title": "Vertragsdokument",
|
||||
/// "message": "Bitte unterschreiben Sie dieses Dokument.",
|
||||
/// "document": {
|
||||
/// "dataAsBase64": "dGVzdC1iYXNlNjQtZGF0YQ=="
|
||||
/// },
|
||||
/// "receivers": [
|
||||
/// {
|
||||
/// "emailAddress": "example@example.com",
|
||||
/// "signatures": [
|
||||
/// {
|
||||
/// "x": 100,
|
||||
/// "y": 200,
|
||||
/// "page": 1
|
||||
/// }
|
||||
/// ],
|
||||
/// "name": "Max Mustermann",
|
||||
/// "phoneNumber": "+49123456789"
|
||||
/// }
|
||||
/// ],
|
||||
/// "language": "de-DE",
|
||||
/// "expiresWhen": "2025-12-31T23:59:59Z",
|
||||
/// "expiresWarningWhen": "2025-12-24T23:59:59Z",
|
||||
/// "contractType": 1,
|
||||
/// "tfaEnabled": false
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <response code="202">Envelope-Erstellung und Sendeprozessbefehl erfolgreich</response>
|
||||
/// <response code="400">Wenn ein Fehler im HTTP-Body auftritt</response>
|
||||
/// <response code="401">Wenn kein autorisierter Token vorhanden ist</response>
|
||||
/// <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] CreateEnvelopeCommand envelope, CancellationToken cancellationToken)
|
||||
{
|
||||
await _mediator.Send(envelope, cancellationToken);
|
||||
return Accepted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user