chore: fix the send email problem

This commit is contained in:
Mahyargdz
2025-05-14 14:59:58 +03:30
parent 9bd662f872
commit 22ba9e52dc
6 changed files with 169 additions and 111 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ export function mailerConfig(): MailerAsyncOptions {
}, },
template: { template: {
dir: process.cwd() + "/src/templates/email", dir: process.cwd() + "/src/modules/templates/email",
adapter: new HandlebarsAdapter(), adapter: new HandlebarsAdapter(),
options: { options: {
strict: true, strict: true,
+4 -4
View File
@@ -10,7 +10,6 @@ import { AdminsService } from "../../users/providers/admins.service";
import { UsersService } from "../../users/providers/users.service"; import { UsersService } from "../../users/providers/users.service";
import { OTPService } from "../../utils/providers/otp.service"; import { OTPService } from "../../utils/providers/otp.service";
import { PasswordService } from "../../utils/providers/password.service"; import { PasswordService } from "../../utils/providers/password.service";
import { SmsService } from "../../utils/providers/sms.service";
import { ChangePasswordDto } from "../DTO/change-password.dto"; import { ChangePasswordDto } from "../DTO/change-password.dto";
import { CompleteRegistrationDto } from "../DTO/complete-register.dto"; import { CompleteRegistrationDto } from "../DTO/complete-register.dto";
import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto";
@@ -26,7 +25,6 @@ export class AuthService {
private readonly tokensService: TokensService, private readonly tokensService: TokensService,
private readonly dataSource: DataSource, private readonly dataSource: DataSource,
private readonly notificationQueue: NotificationQueue, private readonly notificationQueue: NotificationQueue,
private readonly smsService: SmsService,
private readonly referralsService: ReferralsService, private readonly referralsService: ReferralsService,
) {} ) {}
//****************** */ //****************** */
@@ -45,7 +43,8 @@ export class AuthService {
} }
const otpCode = await this.otpService.generateAndSetInCache(phone, "REGISTER"); 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 { return {
message: AuthMessage.OTP_SENT, message: AuthMessage.OTP_SENT,
@@ -169,7 +168,8 @@ export class AuthService {
const otpCode = await this.otpService.generateAndSetInCache(phone, "LOGIN"); 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 { return {
message: AuthMessage.OTP_SENT, message: AuthMessage.OTP_SENT,
@@ -1,6 +1,7 @@
export const NOTIFICATION = Object.freeze({ export const NOTIFICATION = Object.freeze({
QUEUE_NAME: "notification", QUEUE_NAME: "notification",
SEND_NOTIFICATION_JOB_NAME: "sendNotification", SEND_NOTIFICATION_JOB_NAME: "sendNotification",
SEND_LOGIN_OTP_JOB_NAME: "sendLoginOtp",
SEND_NOTIFICATION_JOB_DELAY: 1000, // delay after 1 second SEND_NOTIFICATION_JOB_DELAY: 1000, // delay after 1 second
SEND_NOTIFICATION_JOB_PRIORITY: 1, // high priority SEND_NOTIFICATION_JOB_PRIORITY: 1, // high priority
@@ -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;
};
@@ -6,7 +6,9 @@ import { DataSource } from "typeorm";
import { WorkerProcessor } from "../../../common/queues/worker.processor"; import { WorkerProcessor } from "../../../common/queues/worker.processor";
import { LoggerService } from "../../logger/logger.service"; import { LoggerService } from "../../logger/logger.service";
import { NotifType } from "../../settings/enums/notif-settings.enum"; import { NotifType } from "../../settings/enums/notif-settings.enum";
import { SmsService } from "../../utils/providers/sms.service";
import { NOTIFICATION } from "../constants"; import { NOTIFICATION } from "../constants";
import { NotificationJobData, OtpJobData } from "../interfaces/INotification-job-data";
import { import {
IAnnouncementNotificationData, IAnnouncementNotificationData,
IBlogCommentNotificationData, IBlogCommentNotificationData,
@@ -23,24 +25,6 @@ import {
} from "../interfaces/ISendNotificationData"; } from "../interfaces/ISendNotificationData";
import { NotificationsService } from "../providers/notifications.service"; 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, { @Processor(NOTIFICATION.QUEUE_NAME, {
concurrency: NOTIFICATION.SEND_NOTIFICATION_JOB_CONCURRENCY, concurrency: NOTIFICATION.SEND_NOTIFICATION_JOB_CONCURRENCY,
lockDuration: NOTIFICATION.SEND_NOTIFICATION_JOB_LOCK_DURATION, lockDuration: NOTIFICATION.SEND_NOTIFICATION_JOB_LOCK_DURATION,
@@ -54,11 +38,12 @@ export class NotificationProcessor extends WorkerProcessor {
private readonly notificationsService: NotificationsService, private readonly notificationsService: NotificationsService,
private readonly dataSource: DataSource, private readonly dataSource: DataSource,
protected readonly loggerService: LoggerService, protected readonly loggerService: LoggerService,
private readonly smsService: SmsService,
) { ) {
super(); super();
} }
async process(job: Job<NotificationJobData>, token?: string) { async process(job: Job<NotificationJobData | OtpJobData>, token?: string) {
this.logger.log(`Processing notification job: ${job.id} ${token ? `with token: ${token}` : ""}`); this.logger.log(`Processing notification job: ${job.id} ${token ? `with token: ${token}` : ""}`);
const queryRunner = this.dataSource.createQueryRunner(); const queryRunner = this.dataSource.createQueryRunner();
let heartbeat: NodeJS.Timeout | undefined; let heartbeat: NodeJS.Timeout | undefined;
@@ -71,11 +56,20 @@ export class NotificationProcessor extends WorkerProcessor {
heartbeat = setInterval(() => job.updateProgress(50), 10000); heartbeat = setInterval(() => job.updateProgress(50), 10000);
// //
const { type, recipientId, data } = job.data; 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) { switch (type) {
// Admin Notifications // Admin Notifications
case NotifType.NEW_BLOG_COMMENT: case NotifType.NEW_BLOG_COMMENT:
await this.notificationsService.createNewBlogCommentNotification(recipientId, data as IBlogCommentNotificationData, queryRunner); await this.notificationsService.createNewBlogCommentNotification(
recipientId,
data as IBlogCommentNotificationData,
queryRunner,
);
break; break;
case NotifType.NEW_SERVICE_REVIEW: case NotifType.NEW_SERVICE_REVIEW:
await this.notificationsService.createNewServiceReviewNotification( await this.notificationsService.createNewServiceReviewNotification(
@@ -122,14 +116,22 @@ export class NotificationProcessor extends WorkerProcessor {
await this.notificationsService.createTicketNotification(recipientId, data as ITicketNotificationData, queryRunner); await this.notificationsService.createTicketNotification(recipientId, data as ITicketNotificationData, queryRunner);
break; break;
case NotifType.ASSIGN_TICKET: case NotifType.ASSIGN_TICKET:
await this.notificationsService.createAssignTicketNotificationForAdmin(recipientId, data as ITicketNotificationData, queryRunner); await this.notificationsService.createAssignTicketNotificationForAdmin(
recipientId,
data as ITicketNotificationData,
queryRunner,
);
break; break;
// Invoice Notifications // Invoice Notifications
case NotifType.CREATE_INVOICE: case NotifType.CREATE_INVOICE:
await this.notificationsService.createInvoiceCreationNotification(recipientId, data as IInvoiceNotificationData, queryRunner); await this.notificationsService.createInvoiceCreationNotification(recipientId, data as IInvoiceNotificationData, queryRunner);
break; break;
case NotifType.BILL_INVOICE_REMINDER: case NotifType.BILL_INVOICE_REMINDER:
await this.notificationsService.createBillInvoiceReminderNotification(recipientId, data as IInvoiceNotificationData, queryRunner); await this.notificationsService.createBillInvoiceReminderNotification(
recipientId,
data as IInvoiceNotificationData,
queryRunner,
);
break; break;
case NotifType.BILL_INVOICE: case NotifType.BILL_INVOICE:
await this.notificationsService.createBillInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner); await this.notificationsService.createBillInvoiceNotification(recipientId, data as IInvoiceNotificationData, queryRunner);
@@ -152,11 +154,18 @@ export class NotificationProcessor extends WorkerProcessor {
await this.notificationsService.createPaymentReminderNotification(recipientId, data as IPaymentNotificationData, queryRunner); await this.notificationsService.createPaymentReminderNotification(recipientId, data as IPaymentNotificationData, queryRunner);
break; break;
case NotifType.PAYMENT_CANCELLATION: case NotifType.PAYMENT_CANCELLATION:
await this.notificationsService.createPaymentCancellationNotification(recipientId, data as IPaymentNotificationData, queryRunner); await this.notificationsService.createPaymentCancellationNotification(
recipientId,
data as IPaymentNotificationData,
queryRunner,
);
break; break;
default: default:
this.logger.warn(`Unknown notification type: ${type}`); this.logger.warn(`Unknown notification type: ${type}`);
} }
} else {
this.logger.warn(`Unknown job name: ${job.name}`);
}
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
return true; return true;
} catch (error) { } catch (error) {
@@ -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 // Admin notification methods
async addNewBlogCommentNotification(recipientId: string, data: IBlogCommentNotificationData) { async addNewBlogCommentNotification(recipientId: string, data: IBlogCommentNotificationData) {
await this.addNotificationJob(NotifType.NEW_BLOG_COMMENT, recipientId, data); await this.addNotificationJob(NotifType.NEW_BLOG_COMMENT, recipientId, data);
@@ -78,8 +90,6 @@ export class NotificationQueue {
await this.addNotificationJob(NotifType.CREATE_INVOICE, recipientId, data); await this.addNotificationJob(NotifType.CREATE_INVOICE, recipientId, data);
} }
//TODO:USE THIS
async addAnnouncementNotification(recipientId: string, data: IAnnouncementNotificationData) { async addAnnouncementNotification(recipientId: string, data: IAnnouncementNotificationData) {
await this.addNotificationJob(NotifType.ANNOUNCEMENT, recipientId, data); await this.addNotificationJob(NotifType.ANNOUNCEMENT, recipientId, data);
} }