| 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'; |
|
|
| |
| const emailQueue = new Queue('email-notifications', REDIS_URL || 'redis://localhost:6379'); |
| const reminderQueue = new Queue('event-reminders', REDIS_URL || 'redis://localhost:6379'); |
|
|
| |
| emailQueue.process(async (job) => { |
| const { to, subject, text, html } = job.data; |
| await sendMail({ to, subject, text, html }); |
| }); |
|
|
| |
| reminderQueue.process(async (job) => { |
| const { eventId } = job.data; |
| await processEventReminder(eventId); |
| }); |
|
|
| |
| 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 } } |
| ); |
| } |
| }; |
|
|
| |
| 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; |
| } |
| } |
|
|
| 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> |
| `; |
| } |
|
|
| |
| 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>` |
| }); |
| }; |