Prashikshak / API /src /services /notification.service.ts
Abhisingh-18's picture
Initial commit: Prashikshak - disaster management training platform
9a92a42
Raw
History Blame Contribute Delete
4.37 kB
import Event from '../model/event.model';
import User from '../model/user.model';
import sendMail from '../util/mailer.util';
import Queue from 'bull';
import { REDIS_URL } from '../config/env.config';
// Create Bull queues for async job processing
const emailQueue = new Queue('email-notifications', REDIS_URL || 'redis://localhost:6379');
const reminderQueue = new Queue('event-reminders', REDIS_URL || 'redis://localhost:6379');
// ==================== EMAIL QUEUE PROCESSOR ====================
emailQueue.process(async (job) => {
const { to, subject, text, html } = job.data;
await sendMail({ to, subject, text, html });
});
// ==================== REMINDER QUEUE PROCESSOR ====================
reminderQueue.process(async (job) => {
const { eventId } = job.data;
await processEventReminder(eventId);
});
// ==================== QUEUE EVENT REMINDER (Stateless) ====================
export const queueEventReminder = async (eventId: string, sendAt: Date) => {
const delay = sendAt.getTime() - Date.now();
if (delay > 0) {
await reminderQueue.add(
{ eventId },
{ delay, attempts: 3, backoff: { type: 'exponential', delay: 2000 } }
);
}
};
// ==================== PROCESS EVENT REMINDER ====================
async function processEventReminder(eventId: string) {
try {
const event = await Event.findById(eventId)
.populate('participants.user', 'email username')
.populate('organization', 'username');
if (!event || event.reminderSent) return;
for (const participant of event.participants) {
const user = participant.user as any;
await emailQueue.add({
to: user.email,
subject: `Reminder: ${event.title} - Tomorrow`,
text: `Reminder: ${event.title} starts tomorrow at ${event.startDate.toLocaleString()}`,
html: generateReminderHTML(event, user)
});
}
event.reminderSent = true;
await event.save();
console.log(`Reminder sent for event: ${event.title}`);
} catch (err) {
console.error('Error sending reminder:', err);
throw err; // Bull will retry
}
}
function generateReminderHTML(event: any, user: any): string {
return `
<div style="font-family: Arial, sans-serif; padding: 20px;">
<h2>Event Reminder</h2>
<p>Hi ${user.username},</p>
<p>This is a reminder that you're registered for:</p>
<div style="background: #f5f5f5; padding: 15px; border-radius: 8px; margin: 20px 0;">
<h3 style="margin: 0 0 10px 0;">${event.title}</h3>
<p><strong>Code:</strong> ${event.code}</p>
<p><strong>Start:</strong> ${event.startDate.toLocaleString()}</p>
</div>
</div>
`;
}
// ==================== SCHEDULE ALL UPCOMING REMINDERS (Run on startup) ====================
export async function scheduleUpcomingReminders() {
const now = new Date();
const sevenDaysFromNow = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
const upcomingEvents = await Event.find({
status: 'published',
reminderSent: false,
startDate: { $gte: now, $lte: sevenDaysFromNow }
});
for (const event of upcomingEvents) {
const reminderTime = new Date(event.startDate.getTime() - 24 * 60 * 60 * 1000);
await queueEventReminder(event._id.toString(), reminderTime);
}
console.log(`Scheduled ${upcomingEvents.length} event reminders`);
}
export const sendEventUpdateNotification = async (eventId: string, updateMessage: string) => {
const event = await Event.findById(eventId).populate('participants.user', 'email username');
if (!event) return;
for (const participant of event.participants) {
const user = participant.user as any;
await emailQueue.add({
to: user.email,
subject: `Update: ${event.title}`,
text: updateMessage,
html: `<div><h2>Event Update</h2><p>${updateMessage}</p></div>`
});
}
};
export const sendWaitlistPromotionNotification = async (eventId: string, userId: string) => {
const event = await Event.findById(eventId);
const user = await User.findById(userId);
if (!event || !user) return;
await emailQueue.add({
to: user.email,
subject: `Spot Available: ${event.title}`,
text: `Good news! A spot has opened up for ${event.title}`,
html: `<div><h2>Good News!</h2><p>You've been registered for ${event.title}</p></div>`
});
};