refactor(application): Simplify SendEmailCommand and IEmailQueue/IEmailService interfaces, add Shared reference
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using DigitalData.EmailProfiler.Application.Common.Events;
|
||||
using DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
@@ -7,14 +8,14 @@ namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
/// </summary>
|
||||
public interface IEmailQueue
|
||||
{
|
||||
Task EnqueueAsync(EmailOutbox email, CancellationToken cancellationToken = default);
|
||||
Task<EmailOutbox?> DequeueAsync(CancellationToken cancellationToken = default);
|
||||
Task EnqueueAsync(OutgoingEmailEvent outgoingEmailEvent, CancellationToken cancellationToken = default);
|
||||
Task<OutgoingEmailEvent?> DequeueAsync(CancellationToken cancellationToken = default);
|
||||
Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Start event-driven consumer that calls callback when message received
|
||||
/// Start event-driven consumer that calls callback when mail received
|
||||
/// </summary>
|
||||
/// <param name="onMessageReceived">Callback to process received message</param>
|
||||
/// <param name="onMailReceived">Callback to process received mail</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
Task StartConsumerAsync(Func<EmailOutbox, Task> onMessageReceived, CancellationToken cancellationToken = default);
|
||||
Task StartConsumerAsync(Func<OutgoingEmailEvent, Task> onMailReceived, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using DigitalData.EmailProfiler.Application.Common.Dtos;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -18,4 +18,8 @@
|
||||
<PackageReference Include="MimeKit" Version="4.17.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Common\Dtos\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.EmailProfiler.Application.Common.Events;
|
||||
using DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
||||
@@ -8,13 +8,8 @@ namespace DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
||||
/// <summary>
|
||||
/// Command to send an email (enqueue to RabbitMQ)
|
||||
/// </summary>
|
||||
public record SendEmailCommand : IRequest<int>
|
||||
public record SendEmailCommand : IRequest<OutgoingEmailEvent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Email account ID to use for sending
|
||||
/// </summary>
|
||||
public required int EmailAccountId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Recipient email address
|
||||
/// </summary>
|
||||
@@ -34,37 +29,20 @@ public record SendEmailCommand : IRequest<int>
|
||||
/// Is HTML email (default: true)
|
||||
/// </summary>
|
||||
public bool IsHtml { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Optional reference string (e.g., ticket number, order ID)
|
||||
/// </summary>
|
||||
public string? ReferenceId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment
|
||||
/// </summary>
|
||||
public string? Comment { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for SendEmailCommand
|
||||
/// Creates EmailOutbox entity via AutoMapper and enqueues to RabbitMQ
|
||||
/// </summary>
|
||||
public class SendEmailCommandHandler(IEmailQueue EmailQueue, IMapper Mapper) : IRequestHandler<SendEmailCommand, int>
|
||||
public class SendEmailCommandHandler(IEmailQueue EmailQueue, IMapper Mapper) : IRequestHandler<SendEmailCommand, OutgoingEmailEvent>
|
||||
{
|
||||
public async Task<int> Handle(SendEmailCommand request, CancellationToken cancellationToken)
|
||||
public async Task<OutgoingEmailEvent> Handle(SendEmailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Map command to EmailOutbox entity using AutoMapper
|
||||
var emailOutbox = Mapper.Map<EmailOutbox>(request);
|
||||
|
||||
// Set audit fields
|
||||
emailOutbox.AddedWhen = DateTime.Now;
|
||||
emailOutbox.Sent = false;
|
||||
emailOutbox.RetryCount = 0;
|
||||
var outgoingEmailEvent = Mapper.Map<OutgoingEmailEvent>(request);
|
||||
|
||||
// Enqueue to RabbitMQ
|
||||
await EmailQueue.EnqueueAsync(emailOutbox, cancellationToken);
|
||||
|
||||
return emailOutbox.Id;
|
||||
await EmailQueue.EnqueueAsync(outgoingEmailEvent, cancellationToken);
|
||||
return outgoingEmailEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,6 @@ public class SendEmailCommandValidator : AbstractValidator<SendEmailCommand>
|
||||
{
|
||||
public SendEmailCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.EmailAccountId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("EmailAccountId must be greater than 0");
|
||||
|
||||
RuleFor(x => x.Recipient)
|
||||
.NotEmpty()
|
||||
.WithMessage("Recipient is required")
|
||||
@@ -31,15 +27,5 @@ public class SendEmailCommandValidator : AbstractValidator<SendEmailCommand>
|
||||
RuleFor(x => x.Body)
|
||||
.NotEmpty()
|
||||
.WithMessage("Body is required");
|
||||
|
||||
RuleFor(x => x.ReferenceId)
|
||||
.MaximumLength(200)
|
||||
.When(x => !string.IsNullOrEmpty(x.ReferenceId))
|
||||
.WithMessage("ReferenceId must not exceed 200 characters");
|
||||
|
||||
RuleFor(x => x.Comment)
|
||||
.MaximumLength(500)
|
||||
.When(x => !string.IsNullOrEmpty(x.Comment))
|
||||
.WithMessage("Comment must not exceed 500 characters");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user