diff --git a/backend/src/services/expirationChecker.js b/backend/src/services/expirationChecker.js new file mode 100644 index 0000000..e947adc --- /dev/null +++ b/backend/src/services/expirationChecker.js @@ -0,0 +1,107 @@ +const cron = require('node-cron'); +const { db } = require('../database/db'); +const { archiveEvent } = require('./archiveService'); +const logger = require('../utils/logger'); + +function startExpirationChecker() { + // Check every hour for expired events and warnings + cron.schedule('0 * * * *', async () => { + await checkExpirations(); + }); + + logger.info('Expiration checker started'); +} + +async function checkExpirations() { + try { + const now = new Date(); + const warningDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 7 days from now + + // Check for events needing warning emails + const eventsNeedingWarning = await db('events') + .where('is_active', true) + .where('is_archived', false) + .where('expires_at', '<=', warningDate) + .where('expires_at', '>', now); + + for (const event of eventsNeedingWarning) { + // Check if warning email already sent + const existingWarning = await db('email_queue') + .where('event_id', event.id) + .where('email_type', 'warning') + .first(); + + if (!existingWarning) { + await queueExpirationWarning(event); + } + } + + // Check for expired events + const expiredEvents = await db('events') + .where('is_active', true) + .where('is_archived', false) + .where('expires_at', '<=', now); + + for (const event of expiredEvents) { + await handleExpiredEvent(event); + } + + } catch (error) { + logger.error('Error checking expirations:', error); + } +} + +async function queueExpirationWarning(event) { + const daysRemaining = Math.ceil((new Date(event.expires_at) - new Date()) / (1000 * 60 * 60 * 24)); + + // Queue email to host + await db('email_queue').insert({ + event_id: event.id, + recipient_email: event.host_email, + email_type: 'warning', + email_data: JSON.stringify({ + event_name: event.event_name, + days_remaining: daysRemaining, + share_link: event.share_link + }) + }); + + logger.info(`Queued expiration warning for event ${event.slug}`); +} + +async function handleExpiredEvent(event) { + try { + // Mark as inactive + await db('events').where('id', event.id).update({ is_active: false }); + + // Queue expiration emails + await db('email_queue').insert([ + { + event_id: event.id, + recipient_email: event.host_email, + email_type: 'expiration', + email_data: JSON.stringify({ + event_name: event.event_name + }) + }, + { + event_id: event.id, + recipient_email: event.admin_email, + email_type: 'expiration', + email_data: JSON.stringify({ + event_name: event.event_name, + event_slug: event.slug + }) + } + ]); + + // Start archiving process + await archiveEvent(event); + + logger.info(`Handled expiration for event ${event.slug}`); + } catch (error) { + logger.error(`Error handling expired event ${event.slug}:`, error); + } +} + +module.exports = { startExpirationChecker };