From cecd9f90e9812a2bd84b2bb8026dbc9cce79741f Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sun, 10 May 2026 16:50:36 +0200 Subject: [PATCH] Implemented service bus handling of emails and notification processing --- .../SendShopEmailEnquiryEventHandler.cs | 18 +++++++++ .../Email/Events/SendShopEmailEnquiryEvent.cs | 40 +++++++++++++++++++ .../Commands/CreateNotificationCommand.cs | 9 ++--- .../Events/ProcessEmailNotificationsEvent.cs | 2 - .../LiteCharms.Infrastructure.csproj | 3 +- .../ServiceBus/Exchanges/EmailExchange.cs | 29 +++++++++++++- 6 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 LiteCharms.Features/Email/Events/Handlers/SendShopEmailEnquiryEventHandler.cs create mode 100644 LiteCharms.Features/Email/Events/SendShopEmailEnquiryEvent.cs diff --git a/LiteCharms.Features/Email/Events/Handlers/SendShopEmailEnquiryEventHandler.cs b/LiteCharms.Features/Email/Events/Handlers/SendShopEmailEnquiryEventHandler.cs new file mode 100644 index 0000000..9c19500 --- /dev/null +++ b/LiteCharms.Features/Email/Events/Handlers/SendShopEmailEnquiryEventHandler.cs @@ -0,0 +1,18 @@ +using LiteCharms.Features.Notifications.Commands; +using static LiteCharms.Abstractions.Constants; + +namespace LiteCharms.Features.Email.Events.Handlers; + +public class SendShopEmailEnquiryEventHandler(ISender mediator) : + INotificationHandler +{ + public async ValueTask Handle(SendShopEmailEnquiryEvent notification, CancellationToken cancellationToken) + { + var command = CreateNotificationCommand.Create(Models.NotificationDirection.Outgoing, notification.SenderName!, + notification.SenderAddress!, notification.Subject!, notification.Message!, Models.NotificationPlatforms.Email, + notification.Priority, ShopEmailFromName, ShopEmailFromAddress, Guid.CreateVersion7().ToString(), + Models.CorrelationIdTypes.None, isInternal: true, isHtml: false); + + await mediator.Send(command, cancellationToken); + } +} diff --git a/LiteCharms.Features/Email/Events/SendShopEmailEnquiryEvent.cs b/LiteCharms.Features/Email/Events/SendShopEmailEnquiryEvent.cs new file mode 100644 index 0000000..07e3830 --- /dev/null +++ b/LiteCharms.Features/Email/Events/SendShopEmailEnquiryEvent.cs @@ -0,0 +1,40 @@ +using LiteCharms.Abstractions; +using LiteCharms.Models; + +namespace LiteCharms.Features.Email.Events; + +public class SendShopEmailEnquiryEvent : EventBase, IEvent +{ + public string Name { get; set; } = nameof(SendShopEmailEnquiryEvent); + + public string? SenderName { get; set; } + + public string? SenderAddress { get; set; } + + public string? Subject { get; set; } + + public string? Message { get; set; } + + public Priorities Priority { get; set; } + + public SendShopEmailEnquiryEvent() { } + + private SendShopEmailEnquiryEvent(string senderName, string senderAddress, string subject, string message, Priorities priority = Priorities.Medium) + { + SenderName = senderName; + SenderAddress = senderAddress; + Subject = subject; + Message = message; + Priority = priority; + } + + public static SendShopEmailEnquiryEvent Create(string senderName, string senderAddress, string subject, string message, Priorities priority = Priorities.Medium) + { + ArgumentNullException.ThrowIfNullOrWhiteSpace(senderName, nameof(senderName)); + ArgumentNullException.ThrowIfNullOrWhiteSpace(senderAddress, nameof(senderAddress)); + ArgumentNullException.ThrowIfNullOrWhiteSpace(subject, nameof(subject)); + ArgumentNullException.ThrowIfNullOrWhiteSpace(message, nameof(message)); + + return new(senderName, senderAddress, subject, message, priority); + } +} diff --git a/LiteCharms.Features/Notifications/Commands/CreateNotificationCommand.cs b/LiteCharms.Features/Notifications/Commands/CreateNotificationCommand.cs index a9cf063..2b3e933 100644 --- a/LiteCharms.Features/Notifications/Commands/CreateNotificationCommand.cs +++ b/LiteCharms.Features/Notifications/Commands/CreateNotificationCommand.cs @@ -24,13 +24,13 @@ public class CreateNotificationCommand : IRequest> public string? CorrelationId { get; set; } - public string? CorrelationIdType { get; set; } + public CorrelationIdTypes CorrelationIdType { get; set; } public bool IsInternal { get; set; } public bool IsHtml { get; set; } - private CreateNotificationCommand(NotificationDirection direction, string sender, string senderAddress, string subject, string message, NotificationPlatforms platform, Priorities priority, string recipient, string recipientAddress, string correlationId, string correlationIdType, bool isInternal, bool isHtml = false) + private CreateNotificationCommand(NotificationDirection direction, string sender, string senderAddress, string subject, string message, NotificationPlatforms platform, Priorities priority, string recipient, string recipientAddress, string correlationId, CorrelationIdTypes correlationIdType, bool isInternal, bool isHtml = false) { Direction = direction; Sender = sender; @@ -47,7 +47,7 @@ public class CreateNotificationCommand : IRequest> IsHtml = isHtml; } - public static CreateNotificationCommand Create(NotificationDirection direction, string sender, string senderAddress, string subject, string message, NotificationPlatforms platform, Priorities priority, string recipient, string recipientAddress, string correlationId, string correlationIdType, bool isInternal, bool isHtml = false) + public static CreateNotificationCommand Create(NotificationDirection direction, string sender, string senderAddress, string subject, string message, NotificationPlatforms platform, Priorities priority, string recipient, string recipientAddress, string correlationId, CorrelationIdTypes correlationIdType, bool isInternal, bool isHtml = false) { if (string.IsNullOrWhiteSpace(sender)) throw new ArgumentException("Sender name is required.", nameof(sender)); @@ -67,9 +67,6 @@ public class CreateNotificationCommand : IRequest> if (string.IsNullOrWhiteSpace(correlationId)) throw new ArgumentException("CorrelationId is required.", nameof(correlationId)); - if (string.IsNullOrWhiteSpace(correlationIdType)) - throw new ArgumentException("CorrelationIdType is required.", nameof(correlationIdType)); - return new(direction, sender, senderAddress, subject, message, platform, priority, recipient, recipientAddress, correlationId, correlationIdType, isInternal, isHtml); } } diff --git a/LiteCharms.Features/Notifications/Events/ProcessEmailNotificationsEvent.cs b/LiteCharms.Features/Notifications/Events/ProcessEmailNotificationsEvent.cs index 3735ecd..9ac754f 100644 --- a/LiteCharms.Features/Notifications/Events/ProcessEmailNotificationsEvent.cs +++ b/LiteCharms.Features/Notifications/Events/ProcessEmailNotificationsEvent.cs @@ -8,8 +8,6 @@ public class ProcessEmailNotificationsEvent : EventBase, IEvent public int MaxRecords { get; set; } - public ProcessEmailNotificationsEvent() => MaxRecords = 1000; - private ProcessEmailNotificationsEvent(int maxRecords = 1000) => MaxRecords = maxRecords; public static ProcessEmailNotificationsEvent Create(int maxRecords = 1000) => new(maxRecords); diff --git a/LiteCharms.Infrastructure/LiteCharms.Infrastructure.csproj b/LiteCharms.Infrastructure/LiteCharms.Infrastructure.csproj index 765140f..b387b65 100644 --- a/LiteCharms.Infrastructure/LiteCharms.Infrastructure.csproj +++ b/LiteCharms.Infrastructure/LiteCharms.Infrastructure.csproj @@ -89,10 +89,11 @@ - + + diff --git a/LiteCharms.Infrastructure/ServiceBus/Exchanges/EmailExchange.cs b/LiteCharms.Infrastructure/ServiceBus/Exchanges/EmailExchange.cs index 52928fd..145ce46 100644 --- a/LiteCharms.Infrastructure/ServiceBus/Exchanges/EmailExchange.cs +++ b/LiteCharms.Infrastructure/ServiceBus/Exchanges/EmailExchange.cs @@ -2,11 +2,36 @@ namespace LiteCharms.Infrastructure.ServiceBus.Exchanges; -public class EmailExchange(EmailQueue messages) : BackgroundService +public class EmailExchange(EmailQueue messages, ILogger logger, IPublisher mediator) : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - if(messages.Incoming.CanCount) + while (!stoppingToken.IsCancellationRequested) + { + while (messages.Incoming.TryRead(out var message)) + { + try + { + switch (message.Name) + { + case "SendShopEmailEnquiryEvent": + await mediator.Publish(message, stoppingToken); + break; + case "ProcessEmailNotificationsEvent": + await mediator.Publish(message, stoppingToken); + break; + default: + logger.LogWarning("Unsupported email event {Event}", message.Name); + break; + } + } + catch (Exception ex) + { + logger.LogError(ex, ex.Message); + } + } + await Task.Delay(1000, stoppingToken); + } } }