/** * Fonction schedulée : Envoie quotidienne d'un résumé des alertes non lues * S'exécute tous les jours à 8h00 (Europe/Paris) */ const admin = require('firebase-admin'); const logger = require('firebase-functions/logger'); const nodemailer = require('nodemailer'); const { getSmtpConfig } = require('./utils/emailConfig'); /** * Fonction principale : envoie le digest quotidien */ async function sendDailyDigest() { const db = admin.firestore(); logger.info('[sendDailyDigest] ===== DÉBUT ENVOI DIGEST QUOTIDIEN ====='); try { // 1. Récupérer tous les utilisateurs avec email activé const usersSnapshot = await db.collection('users').get(); const eligibleUsers = []; usersSnapshot.forEach((doc) => { const user = doc.data(); const prefs = user.notificationPreferences || {}; // Vérifier si l'utilisateur a activé les emails if (prefs.emailEnabled !== false && user.email) { eligibleUsers.push({ uid: doc.id, email: user.email, firstName: user.firstName || 'Utilisateur', lastName: user.lastName || '', }); } }); logger.info(`[sendDailyDigest] ${eligibleUsers.length} utilisateurs éligibles`); // 2. Pour chaque utilisateur, récupérer ses alertes non lues des dernières 24h const now = admin.firestore.Timestamp.now(); const yesterday = admin.firestore.Timestamp.fromMillis(now.toMillis() - 24 * 60 * 60 * 1000); const transporter = nodemailer.createTransport(getSmtpConfig()); let emailsSent = 0; for (const user of eligibleUsers) { try { // Récupérer les alertes non lues de l'utilisateur créées dans les dernières 24h const alertsSnapshot = await db.collection('alerts') .where('assignedTo', 'array-contains', user.uid) .where('isRead', '==', false) .where('createdAt', '>=', yesterday) .orderBy('createdAt', 'desc') .get(); if (alertsSnapshot.empty) { continue; // Pas d'alertes non lues pour cet utilisateur } const alerts = []; alertsSnapshot.forEach((doc) => { alerts.push({ id: doc.id, ...doc.data() }); }); logger.info(`[sendDailyDigest] ${user.email}: ${alerts.length} alertes non lues`); // 3. Envoyer l'email de digest const sent = await sendDigestEmail(transporter, user, alerts); if (sent) { emailsSent++; } } catch (error) { logger.error(`[sendDailyDigest] Erreur pour ${user.email}:`, error); } } logger.info(`[sendDailyDigest] ✓ ${emailsSent}/${eligibleUsers.length} emails envoyés`); logger.info('[sendDailyDigest] ===== FIN DIGEST QUOTIDIEN ====='); return { success: true, emailsSent }; } catch (error) { logger.error('[sendDailyDigest] Erreur globale:', error); throw error; } } /** * Envoie l'email de digest à un utilisateur */ async function sendDigestEmail(transporter, user, alerts) { try { // Grouper les alertes par sévérité const criticalAlerts = alerts.filter(a => a.severity === 'CRITICAL'); const warningAlerts = alerts.filter(a => a.severity === 'WARNING'); const infoAlerts = alerts.filter(a => a.severity === 'INFO'); // Construire le HTML const html = buildDigestHtml(user, { critical: criticalAlerts, warning: warningAlerts, info: infoAlerts, }); // Envoyer l'email await transporter.sendMail({ from: `"EM2RP Notifications" <${process.env.SMTP_USER}>`, to: user.email, subject: `📬 ${alerts.length} nouvelle(s) alerte(s) EM2RP`, html, }); logger.info(`[sendDigestEmail] ✓ Email envoyé à ${user.email}`); return true; } catch (error) { logger.error(`[sendDigestEmail] Erreur pour ${user.email}:`, error); return false; } } /** * Construit le HTML du digest */ function buildDigestHtml(user, alertsByType) { const totalAlerts = alertsByType.critical.length + alertsByType.warning.length + alertsByType.info.length; let alertsHtml = ''; // Alertes critiques if (alertsByType.critical.length > 0) { alertsHtml += `
Bonjour ${user.firstName},
Vous avez ${totalAlerts} nouvelle(s) alerte(s) dans les dernières 24 heures.
${alertsHtml}EM2RP - Gestion d'événements
${alert.message || 'Aucun message'}