using AutoMapper; using DigitalData.Core.Abstraction.Application.DTO; using EnvelopeGenerator.Application.Interfaces.Services; using EnvelopeGenerator.Application.Interfaces.SQLExecutor; using EnvelopeGenerator.Application.Dto.Receiver; using EnvelopeGenerator.Application.EnvelopeReceivers.Commands; using EnvelopeGenerator.Application.EnvelopeReceivers.Queries; using EnvelopeGenerator.Application.Envelopes.Queries; using EnvelopeGenerator.Application.SQL; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.GeneratorAPI.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; namespace EnvelopeGenerator.GeneratorAPI.Controllers; /// /// Controller für die Verwaltung von Umschlagempfängern. /// /// /// Dieser Controller bietet Endpunkte für das Abrufen und Verwalten von Umschlagempfängerdaten. /// [Route("api/[controller]")] [Authorize] [ApiController] public class EnvelopeReceiverController : ControllerBase { private readonly ILogger _logger; [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; /// /// Konstruktor für den EnvelopeReceiverController. /// /// Logger-Instanz zur Protokollierung von Informationen und Fehlern. /// Service zur Verwaltung von Umschlagempfängern. /// Mediator-Instanz zur Verarbeitung von Befehlen und Abfragen. /// /// /// /// /// [Obsolete("Use MediatR")] public EnvelopeReceiverController(ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor, IDocumentExecutor documentExecutor, IOptions csOpt) { _logger = logger; _erService = envelopeReceiverService; _mediator = mediator; _mapper = mapper; _envelopeExecutor = envelopeExecutor; _erExecutor = erExecutor; _documentExecutor = documentExecutor; _cnnStr = csOpt.Value.Value; } /// /// Ruft eine Liste von Umschlagempfängern basierend auf den angegebenen Abfrageparametern ab. /// /// Die Abfrageparameter für die Filterung von Umschlagempfängern. /// Eine HTTP-Antwort mit der Liste der gefundenen Umschlagempfänger oder einem Fehlerstatus. /// /// Dieser Endpunkt ermöglicht es, Umschlagempfänger basierend auf dem Benutzernamen und optionalen Statusfiltern abzurufen. /// Wenn der Benutzername nicht ermittelt werden kann, wird ein Serverfehler zurückgegeben. /// /// Die Liste der Umschlagempfänger wurde erfolgreich abgerufen. /// Wenn kein autorisierter Token vorhanden ist /// Ein unerwarteter Fehler ist aufgetreten. [Authorize] [HttpGet] [Obsolete("Use MediatR")] public async Task GetEnvelopeReceiver([FromQuery] ReadEnvelopeReceiverQuery envelopeReceiver) { var username = User.GetUsernameOrDefault(); 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); } 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()) .ThenAsync( Success: Ok, Fail: IActionResult (msg, ntc) => { _logger.LogNotice(ntc); return StatusCode(StatusCodes.Status500InternalServerError, msg); }); } /// /// Ruft den Namen des zuletzt verwendeten Empfängers basierend auf der angegebenen E-Mail-Adresse ab. /// /// Abfrage, bei der nur eine der Angaben ID, Signatur oder E-Mail-Adresse des Empfängers eingegeben werden muss. /// Eine HTTP-Antwort mit dem Namen des Empfängers oder einem Fehlerstatus. /// /// Dieser Endpunkt ermöglicht es, den Namen des zuletzt verwendeten Empfängers basierend auf der E-Mail-Adresse abzurufen. /// /// Der Name des Empfängers wurde erfolgreich abgerufen. /// Wenn kein autorisierter Token vorhanden ist /// Kein Empfänger gefunden. /// Ein unerwarteter Fehler ist aufgetreten. [Authorize] [HttpGet("salute")] [Obsolete("Use MediatR")] public async Task 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); }); } /// /// Datenübertragungsobjekt mit Informationen zu Umschlägen, Empfängern und Unterschriften. /// /// /// HTTP-Antwort /// /// Sample request: /// /// POST /api/envelope /// { /// "title": "Vertragsdokument", /// "message": "Bitte unterschreiben Sie dieses Dokument.", /// "document": { /// "dataAsBase64": "dGVzdC1iYXNlNjQtZGF0YQ==" /// }, /// "receivers": [ /// { /// "emailAddress": "example@example.com", /// "signatures": [ /// { /// "x": 100, /// "y": 200, /// "page": 1 /// } /// ], /// "name": "Max Mustermann", /// "phoneNumber": "+49123456789" /// } /// ], /// "tfaEnabled": false /// } /// /// /// Envelope-Erstellung und Sendeprozessbefehl erfolgreich /// Wenn ein Fehler im HTTP-Body auftritt /// Wenn kein autorisierter Token vorhanden ist /// Es handelt sich um einen unerwarteten Fehler. Die Protokolle sollten überprüft werden. [Authorize] [HttpPost] public async Task CreateAsync([FromBody] CreateEnvelopeReceiverCommand request) { CancellationToken cancel = default; int userId = User.GetId(); #region Create Envelope var envelope = await _envelopeExecutor.CreateEnvelopeAsync(userId, request.Title, request.Message, request.TFAEnabled, cancel); #endregion #region Add receivers List sentReceivers = new(); List unsentReceivers = new(); foreach (var receiver in request.Receivers) { var envelopeReceiver = await _erExecutor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel); if (envelopeReceiver is null) unsentReceivers.Add(receiver); else sentReceivers.Add(envelopeReceiver); } var res = _mapper.Map(envelope); res.UnsentReceivers = unsentReceivers; res.SentReceiver = _mapper.Map>(sentReceivers.Select(er => er.Receiver)); #endregion #region Add document var document = await _documentExecutor.CreateDocumentAsync(request.Document.DataAsBase64, envelope.Uuid, cancel); if (document is null) return StatusCode(StatusCodes.Status500InternalServerError, "Document creation is failed."); #endregion #region Add document element // @DOC_ID, @RECEIVER_ID, @POSITION_X, @POSITION_Y, @PAGE string sql = @" DECLARE @OUT_SUCCESS bit; EXEC [dbo].[PRSIG_API_ADD_DOC_RECEIVER_ELEM] {0}, {1}, {2}, {3}, {4}, @OUT_SUCCESS OUTPUT; SELECT @OUT_SUCCESS as [@OUT_SUCCESS];"; foreach (var rcv in res.SentReceiver) foreach (var sign in request.Receivers.Where(r => r.EmailAddress == rcv.EmailAddress).FirstOrDefault()?.Signatures ?? Array.Empty()) { using (SqlConnection conn = new(_cnnStr)) { conn.Open(); var formattedSQL = string.Format(sql, document.Id.ToSqlParam(), rcv.Id.ToSqlParam(), sign.X.ToSqlParam(), sign.Y.ToSqlParam(), sign.Page.ToSqlParam()); using SqlCommand cmd = new SqlCommand(formattedSQL, conn); cmd.CommandType = CommandType.Text; using SqlDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { bool outSuccess = reader.GetBoolean(0); } } } #endregion #region Create history // ENV_UID, STATUS_ID, USER_ID, string sql_hist = @" USE [DD_ECM] DECLARE @OUT_SUCCESS bit; EXEC [dbo].[PRSIG_API_ADD_HISTORY_STATE] {0}, {1}, {2}, @OUT_SUCCESS OUTPUT; SELECT @OUT_SUCCESS as [@OUT_SUCCESS];"; using (SqlConnection conn = new(_cnnStr)) { conn.Open(); var formattedSQL_hist = string.Format(sql_hist, envelope.Uuid.ToSqlParam(), 1003.ToSqlParam(), userId.ToSqlParam()); using (SqlCommand cmd = new SqlCommand(formattedSQL_hist, conn)) { cmd.CommandType = CommandType.Text; using (SqlDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) { bool outSuccess = reader.GetBoolean(0); } } } } #endregion return Ok(res); } /// /// /// /// /// public static bool IsBase64String(string input) { if (string.IsNullOrWhiteSpace(input)) return false; try { Convert.FromBase64String(input); return true; } catch (FormatException) { return false; } } }