mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 18:31:46 +00:00
- Implement messaging system factory pattern - Fix all transaction notification blockers - Complete listener logic for all notification types
90 lines
3.4 KiB
TypeScript
90 lines
3.4 KiB
TypeScript
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
|
|
import { RedisPubSubService } from '~/common/redis/services';
|
|
import { PageOptionsRequestDto } from '~/core/dtos';
|
|
import { OTP_BODY, OTP_TITLE } from '../../otp/constants';
|
|
import { OtpType } from '../../otp/enums';
|
|
import { ISendOtp } from '../../otp/interfaces';
|
|
import { SendEmailRequestDto } from '../dtos/request';
|
|
import { Notification } from '../entities';
|
|
import { EventType, NotificationChannel, NotificationScope } from '../enums';
|
|
import { NotificationsRepository } from '../repositories';
|
|
import { MessagingSystemFactory } from './messaging/messaging-system-factory.service';
|
|
|
|
@Injectable()
|
|
export class NotificationsService {
|
|
private readonly logger = new Logger(NotificationsService.name);
|
|
constructor(
|
|
private readonly notificationRepository: NotificationsRepository,
|
|
|
|
@Inject(forwardRef(() => RedisPubSubService))
|
|
private readonly redisPubSubService: RedisPubSubService,
|
|
private readonly messagingSystemFactory: MessagingSystemFactory,
|
|
) {}
|
|
|
|
async getNotifications(userId: string, pageOptionsDto: PageOptionsRequestDto) {
|
|
this.logger.log(`Getting notifications for user ${userId}`);
|
|
const [[notifications, count], unreadCount] = await Promise.all([
|
|
this.notificationRepository.getNotifications(userId, pageOptionsDto),
|
|
this.notificationRepository.getUnreadNotificationsCount(userId),
|
|
]);
|
|
|
|
this.logger.log(`Returning notifications for user ${userId}`);
|
|
|
|
return { notifications, count, unreadCount };
|
|
}
|
|
|
|
async createNotification(notification: Partial<Notification>) {
|
|
this.logger.log(`Creating notification for user ${notification.userId}`);
|
|
const savedNotification = await this.notificationRepository.createNotification(notification);
|
|
|
|
const scope = notification.scope || NotificationScope.USER_REGISTERED;
|
|
const messagingSystem = this.messagingSystemFactory.getMessagingSystem(scope);
|
|
|
|
this.logger.log(
|
|
`Publishing ${EventType.NOTIFICATION_CREATED} event to ${messagingSystem.getName()}`
|
|
);
|
|
|
|
messagingSystem.publish(EventType.NOTIFICATION_CREATED, {
|
|
...savedNotification,
|
|
data: notification.data || savedNotification.data,
|
|
}).catch((error) => {
|
|
this.logger.error(
|
|
`Failed to publish notification ${savedNotification.id} to ${messagingSystem.getName()}: ` +
|
|
`${error?.message || 'Unknown error'}`,
|
|
error?.stack
|
|
);
|
|
});
|
|
|
|
return savedNotification;
|
|
}
|
|
|
|
markAsRead(userId: string) {
|
|
this.logger.log(`Marking notifications as read for user ${userId}`);
|
|
return this.notificationRepository.markAsRead(userId);
|
|
}
|
|
|
|
async sendEmailAsync(data: SendEmailRequestDto) {
|
|
this.logger.log(`Creating email notification for ${data.to}`);
|
|
await this.createNotification({
|
|
recipient: data.to,
|
|
title: data.subject,
|
|
message: '',
|
|
scope: NotificationScope.USER_INVITED,
|
|
channel: NotificationChannel.EMAIL,
|
|
data: data.data,
|
|
});
|
|
}
|
|
|
|
async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) {
|
|
this.logger.log(`Sending OTP to ${sendOtpRequest.recipient}`);
|
|
return this.createNotification({
|
|
recipient: sendOtpRequest.recipient,
|
|
title: OTP_TITLE,
|
|
message: OTP_BODY.replace('{otp}', otp),
|
|
scope: NotificationScope.OTP,
|
|
channel: sendOtpRequest.otpType === OtpType.EMAIL ? NotificationChannel.EMAIL : NotificationChannel.SMS,
|
|
data: { otp },
|
|
});
|
|
}
|
|
}
|