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;
|
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||||
|
|
||||||
@@ -7,14 +8,14 @@ namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEmailQueue
|
public interface IEmailQueue
|
||||||
{
|
{
|
||||||
Task EnqueueAsync(EmailOutbox email, CancellationToken cancellationToken = default);
|
Task EnqueueAsync(OutgoingEmailEvent outgoingEmailEvent, CancellationToken cancellationToken = default);
|
||||||
Task<EmailOutbox?> DequeueAsync(CancellationToken cancellationToken = default);
|
Task<OutgoingEmailEvent?> DequeueAsync(CancellationToken cancellationToken = default);
|
||||||
Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default);
|
Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start event-driven consumer that calls callback when message received
|
/// Start event-driven consumer that calls callback when mail received
|
||||||
/// </summary>
|
/// </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>
|
/// <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;
|
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -18,4 +18,8 @@
|
|||||||
<PackageReference Include="MimeKit" Version="4.17.0" />
|
<PackageReference Include="MimeKit" Version="4.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Common\Dtos\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using DigitalData.EmailProfiler.Application.Common.Events;
|
||||||
using DigitalData.EmailProfiler.Application.Common.Interfaces;
|
using DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||||
using DigitalData.EmailProfiler.Domain.Entities;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
namespace DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
||||||
@@ -8,13 +8,8 @@ namespace DigitalData.EmailProfiler.Application.EmailSending.Commands;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command to send an email (enqueue to RabbitMQ)
|
/// Command to send an email (enqueue to RabbitMQ)
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Recipient email address
|
/// Recipient email address
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -34,37 +29,20 @@ public record SendEmailCommand : IRequest<int>
|
|||||||
/// Is HTML email (default: true)
|
/// Is HTML email (default: true)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsHtml { get; init; } = true;
|
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>
|
/// <summary>
|
||||||
/// Handler for SendEmailCommand
|
/// Handler for SendEmailCommand
|
||||||
/// Creates EmailOutbox entity via AutoMapper and enqueues to RabbitMQ
|
/// Creates EmailOutbox entity via AutoMapper and enqueues to RabbitMQ
|
||||||
/// </summary>
|
/// </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 outgoingEmailEvent = Mapper.Map<OutgoingEmailEvent>(request);
|
||||||
var emailOutbox = Mapper.Map<EmailOutbox>(request);
|
|
||||||
|
|
||||||
// Set audit fields
|
|
||||||
emailOutbox.AddedWhen = DateTime.Now;
|
|
||||||
emailOutbox.Sent = false;
|
|
||||||
emailOutbox.RetryCount = 0;
|
|
||||||
|
|
||||||
// Enqueue to RabbitMQ
|
// Enqueue to RabbitMQ
|
||||||
await EmailQueue.EnqueueAsync(emailOutbox, cancellationToken);
|
await EmailQueue.EnqueueAsync(outgoingEmailEvent, cancellationToken);
|
||||||
|
return outgoingEmailEvent;
|
||||||
return emailOutbox.Id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ public class SendEmailCommandValidator : AbstractValidator<SendEmailCommand>
|
|||||||
{
|
{
|
||||||
public SendEmailCommandValidator()
|
public SendEmailCommandValidator()
|
||||||
{
|
{
|
||||||
RuleFor(x => x.EmailAccountId)
|
|
||||||
.GreaterThan(0)
|
|
||||||
.WithMessage("EmailAccountId must be greater than 0");
|
|
||||||
|
|
||||||
RuleFor(x => x.Recipient)
|
RuleFor(x => x.Recipient)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("Recipient is required")
|
.WithMessage("Recipient is required")
|
||||||
@@ -31,15 +27,5 @@ public class SendEmailCommandValidator : AbstractValidator<SendEmailCommand>
|
|||||||
RuleFor(x => x.Body)
|
RuleFor(x => x.Body)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("Body is required");
|
.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