//----------------------------------------------------------------------- // // Copyright (c) aliasvault. All rights reserved. // Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information. // //----------------------------------------------------------------------- namespace AliasVault.TaskRunner.Tasks; using AliasServerDb; using AliasVault.Shared.Server.Services; using Microsoft.EntityFrameworkCore; /// /// A maintenance task that deletes old emails based on server settings. /// public class EmailCleanupTask : IMaintenanceTask { private readonly ILogger _logger; private readonly IAliasServerDbContextFactory _dbContextFactory; private readonly ServerSettingsService _settingsService; /// /// Initializes a new instance of the class. /// /// The logger. /// The database context factory. /// The settings service. public EmailCleanupTask( ILogger logger, IAliasServerDbContextFactory dbContextFactory, ServerSettingsService settingsService) { _logger = logger; _dbContextFactory = dbContextFactory; _settingsService = settingsService; } /// public string Name => "Email Cleanup"; /// public async Task ExecuteAsync(CancellationToken cancellationToken) { var settings = await _settingsService.GetAllSettingsAsync(); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); var totalEmailsDeleted = 0; // First handle global retention settings if (settings.EmailRetentionDays > 0) { var globalCutoffDate = DateTime.UtcNow.AddDays(-settings.EmailRetentionDays); // Delete the emails based on global settings var globalEmailsDeleted = await dbContext.Emails .Where(x => x.DateSystem < globalCutoffDate) .ExecuteDeleteAsync(cancellationToken); if (globalEmailsDeleted > 0) { totalEmailsDeleted += globalEmailsDeleted; _logger.LogInformation( "Deleted {EmailCount} emails older than {Days} days (global setting)", globalEmailsDeleted, settings.EmailRetentionDays); } } // Now handle per-user age limits var usersWithAgeLimits = await dbContext.AliasVaultUsers .Where(u => u.MaxEmailAgeDays > 0) .Select(u => new { u.Id, u.UserName, u.MaxEmailAgeDays }) .ToListAsync(cancellationToken); foreach (var user in usersWithAgeLimits) { var userCutoffDate = DateTime.UtcNow.AddDays(-user.MaxEmailAgeDays); // Get all email addresses for this user var userAddresses = await dbContext.UserEmailClaims .Where(c => c.UserId == user.Id) .Select(c => c.Address) .ToListAsync(cancellationToken); if (userAddresses.Count > 0) { // Delete emails older than user's limit var userEmailsDeleted = await dbContext.Emails .Where(e => userAddresses.Contains(e.To) && e.DateSystem < userCutoffDate) .ExecuteDeleteAsync(cancellationToken); if (userEmailsDeleted > 0) { totalEmailsDeleted += userEmailsDeleted; _logger.LogInformation( "Deleted {EmailCount} emails older than {Days} days for user {UserName} (user-specific setting)", userEmailsDeleted, user.MaxEmailAgeDays, user.UserName); } } } if (totalEmailsDeleted > 0) { _logger.LogInformation( "Total emails deleted by age cleanup: {TotalEmails}", totalEmailsDeleted); } } }