Refactor email handling for improved structure
Refactored `Email` and `SendingEmailEvent` to use `record` types, consolidating email-related data into the `Email` class. Updated `SendEmailCommand` to return a `Guid` and simplified mapping logic in `EmailMappingProfile`. Adjusted `SendEmailCommandHandler` to construct `SendingEmailEvent` manually. Updated `SendingEmailConsumer`, `EmailsController`, and `EmailSender` to reflect the new structure. Removed the old `Email` implementation. Improved logging to reference the `Mail` property. Revised tests to align with the new structure, ensuring immutability and better separation of concerns.
This commit is contained in:
48
src/core/DigitalData.MessagingService.Abstraction/Email.cs
Normal file
48
src/core/DigitalData.MessagingService.Abstraction/Email.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace DigitalData.MessagingService.Abstraction;
|
||||
|
||||
public record Email
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
public EmailAccountDto Sender { get; set; } = null!;
|
||||
#else
|
||||
public required EmailAccountDto Sender { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Recipient email address
|
||||
/// </summary>
|
||||
|
||||
#if NETFRAMEWORK
|
||||
public IEnumerable<string> Recipients { get; set; } = null!;
|
||||
#else
|
||||
public required IEnumerable<string> Recipients { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Email subject
|
||||
/// </summary>
|
||||
|
||||
#if NETFRAMEWORK
|
||||
public string Subject { get; set; } = null!;
|
||||
#else
|
||||
public required string Subject { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Email body (HTML or plain text)
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK
|
||||
public string Body { get; set; } = null!;
|
||||
#else
|
||||
public required string Body { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Is HTML email (default: true)
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK
|
||||
public bool IsHtml { get; set; } = true;
|
||||
#else
|
||||
public bool IsHtml { get; init; } = true;
|
||||
#endif
|
||||
}
|
||||
@@ -2,29 +2,21 @@
|
||||
|
||||
public record SendingEmailEvent
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
public Guid Id { get; set; }
|
||||
#else
|
||||
public required Guid Id { get; init; }
|
||||
#endif
|
||||
|
||||
public EmailAccountDto Sender { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Recipient email address
|
||||
/// </summary>
|
||||
public IEnumerable<string> Recipients { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Email subject
|
||||
/// </summary>
|
||||
public string Subject { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Email body (HTML or plain text)
|
||||
/// </summary>
|
||||
public string Body { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Is HTML email (default: true)
|
||||
/// </summary>
|
||||
public bool IsHtml { get; set; } = true;
|
||||
#if NETFRAMEWORK
|
||||
public Email Mail { get; set; } = null!;
|
||||
#else
|
||||
public required Email Mail { get; init; }
|
||||
#endif
|
||||
|
||||
#if NETFRAMEWORK
|
||||
public DateTime QueuedAt { get; set; }
|
||||
#else
|
||||
public required DateTime QueuedAt { get; init; }
|
||||
#endif
|
||||
}
|
||||
@@ -11,11 +11,8 @@ public class EmailMappingProfile : Profile
|
||||
{
|
||||
public EmailMappingProfile()
|
||||
{
|
||||
// SendEmailCommand -> SendingEmailEvent
|
||||
// SendEmailCommand -> Email
|
||||
// Sender is resolved via MediatR in the handler and set separately after mapping.
|
||||
CreateMap<SendEmailCommand, SendingEmailEvent>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(_ => Guid.NewGuid()))
|
||||
.ForMember(dest => dest.QueuedAt, opt => opt.MapFrom(_ => DateTime.Now))
|
||||
.ForMember(dest => dest.Sender, opt => opt.Ignore());
|
||||
CreateMap<SendEmailCommand, Email>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace DigitalData.MessagingService.Application.EmailSending.Commands;
|
||||
/// <summary>
|
||||
/// Command to send an email (enqueue to RabbitMQ)
|
||||
/// </summary>
|
||||
public record SendEmailCommand : IRequest<SendingEmailEvent>
|
||||
public record SendEmailCommand : IRequest<Guid>
|
||||
{
|
||||
public required GetSenderQuery Sender { get; init; }
|
||||
|
||||
@@ -38,21 +38,24 @@ public record SendEmailCommand : IRequest<SendingEmailEvent>
|
||||
/// Handler for SendEmailCommand
|
||||
/// Resolves the sender account via MediatR, maps to SendingEmailEvent and enqueues to RabbitMQ
|
||||
/// </summary>
|
||||
public class SendEmailCommandHandler(
|
||||
ISender Sender,
|
||||
ISendingEmailPublisher Publisher,
|
||||
IMapper Mapper) : IRequestHandler<SendEmailCommand, SendingEmailEvent>
|
||||
public class SendEmailCommandHandler(ISender Sender, ISendingEmailPublisher Publisher, IMapper Mapper) : IRequestHandler<SendEmailCommand, Guid>
|
||||
{
|
||||
public async Task<SendingEmailEvent> Handle(SendEmailCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Guid> Handle(SendEmailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var senderAccount = await Sender.Send(request.Sender, cancellationToken)
|
||||
?? throw new NotFoundException(
|
||||
$"No email account found for the given sender criteria (Id: {request.Sender.Id}, Username: {request.Sender.Username}).");
|
||||
|
||||
var sendingEmailEvent = Mapper.Map<SendingEmailEvent>(request) with { Sender = senderAccount };
|
||||
var email = Mapper.Map<Email>(request) with { Sender = senderAccount };
|
||||
|
||||
// Enqueue to RabbitMQ
|
||||
var sendingEmailEvent = new SendingEmailEvent()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Mail = email,
|
||||
QueuedAt = DateTime.Now
|
||||
};
|
||||
await Publisher.EnqueueAsync(sendingEmailEvent, cancellationToken);
|
||||
return sendingEmailEvent;
|
||||
return sendingEmailEvent.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user