From cb3b2e09ab781e7730c6085194892fcbcc015b1c Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 12 Aug 2026 12:42:15 +0200 Subject: [PATCH] Refactor email fetching logic in EmailController Consolidated email fetching endpoints by removing `FetchEmailUids` and `FetchEmailByUid` endpoints and integrating their functionality into the `FetchEmails` method. Introduced an `OnlyFilter` enum to allow filtering responses for HTML body or UIDs. Removed related methods (`FetchEmailUidsAsync`, `FetchEmailByUidAsync`) from `IImapEmailService` and deleted associated query classes and handlers. --- .../Common/Interfaces/IImapEmailService.cs | 21 ----- .../Queries/FetchEmailByUidQuery.cs | 62 -------------- .../Queries/FetchEmailUidsQuery.cs | 42 ---------- .../Controllers/EmailController.cs | 80 +++++++------------ 4 files changed, 28 insertions(+), 177 deletions(-) delete mode 100644 src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailByUidQuery.cs delete mode 100644 src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailUidsQuery.cs diff --git a/src/core/DigitalData.MessagingService.Application/Common/Interfaces/IImapEmailService.cs b/src/core/DigitalData.MessagingService.Application/Common/Interfaces/IImapEmailService.cs index 34145aa..445127b 100644 --- a/src/core/DigitalData.MessagingService.Application/Common/Interfaces/IImapEmailService.cs +++ b/src/core/DigitalData.MessagingService.Application/Common/Interfaces/IImapEmailService.cs @@ -22,27 +22,6 @@ public interface IImapEmailService MailSearchFilter filter, CancellationToken cancellationToken = default); - /// - /// Fetches only the UIDs of messages matching the specified filter. - /// - Task> FetchEmailUidsAsync( - EmailAccountDto account, - MailSearchFilter filter, - CancellationToken cancellationToken = default); - - /// - /// Fetches a single email by its UID. - /// - /// When (default), the message is marked as \Seen on the server. - /// Set to for a non-destructive read. - /// - Task FetchEmailByUidAsync( - EmailAccountDto account, - long uid, - string folder = "INBOX", - bool withAttachments = false, - CancellationToken cancellationToken = default); - /// /// Marks a message as seen (read) on the server. /// diff --git a/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailByUidQuery.cs b/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailByUidQuery.cs deleted file mode 100644 index 9597666..0000000 --- a/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailByUidQuery.cs +++ /dev/null @@ -1,62 +0,0 @@ -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; - -/// -/// Query to fetch a single email by its UID from an IMAP mailbox. -/// -public record FetchEmailByUidQuery : IRequest -{ - /// - /// Identifies the email account to use. - /// - public required GetSenderQuery Account { get; init; } - - /// - /// UID of the message to fetch. - /// - internal long? Uid { get; private set; } = null; - - public FetchEmailByUidQuery WithUid(long uid) - { - Uid = uid; - return this; - } - - /// - /// Mailbox folder the message resides in (default: "INBOX"). - /// - public string Folder { get; init; } = "INBOX"; - - /// - /// When , attachment data is included in the result. - /// - public bool WithAttachments { get; init; } = false; -} - -public class FetchEmailByUidQueryHandler( - ISender Sender, - IImapEmailService ImapService) : IRequestHandler -{ - public async Task 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); - } -} diff --git a/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailUidsQuery.cs b/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailUidsQuery.cs deleted file mode 100644 index 7c1d92b..0000000 --- a/src/core/DigitalData.MessagingService.Application/EmailReceiving/Queries/FetchEmailUidsQuery.cs +++ /dev/null @@ -1,42 +0,0 @@ -using DigitalData.MessagingService.Application.Common.Interfaces; -using DigitalData.MessagingService.Application.Common.Models.MailSearch; -using DigitalData.MessagingService.Application.EmailAccount.Queries; -using DigitalData.MessagingService.Domain.Exceptions; -using MediatR; - -namespace DigitalData.MessagingService.Application.EmailReceiving.Queries; - -/// -/// Query to fetch only the UIDs of matching emails from an IMAP mailbox. -/// -public record FetchEmailUidsQuery : IRequest> -{ - /// - /// Identifies the email account to use. - /// - public required GetSenderQuery Account { get; init; } - - /// - /// Mail query used to filter and limit the emails retrieved. - /// - public MailSearchFilter Mail { get; init; } = new(); -} - -public class FetchEmailUidsQueryHandler(ISender Sender, IImapEmailService ImapService) : IRequestHandler> -{ - public async Task> Handle(FetchEmailUidsQuery 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.FetchEmailUidsAsync( - account, - request.Mail, - cancellationToken); - } -} diff --git a/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs b/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs index 316bce6..720949c 100644 --- a/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs +++ b/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs @@ -16,6 +16,21 @@ namespace DigitalData.MessagingService.API.Controllers; [Route("api/[controller]")] public class EmailController(IMediator mediator) : ControllerBase { + /// + /// + /// + public enum OnlyFilter + { + /// + /// + /// + HtmlBody, + /// + /// + /// + Uid, + } + #region Send /// /// Send an email, optionally with file attachments. @@ -72,70 +87,31 @@ public class EmailController(IMediator mediator) : ControllerBase /// Fetch emails from an IMAP mailbox. /// /// Query parameters for filtering and fetching emails from the IMAP mailbox. - /// + /// /// Cancellation token. /// HTTP 200 with list of received emails. [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task FetchEmails([FromQuery] FetchEmailsQuery query, [FromQuery] bool firstHtmlBodyOnly = false, CancellationToken cancellationToken = default) + public async Task FetchEmails([FromQuery] FetchEmailsQuery query, [FromQuery] OnlyFilter? only = null, CancellationToken cancellationToken = default) { var emails = await mediator.Send(query, cancellationToken); if(!emails.Any()) return NotFound("No emails found matching the specified criteria."); - if (firstHtmlBodyOnly && emails.FirstOrDefault()?.HtmlBody is string htmlBody) - return Content(htmlBody, "text/html"); - - return Ok(emails); - } - - /// - /// Fetch only the UIDs of emails matching the given filter from an IMAP mailbox. - /// - /// Query parameters for filtering emails. - /// Cancellation token. - /// HTTP 200 with the list of matching UIDs, or HTTP 404 if none found. - [HttpGet("uid")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task FetchEmailUids([FromQuery] FetchEmailUidsQuery query, CancellationToken cancellationToken = default) - { - var uids = await mediator.Send(query, cancellationToken); - - if (!uids.Any()) - return NotFound("No emails found matching the specified criteria."); - - return Ok(uids); - } - - /// - /// Fetch a single email by its UID from an IMAP mailbox. - /// - /// The unique identifier (UID) of the message. - /// Query parameters including account, folder and attachment flag. - /// - /// Cancellation token. - /// HTTP 200 with the matched email, or HTTP 404 if not found. - [HttpGet("{uid:long}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task FetchEmailByUid([FromRoute] long uid, [FromQuery] FetchEmailByUidQuery query, [FromQuery] bool htmlBodyOnly = false, CancellationToken cancellationToken = default) - { - var queryWithUid = query.WithUid(uid); - var email = await mediator.Send(queryWithUid, cancellationToken); - - if (email is null) - return NotFound($"No email found with UID {uid}."); - - if (htmlBodyOnly) - return Content(email.HtmlBody, "text/html"); - - return Ok(email); + if (only == OnlyFilter.HtmlBody) + { + if (emails.FirstOrDefault()?.HtmlBody is string htmlBody) + return Content(htmlBody, "text/html"); + else + return NotFound(); + } + else if (only == OnlyFilter.Uid) + return Ok(emails.Select(e => e.Uid).ToList()); + else + return Ok(emails); } ///