Add FetchEmailByUidQuery with handler and validation
Introduced `FetchEmailByUidQuery` to fetch a single email by its UID from an IMAP mailbox. The query includes properties for email account, UID, folder, and attachment inclusion, with a fluent method `WithUid(long uid)` to set the UID. Added `FetchEmailByUidQueryHandler` to process the query, leveraging `ISender` for account retrieval and `IImapEmailService` for email fetching. Included error handling for missing accounts and misconfigured IMAP settings. Implemented `FetchEmailByUidQueryValidator` to validate the query, ensuring the `Account` is not null, `Uid` is set and greater than 0, and `Folder` is not empty.
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
using DigitalData.MessagingService.Abstraction;
|
||||||
|
using DigitalData.MessagingService.Application.Common.Interfaces;
|
||||||
|
using DigitalData.MessagingService.Application.EmailAccount.Queries;
|
||||||
|
using DigitalData.MessagingService.Domain.Exceptions;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace DigitalData.MessagingService.Application.EmailReceiving.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Query to fetch a single email by its UID from an IMAP mailbox.
|
||||||
|
/// </summary>
|
||||||
|
public record FetchEmailByUidQuery : IRequest<ReceivedEmailContext?>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the email account to use.
|
||||||
|
/// </summary>
|
||||||
|
public required GetSenderQuery Account { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UID of the message to fetch.
|
||||||
|
/// </summary>
|
||||||
|
internal long? Uid { get; private set; } = null;
|
||||||
|
|
||||||
|
public FetchEmailByUidQuery WithUid(long uid)
|
||||||
|
{
|
||||||
|
Uid = uid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mailbox folder the message resides in (default: "INBOX").
|
||||||
|
/// </summary>
|
||||||
|
public string Folder { get; init; } = "INBOX";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When <see langword="true"/>, attachment data is included in the result.
|
||||||
|
/// </summary>
|
||||||
|
public bool WithAttachments { get; init; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FetchEmailByUidQueryHandler(
|
||||||
|
ISender Sender,
|
||||||
|
IImapEmailService ImapService) : IRequestHandler<FetchEmailByUidQuery, ReceivedEmailContext?>
|
||||||
|
{
|
||||||
|
public async Task<ReceivedEmailContext?> Handle(FetchEmailByUidQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var account = await Sender.Send(request.Account, cancellationToken)
|
||||||
|
?? throw new NotFoundException(
|
||||||
|
$"No email account found for the given criteria (Id: {request.Account.Id}, Username: {request.Account.Username}).");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(account.ImapServer))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"IMAP is not configured for account '{account.Username}' (Id: {account.Id}). Set ImapServer in EmailAccounts configuration.");
|
||||||
|
|
||||||
|
return await ImapService.FetchEmailByUidAsync(
|
||||||
|
account,
|
||||||
|
(long)request.Uid!,
|
||||||
|
request.Folder,
|
||||||
|
request.WithAttachments,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using DigitalData.MessagingService.Application.EmailReceiving.Queries;
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace DigitalData.MessagingService.Application.EmailReceiving.Validators;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates a <see cref="FetchEmailByUidQuery"/> before it is handled by <see cref="FetchEmailByUidQueryHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class FetchEmailByUidQueryValidator : AbstractValidator<FetchEmailByUidQuery>
|
||||||
|
{
|
||||||
|
public FetchEmailByUidQueryValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Account)
|
||||||
|
.NotNull()
|
||||||
|
.WithMessage("Account query must not be null.");
|
||||||
|
|
||||||
|
RuleFor(x => x.Uid)
|
||||||
|
.NotNull()
|
||||||
|
.WithMessage("UID must be provided. Use WithUid() to set the UID before dispatching the query.")
|
||||||
|
.GreaterThan(0)
|
||||||
|
.WithMessage("UID must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.Folder)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("Folder must not be empty.");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user