/** * 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"}