Updated ReadEmailQuery to return a new response type,
ReadEmailQueryResponse, which includes both email data
and metadata (e.g., LastSync). Added the Account property
to ReadEmailQuery for specifying the email account.
Refactored ReadEmailQueryHandler to:
- Use IImapEmailService to fetch LastSync metadata.
- Return ReadEmailQueryResponse instead of a collection
of ReceivedEmailDto.
Introduced ReadEmailQueryResponse class to encapsulate
LastSync and Emails properties.
Updated EmailController to handle the new response
structure, ensuring compatibility with the updated
ReadEmailQuery and its handler.
Replaced `IMemoryCache` with a thread-safe `ConcurrentDictionary`
for managing IMAP sync dates in `LimilabsImapEmailService`. Added
`GetLastImapSyncDate` and `SetLastImapSyncDate` methods to handle
cache operations. Updated the `IImapEmailService` interface to
include `GetLastImapSyncDate`. Simplified the `MarkAsSeenAsync`
method signature for better readability. Introduced a private
record type `ImapCacheKey` to encapsulate cache keys.
Replaced `FetchEmailsAsync` with `SyncEmailsAsync` in `IImapEmailService` to simplify email synchronization. Updated method signatures to use `DateFilter` and added default parameters for `folder` and `cancel`.
Refactored `LimilabsImapEmailService` to remove client-side filtering logic and delegate storage to `IRepository<ReceivedEmail>`. Simplified IMAP search criteria to focus on date-based filtering and added checks to skip already-synced emails.
Updated `EmailSyncWorker` to use the new `SyncEmailsAsync` method. Removed unused code, streamlined exception handling, and improved maintainability by reducing complexity and focusing on server-side filtering.
Replaced `IMailRepository` with `IReceivedEmailRepository` to improve modularity and functionality. Updated `IReceivedEmailRepository` to make the `EmailAccount` parameter optional in the `FindAsync` method.
Added `ReceivedEmailRepository` with advanced filtering capabilities, including account, flags, text, UID, date, and recipient filters. Implemented deferred materialization for recipient filtering due to EF Core limitations.
Registered `IReceivedEmailRepository` in dependency injection. Updated `ReadEmailQueryHandler` to use the new repository. Improved query performance by applying filters conditionally.
Renamed the `IMailRepository` interface to `IReceivedEmailRepository`
to better reflect its purpose. Added a new `FindAsync` method to
the interface, which supports searching for received emails using
a `MailSearchFilter`, an `EmailAccount`, and an optional
`CancellationToken`. The method returns a `Task` resolving to
an `IEnumerable<ReceivedEmail>`.
Renamed `_dbSet` to `DbSet` and changed its accessibility from
`private` to `protected` to allow access in derived classes.
Updated all methods in the `Repository` class to use the new
`DbSet` field for querying, adding, updating, and removing
entities. This includes methods like `CreateAsync`,
`GetByIdAsync`, `FindAsync`, `UpsertAsync`, `UpdateAsync`,
and `DeleteAsync`.
Improved code consistency and readability by removing
redundant `_dbSet` references and standardizing on the
`DbSet` field.
Introduced a new `IMailRepository` interface to abstract email-fetching logic, replacing the direct dependency on `IImapEmailService` in `ReadEmailQueryHandler`. Updated `ReadEmailQueryHandler` to use `IMailRepository` for querying emails and added `IMapper` for mapping entities to DTOs.
Modified the constructor of `ReadEmailQueryHandler` to inject `IMailRepository`, `IMapper`, and renamed `IRepository<EmailAccount>` to `EmailAccountRepo`. Replaced `IImapEmailService.FetchEmailsAsync` with `IMailRepository.FindAsync` in the handler's `Handle` method.
Wrapped all changes in `#if NET` preprocessor directives to ensure compatibility with specific build configurations. These changes improve modularity, testability, and separation of concerns.
Renamed `FetchEmailsQuery` to `ReadEmailQuery` across the codebase, including its handler, validator, and usages in `EmailController`. Updated method signatures, dependencies, and XML documentation to reflect the new naming convention. Adjusted `ILogger` dependency in the handler to match the renamed class.
Simplified the `LimilabsImapEmailService` by removing the dependency on `IMemoryCache` and eliminating all caching logic. The constructor no longer accepts an `IMemoryCache` parameter, and the static `CacheKeyPrefix` field has been removed.
Replaced the caching mechanism with direct email fetching using `imap.GetMessageByUIDAsync`. Refactored the logic for processing attachments and visuals into `EmailAttachmentDto` objects, and streamlined the construction of `ReceivedEmailDto` to include metadata directly from the fetched email data.
These changes reduce complexity, improve maintainability, and ensure the service always retrieves the latest email data from the IMAP server.
- ExceptionHandlingMiddleware: map BadRequestException to 400 Bad Request response
- Add EmailAccountController: GET /email-accounts (with optional Id/Username filter),
POST/PUT/DELETE via EmailAccountModificationCommand for full CRUD over email accounts
- EmailSyncWorker now fetches active email accounts from IRepository<EmailAccount>
on every polling cycle instead of reading from static options list
- Add UpsertSeedEmailAccount: on startup, seed accounts from EmailAccountsOptions
into the database via IRepository.UpsertAsync (insert or update by Username)
- Remove standalone EmailAccountSyncWorker (merged into EmailSyncWorker)
- FetchEmailsQuery, MarkEmailAsSeenCommand, PublishEmailCommand: resolve EmailAccount
via IRepository<EmailAccount> instead of dispatching GetEmailAccountQuery through ISender
- Swap InvalidOperationException for BadRequestException when IMAP server is not configured
- Add ILogger to handlers; warn when multiple accounts match the lookup criteria
- EmailAccountsOptions.Accounts now typed as IEnumerable<EmailAccountModificationDto>
instead of IEnumerable<EmailAccount> to decouple config from domain entity
- EmailMappingProfile: add EmailAccount <-> EmailAccountDto/EmailAccountModificationDto maps
- Rename GetSenderQuery to GetEmailAccountQuery with updated return type (IEnumerable<EmailAccountDto>)
- Handler now queries IRepository<EmailAccount> directly instead of chaining MediatR dispatches
- Add EmailAccountModificationCommand for create/update/delete operations on email accounts
- Update GetSenderQueryValidator to reference renamed query type
- Remove exclusive Id/Username validation rule (now handled by repo query logic)
Introduced the `EmailAccountSyncWorker` background service to initialize and synchronize email accounts using RabbitMQ for event-driven processing. The service resolves email account configurations from application settings and upserts them into the repository.
Updated `MessagingServiceDbContext` to configure the `EmailAccount` entity, setting the `Username` property to use the `SQL_Latin1_General_CP1_CI_AS` collation for case-insensitive comparisons.
Added necessary `using` directives in `DependencyInjection.cs` to integrate new dependencies for AutoMapper, repositories, services, and background processing.
Introduce `EntitySelfMappingProfile` to enable self-mappings (T -> T) for domain entities (`EmailAccount`, `ReceivedEmail`, `EmailAttachment`). This ensures uniform AutoMapper usage in the generic repository, regardless of whether the target type is a DTO or the entity itself. Added necessary `using` directives for `AutoMapper` and domain entities.
Added `CreateAsync` for bulk entity creation and `UpsertAsync`
and `UpsertSingleAsync` for upsert operations in `IRepository`
and `Repository`. Improved error handling in `UpdateSingleAsync`
and `DeleteSingleAsync` by throwing `NotFoundException` when no
matching entity is found. Refactored `FindAsync` and `UpdateAsync`
for better readability and performance. Cleaned up formatting in
`DeleteAsync`.
Added the `Microsoft.EntityFrameworkCore.InMemory` package to enable an in-memory database for testing and lightweight storage. Introduced `MessagingServiceDbContext` with `DbSet` properties for `EmailAccount`, `ReceivedEmail`, and `EmailAttachment`. Configured entity relationships in `OnModelCreating`.
Registered `MessagingServiceDbContext` and a generic repository (`IRepository<>`) in the dependency injection container. Updated namespaces and imports to support the new DbContext and repository.
Improved project structure to enhance modularity and testability by leveraging EF Core's in-memory database.