From f46c2ced99a8d994aee5591404b8b53190d4f015 Mon Sep 17 00:00:00 2001 From: mahyargdz Date: Wed, 30 Jul 2025 09:37:11 +0330 Subject: [PATCH] chore: update webscoket connetion and polling service --- src/common/enums/message.enum.ts | 1 + src/modules/email-gateway/email.gateway.ts | 8 +-- .../interfaces/email-polling-job.interface.ts | 1 + .../queue/email-polling.processor.ts | 44 +++++------- .../services/email-polling.service.ts | 8 ++- .../services/mailbox-resolver.service.ts | 70 +++++++++---------- .../email/constants/email-events.constant.ts | 12 ++-- src/modules/email/email.controller.ts | 12 ++-- src/modules/email/email.module.ts | 4 ++ .../email/interfaces/email.interface.ts | 1 + .../queue/email-bulk-action.processor.ts | 30 ++++---- src/modules/email/services/email.service.ts | 60 ++++++++++++---- src/modules/mail-server/DTO/message.dto.ts | 2 + 13 files changed, 140 insertions(+), 113 deletions(-) diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index a67fdb1..ce877bc 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -280,6 +280,7 @@ export const enum EmailMessage { MESSAGE_REMOVED_FROM_FAVORITE_SUCCESSFULLY = "پیام با موفقیت از مورد علاقه حذف شد", TRASH_EMPTYED_SUCCESSFULLY = "سطل زباله با موفقیت خالی شد", SPAM_EMPTYED_SUCCESSFULLY = "همه پیام های اسپم با موفقیت حذف شدند", + SAVE_DRAFT_SUCCESS = "پیش نویس با موفقیت ذخیره شد", } export const enum WebSocketMessage { diff --git a/src/modules/email-gateway/email.gateway.ts b/src/modules/email-gateway/email.gateway.ts index fb4b266..1fb2f1d 100644 --- a/src/modules/email-gateway/email.gateway.ts +++ b/src/modules/email-gateway/email.gateway.ts @@ -28,11 +28,7 @@ import { EmailPollingService } from "../email-utils/services/email-polling.servi @UsePipes(new ValidationPipe({ transform: true })) @UseFilters(WsExceptionFilter) -@WebSocketGateway({ - namespace: WEBSOCKET_NAMESPACES.EMAIL, - cors: { origin: true, credentials: true }, - transports: ["websocket", "polling"], -}) +@WebSocketGateway({ namespace: WEBSOCKET_NAMESPACES.EMAIL, cors: { origin: true, credentials: true }, transports: ["websocket", "polling"] }) export class EmailGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() server: Server; @@ -86,7 +82,7 @@ export class EmailGateway implements OnGatewayInit, OnGatewayConnection, OnGatew // Start email polling for this user try { - await this.emailPollingService.startPollingForUser(user.id, client.id); + await this.emailPollingService.startPollingForUser(user.wildduckUserId, user.id, client.id); this.logger.log(`Email polling started for user ${user.id}`); } catch (pollingError) { this.logger.error(`Failed to start email polling for user ${user.id}:`, pollingError); diff --git a/src/modules/email-utils/interfaces/email-polling-job.interface.ts b/src/modules/email-utils/interfaces/email-polling-job.interface.ts index 7e57e08..f4e5f31 100644 --- a/src/modules/email-utils/interfaces/email-polling-job.interface.ts +++ b/src/modules/email-utils/interfaces/email-polling-job.interface.ts @@ -1,4 +1,5 @@ export interface EmailPollingJobData { + wildduckUserId: string; userId: string; lastCheckTimestamp?: string; connectionId: string; diff --git a/src/modules/email-utils/queue/email-polling.processor.ts b/src/modules/email-utils/queue/email-polling.processor.ts index 1b0e007..135b91f 100644 --- a/src/modules/email-utils/queue/email-polling.processor.ts +++ b/src/modules/email-utils/queue/email-polling.processor.ts @@ -23,47 +23,41 @@ export class EmailPollingProcessor extends WorkerProcessor { } async process(job: Job): Promise { - const { userId, lastCheckTimestamp, connectionId } = job.data; + const { wildduckUserId, userId, lastCheckTimestamp, connectionId } = job.data; this.logger.debug(`Processing email polling job for user ${userId} (connection: ${connectionId})`); try { - // Check if user is still connected before processing if (!this.emailGateway.isUserConnected(userId)) { this.logger.debug(`User ${userId} no longer connected, skipping email check`); return; } - // Get user's mailbox information - const mailboxIds = await this.mailboxResolverService.getUserMailboxIds(userId); + const mailboxIds = await this.mailboxResolverService.getUserMailboxIds(wildduckUserId); if (!mailboxIds.inbox) { this.logger.warn(`No inbox found for user ${userId}`); return; } - // Calculate time range for checking new emails const checkSince = lastCheckTimestamp ? new Date(lastCheckTimestamp) : new Date(Date.now() - 5 * 60 * 1000); const now = new Date(); this.logger.debug(`Checking emails for user ${userId} since ${checkSince.toISOString()}`); - // Get new emails from inbox since last check - const newEmails = await this.getRecentEmails(userId, mailboxIds.inbox, checkSince); + const newEmails = await this.getRecentEmails(wildduckUserId, mailboxIds.inbox, checkSince); if (newEmails.length > 0) { - this.logger.log(`Found ${newEmails.length} new emails for user ${userId}`); - - // Notify user of each new email via websocket + this.logger.log(`Found ${newEmails.length} new emails for user ${wildduckUserId}`); const lastEmail = newEmails[newEmails.length - 1]; await this.emailGateway.notifyNewEmail(userId, { - wildduckUserId: userId, + wildduckUserId, + userId, messageId: lastEmail.id, date: lastEmail.date || new Date().toISOString(), from: lastEmail.from, to: lastEmail.to || [], subject: lastEmail.subject, - userId, timestamp: lastEmail.date || new Date().toISOString(), mailboxId: lastEmail.mailbox, mailboxName: "Inbox", @@ -72,7 +66,7 @@ export class EmailPollingProcessor extends WorkerProcessor { }); // Update unread count - const unreadStats = await this.getUnreadCounts(userId, mailboxIds); + const unreadStats = await this.getUnreadCounts(wildduckUserId, mailboxIds); await this.emailGateway.notifyUnreadCountUpdate(userId, { userId, totalUnread: unreadStats.total, @@ -96,15 +90,15 @@ export class EmailPollingProcessor extends WorkerProcessor { throw error; // Re-throw to trigger retry mechanism } } - - // Helper method to get recent emails from a mailbox - private async getRecentEmails(userId: string, mailboxId: string, since: Date) { + //======================================================= + private async getRecentEmails(wildduckUserId: string, mailboxId: string, since: Date) { try { const response = await firstValueFrom( - this.mailServerService.messages.searchMessages(userId, { + this.mailServerService.messages.searchMessages(wildduckUserId, { mailbox: mailboxId, - limit: 50, // Limit to avoid too many results - order: "desc", // Most recent first + limit: 50, + order: "desc", + unseen: true, }), ); @@ -117,22 +111,20 @@ export class EmailPollingProcessor extends WorkerProcessor { return emailDate >= since; }); } catch (error) { - this.logger.error(`Error fetching recent emails for user ${userId}:`, error); + this.logger.error(`Error fetching recent emails for user ${wildduckUserId}:`, error); return []; } } - - // Helper method to get unread counts from all mailboxes - private async getUnreadCounts(userId: string, mailboxIds: UserMailboxIds) { + //======================================================= + private async getUnreadCounts(wildduckUserId: string, mailboxIds: UserMailboxIds) { try { const mailboxCounts: Record = {}; let total = 0; - // Get unread count from each mailbox for (const [mailboxName, mailboxId] of Object.entries(mailboxIds)) { if (mailboxId) { try { - const response = await firstValueFrom(this.mailServerService.mailboxes.getMailbox(userId, mailboxId)); + const response = await firstValueFrom(this.mailServerService.mailboxes.getMailbox(wildduckUserId, mailboxId)); if (response.success && response.unseen !== undefined) { mailboxCounts[mailboxName] = response.unseen; @@ -150,7 +142,7 @@ export class EmailPollingProcessor extends WorkerProcessor { mailboxCounts, }; } catch (error) { - this.logger.error(`Error calculating unread counts for user ${userId}:`, error); + this.logger.error(`Error calculating unread counts for user ${wildduckUserId}:`, error); return { total: 0, mailboxCounts: {}, diff --git a/src/modules/email-utils/services/email-polling.service.ts b/src/modules/email-utils/services/email-polling.service.ts index 166e2b2..b668995 100644 --- a/src/modules/email-utils/services/email-polling.service.ts +++ b/src/modules/email-utils/services/email-polling.service.ts @@ -14,11 +14,12 @@ export class EmailPollingService { constructor(@InjectQueue(EMAIL_QUEUE_CONSTANTS.EMAIL_POLLING_QUEUE) private readonly emailPollingQueue: Queue) {} //======================================================= - async startPollingForUser(userId: string, connectionId: string): Promise { + async startPollingForUser(wildduckUserId: string, userId: string, connectionId: string): Promise { try { await this.stopPollingForUser(userId); const jobData: EmailPollingJobData = { + wildduckUserId, userId, connectionId, lastCheckTimestamp: new Date().toISOString(), @@ -54,6 +55,7 @@ export class EmailPollingService { async stopPollingForUser(userId: string): Promise { try { const activeJob = this.activeJobs.get(userId); + console.log(activeJob); if (!activeJob) { this.logger.debug(`No active polling job found for user ${userId}`); return; @@ -140,9 +142,9 @@ export class EmailPollingService { } //======================================================= - async restartPollingForUser(userId: string, connectionId: string): Promise { + async restartPollingForUser(wildduckUserId: string, userId: string, connectionId: string): Promise { this.logger.log(`Restarting email polling for user ${userId}`); await this.stopPollingForUser(userId); - await this.startPollingForUser(userId, connectionId); + await this.startPollingForUser(wildduckUserId, userId, connectionId); } } diff --git a/src/modules/email-utils/services/mailbox-resolver.service.ts b/src/modules/email-utils/services/mailbox-resolver.service.ts index 51b51e0..fdd02e6 100644 --- a/src/modules/email-utils/services/mailbox-resolver.service.ts +++ b/src/modules/email-utils/services/mailbox-resolver.service.ts @@ -18,14 +18,14 @@ export class MailboxResolverService { /** * Get user mailbox IDs with caching */ - async getUserMailboxIds(userId: string): Promise { - const cached = this.getCachedMailboxIds(userId); + async getUserMailboxIds(wildduckUserId: string): Promise { + const cached = this.getCachedMailboxIds(wildduckUserId); if (cached) return cached; - this.logger.log(`Fetching mailbox IDs for user: ${userId}`); + this.logger.log(`Fetching mailbox IDs for user: ${wildduckUserId}`); try { - const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(userId)); + const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(wildduckUserId)); const mailboxIds: UserMailboxIds = { inbox: this.findMailboxId(mailboxes.results, MailboxEnum.INBOX), @@ -37,12 +37,12 @@ export class MailboxResolverService { // favorite: this.findMailboxId(mailboxes.results, MailboxEnum.FAVORITE, false), }; - this.cacheMailboxIds(userId, mailboxIds); + this.cacheMailboxIds(wildduckUserId, mailboxIds); - this.logger.log(`Mailbox IDs cached for user: ${userId}`); + this.logger.log(`Mailbox IDs cached for user: ${wildduckUserId}`); return mailboxIds; } catch (error) { - this.logger.error(`Failed to fetch mailbox IDs for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); + this.logger.error(`Failed to fetch mailbox IDs for user ${wildduckUserId}: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } @@ -50,12 +50,12 @@ export class MailboxResolverService { /** * Get specific mailbox ID */ - async getMailboxId(userId: string, mailboxType: keyof UserMailboxIds): Promise { - const mailboxIds = await this.getUserMailboxIds(userId); + async getMailboxId(wildduckUserId: string, mailboxType: keyof UserMailboxIds): Promise { + const mailboxIds = await this.getUserMailboxIds(wildduckUserId); const mailboxId = mailboxIds[mailboxType]; if (!mailboxId) { - throw new NotFoundException(`${mailboxType} mailbox not found for user ${userId}`); + throw new NotFoundException(`${mailboxType} mailbox not found for user ${wildduckUserId}`); } return mailboxId; @@ -73,37 +73,37 @@ export class MailboxResolverService { /** * Get drafts mailbox ID */ - async getDraftsMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "drafts"); + async getDraftsMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "drafts"); } /** * Get inbox mailbox ID */ - async getInboxMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "inbox"); + async getInboxMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "inbox"); } /** * Get sent mailbox ID */ - async getSentMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "sent"); + async getSentMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "sent"); } /** * Get trash mailbox ID */ - async getTrashMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "trash"); + async getTrashMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "trash"); } - async getJunkMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "junk"); + async getJunkMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "junk"); } - async getArchiveMailboxId(userId: string): Promise { - return this.getMailboxId(userId, "archive"); + async getArchiveMailboxId(wildduckUserId: string): Promise { + return this.getMailboxId(wildduckUserId, "archive"); } // async getFavoriteMailboxId(userId: string): Promise { @@ -113,10 +113,10 @@ export class MailboxResolverService { /** * Clear cache for a specific user */ - clearUserCache(userId: string): void { - this.mailboxCache.delete(userId); - this.cacheExpiry.delete(userId); - this.logger.log(`Cache cleared for user: ${userId}`); + clearUserCache(wildduckUserId: string): void { + this.mailboxCache.delete(wildduckUserId); + this.cacheExpiry.delete(wildduckUserId); + this.logger.log(`Cache cleared for user: ${wildduckUserId}`); } /** @@ -131,18 +131,18 @@ export class MailboxResolverService { /** * Get cached mailbox IDs if not expired */ - private getCachedMailboxIds(userId: string): UserMailboxIds | null { - const cached = this.mailboxCache.get(userId); - const expiry = this.cacheExpiry.get(userId); + private getCachedMailboxIds(wildduckUserId: string): UserMailboxIds | null { + const cached = this.mailboxCache.get(wildduckUserId); + const expiry = this.cacheExpiry.get(wildduckUserId); if (cached && expiry && Date.now() < expiry) { - this.logger.debug(`Using cached mailbox IDs for user: ${userId}`); + this.logger.debug(`Using cached mailbox IDs for user: ${wildduckUserId}`); return cached; } if (cached) { - this.logger.debug(`Cache expired for user: ${userId}`); - this.clearUserCache(userId); + this.logger.debug(`Cache expired for user: ${wildduckUserId}`); + this.clearUserCache(wildduckUserId); } return null; @@ -151,9 +151,9 @@ export class MailboxResolverService { /** * Cache mailbox IDs with expiry */ - private cacheMailboxIds(userId: string, mailboxIds: UserMailboxIds): void { - this.mailboxCache.set(userId, mailboxIds); - this.cacheExpiry.set(userId, Date.now() + this.CACHE_DURATION); + private cacheMailboxIds(wildduckUserId: string, mailboxIds: UserMailboxIds): void { + this.mailboxCache.set(wildduckUserId, mailboxIds); + this.cacheExpiry.set(wildduckUserId, Date.now() + this.CACHE_DURATION); } /** diff --git a/src/modules/email/constants/email-events.constant.ts b/src/modules/email/constants/email-events.constant.ts index 3d0dee8..33f315c 100644 --- a/src/modules/email/constants/email-events.constant.ts +++ b/src/modules/email/constants/email-events.constant.ts @@ -49,13 +49,13 @@ export const EMAIL_QUEUE_CONSTANTS = { EMAIL_BULK_ACTION_DELAY: 1000, EMAIL_BULK_ACTION_BATCH_SIZE: 250, EMAIL_BULK_ACTION_ATTEMPTS: 3, - EMAIL_BULK_ACTION_BACKOFF_DELAY: 2000, // 2 seconds + EMAIL_BULK_ACTION_BACKOFF_DELAY: 2000, EMAIL_BULK_ACTION_PRIORITY: 1, // - EMAIL_POLLING_INTERVAL: 30000, // 30 seconds - EMAIL_POLLING_REMOVE_ON_COMPLETE: 5, // Keep last 5 completed jobs - EMAIL_POLLING_REMOVE_ON_FAIL: 10, // Keep last 10 failed jobs - EMAIL_POLLING_ATTEMPTS: 3, // Retry failed jobs 3 times - EMAIL_POLLING_BACKOFF_DELAY: 2000, // 2 seconds + EMAIL_POLLING_INTERVAL: 3000, + EMAIL_POLLING_REMOVE_ON_COMPLETE: true, + EMAIL_POLLING_REMOVE_ON_FAIL: 10, + EMAIL_POLLING_ATTEMPTS: 3, + EMAIL_POLLING_BACKOFF_DELAY: 2000, EMAIL_POLLING_PRIORITY: 1, } as const; diff --git a/src/modules/email/email.controller.ts b/src/modules/email/email.controller.ts index ba4e92a..ccddd66 100644 --- a/src/modules/email/email.controller.ts +++ b/src/modules/email/email.controller.ts @@ -115,24 +115,24 @@ export class EmailController { @ApiResponse({ status: 206, description: "Some messages marked as read, some failed" }) @ApiResponse({ status: 404, description: "Mailbox not found" }) @ApiResponse({ status: 403, description: "Not authorized to mark messages as read" }) - markAllMessagesAsRead(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) { - return this.emailService.markAllMessagesAsRead(userId, query.mailbox); + markAllMessagesAsRead(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) { + return this.emailService.markAllMessagesAsRead(wildduckUserId, userId, query.mailbox); } @Patch("messages/empty-trash") @ApiOperation({ summary: "Empty trash" }) @ApiResponse({ status: 200, description: "Trash emptied successfully" }) @ApiResponse({ status: 404, description: "Trash not found" }) - emptyTrash(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) { - return this.emailService.emptyTrash(userId, query.mailbox); + emptyTrash(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) { + return this.emailService.emptyTrash(wildduckUserId, userId, query.mailbox); } @Patch("messages/empty-spam") @ApiOperation({ summary: "Empty spam" }) @ApiResponse({ status: 200, description: "Spam emptied successfully" }) @ApiResponse({ status: 404, description: "Spam not found" }) - emptySpam(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) { - return this.emailService.emptySpam(userId, query.mailbox); + emptySpam(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) { + return this.emailService.emptySpam(wildduckUserId, userId, query.mailbox); } @Get("messages/inbox") diff --git a/src/modules/email/email.module.ts b/src/modules/email/email.module.ts index 450fa96..97d2659 100644 --- a/src/modules/email/email.module.ts +++ b/src/modules/email/email.module.ts @@ -17,6 +17,10 @@ import { User } from "../users/entities/user.entity"; imports: [ BullModule.registerQueue({ name: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_QUEUE, + defaultJobOptions: { + removeOnComplete: true, + removeOnFail: false, + }, }), MailServerModule, TemplatesModule, diff --git a/src/modules/email/interfaces/email.interface.ts b/src/modules/email/interfaces/email.interface.ts index c55494d..c5dfbdf 100644 --- a/src/modules/email/interfaces/email.interface.ts +++ b/src/modules/email/interfaces/email.interface.ts @@ -1,4 +1,5 @@ export interface IEmailBulkActionJob { wildduckUserId: string; + userId: string; mailboxId: string; } diff --git a/src/modules/email/queue/email-bulk-action.processor.ts b/src/modules/email/queue/email-bulk-action.processor.ts index 6122779..05e03bb 100644 --- a/src/modules/email/queue/email-bulk-action.processor.ts +++ b/src/modules/email/queue/email-bulk-action.processor.ts @@ -31,17 +31,17 @@ export class EmailBulkActionProcessor extends WorkerHost { switch (name) { case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_SEEN_ALL: this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`); - await this.markAllMessagesAsRead(data.wildduckUserId, data.mailboxId); + await this.markAllMessagesAsRead(data.wildduckUserId, data.userId, data.mailboxId); break; case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH: this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`); - await this.emptyTrash(data.wildduckUserId, data.mailboxId); + await this.emptyTrash(data.wildduckUserId, data.userId, data.mailboxId); break; case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM: this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`); - await this.emptySpam(data.wildduckUserId, data.mailboxId); + await this.emptySpam(data.wildduckUserId, data.userId, data.mailboxId); break; default: @@ -55,12 +55,11 @@ export class EmailBulkActionProcessor extends WorkerHost { } //============================================== - private async markAllMessagesAsRead(wildduckUserId: string, mailboxId: string) { + private async markAllMessagesAsRead(wildduckUserId: string, userId: string, mailboxId: string) { this.logger.log(`Marking all messages as read for user ${wildduckUserId} in mailbox ${mailboxId}`); try { - // Get all unread messages from the mailbox with a reasonable limit - const limit = EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BATCH_SIZE; // Process in batches to avoid memory issues + const limit = EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BATCH_SIZE; let totalMarked = 0; let hasMore = true; let next: string | undefined; @@ -72,11 +71,10 @@ export class EmailBulkActionProcessor extends WorkerHost { }; while (hasMore) { - // Fetch unread messages in batches const query: Record = { limit, order: "desc", - unseen: true, // Only get unread messages + unseen: true, }; if (next) { @@ -90,7 +88,6 @@ export class EmailBulkActionProcessor extends WorkerHost { break; } - // Mark each message as seen for (const message of response.results) { try { await this.emailService.markMessageAsSeen(wildduckUserId, message.id, mailboxId); @@ -105,7 +102,6 @@ export class EmailBulkActionProcessor extends WorkerHost { } } - // Check if there are more messages next = typeof response.nextCursor === "string" ? response.nextCursor : undefined; hasMore = !!next && response.results.length === limit; } @@ -113,12 +109,14 @@ export class EmailBulkActionProcessor extends WorkerHost { results.totalMarked = totalMarked; await this.emailNotificationService.notifyEmailRead({ - userId: wildduckUserId, + userId, messageId: results.successful[0], mailboxId, }); - this.logger.log(`Marked ${totalMarked} messages as read for user ${wildduckUserId} in mailbox ${mailboxId}, ${results.failed.length} failed`); + this.logger.verbose( + `Marked ${totalMarked} messages as read for user ${wildduckUserId} in mailbox ${mailboxId}, ${results.failed.length} failed`, + ); return { success: true, @@ -133,7 +131,7 @@ export class EmailBulkActionProcessor extends WorkerHost { //============================================== - private async emptyTrash(wildduckUserId: string, mailboxId: string) { + private async emptyTrash(wildduckUserId: string, userId: string, mailboxId: string) { this.logger.log(`Emptying trash for user ${wildduckUserId} in mailbox ${mailboxId}`); try { @@ -145,7 +143,7 @@ export class EmailBulkActionProcessor extends WorkerHost { } await this.emailNotificationService.notifyEmailDeleted({ - userId: wildduckUserId, + userId, messageId: randomInt(1, 500), mailboxId, }); @@ -162,7 +160,7 @@ export class EmailBulkActionProcessor extends WorkerHost { } //============================================== - private async emptySpam(wildduckUserId: string, mailboxId: string) { + private async emptySpam(wildduckUserId: string, userId: string, mailboxId: string) { this.logger.log(`Emptying spam for user ${wildduckUserId} in mailbox ${mailboxId}`); try { @@ -174,7 +172,7 @@ export class EmailBulkActionProcessor extends WorkerHost { } await this.emailNotificationService.notifyEmailDeleted({ - userId: wildduckUserId, + userId, messageId: randomInt(1, 500), mailboxId, }); diff --git a/src/modules/email/services/email.service.ts b/src/modules/email/services/email.service.ts index d42d285..968499e 100644 --- a/src/modules/email/services/email.service.ts +++ b/src/modules/email/services/email.service.ts @@ -88,7 +88,7 @@ export class EmailService { }); return { - message: EmailMessage.EMAIL_SENDING_SUCCESS, + message: sendEmailDto.isDraft ? EmailMessage.SAVE_DRAFT_SUCCESS : EmailMessage.EMAIL_SENDING_SUCCESS, messageId: response.message.id, queueId: response.message.queueId, }; @@ -109,15 +109,18 @@ export class EmailService { async searchMessages(wildduckUserId: string, query: SearchMessagesQueryDto) { const wildDuckQuery: SearchMessagesMailServerQueryDto = { ...query, - limit: query.limit || 20, + limit: 100, page: query.page || 1, order: query.order || "desc", + searchable: true, query: query.search, - from: query.from || query.search, - // mailbox: query.mailbox, + // subject: query.subject || query.search, + // from: query.from || query.search, + // to: query.to || query.search, }; delete wildDuckQuery?.mailbox; + delete wildDuckQuery.search; const response = await firstValueFrom(this.mailServerService.messages.searchMessages(wildduckUserId, wildDuckQuery)); @@ -283,11 +286,12 @@ export class EmailService { } //============================================== - async markAllMessagesAsRead(wildduckUserId: string, mailboxId: string) { + async markAllMessagesAsRead(wildduckUserId: string, userId: string, mailboxId: string) { await this.emailBulkActionQueue.add( EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_SEEN_ALL, { wildduckUserId, + userId, mailboxId, }, { @@ -308,11 +312,24 @@ export class EmailService { } //============================================== - async emptyTrash(wildduckUserId: string, mailboxId: string) { - await this.emailBulkActionQueue.add(EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH, { - wildduckUserId, - mailboxId, - }); + async emptyTrash(wildduckUserId: string, userId: string, mailboxId: string) { + await this.emailBulkActionQueue.add( + EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH, + { + wildduckUserId, + userId, + mailboxId, + }, + { + delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_DELAY, + priority: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_PRIORITY, + attempts: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_ATTEMPTS, + backoff: { + type: "exponential", + delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BACKOFF_DELAY, + }, + }, + ); return { success: true, @@ -321,11 +338,24 @@ export class EmailService { } //============================================== - async emptySpam(wildduckUserId: string, mailboxId: string) { - await this.emailBulkActionQueue.add(EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM, { - wildduckUserId, - mailboxId, - }); + async emptySpam(wildduckUserId: string, userId: string, mailboxId: string) { + await this.emailBulkActionQueue.add( + EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM, + { + wildduckUserId, + userId, + mailboxId, + }, + { + delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_DELAY, + priority: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_PRIORITY, + attempts: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_ATTEMPTS, + backoff: { + type: "exponential", + delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BACKOFF_DELAY, + }, + }, + ); return { success: true, diff --git a/src/modules/mail-server/DTO/message.dto.ts b/src/modules/mail-server/DTO/message.dto.ts index 1955434..82cc8d2 100644 --- a/src/modules/mail-server/DTO/message.dto.ts +++ b/src/modules/mail-server/DTO/message.dto.ts @@ -27,6 +27,8 @@ export class UpdateMessageDto { } export class SearchMessagesMailServerQueryDto { + search?: string; + q?: string; mailbox?: string;