chore: add unread event for webscoket

This commit is contained in:
mahyargdz
2025-07-23 14:46:15 +03:30
parent 24783634fd
commit c739e0bd59
4 changed files with 55 additions and 40 deletions
@@ -134,6 +134,12 @@ export class EmailGateway implements OnGatewayInit, OnGatewayConnection, OnGatew
async notifyEmailRead(userId: string, data: EmailStatusPayload) {
return await this.sendUserNotification(userId, WEBSOCKET_EVENTS.EMAIL_READ, data, `Message ${data.messageId} marked as read`);
}
//************************************************************************ */
async notifyEmailUnread(userId: string, data: EmailStatusPayload) {
return await this.sendUserNotification(userId, WEBSOCKET_EVENTS.EMAIL_UNREAD, data, `Message ${data.messageId} marked as unread`);
}
//************************************************************************ */
async notifyEmailDeleted(userId: string, data: EmailDeletePayload) {
return await this.sendUserNotification(userId, WEBSOCKET_EVENTS.EMAIL_DELETED, data, `Message ${data.messageId} deleted`);
@@ -58,6 +58,41 @@ export class EmailNotificationService {
}
}
//************************************************************************ */
async notifyEmailUnread(params: EmailStatusNotificationParams) {
try {
const em = this.em.fork();
const user = await em.findOne(User, {
wildduckUserId: params.userId,
emailEnabled: true,
deletedAt: null,
});
if (!user) {
this.logger.warn(`User not found with wildduckUserId: ${params.userId}`);
return;
}
const payload: EmailStatusPayload = {
userId: user.id,
messageId: params.messageId,
mailboxId: params.mailboxId,
timestamp: new Date().toISOString(),
};
const success = await this.emailGateway.notifyEmailUnread(user.id, payload);
await this.updateUnreadCount(params.userId);
if (success) {
this.logger.log(`Email unread notification dispatched for user ${user.id}: message ${params.messageId}`);
} else {
this.logger.warn(`Failed to dispatch email unread notification for user ${user.id}: user not connected`);
}
} catch (error) {
this.logger.error(`Failed to notify email unread for user ${params.userId}:`, error);
}
}
//************************************************************************ */
async notifyEmailRead(params: EmailStatusNotificationParams) {
try {
@@ -237,6 +237,11 @@ export class EmailService {
async markMessageAsUnseen(wildduckUserId: string, messageId: number, mailboxId: string) {
const { updated } = await firstValueFrom(this.mailServerService.messages.updateMessage(wildduckUserId, mailboxId, messageId, { seen: false }));
await this.emailNotificationService.notifyEmailUnread({
userId: wildduckUserId,
messageId,
mailboxId,
});
return {
success: true,
message: EmailMessage.MESSAGE_MARKED_AS_UNSEEN_SUCCESSFULLY,
@@ -11,9 +11,7 @@ export class MailboxService {
constructor(private readonly mailServerService: MailServerService) {}
/**
* List all mailboxes for a user
*/
//########################################################
listMailboxes(userId: string, query?: MailboxQueryDto): Observable<any[]> {
this.logger.log(`Listing mailboxes for user: ${userId}`);
@@ -29,50 +27,27 @@ export class MailboxService {
);
}
/**
* Get mailbox message counts for a user
*/
//########################################################
getMailboxCounts(userId: string) {
this.logger.log(`Getting mailbox counts for user: ${userId}`);
return this.mailServerService.mailboxes.listMailboxes(userId, { counters: true }).pipe(
map((response) => {
this.logger.log(`Found ${response.results.length} mailboxes with counts for user: ${userId}`);
const mailboxes = response.results.map((mailbox) => ({
id: mailbox.id,
name: mailbox.name,
path: mailbox.path,
specialUse: mailbox.specialUse,
total: mailbox.total || 0,
unseen: mailbox.unseen || 0,
size: mailbox.size || 0,
total: mailbox.total || 0,
}));
const totalMailboxes = mailboxes.length;
const totalMessages = mailboxes.reduce((sum, mailbox) => sum + mailbox.total, 0);
const totalUnseen = mailboxes.reduce((sum, mailbox) => sum + mailbox.unseen, 0);
const totalSize = mailboxes.reduce((sum, mailbox) => sum + mailbox.size, 0);
return {
mailboxes,
totalMailboxes,
totalMessages,
totalUnseen,
totalSize,
};
return { mailboxes };
}),
catchError((error) => {
this.logger.error(`Failed to get mailbox counts for user ${userId}: ${error.message}`);
return throwError(() => error);
}),
);
}
/**
* Get a specific mailbox
*/
getMailbox(userId: string, mailboxId: string): Observable<any> {
//########################################################
getMailbox(userId: string, mailboxId: string) {
this.logger.log(`Getting mailbox ${mailboxId} for user: ${userId}`);
return this.mailServerService.mailboxes.getMailbox(userId, mailboxId).pipe(
@@ -90,9 +65,7 @@ export class MailboxService {
);
}
/**
* Create a new mailbox
*/
//########################################################
createMailbox(userId: string, createMailboxDto: CreateMailboxDto): Observable<any> {
this.logger.log(`Creating mailbox "${createMailboxDto.path}" for user: ${userId}`);
@@ -108,9 +81,7 @@ export class MailboxService {
);
}
/**
* Update a mailbox
*/
//########################################################
updateMailbox(userId: string, mailboxId: string, updateMailboxDto: UpdateMailboxDto): Observable<any> {
this.logger.log(`Updating mailbox ${mailboxId} for user: ${userId}`);
@@ -129,9 +100,7 @@ export class MailboxService {
);
}
/**
* Delete a mailbox
*/
//########################################################
deleteMailbox(userId: string, mailboxId: string): Observable<any> {
this.logger.log(`Deleting mailbox ${mailboxId} for user: ${userId}`);