Compare commits
17 Commits
1c9d0a6c47
...
f20243d02c
| Author | SHA1 | Date | |
|---|---|---|---|
| f20243d02c | |||
| c1c30caeec | |||
| 5ccd1fee26 | |||
| 954d665ac3 | |||
| bb85437cc4 | |||
| 763f022a5e | |||
| f87f8a1d17 | |||
| fb5d2110bd | |||
| aafed0f4f4 | |||
| a433654f86 | |||
| b599ada864 | |||
| 6b00ab6a45 | |||
| 6ab85f25eb | |||
| fa46dd1fa8 | |||
| e623680c3f | |||
| f6e34c6d91 | |||
| fc443fb87f |
@@ -23,5 +23,5 @@ public class DispatcherParams
|
||||
/// <summary>
|
||||
/// Default value is string.Empty
|
||||
/// </summary>
|
||||
public string EmailAttmt1 { get; init; } = string.Empty;
|
||||
public string? EmailAttmt1 { get; init; } = null;
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using DigitalData.Core.Client;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Interfaces.Services;
|
||||
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.Interfaces.Services;
|
||||
using System.Reflection;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
|
||||
|
||||
namespace EnvelopeGenerator.Application;
|
||||
|
||||
@@ -58,7 +57,6 @@ public static class DependencyInjection
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
|
||||
cfg.RegisterServicesFromAssembly(typeof(CreateEnvelopeReceiverCommandHandler).Assembly);
|
||||
});
|
||||
|
||||
return services;
|
||||
|
||||
@@ -3,6 +3,8 @@ using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Application.Dto;
|
||||
using AutoMapper;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
|
||||
@@ -10,44 +12,25 @@ namespace EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
/// 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<int?>;
|
||||
public record SaveDocStatusCommand : ModifyDocStatusCommandBase, IRequest<DocumentStatusDto?>;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand, DocumentStatusDto?>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mediator"></param>
|
||||
/// <param name="uuid"></param>
|
||||
/// <param name="signature"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<int?> SignDocAsync(this IMediator mediator, string uuid, string signature, string value, CancellationToken cancel = default)
|
||||
=> mediator.Send(new SaveDocStatusCommand()
|
||||
{
|
||||
Envelope = new() { Uuid = uuid },
|
||||
Receiver = new() { Signature = signature },
|
||||
Value = value
|
||||
}, cancel);
|
||||
}
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand, int?>
|
||||
{
|
||||
private readonly IRepository<DocumentStatus> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mapper"></param>
|
||||
/// <param name="repo"></param>
|
||||
public SaveDocStatusCommandHandler(IRepository<DocumentStatus> repo)
|
||||
public SaveDocStatusCommandHandler(IMapper mapper, IRepository<DocumentStatus> repo)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
@@ -57,7 +40,7 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
|
||||
public async Task<DocumentStatusDto?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
|
||||
{
|
||||
// ceck if exists
|
||||
bool isExists = await _repo.ReadOnly().Where(request).AnyAsync(cancel);
|
||||
@@ -74,6 +57,7 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
|
||||
}
|
||||
|
||||
var docStatus = await _repo.ReadOnly().Where(request).SingleOrDefaultAsync(cancel);
|
||||
return docStatus?.Id;
|
||||
|
||||
return _mapper.Map<DocumentStatusDto>(docStatus);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public record ReadDocumentQuery(int? Id = null, int? EnvelopeId = null) : IReque
|
||||
public class ReadDocumentQueryHandler : IRequestHandler<ReadDocumentQuery, EnvelopeDocumentDto?>
|
||||
{
|
||||
/// <summary>
|
||||
/// Repository for accessing <see cref="EnvelopeDocument"/> entities.
|
||||
/// TempRepo for accessing <see cref="EnvelopeDocument"/> entities.
|
||||
/// </summary>
|
||||
private readonly IRepository<EnvelopeDocument> _repo;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Dto;
|
||||
|
||||
@@ -26,7 +27,7 @@ public class DocumentStatusDto
|
||||
/// <summary>
|
||||
/// Gets or sets the current status code.
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
public EnvelopeStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp when the status was changed.
|
||||
|
||||
@@ -9,11 +9,21 @@ namespace EnvelopeGenerator.Application.Histories.Queries;
|
||||
/// <summary>
|
||||
/// Repräsentiert eine Abfrage für die Verlaufshistorie eines Umschlags.
|
||||
/// </summary>
|
||||
/// <param name="EnvelopeId">Die eindeutige Kennung des Umschlags.</param>
|
||||
/// <param name="Status">Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.</param>
|
||||
/// <param name="OnlyLast">Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.</param>
|
||||
public record ReadHistoryQuery(
|
||||
public record ReadHistoryQuery : IRequest<IEnumerable<EnvelopeHistoryDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung des Umschlags.
|
||||
/// </summary>
|
||||
[Required]
|
||||
int EnvelopeId,
|
||||
EnvelopeStatus? Status = null,
|
||||
bool? OnlyLast = true) : IRequest<IEnumerable<EnvelopeHistoryDto>>;
|
||||
public int EnvelopeId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.
|
||||
/// </summary>
|
||||
public EnvelopeStatus? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.
|
||||
/// </summary>
|
||||
public bool? OnlyLast { get; init; } = true;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
|
||||
using MediatR;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Notifications.DocSigned;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="Original"></param>
|
||||
public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeReceiverDto(Original), INotification
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required ExpandoObject Annotations { get; init; }
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using EnvelopeGenerator.Application.Histories.Commands;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.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);
|
||||
}
|
||||
}
|
||||
148
EnvelopeGenerator.Application/Notifications/SendMailHandler.cs
Normal file
148
EnvelopeGenerator.Application/Notifications/SendMailHandler.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.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 virtual Dictionary<string, string> BodyPlaceHolders { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly MailParams MailParams;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly DispatcherParams DispatcherParams;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected virtual Dictionary<string, string> SubjectPlaceHolders { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ReferenceString = Envelope.Uuid
|
||||
/// </summary>
|
||||
/// <param name="emailOut"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract void ConfigEmailOut(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 async Task Handle(TNotification notification, CancellationToken cancel)
|
||||
{
|
||||
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, SubjectPlaceHolders, MailParams.Placeholders);
|
||||
|
||||
temp.Body = ReplacePlaceHolders(temp.Body, BodyPlaceHolders, MailParams.Placeholders);
|
||||
|
||||
var emailOut = new EmailOut
|
||||
{
|
||||
EmailAddress = notification.EmailAddress,
|
||||
EmailBody = temp.Body,
|
||||
EmailSubj = temp.Subject,
|
||||
AddedWhen = DateTime.UtcNow,
|
||||
AddedWho = DispatcherParams.AddedWho,
|
||||
SendingProfile = DispatcherParams.SendingProfile,
|
||||
ReminderTypeId = DispatcherParams.ReminderTypeId,
|
||||
EmailAttmt1 = DispatcherParams.EmailAttmt1,
|
||||
WfId = (int)EnvelopeStatus.MessageConfirmationSent,
|
||||
|
||||
};
|
||||
ConfigEmailOut(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 (4 non-breaking spaces)
|
||||
encoded = encoded.Replace("\t", " ");
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
26
EnvelopeGenerator.Domain/Constants/Format.cs
Normal file
26
EnvelopeGenerator.Domain/Constants/Format.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Constants
|
||||
{
|
||||
public class Format
|
||||
{
|
||||
#region Json Serializer Settings
|
||||
public static class Json
|
||||
{
|
||||
public static readonly JsonSerializerSettings ForDiagnostics = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Include
|
||||
};
|
||||
public static readonly JsonSerializerSettings ForAnnotations = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
Formatting = Formatting.None,
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
140
EnvelopeGenerator.Domain/Entities/EmailOut.cs
Normal file
140
EnvelopeGenerator.Domain/Entities/EmailOut.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
{
|
||||
[Obsolete("Use EmailDispatcher.EmailOut")]
|
||||
[Table("TBEMLP_EMAIL_OUT")]
|
||||
internal class EmailOut
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[DefaultValue(1)]
|
||||
[Column("REMINDER_TYPE_ID")]
|
||||
public int ReminderTypeId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("SENDING_PROFILE")]
|
||||
public int SendingProfile { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("REFERENCE_ID")]
|
||||
public int ReferenceId { get; set; }
|
||||
|
||||
[Column("REFERENCE_STRING", TypeName = "varchar(200)")]
|
||||
[StringLength(200)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
ReferenceString { get; set; }
|
||||
|
||||
[Column("ENTITY_ID")]
|
||||
public int? EntityId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("WF_ID")]
|
||||
public int WfId { get; set; }
|
||||
|
||||
[Column("WF_REFERENCE", TypeName = "varchar(200)")]
|
||||
[StringLength(200)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
WfReference
|
||||
{ get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("EMAIL_ADRESS", TypeName = "varchar(1000)")]
|
||||
[StringLength(1000)]
|
||||
public
|
||||
#if NET
|
||||
required
|
||||
#endif
|
||||
string EmailAddress { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("EMAIL_SUBJ", TypeName = "varchar(500)")]
|
||||
[StringLength(500)]
|
||||
public
|
||||
#if NET
|
||||
required
|
||||
#endif
|
||||
string EmailSubj { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("EMAIL_BODY", TypeName = "varchar(max)")]
|
||||
public
|
||||
#if NET
|
||||
required
|
||||
#endif
|
||||
string EmailBody { get; set; }
|
||||
|
||||
[Column("EMAIL_ATTMT1", TypeName = "varchar(512)")]
|
||||
[StringLength(512)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
EmailAttmt1
|
||||
{ get; set; }
|
||||
|
||||
[Column("EMAIL_SENT")]
|
||||
public DateTime? EmailSent { get; set; }
|
||||
|
||||
[Column("COMMENT", TypeName = "varchar(500)")]
|
||||
[StringLength(500)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Comment
|
||||
{ get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("ADDED_WHO", TypeName = "varchar(50)")]
|
||||
[StringLength(50)]
|
||||
[DefaultValue("DEFAULT")]
|
||||
public
|
||||
#if NET
|
||||
required
|
||||
#endif
|
||||
string AddedWho { get; set; }
|
||||
|
||||
[Column("ADDED_WHEN")]
|
||||
[DefaultValue("getdate()")]
|
||||
[NotMapped]
|
||||
public DateTime? AddedWhen { get; set; }
|
||||
|
||||
[Column("CHANGED_WHO", TypeName = "varchar(50)")]
|
||||
[StringLength(50)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
ChangedWho { get; set; }
|
||||
|
||||
[Column("CHANGED_WHEN")]
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[Column("ERROR_TIMESTAMP")]
|
||||
public DateTime? ErrorTimestamp { get; set; }
|
||||
|
||||
[Column("ERROR_MSG", TypeName = "varchar(900)")]
|
||||
[StringLength(900)]
|
||||
public string
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
ErrorMsg { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -54,25 +54,23 @@ public class EnvelopeHistory : IHasEnvelope, IHasReceiver
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public virtual Envelope
|
||||
#if NET
|
||||
?
|
||||
?
|
||||
#endif
|
||||
Envelope { get; set; }
|
||||
Envelope { get; set; }
|
||||
|
||||
[ForeignKey("UserReference")]
|
||||
public virtual User
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Sender
|
||||
{ get; set; }
|
||||
Sender { get; set; }
|
||||
|
||||
[ForeignKey("UserReference")]
|
||||
public virtual Receiver
|
||||
#if NET
|
||||
?
|
||||
#endif
|
||||
Receiver
|
||||
{ get; set; }
|
||||
Receiver { get; set; }
|
||||
|
||||
#if NETFRAMEWORK
|
||||
[NotMapped]
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction.Attributes" Version="1.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="UserManager.Domain" Version="3.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Dapper;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Infrastructure;
|
||||
|
||||
@@ -60,6 +61,7 @@ public static class DIExtensions
|
||||
services.AddDbRepository<EGDbContext, EnvelopeDocument>(context => context.EnvelopeDocument).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, DocumentStatus>(context => context.DocumentStatus).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, EmailTemplate>(context => context.EmailTemplate).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, EmailOut>(context => context.EMailOuts).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, Envelope>(context => context.Envelopes).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, EnvelopeHistory>(context => context.EnvelopeHistories).UseAutoMapper();
|
||||
services.AddDbRepository<EGDbContext, EnvelopeReceiver>(context => context.EnvelopeReceivers).UseAutoMapper();
|
||||
|
||||
@@ -7,7 +7,7 @@ using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Infrastructure.Repositories;
|
||||
|
||||
[Obsolete("Use Repository")]
|
||||
[Obsolete("Use TempRepo")]
|
||||
public class EmailTemplateRepository : CRUDRepository<EmailTemplate, int, EGDbContext>, IEmailTemplateRepository
|
||||
{
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
@@ -6,7 +6,7 @@ using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Infrastructure.Repositories;
|
||||
|
||||
[Obsolete("Use Repository")]
|
||||
[Obsolete("Use TempRepo")]
|
||||
public class EnvelopeHistoryRepository : CRUDRepository<EnvelopeHistory, long, EGDbContext>, IEnvelopeHistoryRepository
|
||||
{
|
||||
public EnvelopeHistoryRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeHistories)
|
||||
|
||||
@@ -8,7 +8,7 @@ using EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Infrastructure.Repositories;
|
||||
|
||||
[Obsolete("Use Repository")]
|
||||
[Obsolete("Use TempRepo")]
|
||||
public class EnvelopeReceiverRepository : CRUDRepository<EnvelopeReceiver, (int Envelope, int Receiver), EGDbContext>, IEnvelopeReceiverRepository
|
||||
{
|
||||
public EnvelopeReceiverRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeReceivers)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Application.Dto.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Application.Histories.Commands;
|
||||
using EnvelopeGenerator.Application.Histories.Queries;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
@@ -35,7 +36,7 @@ public class HistoryTests : TestBase
|
||||
var createReceiverCmd = this.CreateReceiverCommand();
|
||||
(var receiver, _) = await Mediator.Send(createReceiverCmd);
|
||||
|
||||
// Create EnvelopeReceiver
|
||||
// Create envelope receiver
|
||||
var envRcv = this.CreateEnvelopeReceiver(envelope.Id, receiver.Id);
|
||||
envRcv = await GetRepository<EnvelopeReceiver>().CreateAsync(envRcv, cancel);
|
||||
|
||||
@@ -53,38 +54,59 @@ public class HistoryTests : TestBase
|
||||
[Test]
|
||||
public async Task ReadHistory_Should_Filter_By_Status()
|
||||
{
|
||||
// Arrange
|
||||
/// Arrange
|
||||
CancellationToken cancel = default;
|
||||
|
||||
// Create envelope
|
||||
var envelope = FakeEnvelope;
|
||||
envelope = await GetRepository<Envelope>().CreateAsync(envelope, cancel);
|
||||
|
||||
// Create receiver
|
||||
var createReceiverCmd = this.CreateReceiverCommand();
|
||||
(var receiver, _) = await Mediator.Send(createReceiverCmd);
|
||||
|
||||
// Create envelope receiver
|
||||
var envRcv = this.CreateEnvelopeReceiver(envelope.Id, receiver.Id);
|
||||
envRcv = await GetRepository<EnvelopeReceiver>().CreateAsync(envRcv, cancel);
|
||||
|
||||
var createCmd1 = new CreateHistoryCommand
|
||||
{
|
||||
EnvelopeId = 2,
|
||||
UserReference = "UserX",
|
||||
Status = EnvelopeStatus.EnvelopeCreated
|
||||
EnvelopeId = envelope.Id,
|
||||
UserReference = receiver.EmailAddress,
|
||||
Status = EnvelopeStatus.AccessCodeRequested
|
||||
};
|
||||
|
||||
var createCmd2 = new CreateHistoryCommand
|
||||
{
|
||||
EnvelopeId = 2,
|
||||
UserReference = "UserX",
|
||||
Status = EnvelopeStatus.EnvelopePartlySigned
|
||||
EnvelopeId = envelope.Id,
|
||||
UserReference = receiver.EmailAddress,
|
||||
Status = EnvelopeStatus.EnvelopeCompletelySigned
|
||||
};
|
||||
|
||||
await Mediator.Send(createCmd1);
|
||||
await Mediator.Send(createCmd2);
|
||||
await Mediator.Send(createCmd1, cancel);
|
||||
await Mediator.Send(createCmd2, cancel);
|
||||
|
||||
// Act
|
||||
var result = await Mediator.Send(new ReadHistoryQuery(2, EnvelopeStatus.EnvelopePartlySigned));
|
||||
|
||||
var readQuery = new ReadHistoryQuery()
|
||||
{
|
||||
EnvelopeId = envelope.Id,
|
||||
Status = EnvelopeStatus.EnvelopeCompletelySigned
|
||||
};
|
||||
var result = await Mediator.Send(readQuery, cancel);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Has.Exactly(1).Items);
|
||||
Assert.That(result, Has.All.Matches<EnvelopeGenerator.Application.Dto.EnvelopeHistory.EnvelopeHistoryDto>(
|
||||
r => r.Status == EnvelopeStatus.EnvelopePartlySigned));
|
||||
Assert.That(result, Has.All.Matches<EnvelopeHistoryDto>(r => r.Status == EnvelopeStatus.EnvelopeCompletelySigned));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReadHistory_Should_Return_Empty_When_No_Record()
|
||||
{
|
||||
// Act
|
||||
var result = await Mediator.Send(new ReadHistoryQuery(999));
|
||||
var result = await Mediator.Send(new ReadHistoryQuery()
|
||||
{
|
||||
EnvelopeId = 9999
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.Empty);
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EnvelopeGenerator.CommonServices;
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers;
|
||||
|
||||
[Authorize(Roles = Domain.Constants.ReceiverRole.FullyAuth)]
|
||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DocumentController : BaseController
|
||||
public class DocumentController : ControllerBase
|
||||
{
|
||||
private readonly EnvelopeOldService envelopeService;
|
||||
private readonly ActionService? actionService;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
private readonly ILogger<DocumentController> _logger;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public DocumentController(DatabaseService database, EnvelopeOldService envelope, ILogger<DocumentController> logger) : base(database, logger)
|
||||
public DocumentController(IMediator mediator, ILogger<DocumentController> logger)
|
||||
{
|
||||
envelopeService = envelope;
|
||||
actionService = database.Services?.actionService;
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
[NonAction]
|
||||
public async Task<IActionResult> Get([FromRoute] string envelopeKey, [FromQuery] int index)
|
||||
[HttpGet("{envelopeKey}")]
|
||||
public async Task<IActionResult> GetDocument([FromRoute] string envelopeKey, CancellationToken cancel)
|
||||
{
|
||||
// Load document info
|
||||
var document = await envelopeService.GetDocument(index, envelopeKey);
|
||||
var envRcv = await _mediator.ReadEnvelopeReceiverAsync(envelopeKey, cancel) ?? throw new NotFoundException("Envelope Receiver is not found.");
|
||||
|
||||
// Load the document from disk
|
||||
var bytes = await envelopeService.GetDocumentContents(document);
|
||||
var byteData = envRcv.Envelope?.Documents?.FirstOrDefault()?.ByteData;
|
||||
|
||||
// Return the document as bytes
|
||||
return File(bytes, "application/octet-stream");
|
||||
if(byteData is null || byteData.Length == 0)
|
||||
{
|
||||
_logger.LogError("Document byte data is null or empty for envelope-receiver entity:\n{envelopeKey}.",
|
||||
JsonConvert.SerializeObject(envRcv, Format.Json.ForDiagnostics));
|
||||
throw new NotFoundException("Document is empty.");
|
||||
}
|
||||
|
||||
return File(byteData, "application/octet-stream");
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Encodings.Web;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Application.Interfaces.Services;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
@@ -12,8 +11,8 @@ using EnvelopeGenerator.Web.Extensions;
|
||||
using MediatR;
|
||||
using System.Dynamic;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
using Newtonsoft.Json;
|
||||
using EnvelopeGenerator.Application.Notifications.DocSigned;
|
||||
using DigitalData.Core.Exceptions;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers;
|
||||
|
||||
@@ -65,7 +64,11 @@ public class EnvelopeController : BaseController
|
||||
if (await _mediator.IsSignedAsync(uuid, signature, cancel))
|
||||
return Problem(statusCode: 403);
|
||||
|
||||
await _mediator.SignDocAsync(uuid, signature, JsonConvert.SerializeObject(annotations), cancel);
|
||||
var notification = await _mediator.ReadEnvelopeReceiverAsync(envelopeKey, cancel)
|
||||
.ToDocSignedNotification(annotations)
|
||||
?? throw new NotFoundException("Envelope receiver is not found.");
|
||||
|
||||
await _mediator.Publish(notification, cancel);
|
||||
|
||||
EnvelopeReceiver response = await envelopeService.LoadEnvelope(envelopeKey);
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
"SendingProfile": 1,
|
||||
"AddedWho": "DDEnvelopGenerator",
|
||||
"ReminderTypeId": 202377,
|
||||
"EmailAttmt1": ""
|
||||
"EmailAttmt1": null
|
||||
},
|
||||
"MailParams": {
|
||||
"Placeholders": {
|
||||
|
||||
Reference in New Issue
Block a user