import cron from 'node-cron'; import pool from '../config/database.js'; import { sendDemoExpiryReminderMail, sendDemoLastDayMail, sendDemoExpiredMail, } from './mail.js'; // Findet Demo-Tenants, deren Ablauf in [from, to] liegt UND fuer die noch // keine entsprechende Benachrichtigung versandt wurde, schickt die Mail // und markiert die Spalte mit NOW(). async function processWindow({ flagColumn, daysFrom, daysTo, sender }) { const [rows] = await pool.query( `SELECT id, name, kontakt_email, slug, demo_expires_at FROM tenants WHERE typ = 'demo' AND kontakt_email IS NOT NULL AND ${flagColumn} IS NULL AND demo_expires_at IS NOT NULL AND demo_expires_at BETWEEN DATE_ADD(NOW(), INTERVAL ? DAY) AND DATE_ADD(NOW(), INTERVAL ? DAY)`, [daysFrom, daysTo] ); for (const t of rows) { try { await sender(t); await pool.query(`UPDATE tenants SET ${flagColumn} = NOW() WHERE id = ?`, [t.id]); console.log(`[expiry] ${flagColumn} -> ${t.kontakt_email} (slug=${t.slug})`); } catch (e) { console.error(`[expiry] Mail-Fehler ${flagColumn} fuer ${t.kontakt_email}:`, e.message); } } } async function processExpiredToday() { const [rows] = await pool.query( `SELECT id, name, kontakt_email, slug, demo_expires_at FROM tenants WHERE typ = 'demo' AND kontakt_email IS NOT NULL AND notified_expired_at IS NULL AND demo_expires_at IS NOT NULL AND demo_expires_at <= NOW()` ); for (const t of rows) { try { await sendDemoExpiredMail({ to: t.kontakt_email, name: t.name }); await pool.query( `UPDATE tenants SET notified_expired_at = NOW(), status = 'abgelaufen' WHERE id = ?`, [t.id] ); console.log(`[expiry] expired-mail -> ${t.kontakt_email} (slug=${t.slug})`); } catch (e) { console.error(`[expiry] expired-Mail-Fehler ${t.kontakt_email}:`, e.message); } } } export async function runExpiryCheck() { console.log('[expiry] check start', new Date().toISOString()); // 7-Tage-Erinnerung: Ablauf in [6, 7] Tagen await processWindow({ flagColumn: 'notified_7d_at', daysFrom: 6, daysTo: 7, sender: (t) => sendDemoExpiryReminderMail({ to: t.kontakt_email, name: t.name, slug: t.slug, daysLeft: 7, expiresAt: t.demo_expires_at, }), }); // 1-Tag-Erinnerung: Ablauf in [0, 1] Tagen (aber noch nicht abgelaufen) await processWindow({ flagColumn: 'notified_1d_at', daysFrom: 0, daysTo: 1, sender: (t) => sendDemoLastDayMail({ to: t.kontakt_email, name: t.name, slug: t.slug, expiresAt: t.demo_expires_at, }), }); // Heute (oder bereits) abgelaufen await processExpiredToday(); console.log('[expiry] check done'); } export function startExpiryCron() { // Taeglich um 08:00 Uhr (Server-Zeit = UTC). Anpassbar via env CRON_EXPIRY_AT const expr = process.env.CRON_EXPIRY_AT || '0 8 * * *'; cron.schedule(expr, () => { runExpiryCheck().catch(e => console.error('[expiry] cron error:', e)); }); console.log('[expiry] cron registriert:', expr); }