From 22ba9e52dcd72169e1a9115a939bd22848e5c638 Mon Sep 17 00:00:00 2001 From: Mahyargdz Date: Wed, 14 May 2025 14:59:58 +0330 Subject: [PATCH] chore: fix the send email problem --- src/configs/mailer.config.ts | 2 +- src/modules/auth/providers/auth.service.ts | 8 +- src/modules/notifications/constants/index.ts | 1 + .../interfaces/INotification-job-data.ts | 38 +++ .../queue/notification.processor.ts | 217 +++++++++--------- .../notifications/queue/notification.queue.ts | 14 +- 6 files changed, 169 insertions(+), 111 deletions(-) create mode 100644 src/modules/notifications/interfaces/INotification-job-data.ts diff --git a/src/configs/mailer.config.ts b/src/configs/mailer.config.ts index d51a2c3..81ca9cc 100755 --- a/src/configs/mailer.config.ts +++ b/src/configs/mailer.config.ts @@ -20,7 +20,7 @@ export function mailerConfig(): MailerAsyncOptions { }, template: { - dir: process.cwd() + "/src/templates/email", + dir: process.cwd() + "/src/modules/templates/email", adapter: new HandlebarsAdapter(), options: { strict: true, diff --git a/src/modules/auth/providers/auth.service.ts b/src/modules/auth/providers/auth.service.ts index 8741ec9..4e25c17 100755 --- a/src/modules/auth/providers/auth.service.ts +++ b/src/modules/auth/providers/auth.service.ts @@ -10,7 +10,6 @@ import { AdminsService } from "../../users/providers/admins.service"; import { UsersService } from "../../users/providers/users.service"; import { OTPService } from "../../utils/providers/otp.service"; import { PasswordService } from "../../utils/providers/password.service"; -import { SmsService } from "../../utils/providers/sms.service"; import { ChangePasswordDto } from "../DTO/change-password.dto"; import { CompleteRegistrationDto } from "../DTO/complete-register.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto"; @@ -26,7 +25,6 @@ export class AuthService { private readonly tokensService: TokensService, private readonly dataSource: DataSource, private readonly notificationQueue: NotificationQueue, - private readonly smsService: SmsService, private readonly referralsService: ReferralsService, ) {} //****************** */ @@ -45,7 +43,8 @@ export class AuthService { } const otpCode = await this.otpService.generateAndSetInCache(phone, "REGISTER"); // - await this.smsService.sendSmsVerifyCode(phone, otpCode); + // await this.smsService.sendSmsVerifyCode(phone, otpCode); + await this.notificationQueue.addLoginOtpNotification({ phone, code: otpCode }); return { message: AuthMessage.OTP_SENT, @@ -169,7 +168,8 @@ export class AuthService { const otpCode = await this.otpService.generateAndSetInCache(phone, "LOGIN"); // - await this.smsService.sendSmsVerifyCode(phone, otpCode); + // await this.smsService.sendSmsVerifyCode(phone, otpCode); + await this.notificationQueue.addLoginOtpNotification({ phone, code: otpCode }); return { message: AuthMessage.OTP_SENT, diff --git a/src/modules/notifications/constants/index.ts b/src/modules/notifications/constants/index.ts index 199084c..d666efd 100644 --- a/src/modules/notifications/constants/index.ts +++ b/src/modules/notifications/constants/index.ts @@ -1,6 +1,7 @@ export const NOTIFICATION = Object.freeze({ QUEUE_NAME: "notification", SEND_NOTIFICATION_JOB_NAME: "sendNotification", + SEND_LOGIN_OTP_JOB_NAME: "sendLoginOtp", SEND_NOTIFICATION_JOB_DELAY: 1000, // delay after 1 second SEND_NOTIFICATION_JOB_PRIORITY: 1, // high priority diff --git a/src/modules/notifications/interfaces/INotification-job-data.ts b/src/modules/notifications/interfaces/INotification-job-data.ts new file mode 100644 index 0000000..84722a8 --- /dev/null +++ b/src/modules/notifications/interfaces/INotification-job-data.ts @@ -0,0 +1,38 @@ +import { + IAnnouncementNotificationData, + IBlogCommentNotificationData, + IInvoiceNotificationData, + INewCriticismNotificationData, + INewCustomerNotificationData, + INewSubscriptionNotificationData, + INewTicketNotificationData, + IPaymentNotificationData, + IServiceReviewNotificationData, + ISubscriptionNotificationData, + ITicketNotificationData, + IWalletNotificationData, +} from "./ISendNotificationData"; +import { NotifType } from "../../settings/enums/notif-settings.enum"; + +export type NotificationJobData = { + type: NotifType; + recipientId: string; + data: + | IBlogCommentNotificationData + | IServiceReviewNotificationData + | INewCustomerNotificationData + | INewSubscriptionNotificationData + | ITicketNotificationData + | INewCriticismNotificationData + | IInvoiceNotificationData + | IAnnouncementNotificationData + | IWalletNotificationData + | ISubscriptionNotificationData + | IPaymentNotificationData + | INewTicketNotificationData; +}; + +export type OtpJobData = { + phone: string; + code: string; +}; diff --git a/src/modules/notifications/queue/notification.processor.ts b/src/modules/notifications/queue/notification.processor.ts index 184ac9f..f889c23 100644 --- a/src/modules/notifications/queue/notification.processor.ts +++ b/src/modules/notifications/queue/notification.processor.ts @@ -6,7 +6,9 @@ import { DataSource } from "typeorm"; import { WorkerProcessor } from "../../../common/queues/worker.processor"; import { LoggerService } from "../../logger/logger.service"; import { NotifType } from "../../settings/enums/notif-settings.enum"; +import { SmsService } from "../../utils/providers/sms.service"; import { NOTIFICATION } from "../constants"; +import { NotificationJobData, OtpJobData } from "../interfaces/INotification-job-data"; import { IAnnouncementNotificationData, IBlogCommentNotificationData, @@ -23,24 +25,6 @@ import { } from "../interfaces/ISendNotificationData"; import { NotificationsService } from "../providers/notifications.service"; -type NotificationJobData = { - type: NotifType; - recipientId: string; - data: - | IBlogCommentNotificationData - | IServiceReviewNotificationData - | INewCustomerNotificationData - | INewSubscriptionNotificationData - | ITicketNotificationData - | INewCriticismNotificationData - | IInvoiceNotificationData - | IAnnouncementNotificationData - | IWalletNotificationData - | ISubscriptionNotificationData - | IPaymentNotificationData - | INewTicketNotificationData; -}; - @Processor(NOTIFICATION.QUEUE_NAME, { concurrency: NOTIFICATION.SEND_NOTIFICATION_JOB_CONCURRENCY, lockDuration: NOTIFICATION.SEND_NOTIFICATION_JOB_LOCK_DURATION, @@ -54,11 +38,12 @@ export class NotificationProcessor extends WorkerProcessor { private readonly notificationsService: NotificationsService, private readonly dataSource: DataSource, protected readonly loggerService: LoggerService, + private readonly smsService: SmsService, ) { super(); } - async process(job: Job, token?: string) { + async process(job: Job, token?: string) { this.logger.log(`Processing notification job: ${job.id} ${token ? `with token: ${token}` : ""}`); const queryRunner = this.dataSource.createQueryRunner(); let heartbeat: NodeJS.Timeout | undefined; @@ -71,91 +56,115 @@ export class NotificationProcessor extends WorkerProcessor { heartbeat = setInterval(() => job.updateProgress(50), 10000); // - const { type, recipientId, data } = job.data; - switch (type) { - // Admin Notifications - case NotifType.NEW_BLOG_COMMENT: - await this.notificationsService.createNewBlogCommentNotification(recipientId, data as IBlogCommentNotificationData, queryRunner); - break; - case NotifType.NEW_SERVICE_REVIEW: - await this.notificationsService.createNewServiceReviewNotification( - recipientId, - data as IServiceReviewNotificationData, - queryRunner, - ); - break; - case NotifType.NEW_CUSTOMER: - await this.notificationsService.createNewCustomerNotification(recipientId, data as INewCustomerNotificationData, queryRunner); - break; - case NotifType.NEW_SUBSCRIPTION: - await this.notificationsService.createNewSubscriptionNotification( - recipientId, - data as INewSubscriptionNotificationData, - queryRunner, - ); - break; - case NotifType.NEW_CRITICISM: - await this.notificationsService.createNewCriticismNotification(recipientId, data as INewCriticismNotificationData, queryRunner); - break; - case NotifType.NEW_TICKET: - await this.notificationsService.createNewTicketGlobalNotification(recipientId, data as INewTicketNotificationData, queryRunner); - break; - // User Notifications - case NotifType.USER_LOGIN: - await this.notificationsService.createLoginNotification(recipientId, data); - break; - case NotifType.ANNOUNCEMENT: - await this.notificationsService.createAnnouncementNotification(recipientId, data as IAnnouncementNotificationData, queryRunner); - break; - // Wallet Notifications - case NotifType.WALLET_CHARGE: - await this.notificationsService.createWalletChargeNotification(recipientId, data as IWalletNotificationData, queryRunner); - break; - case NotifType.WALLET_DEDUCTION: - await this.notificationsService.createWalletDeductionNotification(recipientId, data as IWalletNotificationData, queryRunner); - break; - // Ticket Notifications - case NotifType.ANSWER_TICKET: - await this.notificationsService.createAnswerTicketNotification(recipientId, data as ITicketNotificationData, queryRunner); - break; - case NotifType.CREATE_TICKET: - await this.notificationsService.createTicketNotification(recipientId, data as ITicketNotificationData, queryRunner); - break; - case NotifType.ASSIGN_TICKET: - await this.notificationsService.createAssignTicketNotificationForAdmin(recipientId, data as ITicketNotificationData, queryRunner); - break; - // Invoice Notifications - case NotifType.CREATE_INVOICE: - await this.notificationsService.createInvoiceCreationNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - case NotifType.BILL_INVOICE_REMINDER: - await this.notificationsService.createBillInvoiceReminderNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - case NotifType.BILL_INVOICE: - await this.notificationsService.createBillInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - case NotifType.APPROVE_INVOICE: - await this.notificationsService.createApprovedInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - case NotifType.INVOICE_OVERDUE: - await this.notificationsService.createInvoiceOverdueNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - case NotifType.RECURRING_INVOICE: - await this.notificationsService.createRecurringInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); - break; - // Service Notifications - case NotifType.BLOCK_SERVICE: - await this.notificationsService.createBlockServiceNotification(recipientId, data as ISubscriptionNotificationData, queryRunner); - break; - // Payment Notifications - case NotifType.PAYMENT_REMINDER: - await this.notificationsService.createPaymentReminderNotification(recipientId, data as IPaymentNotificationData, queryRunner); - break; - case NotifType.PAYMENT_CANCELLATION: - await this.notificationsService.createPaymentCancellationNotification(recipientId, data as IPaymentNotificationData, queryRunner); - break; - default: - this.logger.warn(`Unknown notification type: ${type}`); + if (job.name === NOTIFICATION.SEND_LOGIN_OTP_JOB_NAME) { + const { phone, code } = job.data as OtpJobData; + await this.smsService.sendSmsVerifyCode(phone, code); + // + } else if (job.name === NOTIFICATION.SEND_NOTIFICATION_JOB_NAME) { + const { type, recipientId, data } = job.data as NotificationJobData; + switch (type) { + // Admin Notifications + case NotifType.NEW_BLOG_COMMENT: + await this.notificationsService.createNewBlogCommentNotification( + recipientId, + data as IBlogCommentNotificationData, + queryRunner, + ); + break; + case NotifType.NEW_SERVICE_REVIEW: + await this.notificationsService.createNewServiceReviewNotification( + recipientId, + data as IServiceReviewNotificationData, + queryRunner, + ); + break; + case NotifType.NEW_CUSTOMER: + await this.notificationsService.createNewCustomerNotification(recipientId, data as INewCustomerNotificationData, queryRunner); + break; + case NotifType.NEW_SUBSCRIPTION: + await this.notificationsService.createNewSubscriptionNotification( + recipientId, + data as INewSubscriptionNotificationData, + queryRunner, + ); + break; + case NotifType.NEW_CRITICISM: + await this.notificationsService.createNewCriticismNotification(recipientId, data as INewCriticismNotificationData, queryRunner); + break; + case NotifType.NEW_TICKET: + await this.notificationsService.createNewTicketGlobalNotification(recipientId, data as INewTicketNotificationData, queryRunner); + break; + // User Notifications + case NotifType.USER_LOGIN: + await this.notificationsService.createLoginNotification(recipientId, data); + break; + case NotifType.ANNOUNCEMENT: + await this.notificationsService.createAnnouncementNotification(recipientId, data as IAnnouncementNotificationData, queryRunner); + break; + // Wallet Notifications + case NotifType.WALLET_CHARGE: + await this.notificationsService.createWalletChargeNotification(recipientId, data as IWalletNotificationData, queryRunner); + break; + case NotifType.WALLET_DEDUCTION: + await this.notificationsService.createWalletDeductionNotification(recipientId, data as IWalletNotificationData, queryRunner); + break; + // Ticket Notifications + case NotifType.ANSWER_TICKET: + await this.notificationsService.createAnswerTicketNotification(recipientId, data as ITicketNotificationData, queryRunner); + break; + case NotifType.CREATE_TICKET: + await this.notificationsService.createTicketNotification(recipientId, data as ITicketNotificationData, queryRunner); + break; + case NotifType.ASSIGN_TICKET: + await this.notificationsService.createAssignTicketNotificationForAdmin( + recipientId, + data as ITicketNotificationData, + queryRunner, + ); + break; + // Invoice Notifications + case NotifType.CREATE_INVOICE: + await this.notificationsService.createInvoiceCreationNotification(recipientId, data as IInvoiceNotificationData, queryRunner); + break; + case NotifType.BILL_INVOICE_REMINDER: + await this.notificationsService.createBillInvoiceReminderNotification( + recipientId, + data as IInvoiceNotificationData, + queryRunner, + ); + break; + case NotifType.BILL_INVOICE: + await this.notificationsService.createBillInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); + break; + case NotifType.APPROVE_INVOICE: + await this.notificationsService.createApprovedInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); + break; + case NotifType.INVOICE_OVERDUE: + await this.notificationsService.createInvoiceOverdueNotification(recipientId, data as IInvoiceNotificationData, queryRunner); + break; + case NotifType.RECURRING_INVOICE: + await this.notificationsService.createRecurringInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); + break; + // Service Notifications + case NotifType.BLOCK_SERVICE: + await this.notificationsService.createBlockServiceNotification(recipientId, data as ISubscriptionNotificationData, queryRunner); + break; + // Payment Notifications + case NotifType.PAYMENT_REMINDER: + await this.notificationsService.createPaymentReminderNotification(recipientId, data as IPaymentNotificationData, queryRunner); + break; + case NotifType.PAYMENT_CANCELLATION: + await this.notificationsService.createPaymentCancellationNotification( + recipientId, + data as IPaymentNotificationData, + queryRunner, + ); + break; + default: + this.logger.warn(`Unknown notification type: ${type}`); + } + } else { + this.logger.warn(`Unknown job name: ${job.name}`); } await queryRunner.commitTransaction(); return true; diff --git a/src/modules/notifications/queue/notification.queue.ts b/src/modules/notifications/queue/notification.queue.ts index 8144ff3..a12196e 100644 --- a/src/modules/notifications/queue/notification.queue.ts +++ b/src/modules/notifications/queue/notification.queue.ts @@ -44,6 +44,18 @@ export class NotificationQueue { ); } + //*********************************** */ + async addLoginOtpNotification(data: { phone: string; code: string }) { + await this.notificationsQueue.add(NOTIFICATION.SEND_LOGIN_OTP_JOB_NAME, data, { + delay: NOTIFICATION.SEND_NOTIFICATION_JOB_DELAY, + attempts: NOTIFICATION.SEND_NOTIFICATION_JOB_ATTEMPTS, + backoff: { + type: "exponential", + delay: NOTIFICATION.SEND_NOTIFICATION_JOB_BACKOFF, + }, + priority: NOTIFICATION.SEND_NOTIFICATION_JOB_PRIORITY, + }); + } // Admin notification methods async addNewBlogCommentNotification(recipientId: string, data: IBlogCommentNotificationData) { await this.addNotificationJob(NotifType.NEW_BLOG_COMMENT, recipientId, data); @@ -78,8 +90,6 @@ export class NotificationQueue { await this.addNotificationJob(NotifType.CREATE_INVOICE, recipientId, data); } - //TODO:USE THIS - async addAnnouncementNotification(recipientId: string, data: IAnnouncementNotificationData) { await this.addNotificationJob(NotifType.ANNOUNCEMENT, recipientId, data); }