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'; @Injectable() export class NotificationsService { private readonly logger = new Logger(NotificationsService.name); constructor( private readonly notificationRepository: NotificationsRepository, @Inject(forwardRef(() => RedisPubSubService)) private readonly redisPubSubService: RedisPubSubService, ) {} 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 }; } createNotification(notification: Partial) { this.logger.log(`Creating notification for user ${notification.userId}`); return this.notificationRepository.createNotification(notification); } 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(`emitting ${EventType.NOTIFICATION_CREATED} event`); const notification = await this.createNotification({ recipient: data.to, title: data.subject, message: '', scope: NotificationScope.USER_INVITED, channel: NotificationChannel.EMAIL, }); // return this.redisPubSubService.emit(EventType.NOTIFICATION_CREATED, notification, data.data); this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, { ...notification, data, }); } async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) { this.logger.log(`Sending OTP to ${sendOtpRequest.recipient}`); const notification = await 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, }); this.logger.log(`emitting ${EventType.NOTIFICATION_CREATED} event`); return this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, { ...notification, data: { otp }, }); } }