Compare commits

3 Commits

Author SHA1 Message Date
OlgunR
c9cb3f6aa8 Refactor: Properties in der react app geändert. 2025-07-28 10:29:05 +02:00
OlgunR
4b3c5907ae feat: update application name and user references to "Umschläge"
- Changed application name from "Minimal UI" to "SignFlow" in config-global.ts
- Updated navigation titles and paths from "User" to "Umschläge" in nav-config-dashboard.tsx
- Modified page title in user.tsx to reflect "Umschläge"
- Changed placeholder text in user-table-toolbar.tsx from "Search user..." to "Nach Umschlag suchen..."
- Updated headings and button labels in user-view.tsx to use "Umschläge" and "Neuer Umschlag"
- Commented out NavUpgrade component in nav.tsx
- Removed unused product and blog navigation items in nav-config-dashboard.tsx
- Added envelope-service.ts to handle envelope data with a basic structure
- Updated yarn.lock with dependency version changes
2025-07-24 09:53:48 +02:00
cce240125d feat(envelope-generator-react-ui): init 2025-07-21 15:13:16 +02:00
607 changed files with 26091 additions and 6401 deletions

View File

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

View File

@@ -1,182 +0,0 @@
using EnvelopeGenerator.Domain.Constants;
using System.Text;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///
/// </summary>
public static class DecodingExtensions
{
/// <summary>
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
/// </summary>
/// <remarks>
/// This method checks the string for proper Base-64 formatting, which includes validating
/// the length of the string (must be divisible by 4). It also checks each character to ensure
/// it belongs to the Base-64 character set (A-Z, a-z, 0-9, '+', '/', and '=' for padding).
/// The method ensures that padding characters ('=') only appear at the end of the string and
/// are in a valid configuration (either one '=' at the end if the string's length % 4 is 3,
/// or two '==' if the length % 4 is 2).
/// </remarks>
/// <param name="input">The Base-64 encoded string to validate.</param>
/// <returns>
/// <c>true</c> if the string is a valid Base-64 encoded string; otherwise, <c>false</c>.
/// </returns>
/// <example>
/// <code>
/// string testString = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk=";
/// bool isValid = IsValidBase64String(testString);
/// Console.WriteLine(isValid); // Output: true
/// </code>
/// </example>
public static bool IsBase64String(this string input)
{
// Check if the string is null or empty
if (string.IsNullOrEmpty(input))
{
return false;
}
// Replace valid base-64 padding
input = input.Trim();
int mod4 = input.Length % 4;
if (mod4 > 0)
{
// Base-64 string lengths should be divisible by 4
return false;
}
// Check each character to ensure it is valid base-64
foreach (char c in input)
{
if (!char.IsLetterOrDigit(c) && c != '+' && c != '/' && c != '=')
{
// Invalid character detected
return false;
}
}
// Ensure no invalid padding scenarios exist
if (input.EndsWith("==") && input.Length % 4 == 0 ||
input.EndsWith("=") && input.Length % 4 == 3)
{
return true;
}
return input.IndexOf('=') == -1; // No padding allowed except at the end
}
/// <summary>
///
/// </summary>
/// <param name="encodedKey"></param>
/// <param name="decodedKeys"></param>
/// <returns></returns>
public static bool TryDecode(this string encodedKey, out string[] decodedKeys)
{
try
{
byte[] bytes = Convert.FromBase64String(encodedKey);
string decodedString = Encoding.UTF8.GetString(bytes);
decodedKeys = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
return true;
}
catch(ArgumentNullException) { }
catch (FormatException) { }
catch(ArgumentException) { }
decodedKeys = Array.Empty<string>();
return false;
}
/// <summary>
///
/// </summary>
/// <param name="decodedKeys"></param>
/// <returns></returns>
public static EncodeType GetEncodeType(this string[] decodedKeys) => decodedKeys.Length switch
{
2 => EncodeType.EnvelopeReceiver,
3 => long.TryParse(decodedKeys[1], out var _) ? EncodeType.EnvelopeReceiverReadOnly : EncodeType.Undefined,
_ => EncodeType.Undefined,
};
/// <summary>
///
/// </summary>
/// <param name="decodedKeys"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public static (string? EnvelopeUuid, string? ReceiverSignature) ParseEnvelopeReceiverId(this string[] decodedKeys)
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiver
? (EnvelopeUuid: decodedKeys[0], ReceiverSignature: decodedKeys[1])
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver.");
/// <summary>
///
/// </summary>
/// <param name="decodedKeys"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public static long ParseReadOnlyId(this string[] decodedKeys)
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly
? long.Parse(decodedKeys[1])
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
/// <summary>
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
/// </summary>
/// <param name="envelopeReceiverId">The base64 encoded string containing the envelope UUID and receiver signature.</param>
/// <returns>A tuple containing the envelope UUID and receiver signature.</returns>
public static (string? EnvelopeUuid, string? ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
{
if (!envelopeReceiverId.IsBase64String())
{
return (null, null);
}
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
string decodedString = Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
if (parts.Length > 1)
return (EnvelopeUuid: parts[0], ReceiverSignature: parts[1]);
else
return (string.Empty, string.Empty);
}
/// <summary>
///
/// </summary>
/// <param name="envelopeReceiverReadOnlyId"></param>
/// <returns></returns>
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
{
if (!envelopeReceiverReadOnlyId.IsBase64String())
{
return null;
}
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
string decodedString = Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
if (parts.Length > 2)
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
else
return null;
}
/// <summary>
/// Gets the envelope UUID from the decoded envelope receiver ID.
/// </summary>
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
/// <returns>The envelope UUID.</returns>
public static string? GetEnvelopeUuid(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().EnvelopeUuid;
/// <summary>
/// Gets the receiver signature from the decoded envelope receiver ID.
/// </summary>
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
/// <returns>The receiver signature.</returns>
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
}

View File

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

View File

@@ -1,125 +0,0 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Domain.Interfaces;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
///
/// </summary>
public static class QueryExtensions
{
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, EnvelopeQueryBase query, bool notnull = true)
where TEntity : IHasEnvelope
{
if (query.Id is not null)
root = root.Where(e => e.Envelope!.Id == query.Id);
else if (query.Uuid is not null)
root = root.Where(e => e.Envelope!.Uuid == query.Uuid);
else if (notnull)
throw new BadRequestException(
"Either Envelope Id or Envelope Uuid must be provided in the query."
);
return root;
}
/// <summary>
///
/// </summary>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<Envelope> Where(this IQueryable<Envelope> root, EnvelopeQueryBase query, bool notnull = true)
{
if (query.Id is not null)
root = root.Where(e => e.Id == query.Id);
else if (query.Uuid is not null)
root = root.Where(e => e.Uuid == query.Uuid);
else if (notnull)
throw new BadRequestException(
"Either Envelope Id or Envelope Uuid must be provided in the query."
);
return root;
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, ReceiverQueryBase query, bool notnull = true)
where TEntity : IHasReceiver
{
if (query.Id is not null)
root = root.Where(e => e.Receiver!.Id == query.Id);
else if (query.EmailAddress is not null)
root = root.Where(e => e.Receiver!.EmailAddress == query.EmailAddress);
else if (query.Signature is not null)
root = root.Where(e => e.Receiver!.Signature == query.Signature);
else if (notnull)
throw new BadRequestException(
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
);
return root;
}
/// <summary>
///
/// </summary>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<Receiver> Where(this IQueryable<Receiver> root, ReceiverQueryBase query, bool notnull = true)
{
if (query.Id is not null)
root = root.Where(e => e.Id == query.Id);
else if (query.EmailAddress is not null)
root = root.Where(e => e.EmailAddress == query.EmailAddress);
else if (query.Signature is not null)
root = root.Where(e => e.Signature == query.Signature);
else if (notnull)
throw new BadRequestException(
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
);
return root;
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TEnvelopeQuery"></typeparam>
/// <typeparam name="TReceiverQuery"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
public static IQueryable<TEntity> Where<TEntity, TEnvelopeQuery, TReceiverQuery>(this IQueryable<TEntity> root, EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery> query, bool notnull = true)
where TEntity : IHasEnvelope, IHasReceiver
where TEnvelopeQuery : EnvelopeQueryBase, new()
where TReceiverQuery : ReceiverQueryBase, new()
=> root.Where(query.Envelope, notnull).Where(query.Receiver, notnull);
}

View File

@@ -1,78 +0,0 @@
using DigitalData.Core.Exceptions;
namespace EnvelopeGenerator.Application.Common.Extensions;
/// <summary>
/// Extension methods for tasks
/// </summary>
public static class TaskExtensions
{
/// <summary>
/// Awaits the specified task and ensures that the result is not <c>null</c>.
/// If the result is <c>null</c>, the exception created by factory-method is thrown.
/// </summary>
/// <typeparam name="T">The type of the result.</typeparam>
/// <typeparam name="TException">The type of the exception.</typeparam>
/// <param name="task">The task to await.</param>
/// <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>
public static async Task<T> ThrowIfNull<T, TException>(this Task<T?> task, Func<TException> factory) where TException : Exception
{
var result = await task;
return result ?? throw factory();
}
/// <summary>
/// Awaits the specified task and ensures that the result is not <c>empty</c>.
/// If the result contains no elements, the exception created by factory-method is thrown.
/// </summary>
/// <typeparam name="T">The element type of the collection.</typeparam>
/// <typeparam name="TException">The type of the exception.</typeparam>
/// <param name="task">The task to await.</param>
/// <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>
public static async Task<IEnumerable<T>> ThrowIfEmpty<T, TException>(this Task<IEnumerable<T>> task, Func<TException> factory) where TException : Exception
{
var result = await task;
return result?.Any() ?? false ? result : throw factory();
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="I"></typeparam>
/// <param name="task"></param>
/// <param name="act"></param>
/// <returns></returns>
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>
public static class Exceptions
{
/// <summary>
///
/// </summary>
public static NotFoundException NotFound() => new();
/// <summary>
///
/// </summary>
/// <returns></returns>
public static BadRequestException BadRequest() => new();
/// <summary>
///
/// </summary>
/// <returns></returns>
public static ForbiddenException Forbidden() => new();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,62 +0,0 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
///
/// </summary>
public record EnvelopeReceiverQueryBase : EnvelopeReceiverQueryBase<EnvelopeQueryBase, ReceiverQueryBase>;
/// <summary>
///
/// </summary>
/// <typeparam name="TEnvelopeQuery"></typeparam>
/// <typeparam name="TReceiverQuery"></typeparam>
public record EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery>
where TEnvelopeQuery : EnvelopeQueryBase, new()
where TReceiverQuery : ReceiverQueryBase, new()
{
private string? _key;
/// <summary>
///
/// </summary>
public virtual string? Key
{
get => _key;
set
{
if (value is null)
{
_key = null;
return;
}
(string? EnvelopeUuid, string? ReceiverSignature) = value.DecodeEnvelopeReceiverId();
if (string.IsNullOrEmpty(EnvelopeUuid) || string.IsNullOrEmpty(ReceiverSignature))
throw new BadRequestException("Der EnvelopeReceiverKey muss ein gültiger Base64-kodierter String sein, der die EnvelopeUuid und die ReceiverSignature enthält.");
Envelope = new TEnvelopeQuery()
{
Uuid = EnvelopeUuid
};
Receiver = new TReceiverQuery()
{
Signature = ReceiverSignature
};
_key = value;
}
}
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
/// </summary>
public virtual TEnvelopeQuery Envelope { get; set; } = new();
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public virtual TReceiverQuery Receiver { get; set; } = new();
}

View File

@@ -1,20 +0,0 @@
using AutoMapper;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
///
/// </summary>
public class MappingProfile : Profile
{
/// <summary>
///
/// </summary>
public MappingProfile()
{
CreateMap<EnvelopeQueryBase, Envelope>();
CreateMap<ReceiverQueryBase, Receiver>();
CreateMap<EnvelopeReceiverQueryBase, EnvelopeReceiver>();
}
}

View File

@@ -1,23 +0,0 @@
namespace EnvelopeGenerator.Application.Common.Query;
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public record ReceiverQueryBase
{
/// <summary>
/// ID des Empfängers
/// </summary>
public virtual int? Id { get; set; }
/// <summary>
/// E-Mail Adresse des Empfängers
/// </summary>
public virtual string? EmailAddress { get; set; }
/// <summary>
/// Eindeutige Signatur des Empfängers
/// </summary>
public virtual string? Signature { get; set; }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -1,11 +1,11 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IDocumentReceiverElementRepository : ICRUDRepository<Signature, int>
public interface IDocumentReceiverElementRepository : ICRUDRepository<DocumentReceiverElement, int>
{
}

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -1,8 +1,8 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
using static EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -0,0 +1,12 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
/// </summary>
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
public interface IEnvelopeCertificateRepository : ICRUDRepository<EnvelopeCertificate, int>
{
}

View File

@@ -1,12 +1,12 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IEnvelopeDocumentRepository : ICRUDRepository<Document, int>
public interface IEnvelopeDocumentRepository : ICRUDRepository<EnvelopeDocument, int>
{
}

View File

@@ -1,14 +1,14 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
/// </summary>
[Obsolete("Use IRepository")]
public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
public interface IEnvelopeHistoryRepository : ICRUDRepository<EnvelopeHistory, long>
{
/// <summary>
///
@@ -17,7 +17,7 @@ public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
/// <param name="userReference"></param>
/// <param name="status"></param>
/// <returns></returns>
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null);
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, Constants.EnvelopeStatus? status = null);
/// <summary>
///
@@ -28,5 +28,5 @@ public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
/// <param name="withSender"></param>
/// <param name="withReceiver"></param>
/// <returns></returns>
Task<IEnumerable<History>> ReadAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, Constants.EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
}

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -1,9 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
@@ -85,7 +83,7 @@ public interface IEnvelopeReceiverRepository : ICRUDRepository<EnvelopeReceiver,
/// <param name="max_status"></param>
/// <param name="ignore_statuses"></param>
/// <returns></returns>
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
/// <summary>
///

View File

@@ -1,8 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///
@@ -39,5 +38,5 @@ public interface IEnvelopeRepository : ICRUDRepository<Envelope, int>
/// <param name="max_status"></param>
/// <param name="ignore_statuses"></param>
/// <returns></returns>
Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
}

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Repositories;
namespace EnvelopeGenerator.Application.Contracts.Repositories;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
///
@@ -14,5 +14,5 @@ public interface IDocumentExecutor
/// <param name="envelope_uuid"></param>
/// <param name="cancellation"></param>
/// <returns></returns>
Task<Document> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
Task<EnvelopeDocument> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
}

View File

@@ -1,7 +1,7 @@
using Dapper;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
///

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
/// Provides methods for executing common queries on a given entity type.

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
/// Represents a raw SQL query contract.

View File

@@ -1,4 +1,4 @@
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
/// Defines methods for executing raw SQL queries or custom SQL query classes and returning query executors for further operations.

View File

@@ -1,6 +1,6 @@
using Dapper;
namespace EnvelopeGenerator.Application.Interfaces.SQLExecutor;
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
///

View File

@@ -1,6 +1,6 @@
using OtpNet;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

@@ -1,9 +1,9 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

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

View File

@@ -1,7 +1,7 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

@@ -1,10 +1,10 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using static EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

@@ -0,0 +1,13 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IEnvelopeCertificateService : IBasicCRUDService<EnvelopeCertificateDto, EnvelopeCertificate, int>
{
}

View File

@@ -0,0 +1,13 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///
/// </summary>
[Obsolete("Use MediatR")]
public interface IEnvelopeDocumentService : IBasicCRUDService<EnvelopeDocumentDto, EnvelopeDocument, int>
{
}

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

@@ -1,16 +1,13 @@
using CommandDotNet;
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.Messaging;
using EnvelopeGenerator.Application.Envelopes;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Application.Receivers.Queries;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Receivers.Queries.Read;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///
@@ -123,7 +120,7 @@ public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDt
/// <param name="receiverQuery"></param>
/// <param name="ignore_statuses"></param>
/// <returns></returns>
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, ReadEnvelopeQuery? envelopeQuery = null, ReadReceiverQuery? receiverQuery = null, params EnvelopeStatus[] ignore_statuses);
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, EnvelopeQuery? envelopeQuery = null, ReadReceiverQuery? receiverQuery = null, params int[] ignore_statuses);
/// <summary>
///

View File

@@ -1,10 +1,9 @@
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///
@@ -41,5 +40,5 @@ public interface IEnvelopeService : IBasicCRUDService<EnvelopeDto, Envelope, int
/// <param name="max_status"></param>
/// <param name="ignore_statuses"></param>
/// <returns></returns>
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
}

View File

@@ -1,7 +1,7 @@
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.Messaging;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.Messaging;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

@@ -1,8 +1,8 @@
using DigitalData.Core.Abstraction.Application;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
/// <summary>
///

View File

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

View File

@@ -1,6 +1,6 @@
using EnvelopeGenerator.Application.Common.Dto.Messaging;
using EnvelopeGenerator.Application.DTOs.Messaging;
namespace EnvelopeGenerator.Application.Interfaces.Services;
namespace EnvelopeGenerator.Application.Contracts.Services;
//TODO: move to DigitalData.Core
/// <summary>

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.DTOs;
/// <summary>
/// Data Transfer Object representing certificate information for an envelope.
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public class EnvelopeCertificateDto
{
/// <summary>
/// Gets the unique identifier of the certificate.
/// </summary>
public int Id { get; init; }
/// <summary>
/// Gets the envelope ID associated with the certificate.
/// </summary>
public int EnvelopeId { get; init; }
/// <summary>
/// Gets the UUID of the envelope.
/// </summary>
public string EnvelopeUuid { get; init; } = string.Empty;
/// <summary>
/// Gets the subject of the envelope.
/// </summary>
public string EnvelopeSubject { get; init; } = string.Empty;
/// <summary>
/// Gets the ID of the creator of the envelope.
/// </summary>
public int CreatorId { get; init; }
/// <summary>
/// Gets the name of the creator.
/// </summary>
public string CreatorName { get; init; } = string.Empty;
/// <summary>
/// Gets the email address of the creator.
/// </summary>
public string CreatorEmail { get; init; } = string.Empty;
/// <summary>
/// Gets the current status of the envelope.
/// </summary>
public int EnvelopeStatus { get; init; }
}

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
using DigitalData.UserManager.Application.DTOs.User;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.DTOs.Receiver;
using static EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.Common.Dto.History;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
/// <summary>
/// Data Transfer Object representing the history of an envelope, including status, sender, receiver, and related metadata.
/// </summary>
public record HistoryDto
public record EnvelopeHistoryDto
{
/// <summary>
/// Unique identifier for the envelope history entry.
@@ -25,19 +25,9 @@ public record HistoryDto
public required string UserReference { get; set; }
/// <summary>
/// Include code of the envelope at this history point.
/// Status code of the envelope at this history point.
/// </summary>
public EnvelopeStatus Status { get; set; }
/// <summary>
/// Type of reference for this history entry.
/// </summary>
public ReferenceType ReferenceType => ((int)Status).ToString().FirstOrDefault() switch
{
'1' => ReferenceType.Sender,
'2' => ReferenceType.Receiver,
_ => ReferenceType.System,
};
public int Status { get; set; }
/// <summary>
/// Human-readable name of the status.
@@ -62,7 +52,12 @@ public record HistoryDto
/// <summary>
/// Information about the receiver associated with this history entry.
/// </summary>
public ReceiverDto? Receiver { get; set; }
public ReceiverReadDto? Receiver { get; set; }
/// <summary>
/// Type of reference for this history entry.
/// </summary>
public ReferenceType ReferenceType { get; set; }
/// <summary>
/// Optional comment related to this history entry.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;
namespace EnvelopeGenerator.Application.DTOs.Receiver;
/// <summary>
///
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public record ReceiverCreateDto
{
/// <summary>
///
/// </summary>
public ReceiverCreateDto()
{
_sha256HexOfMail = new(() =>
{
var bytes_arr = Encoding.UTF8.GetBytes(EmailAddress!.ToUpper());
var hash_arr = SHA256.HashData(bytes_arr);
var hexa_str = BitConverter.ToString(hash_arr);
return hexa_str.Replace("-", string.Empty);
});
}
/// <summary>
///
/// </summary>
[EmailAddress]
public required string EmailAddress { get; init; }
/// <summary>
///
/// </summary>
public string? TotpSecretkey { get; init; }
/// <summary>
/// var bytes_arr = Encoding.UTF8.GetBytes(EmailAddress.ToUpper());<br/>
/// var hash_arr = SHA256.HashData(bytes_arr);
/// var hexa_str = BitConverter.ToString(hash_arr);
/// return hexa_str.Replace("-", string.Empty);
/// </summary>
public string Signature => _sha256HexOfMail.Value;
private readonly Lazy<string> _sha256HexOfMail;
/// <summary>
/// Default value is DateTime.Now
/// </summary>
public DateTime AddedWhen { get; } = DateTime.Now;
};

View File

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

View File

@@ -1,12 +1,12 @@
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Application.Receivers.Commands;
namespace EnvelopeGenerator.Application.DTOs.Receiver;
/// <summary>
/// Data Transfer Object for updating a receiver's information.
/// </summary>
[ApiExplorerSettings(IgnoreApi = true)]
public class UpdateReceiverCommand
public class ReceiverUpdateDto
{
/// <summary>
/// Gets or sets the unique identifier of the receiver.

View File

@@ -1,12 +1,13 @@
using DigitalData.Core.Client;
using EnvelopeGenerator.Application.Common.Configurations;
using EnvelopeGenerator.Application.Interfaces.Services;
using EnvelopeGenerator.Application.Configurations;
using EnvelopeGenerator.Application.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using DigitalData.Core.Client;
using QRCoder;
using EnvelopeGenerator.Application.Contracts.Services;
using System.Reflection;
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create;
namespace EnvelopeGenerator.Application;
@@ -32,6 +33,7 @@ public static class DependencyInjection
services.TryAddScoped<IDocumentStatusService, DocumentStatusService>();
services.TryAddScoped<IEmailTemplateService, EmailTemplateService>();
services.TryAddScoped<IEnvelopeService, EnvelopeService>();
services.TryAddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
services.TryAddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
services.TryAddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
services.TryAddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
@@ -57,6 +59,7 @@ public static class DependencyInjection
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
cfg.RegisterServicesFromAssembly(typeof(CreateEnvelopeReceiverCommandHandler).Assembly);
});
return services;

View File

@@ -1,12 +0,0 @@
namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// <summary>
///
/// </summary>
public record CreateDocStatusCommand : ModifyDocStatusCommandBase
{
/// <summary>
/// Gets timestamp when this record was added. Returns the StatusChangedWhen value.
/// </summary>
public DateTime AddedWhen => StatusChangedWhen;
}

View File

@@ -1,54 +0,0 @@
using EnvelopeGenerator.Application.Common.Query;
using EnvelopeGenerator.Domain.Constants;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// <summary>
///
/// </summary>
public record ModifyDocStatusCommandBase : EnvelopeReceiverQueryBase
{
/// <summary>
///
/// </summary>
public int? EnvelopeId => Envelope.Id;
/// <summary>
///
/// </summary>
public int? ReceiverId => Receiver.Id;
/// <summary>
///
/// </summary>
public override ReceiverQueryBase Receiver { get => base.Receiver; set => base.Receiver = value; }
/// <summary>
/// Gets the current status code.
/// </summary>
public DocumentStatus Status => Value is null ? DocumentStatus.Created : DocumentStatus.Signed;
/// <summary>
/// Gets or sets the display value associated with the status.
/// </summary>
public string? Value { get; set; }
/// <summary>
/// Gets timestamp when this record was added.
/// </summary>
public DateTime StatusChangedWhen { get; } = DateTime.Now;
/// <summary>
/// Maps the current command to a new instance of the specified type.
/// </summary>
/// <typeparam name="TDest"></typeparam>
/// <returns></returns>
public TDest To<TDest>() where TDest : ModifyDocStatusCommandBase, new()
=> new()
{
Key = Key,
Envelope = Envelope,
Receiver = Receiver,
Value = Value
};
}

View File

@@ -1,77 +0,0 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// <summary>
/// Represents a command to save the status of a document, either by creating a new status or updating an existing one based on the provided envelope and receiver identifiers.
/// It returns the identifier of the saved document status.
/// </summary>
public record SaveDocStatusCommand : ModifyDocStatusCommandBase, IRequest<DocumentStatusDto?>;
/// <summary>
///
/// </summary>
public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand, DocumentStatusDto?>
{
private readonly IMapper _mapper;
private readonly IRepository<DocumentStatus> _repo;
private readonly IRepository<Envelope> _envRepo;
private readonly IRepository<Receiver> _rcvRepo;
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="repo"></param>
/// <param name="rcvRepo"></param>
/// <param name="envRepo"></param>
public SaveDocStatusCommandHandler(IMapper mapper, IRepository<DocumentStatus> repo, IRepository<Receiver> rcvRepo, IRepository<Envelope> envRepo)
{
_mapper = mapper;
_repo = repo;
_rcvRepo = rcvRepo;
_envRepo = envRepo;
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public async Task<DocumentStatusDto?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
{
// ceck if exists
bool isExists = await _repo.ReadOnly().Where(request).AnyAsync(cancel);
var env = await _envRepo.ReadOnly().Where(request.Envelope).FirstAsync(cancel);
var rcv = await _rcvRepo.ReadOnly().Where(request.Receiver).FirstAsync(cancel);
request.Envelope.Id = env.Id;
request.Receiver.Id = rcv.Id;
if (isExists)
{
var uReq = request.To<UpdateDocStatusCommand>();
await _repo.UpdateAsync(uReq, q => q.Where(request), cancel);
}
else
{
var cReq = request.To<CreateDocStatusCommand>();
await _repo.CreateAsync(cReq, cancel);
}
var docStatus = await _repo.ReadOnly().Where(request).SingleOrDefaultAsync(cancel);
return _mapper.Map<DocumentStatusDto>(docStatus);
}
}

View File

@@ -1,14 +0,0 @@
using EnvelopeGenerator.Domain;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// <summary>
///
/// </summary>
public record UpdateDocStatusCommand : ModifyDocStatusCommandBase
{
/// <summary>
/// Gets timestamp when this record was added. Returns the StatusChangedWhen value.
/// </summary>
public DateTime? ChangedWhen => StatusChangedWhen;
}

View File

@@ -1,25 +0,0 @@
using AutoMapper;
using EnvelopeGenerator.Application.DocStatus.Commands;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.DocStatus;
/// <summary>
///
/// </summary>
public class MappingProfile : Profile
{
/// <summary>
///
/// </summary>
public MappingProfile()
{
CreateMap<CreateDocStatusCommand, DocumentStatus>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
CreateMap<UpdateDocStatusCommand, DocumentStatus>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore());
}
}

View File

@@ -0,0 +1,18 @@
using AutoMapper;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Documents.Queries.Read;
/// <summary>
///
/// </summary>
public class ReadDocumentMappingProfile : Profile
{
/// <summary>
///
/// </summary>
public ReadDocumentMappingProfile()
{
CreateMap<EnvelopeDocument, ReadDocumentResponse>();
}
}

View File

@@ -0,0 +1,12 @@
using MediatR;
namespace EnvelopeGenerator.Application.Documents.Queries.Read;
/// <summary>
/// Represents a query to read a document based on its unique identifier or associated envelope identifier.
/// </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<ReadDocumentResponse?>
{
}

View File

@@ -0,0 +1,48 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
namespace EnvelopeGenerator.Application.Documents.Queries.Read;
/// <summary>
/// Handles queries for reading <see cref="EnvelopeDocument"/> data based on either the document ID or the envelope ID.
/// </summary>
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, ReadDocumentResponse?>
{
/// <summary>
/// Repository for accessing <see cref="EnvelopeDocument"/> entities.
/// </summary>
private readonly IRepository<EnvelopeDocument> _repo;
/// <summary>
/// Initializes a new instance of the <see cref="ReadDocumentQueryHandler"/> class.
/// </summary>
/// <param name="envelopeDocumentRepository">The repository used to access <see cref="EnvelopeDocument"/> entities.</param>
public ReadDocumentQueryHandler(IRepository<EnvelopeDocument> envelopeDocumentRepository)
{
_repo = envelopeDocumentRepository;
}
/// <summary>
/// Handles the <see cref="ReadDocumentQuery"/> and returns a <see cref="ReadDocumentResponse"/> based on the provided identifiers.
/// </summary>
/// <param name="query">The query containing the document ID or envelope ID to search for.</param>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <returns>
/// A <see cref="ReadDocumentResponse"/> if a matching document is found; otherwise, <c>null</c>.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Thrown when neither <see cref="ReadDocumentQuery.Id"/> nor <see cref="ReadDocumentQuery.EnvelopeId"/> is provided.
/// </exception>
[Obsolete("Use MediatR")]
public async Task<ReadDocumentResponse?> Handle(ReadDocumentQuery query, CancellationToken cancellationToken)
{
if (query.Id is not null)
return await _repo.ReadOrDefaultAsync<ReadDocumentResponse>(d => d.Id == query.Id);
else if (query.EnvelopeId is not null)
return await _repo.ReadOrDefaultAsync<ReadDocumentResponse>(d => d.EnvelopeId == query.EnvelopeId);
throw new InvalidOperationException(
$"Invalid {nameof(ReadDocumentQuery)}: either {nameof(query.Id)} or {nameof(query.EnvelopeId)} must be provided.");
}
}

View File

@@ -0,0 +1,12 @@
namespace EnvelopeGenerator.Application.Documents.Queries.Read;
/// <summary>
/// Represents the response for reading a document.
/// </summary>
public class ReadDocumentResponse : ReadDocumentResponseBase
{
/// <summary>
/// The binary data of the document, if available.
/// </summary>
public byte[]? ByteData { get; init; }
}

View File

@@ -0,0 +1,22 @@
namespace EnvelopeGenerator.Application.Documents.Queries.Read;
/// <summary>
/// Represents the response for reading a document.
/// </summary>
public class ReadDocumentResponseBase
{
/// <summary>
/// The unique identifier of the document.
/// </summary>
public int Guid { get; init; }
/// <summary>
/// The identifier of the associated envelope.
/// </summary>
public int EnvelopeId { get; init; }
/// <summary>
/// The date and time when the document was added.
/// </summary>
public DateTime AddedWhen { get; init; }
}

View File

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

View File

@@ -1,5 +1,4 @@
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Reset;
@@ -34,8 +33,8 @@ public record ResetEmailTemplateCommand : EmailTemplateQuery, IRequest
///
/// </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)
/// <param name="Type">Der Typ der E-Mail-Vorlage, z. B. <see cref="Constants.EmailTemplateType"/> (optional).</param>
public ResetEmailTemplateCommand(int? Id = null, Constants.EmailTemplateType? Type = null) : base(Id, Type)
{
}
};

View File

@@ -1,9 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Reset;
@@ -33,10 +31,10 @@ public class ResetEmailTemplateCommandHandler : IRequestHandler<ResetEmailTempla
public async Task Handle(ResetEmailTemplateCommand request, CancellationToken cancel)
{
var temps = request.Id is not null
? await _repository.ReadOnly().Where(t => t.Id == request.Id).ToListAsync(cancel)
? await _repository.ReadAllAsync<EmailTemplateDto>(t => t.Id == request.Id, cancel)
: request.Type is not null
? await _repository.ReadOnly().Where(t => t.Name == request.Type.ToString()).ToListAsync(cancel)
: await _repository.ReadOnly().ToListAsync(cancel);
? await _repository.ReadAllAsync<EmailTemplateDto>(t => t.Name == request.Type.ToString(), cancel)
: await _repository.ReadAllAsync<EmailTemplateDto>(cancellation: cancel);
foreach (var temp in temps)
{
@@ -84,7 +82,7 @@ public class ResetEmailTemplateCommandHandler : IRequestHandler<ResetEmailTempla
new(){
Id = 6,
Name = "DocumentRejected_ADM",
Body = "Guten Tag [NAME_SENDER],<p><B><I>[NAME_RECEIVER]</I></B> hat den Umschlag <B><I>'[DOCUMENT_TITLE]'</I></B> mit folgendem Grund abgelehnt: <p>\r\n[REASON] \r\n<p>Der Umschlag wurde auf den Include Rejected gesetzt. <p> \r\nMit freundlichen Grüßen<br />\r\n<br />\r\n[NAME_PORTAL]",
Body = "Guten Tag [NAME_SENDER],<p><B><I>[NAME_RECEIVER]</I></B> hat den Umschlag <B><I>'[DOCUMENT_TITLE]'</I></B> mit folgendem Grund abgelehnt: <p>\r\n[REASON] \r\n<p>Der Umschlag wurde auf den Status Rejected gesetzt. <p> \r\nMit freundlichen Grüßen<br />\r\n<br />\r\n[NAME_PORTAL]",
Subject = "'[DOCUMENT_TITLE]' - Unterzeichnungsvorgang zurückgezogen"
},
new(){

View File

@@ -1,11 +1,9 @@
using AutoMapper;
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.Exceptions;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Dto;
namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Update;
@@ -15,17 +13,14 @@ namespace EnvelopeGenerator.Application.EmailTemplates.Commands.Update;
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)
public UpdateEmailTemplateCommandHandler(IRepository<EmailTemplate> repository)
{
_repository = repository;
_mapper = mapper;
}
/// <summary>
@@ -39,34 +34,32 @@ public class UpdateEmailTemplateCommandHandler : IRequestHandler<UpdateEmailTemp
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
public async Task Handle(UpdateEmailTemplateCommand request, CancellationToken cancel)
{
EmailTemplateDto? tempDto;
EmailTemplateDto? temp;
if (request.EmailTemplateQuery?.Id is int id)
{
var temp = await _repository.ReadOnly().Where(t => t.Id == id).FirstOrDefaultAsync(cancel);
tempDto = _mapper.Map<EmailTemplateDto>(temp);
temp = await _repository.ReadOrDefaultAsync<EmailTemplateDto>(t => t.Id == id, single: false, cancel);
}
else if (request!.EmailTemplateQuery!.Type is EmailTemplateType type)
else if (request!.EmailTemplateQuery!.Type is Constants.EmailTemplateType type)
{
var temp = await _repository.ReadOnly().Where(t => t.Name == type.ToString()).FirstOrDefaultAsync(cancel);
tempDto = _mapper.Map<EmailTemplateDto>(temp);
temp = await _repository.ReadOrDefaultAsync<EmailTemplateDto>(t => t.Name == type.ToString(), single: false, cancel);
}
else
{
throw new InvalidOperationException("Both id and type is null. Id: " + request.EmailTemplateQuery.Id +". Type: " + request.EmailTemplateQuery.Type.ToString());
}
if (tempDto == null)
if (temp == null)
{
throw new NotFoundException();
}
if (request.Body is not null)
tempDto.Body = request.Body;
temp.Body = request.Body;
if (request.Subject is not null)
tempDto.Subject = request.Subject;
temp.Subject = request.Subject;
await _repository.UpdateAsync(tempDto, t => t.Id == tempDto.Id, cancel);
await _repository.UpdateAsync(temp, t => t.Id == temp.Id, cancel);
}
}

View File

@@ -1,4 +1,4 @@
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain;
namespace EnvelopeGenerator.Application.EmailTemplates;
@@ -7,7 +7,7 @@ namespace EnvelopeGenerator.Application.EmailTemplates;
/// 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:
/// <param name="Type">Der Typ der E-Mail-Vorlage, z. B. <see cref="Constants.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.
@@ -19,6 +19,6 @@ namespace EnvelopeGenerator.Application.EmailTemplates;
/// 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)
public record EmailTemplateQuery(int? Id = null, Constants.EmailTemplateType? Type = null)
{
}

View File

@@ -1,5 +1,4 @@
using AutoMapper;
using EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
using EnvelopeGenerator.Domain.Entities;
using System;
using System.Collections.Generic;
@@ -7,17 +6,17 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnvelopeGenerator.Application.EmailTemplates;
namespace EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
/// <summary>
///
/// </summary>
public class MappingProfile : Profile
public class ReadEmailTemplateMappingProfile : Profile
{
/// <summary>
///
/// </summary>
public MappingProfile()
public ReadEmailTemplateMappingProfile()
{
CreateMap<EmailTemplate, ReadEmailTemplateResponse>();
}

View File

@@ -1,6 +1,6 @@
using AutoMapper;
using EnvelopeGenerator.Application.Interfaces.Repositories;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Contracts.Repositories;
using EnvelopeGenerator.Domain;
using MediatR;
namespace EnvelopeGenerator.Application.EmailTemplates.Queries.Read;
@@ -41,7 +41,7 @@ public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQu
{
var temp = request.Id is int id
? await _repository.ReadByIdAsync(id)
: request.Type is EmailTemplateType type
: request.Type is Constants.EmailTemplateType type
? await _repository.ReadByNameAsync(type)
: throw new InvalidOperationException("Either a valid integer ID or a valid EmailTemplateType must be provided in the request.");

View File

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

View File

@@ -14,34 +14,22 @@
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.2.1" />
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.0.0" />
<PackageReference Include="DigitalData.Core.Application" Version="3.3.4" />
<PackageReference Include="DigitalData.Core.Client" Version="2.1.0" />
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
<PackageReference Include="MediatR" Version="12.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
<PackageReference Include="Otp.NET" Version="1.4.0" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="QRCoder-ImageSharp" Version="0.10.0" />
<PackageReference Include="UserManager" Version="1.1.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
<PackageReference Include="UserManager" Version="1.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,21 @@
using EnvelopeGenerator.Application.Envelopes.Commands;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create;
/// <summary>
/// Befehl zur Erstellung eines Umschlags.
/// </summary>
/// <param name="Title">Der Titel des Umschlags. Dies ist ein Pflichtfeld.</param>
/// <param name="Message">Die Nachricht, die im Umschlag enthalten sein soll. Dies ist ein Pflichtfeld.</param>
/// <param name="Document">Das mit dem Umschlag verknüpfte Dokument. Dies ist ein Pflichtfeld.</param>
/// <param name="Receivers">Eine Sammlung von Empfängern, die den Umschlag erhalten. Dies ist ein Pflichtfeld.</param>
/// <param name="TFAEnabled">Gibt an, ob die Zwei-Faktor-Authentifizierung für den Umschlag aktiviert ist. Standardmäßig false.</param>
public record CreateEnvelopeReceiverCommand(
[Required] string Title,
[Required] string Message,
[Required] DocumentCreateCommand Document,
[Required] IEnumerable<ReceiverGetOrCreateCommand> Receivers,
bool TFAEnabled = false
) : CreateEnvelopeCommand(Title, Message, TFAEnabled), IRequest<CreateEnvelopeReceiverResponse>;

View File

@@ -1,10 +1,10 @@
using AutoMapper;
using EnvelopeGenerator.Application.Interfaces.SQLExecutor;
using EnvelopeGenerator.Application.Contracts.SQLExecutor;
using EnvelopeGenerator.Application.DTOs.Receiver;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using EnvelopeGenerator.Application.Common.Dto.Receiver;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create;
/// <summary>
/// Handles the creation of an envelope along with its associated document and recipients.
@@ -42,7 +42,9 @@ public class CreateEnvelopeReceiverCommandHandler : IRequestHandler<CreateEnvelo
/// <returns>A task representing the asynchronous operation.</returns>
public async Task<CreateEnvelopeReceiverResponse> Handle(CreateEnvelopeReceiverCommand request, CancellationToken cancel)
{
var envelope = await _envelopeExecutor.CreateEnvelopeAsync(request.UserId, request.Title, request.Message, request.TFAEnabled, cancel);
int userId = request.UserId ?? throw new InvalidOperationException("UserId cannot be null when creating an envelope.");
var envelope = await _envelopeExecutor.CreateEnvelopeAsync(userId, request.Title, request.Message, request.TFAEnabled, cancel);
List<EnvelopeReceiver> sentRecipients = new();
List<ReceiverGetOrCreateCommand> unsentRecipients = new();
@@ -59,7 +61,7 @@ public class CreateEnvelopeReceiverCommandHandler : IRequestHandler<CreateEnvelo
var res = _mapper.Map<CreateEnvelopeReceiverResponse>(envelope);
res.UnsentReceivers = unsentRecipients;
res.SentReceiver = _mapper.Map<IEnumerable<ReceiverDto>>(sentRecipients);
res.SentReceiver = _mapper.Map<IEnumerable<ReceiverReadDto>>(sentRecipients);
return res;
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create;
#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] double X, [Required] double 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="Salution">Der Name, mit dem der Empfänger 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 ReceiverGetOrCreateCommand([Required] IEnumerable<Signature> Signatures, string? Salution = null, string? PhoneNumber = null)
{
private string _emailAddress = string.Empty;
/// <summary>
/// E-Mail-Adresse des Empfängers.
/// </summary>
[Required]
public string EmailAddress { get => _emailAddress.ToLower(); init => _emailAddress = value.ToLower(); }
};
/// <summary>
/// DTO zum Erstellen eines Dokuments.
/// </summary>
public record DocumentCreateCommand()
{
/// <summary>
/// Die Dokumentdaten im Base64-String-Format. Wird verwendet, wenn das Dokument als Base64-codierter String bereitgestellt wird.
/// </summary>
[Required]
public required string DataAsBase64 { get; init; }
};
#endregion

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