update: find mailbox id and name from any where

This commit is contained in:
mahyargdz
2025-07-12 12:13:26 +03:30
parent 24e315ff46
commit 352cdde13f
4 changed files with 114 additions and 32 deletions
+1
View File
@@ -203,6 +203,7 @@ export const enum EmailMessage {
MESSAGE_MOVED_TO_TRASH_SUCCESSFULLY = "پیام با موفقیت به سطل زباله منتقل شد", MESSAGE_MOVED_TO_TRASH_SUCCESSFULLY = "پیام با موفقیت به سطل زباله منتقل شد",
MESSAGE_MOVED_TO_INBOX_FROM_ARCHIVE_SUCCESSFULLY = "پیام با موفقیت از آرشیو به صندوق ورودی منتقل شد", MESSAGE_MOVED_TO_INBOX_FROM_ARCHIVE_SUCCESSFULLY = "پیام با موفقیت از آرشیو به صندوق ورودی منتقل شد",
MESSAGE_MOVED_TO_INBOX_FROM_FAVORITE_SUCCESSFULLY = "پیام با موفقیت از علاقه مندی ها به صندوق ورودی منتقل شد", MESSAGE_MOVED_TO_INBOX_FROM_FAVORITE_SUCCESSFULLY = "پیام با موفقیت از علاقه مندی ها به صندوق ورودی منتقل شد",
MESSAGE_NOT_FOUND = "پیام یافت نشد",
} }
export const enum WebSocketMessage { export const enum WebSocketMessage {
+2 -2
View File
@@ -31,7 +31,7 @@ export class EmailController {
return this.emailService.getEmailStatus(params.queueId); return this.emailService.getEmailStatus(params.queueId);
} }
@Get("messages/inbox/:messageId") @Get("messages/:messageId")
@ApiOperation({ summary: "Get a specific message" }) @ApiOperation({ summary: "Get a specific message" })
@ApiResponse({ status: 200, description: "Message details" }) @ApiResponse({ status: 200, description: "Message details" })
@ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 404, description: "Message not found" })
@@ -39,7 +39,7 @@ export class EmailController {
return this.emailService.getMessage(userId, params.messageId); return this.emailService.getMessage(userId, params.messageId);
} }
@Delete("messages/inbox/:messageId") @Delete("messages/:messageId")
@ApiOperation({ summary: "Delete a message" }) @ApiOperation({ summary: "Delete a message" })
@ApiResponse({ status: 200, description: "Message deleted successfully" }) @ApiResponse({ status: 200, description: "Message deleted successfully" })
@ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 404, description: "Message not found" })
+110 -27
View File
@@ -1,9 +1,10 @@
import { Injectable, Logger } from "@nestjs/common"; import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import { MailboxResolverService } from "./mailbox-resolver.service"; import { MailboxResolverService } from "./mailbox-resolver.service";
import { EmailMessage } from "../../../common/enums/message.enum"; import { EmailMessage } from "../../../common/enums/message.enum";
import { MailServerService } from "../../mail-server/services/mail-server.service"; import { MailServerService } from "../../mail-server/services/mail-server.service";
import { MailboxEnum } from "../../mailbox/enums/mailbox.enum";
import { MessageListQueryDto, SearchMessagesQueryDto } from "../DTO/email-query.dto"; import { MessageListQueryDto, SearchMessagesQueryDto } from "../DTO/email-query.dto";
import { SendEmailDto, UpdateDraftDto } from "../DTO/send-email.dto"; import { SendEmailDto, UpdateDraftDto } from "../DTO/send-email.dto";
import { EmailGateway } from "../email.gateway"; import { EmailGateway } from "../email.gateway";
@@ -111,13 +112,16 @@ export class EmailService {
//######################################################## //########################################################
async getMessage(userId: string, messageId: number) { async getMessage(userId: string, messageId: number) {
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
this.logger.log(`Getting message ${messageId} from inbox ${inboxMailboxId} for user: ${userId}`);
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
this.logger.log(`Getting message ${messageId} from ${messageLocation.mailboxName} mailbox for user: ${userId}`);
await this.markMessageAsSeen(userId, messageId); await this.markMessageAsSeen(userId, messageId);
const message = await firstValueFrom(this.mailServerService.messages.getMessage(userId, inboxMailboxId, messageId)); const message = await firstValueFrom(this.mailServerService.messages.getMessage(userId, messageLocation.mailboxId, messageId));
this.logger.log(`Retrieved message ${messageId} for user: ${userId}`); this.logger.log(`Retrieved message ${messageId} from ${messageLocation.mailboxName} for user: ${userId}`);
return { return {
message, message,
@@ -128,22 +132,65 @@ export class EmailService {
} }
} }
//########################################################
private async findMessageMailbox(userId: string, messageId: number): Promise<{ mailboxId: string; mailboxName: string } | null> {
try {
const mailboxIds = await this.mailboxResolverService.getUserMailboxIds(userId);
const mailboxesToSearch = [
{ id: mailboxIds.inbox, name: MailboxEnum.INBOX },
{ id: mailboxIds.sent, name: MailboxEnum.SENT },
{ id: mailboxIds.drafts, name: MailboxEnum.DRAFTS },
{ id: mailboxIds.trash, name: MailboxEnum.TRASH },
{ id: mailboxIds.archive, name: MailboxEnum.ARCHIVE },
{ id: mailboxIds.favorite, name: MailboxEnum.FAVORITE },
{ id: mailboxIds.junk, name: MailboxEnum.Junk },
];
for (const mailbox of mailboxesToSearch) {
if (!mailbox.id) continue;
try {
await firstValueFrom(this.mailServerService.messages.getMessage(userId, mailbox.id, messageId));
this.logger.log(`Message ${messageId} found in ${mailbox.name} mailbox`);
return { mailboxId: mailbox.id, mailboxName: mailbox.name };
} catch (_error) {
continue;
}
}
this.logger.warn(`Message ${messageId} not found in any mailbox for user ${userId}`);
return null;
} catch (error) {
this.logger.error(`Failed to find message ${messageId} for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//######################################################## //########################################################
async deleteMessage(userId: string, messageId: number) { async deleteMessage(userId: string, messageId: number) {
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, inboxMailboxId, messageId));
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
this.logger.log(`Deleting message ${messageId} from ${messageLocation.mailboxName} mailbox for user: ${userId}`);
const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, messageLocation.mailboxId, messageId));
// Emit WebSocket notification // Emit WebSocket notification
const payload: EmailDeletePayload = { const payload: EmailDeletePayload = {
messageId, messageId,
userId, userId,
mailboxId: inboxMailboxId, mailboxId: messageLocation.mailboxId,
mailboxName: "Inbox", mailboxName: messageLocation.mailboxName,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
await this.emailGateway.notifyMessageDeleted(payload); await this.emailGateway.notifyMessageDeleted(payload);
this.logger.log(`Message ${messageId} deleted successfully from ${messageLocation.mailboxName}`);
return { return {
success: true, success: true,
message: EmailMessage.MESSAGE_DELETED_SUCCESSFULLY, message: EmailMessage.MESSAGE_DELETED_SUCCESSFULLY,
@@ -158,19 +205,28 @@ export class EmailService {
//============================================== //==============================================
async markMessageAsSeen(userId: string, messageId: number) { async markMessageAsSeen(userId: string, messageId: number) {
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
const result = await firstValueFrom(this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { seen: true }));
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
this.logger.log(`Marking message ${messageId} as seen in ${messageLocation.mailboxName} mailbox for user: ${userId}`);
const result = await firstValueFrom(
this.mailServerService.messages.updateMessage(userId, messageLocation.mailboxId, messageId, { seen: true }),
);
// Emit WebSocket notification // Emit WebSocket notification
const payload: EmailStatusUpdatePayload = { const payload: EmailStatusUpdatePayload = {
messageId, messageId,
userId, userId,
status: "read", status: "read",
mailboxId: inboxMailboxId, mailboxId: messageLocation.mailboxId,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
await this.emailGateway.notifyMessageStatusUpdate(payload); await this.emailGateway.notifyMessageStatusUpdate(payload);
this.logger.log(`Message ${messageId} marked as seen successfully in ${messageLocation.mailboxName}`);
return { return {
success: true, success: true,
message: EmailMessage.MESSAGE_MARKED_AS_SEEN_SUCCESSFULLY, message: EmailMessage.MESSAGE_MARKED_AS_SEEN_SUCCESSFULLY,
@@ -394,11 +450,16 @@ export class EmailService {
this.logger.log(`Moving message ${messageId} to archive for user: ${userId}`); this.logger.log(`Moving message ${messageId} to archive for user: ${userId}`);
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
const archiveMailboxId = await this.mailboxResolverService.getArchiveMailboxId(userId); const archiveMailboxId = await this.mailboxResolverService.getArchiveMailboxId(userId);
this.logger.log(`Moving message ${messageId} from ${messageLocation.mailboxName} to ${MailboxEnum.ARCHIVE} for user: ${userId}`);
const result = await firstValueFrom( const result = await firstValueFrom(
this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { this.mailServerService.messages.updateMessage(userId, messageLocation.mailboxId, messageId, {
moveTo: archiveMailboxId, moveTo: archiveMailboxId,
}), }),
); );
@@ -407,15 +468,15 @@ export class EmailService {
const payload: EmailMovePayload = { const payload: EmailMovePayload = {
messageId, messageId,
userId, userId,
fromMailboxId: inboxMailboxId, fromMailboxId: messageLocation.mailboxId,
toMailboxId: archiveMailboxId, toMailboxId: archiveMailboxId,
fromMailboxName: "Inbox", fromMailboxName: messageLocation.mailboxName,
toMailboxName: "Archive", toMailboxName: MailboxEnum.ARCHIVE,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
await this.emailGateway.notifyMessageMoved(payload); await this.emailGateway.notifyMessageMoved(payload);
this.logger.log(`Message ${messageId} moved to archive successfully`); this.logger.log(`Message ${messageId} moved to archive successfully from ${messageLocation.mailboxName}`);
return { return {
success: true, success: true,
@@ -435,11 +496,16 @@ export class EmailService {
this.logger.log(`Moving message ${messageId} to favorite for user: ${userId}`); this.logger.log(`Moving message ${messageId} to favorite for user: ${userId}`);
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
const favoriteMailboxId = await this.mailboxResolverService.getFavoriteMailboxId(userId); const favoriteMailboxId = await this.mailboxResolverService.getFavoriteMailboxId(userId);
this.logger.log(`Moving message ${messageId} from ${messageLocation.mailboxName} to ${MailboxEnum.FAVORITE} for user: ${userId}`);
const result = await firstValueFrom( const result = await firstValueFrom(
this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { this.mailServerService.messages.updateMessage(userId, messageLocation.mailboxId, messageId, {
moveTo: favoriteMailboxId, moveTo: favoriteMailboxId,
}), }),
); );
@@ -448,15 +514,15 @@ export class EmailService {
const payload: EmailMovePayload = { const payload: EmailMovePayload = {
messageId, messageId,
userId, userId,
fromMailboxId: inboxMailboxId, fromMailboxId: messageLocation.mailboxId,
toMailboxId: favoriteMailboxId, toMailboxId: favoriteMailboxId,
fromMailboxName: "Inbox", fromMailboxName: messageLocation.mailboxName,
toMailboxName: "Favorite", toMailboxName: MailboxEnum.FAVORITE,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
await this.emailGateway.notifyMessageMoved(payload); await this.emailGateway.notifyMessageMoved(payload);
this.logger.log(`Message ${messageId} moved to favorite successfully`); this.logger.log(`Message ${messageId} moved to favorite successfully from ${messageLocation.mailboxName}`);
return { return {
success: true, success: true,
@@ -475,16 +541,33 @@ export class EmailService {
this.logger.log(`Moving message ${messageId} to trash for user: ${userId}`); this.logger.log(`Moving message ${messageId} to trash for user: ${userId}`);
try { try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); const messageLocation = await this.findMessageMailbox(userId, messageId);
if (!messageLocation) throw new BadRequestException(EmailMessage.MESSAGE_NOT_FOUND);
const trashMailboxId = await this.mailboxResolverService.getTrashMailboxId(userId); const trashMailboxId = await this.mailboxResolverService.getTrashMailboxId(userId);
this.logger.log(`Moving message ${messageId} from ${messageLocation.mailboxName} to ${MailboxEnum.TRASH} for user: ${userId}`);
const result = await firstValueFrom( const result = await firstValueFrom(
this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { this.mailServerService.messages.updateMessage(userId, messageLocation.mailboxId, messageId, {
moveTo: trashMailboxId, moveTo: trashMailboxId,
}), }),
); );
this.logger.log(`Message ${messageId} moved to trash successfully`); // Emit WebSocket notification
const payload: EmailMovePayload = {
messageId,
userId,
fromMailboxId: messageLocation.mailboxId,
toMailboxId: trashMailboxId,
fromMailboxName: messageLocation.mailboxName,
toMailboxName: MailboxEnum.TRASH,
timestamp: new Date().toISOString(),
};
await this.emailGateway.notifyMessageMoved(payload);
this.logger.log(`Message ${messageId} moved to trash successfully from ${messageLocation.mailboxName}`);
return { return {
success: true, success: true,
@@ -29,9 +29,7 @@ export class MailboxResolverService {
*/ */
async getUserMailboxIds(userId: string): Promise<UserMailboxIds> { async getUserMailboxIds(userId: string): Promise<UserMailboxIds> {
const cached = this.getCachedMailboxIds(userId); const cached = this.getCachedMailboxIds(userId);
if (cached) { if (cached) return cached;
return cached;
}
this.logger.log(`Fetching mailbox IDs for user: ${userId}`); this.logger.log(`Fetching mailbox IDs for user: ${userId}`);