diff --git a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentReceivedNotification.cs b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentReceivedNotification.cs
new file mode 100644
index 00000000..7ca460ab
--- /dev/null
+++ b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentReceivedNotification.cs
@@ -0,0 +1,73 @@
+using EnvelopeGenerator.Domain.Constants;
+
+namespace EnvelopeGenerator.Application.Common.Interfaces.Services.Notification;
+
+///
+///
+///
+public record DocumentReceivedNotification : EnvelopeNotificationBase
+{
+ ///
+ ///
+ ///
+ public required string DocumentTitle { get; init; }
+
+ ///
+ ///
+ ///
+ public required string NameReceiver { get; init; }
+
+ ///
+ ///
+ ///
+ public required string NameSender { get; init; }
+
+ ///
+ /// [SIGNATURE_TYPE]
+ ///
+ public required bool IsReadAndConfirm { private get; init; }
+
+ ///
+ ///
+ ///
+ public string SignatureType => IsReadAndConfirm ? "Signieren" : "Lesen und bestätigen";
+
+ ///
+ ///
+ ///
+ public required bool AdvancedSignature { private get; init; }
+
+ ///
+ ///
+ ///
+ public string DocumentProcess => AdvancedSignature ? " und elektronisch unterschreiben" : string.Empty;
+
+ ///
+ ///
+ ///
+ public required string LinkToDocument { get; init; }
+
+ ///
+ ///
+ ///
+ public string LinkToDocumentText => LinkToDocument[..Math.Min(LinkToDocument.Length, 40)];
+
+ ///
+ ///
+ ///
+ public required string Message { get; init; }
+
+ ///
+ ///
+ ///
+ public string NamePortal { get; set; } = "signFLOW Portal";
+
+ ///
+ ///
+ ///
+ ///
+ public override EmailTemplateType GetTemplateType()
+ {
+ return EmailTemplateType.DocumentReceived;
+ }
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentSignedNotification.cs b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentSignedNotification.cs
index 01fb3573..90784253 100644
--- a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentSignedNotification.cs
+++ b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/DocumentSignedNotification.cs
@@ -1,9 +1,11 @@
-namespace EnvelopeGenerator.Application.Common.Interfaces.Services.Notification;
+using EnvelopeGenerator.Domain.Constants;
+
+namespace EnvelopeGenerator.Application.Common.Interfaces.Services.Notification;
///
///
///
-public record DocumentSignedNotification
+public record DocumentSignedNotification : EnvelopeNotificationBase
{
///
///
@@ -19,11 +21,11 @@ public record DocumentSignedNotification
///
///
public string NamePortal { get; init; } = "signFLOW Portal";
-
+
///
///
///
- public required byte[] Attachment { get; init; }
+ public override EmailTemplateType GetTemplateType() => EmailTemplateType.DocumentSigned;
}
/*
diff --git a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/EnvelopeNotificationBase.cs b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/EnvelopeNotificationBase.cs
new file mode 100644
index 00000000..1d22fd01
--- /dev/null
+++ b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/EnvelopeNotificationBase.cs
@@ -0,0 +1,19 @@
+using EnvelopeGenerator.Domain.Constants;
+
+namespace EnvelopeGenerator.Application.Common.Interfaces.Services.Notification;
+
+///
+///
+///
+public abstract record EnvelopeNotificationBase
+{
+ ///
+ ///
+ ///
+ public abstract EmailTemplateType GetTemplateType();
+
+ ///
+ ///
+ ///
+ public List<(string FileName, byte[] Content)>? Attachments { get; init; }
+}
diff --git a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/IEnvelopeNotificationService.cs b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/IEnvelopeNotificationService.cs
index 2fb618f7..7ad10284 100644
--- a/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/IEnvelopeNotificationService.cs
+++ b/EnvelopeGenerator.Application/Common/Interfaces/Services/Notification/IEnvelopeNotificationService.cs
@@ -8,9 +8,11 @@ public interface IEnvelopeNotificationService
///
///
///
+ ///
///
- ///
+ ///
///
///
- public Task Notify(string email, DocumentSignedNotification documentSigned, CancellationToken cancel = default);
+ public Task Notify(string email, TEnvelopeNotificationBase notification, CancellationToken cancel = default)
+ where TEnvelopeNotificationBase : EnvelopeNotificationBase;
}
diff --git a/EnvelopeGenerator.Application/PdfSigning/FinalizeEnvelopeCommand.cs b/EnvelopeGenerator.Application/PdfSigning/FinalizeEnvelopeCommand.cs
index de3f469b..2a7aff81 100644
--- a/EnvelopeGenerator.Application/PdfSigning/FinalizeEnvelopeCommand.cs
+++ b/EnvelopeGenerator.Application/PdfSigning/FinalizeEnvelopeCommand.cs
@@ -98,7 +98,9 @@ public class FinalizeEnvelopeCommandHandler(IRepository Repo, ISender
{
DocumentTitle = envelope.Title,
NameReceiver = er.Name,
- Attachment = doc
+ Attachments = [
+ ($"unterzeichnetes-dokument.pdf", doc)
+ ]
}, cancel);
}
diff --git a/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationExtensions.cs b/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationExtensions.cs
new file mode 100644
index 00000000..f080363c
--- /dev/null
+++ b/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationExtensions.cs
@@ -0,0 +1,15 @@
+using DigitalData.MessagingService.Application.Common.Dto;
+
+namespace EnvelopeGenerator.Infrastructure.Notification;
+
+public static class EnvelopeNotificationExtensions
+{
+ public static EmailAttachmentDto ToEmailAttachmentDto(this (string FileName, byte[] Content) attachment) => new()
+ {
+ FileName = attachment.FileName,
+ Content = attachment.Content
+ };
+
+ public static IEnumerable ToEmailAttachmentDto(this IEnumerable<(string FileName, byte[] Content)> attachments)
+ => attachments.Select(ToEmailAttachmentDto);
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationService.cs b/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationService.cs
index 79e87020..5bf02122 100644
--- a/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationService.cs
+++ b/EnvelopeGenerator.Infrastructure.Notification/EnvelopeNotificationService.cs
@@ -1,11 +1,11 @@
using DigitalData.Core.Abstraction.Application.Repository;
-using DigitalData.Core.Exceptions;
using DigitalData.MessagingService.Application.Common.Dto;
using DigitalData.MessagingService.Client;
using DigitalData.MessagingService.Domain.Entities;
using EnvelopeGenerator.Application.Common.Interfaces.Services.Notification;
+using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
-using MediatR;
+using EnvelopeGenerator.Domain.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
@@ -13,32 +13,23 @@ namespace EnvelopeGenerator.Infrastructure.Notification;
public class EnvelopeNotificationService(IOptions EmailAccountOptions, IRepository TempRepo) : IEnvelopeNotificationService
{
- public async Task Notify(string email, DocumentSignedNotification documentSigned, CancellationToken cancel = default)
+ private async Task GetTemplateAsync(EmailTemplateType templateType, CancellationToken cancel = default)
{
- var template = await TempRepo.Where(t => t.Name == "DocumentCompleted").FirstOrDefaultAsync(cancel)
- ?? throw new NotFoundException("DocumentCompleted email template not found");
- var subjectTemplate = Replace(template.Subject, documentSigned);
- var bodyTemplate = Replace(template.Body, documentSigned);
+ return await TempRepo.Where(t => t.Name == templateType.ToString()).FirstOrDefaultAsync(cancel)
+ ?? throw new DataIntegrityException($"{templateType} email template not found");
+ }
+ public async Task Notify(string email, TEnvelopeNotificationBase notification, CancellationToken cancel = default)
+ where TEnvelopeNotificationBase : EnvelopeNotificationBase
+ {
+ var template = await GetTemplateAsync(notification.GetTemplateType(), cancel);
await EmailSender.Send(new EmailContext()
{
- Body = bodyTemplate,
- Subject = subjectTemplate,
+ Body = template.Body.ReplacePlaceholders(notification),
+ Subject = template.Subject.ReplacePlaceholders(notification),
Recipients = [email],
Sender = EmailAccountOptions.Value,
- Attachments = [new EmailAttachmentDto()
- {
- FileName = "unterzeichnetes-dokument.pdf",
- Content = documentSigned.Attachment
- }]
+ Attachments = notification.Attachments?.ToEmailAttachmentDto() ?? []
});
}
-
- private static string Replace(string template, DocumentSignedNotification documentSigned)
- {
- return template
- .Replace("[DOCUMENT_TITLE]", documentSigned.DocumentTitle)
- .Replace("[NAME_PORTAL]", documentSigned.NamePortal)
- .Replace("[NAME_RECEIVER]", documentSigned.NameReceiver);
- }
-}
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.Infrastructure.Notification/ReplacePlaceholderExtensions.cs b/EnvelopeGenerator.Infrastructure.Notification/ReplacePlaceholderExtensions.cs
new file mode 100644
index 00000000..3ffccb4c
--- /dev/null
+++ b/EnvelopeGenerator.Infrastructure.Notification/ReplacePlaceholderExtensions.cs
@@ -0,0 +1,47 @@
+using System.Collections.Concurrent;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace EnvelopeGenerator.Infrastructure.Notification;
+
+public static class ReplacePlaceholderExtensions
+{
+ private sealed record PlaceholderProperty(string Placeholder, PropertyInfo Property);
+
+ private static readonly ConcurrentDictionary PropertyCache = new();
+
+ public static string ReplacePlaceholders(this string template, object data)
+ {
+ var properties = PropertyCache.GetOrAdd(data.GetType(), CreatePlaceholderProperties);
+
+ foreach (var item in properties)
+ {
+ var value = item.Property.GetValue(data)?.ToString() ?? string.Empty;
+ template = template.Replace(
+ item.Placeholder,
+ value,
+ StringComparison.Ordinal);
+ }
+
+ return template;
+ }
+
+ private static PlaceholderProperty[] CreatePlaceholderProperties(
+ Type type)
+ {
+ return [.. type
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Where(p => p.CanRead && p.GetIndexParameters().Length == 0)
+ .Select(p => new PlaceholderProperty(
+ $"[{ToCapitalSnakeCase(p.Name)}]",
+ p))];
+ }
+
+ private static string ToCapitalSnakeCase(string name)
+ {
+ return Regex.Replace(
+ Regex.Replace(name, @"([A-Z]+)([A-Z][a-z])", "$1_$2"),
+ @"([a-z0-9])([A-Z])",
+ "$1_$2").ToUpperInvariant();
+ }
+}
\ No newline at end of file