import { getDb } from "./db";
import { eq, and, lte, sql } from "drizzle-orm";
import {
questionnaires,
sequences,
inscriptions,
apprenants,
datesFormation,
envoisQuestionnaires,
} from "../drizzle/schema";
import {
getAllQuestionnaires,
checkEnvoiExists,
createEnvoiQuestionnaire,
} from "./questionnaireDb";
import { sendEmail } from "./_core/emailSender";
import crypto from "crypto";
/**
* Génère un token unique pour accéder au questionnaire
*/
function generateToken(): string {
return crypto.randomBytes(32).toString("hex");
}
/**
* Envoie un questionnaire à un apprenant pour une séquence donnée
*/
async function envoyerQuestionnaire(
questionnaireId: number,
apprenantId: number,
sequenceId: number,
apprenantEmail: string,
apprenantNom: string,
apprenantPrenom: string,
questionnairenom: string,
sequenceNom: string
) {
// Vérifier si le questionnaire n'a pas déjà été envoyé
const dejaEnvoye = await checkEnvoiExists(questionnaireId, apprenantId, sequenceId);
if (dejaEnvoye) {
console.log(
`[Questionnaires] Questionnaire ${questionnaireId} déjà envoyé à l'apprenant ${apprenantId} pour la séquence ${sequenceId}`
);
return false;
}
// Générer un token unique
const token = generateToken();
// Créer l'envoi
await createEnvoiQuestionnaire({
questionnaireId,
apprenantId,
sequenceId,
token,
dateEnvoi: new Date(),
dateReponse: null,
});
// Envoyer l'email
const lienQuestionnaire = `${process.env.VITE_FRONTEND_URL || "http://localhost:3000"}/questionnaire/${token}`;
const emailSent = await sendEmail({
to: apprenantEmail,
subject: `Questionnaire : ${questionnairenom}`,
html: `
Bonjour ${apprenantPrenom} ${apprenantNom},
Nous vous remercions d'avoir participé à la formation ${sequenceNom}.
Afin d'améliorer continuellement la qualité de nos formations, nous vous invitons à répondre à ce questionnaire :
Répondre au questionnaire
Ce questionnaire ne vous prendra que quelques minutes.
Merci pour votre participation !
Si le bouton ne fonctionne pas, copiez ce lien dans votre navigateur :
${lienQuestionnaire}
`,
});
if (emailSent) {
console.log(
`[Questionnaires] Questionnaire ${questionnaireId} envoyé à ${apprenantEmail} pour la séquence ${sequenceId}`
);
return true;
} else {
console.error(
`[Questionnaires] Échec de l'envoi du questionnaire ${questionnaireId} à ${apprenantEmail}`
);
return false;
}
}
/**
* Traite les envois automatiques de questionnaires post-formation
*/
export async function processEnvoisAutomatiques() {
console.log("[Questionnaires] Démarrage du traitement des envois automatiques...");
const db = await getDb();
if (!db) {
console.log("[Questionnaires] Base de données non disponible");
return { success: false, message: "Base de données non disponible" };
}
try {
// Récupérer tous les questionnaires actifs avec envoi automatique
const questionnairesActifs = await getAllQuestionnaires();
const questionnairesAEnvoyer = questionnairesActifs.filter(
(q) => q.actif && q.envoiAutomatique
);
if (questionnairesAEnvoyer.length === 0) {
console.log("[Questionnaires] Aucun questionnaire avec envoi automatique configuré");
return { success: true, message: "Aucun questionnaire à envoyer", count: 0 };
}
let totalEnvoyes = 0;
for (const questionnaire of questionnairesAEnvoyer) {
console.log(
`[Questionnaires] Traitement du questionnaire "${questionnaire.nom}" (délai: J+${questionnaire.delaiEnvoiJours})`
);
// Calculer la date cible (aujourd'hui - délai)
const dateCible = new Date();
dateCible.setDate(dateCible.getDate() - questionnaire.delaiEnvoiJours);
dateCible.setHours(0, 0, 0, 0);
// Récupérer les séquences terminées à la date cible
const sequencesTerminees = await db
.select({
sequenceId: sequences.id,
sequenceNom: sequences.nom,
formationId: sequences.formationId,
})
.from(sequences)
.innerJoin(datesFormation, eq(datesFormation.sequenceId, sequences.id))
.where(lte(datesFormation.dateFin, dateCible))
.groupBy(sequences.id);
console.log(
`[Questionnaires] ${sequencesTerminees.length} séquence(s) terminée(s) trouvée(s) pour le ${dateCible.toLocaleDateString("fr-FR")}`
);
// Pour chaque séquence terminée
for (const seq of sequencesTerminees) {
// Vérifier si le questionnaire est lié à une formation spécifique
if (questionnaire.formationId && questionnaire.formationId !== seq.formationId) {
continue;
}
// Récupérer les apprenants inscrits et validés
const apprenantsInscrits = await db
.select({
apprenantId: apprenants.id,
apprenantEmail: apprenants.email,
apprenantNom: apprenants.nom,
apprenantPrenom: apprenants.prenom,
})
.from(inscriptions)
.innerJoin(apprenants, eq(apprenants.id, inscriptions.apprenantId))
.where(
and(
eq(inscriptions.sequenceId, seq.sequenceId),
eq(inscriptions.statut, "confirmee")
)
);
console.log(
`[Questionnaires] ${apprenantsInscrits.length} apprenant(s) inscrit(s) à la séquence ${seq.sequenceId}`
);
// Envoyer le questionnaire à chaque apprenant
for (const apprenant of apprenantsInscrits) {
if (!apprenant.apprenantEmail) {
console.log(
`[Questionnaires] Apprenant ${apprenant.apprenantId} sans email, envoi ignoré`
);
continue;
}
const envoye = await envoyerQuestionnaire(
questionnaire.id,
apprenant.apprenantId,
seq.sequenceId,
apprenant.apprenantEmail,
apprenant.apprenantNom,
apprenant.apprenantPrenom,
questionnaire.nom,
seq.sequenceNom
);
if (envoye) {
totalEnvoyes++;
}
}
}
}
console.log(`[Questionnaires] Traitement terminé - ${totalEnvoyes} questionnaire(s) envoyé(s)`);
return {
success: true,
message: `${totalEnvoyes} questionnaire(s) envoyé(s)`,
count: totalEnvoyes,
};
} catch (error: any) {
console.error("[Questionnaires] Erreur lors du traitement :", error);
return { success: false, message: error.message, count: 0 };
}
}
/**
* Initialise le scheduler pour les envois automatiques de questionnaires
* Exécute le traitement tous les jours à 9h00
*/
export function initQuestionnaireScheduler() {
console.log("[Questionnaires] Initialisation du scheduler d'envoi automatique");
// Exécuter immédiatement au démarrage
processEnvoisAutomatiques();
// Puis exécuter tous les jours à 9h00
const interval = setInterval(
() => {
const now = new Date();
if (now.getHours() === 9 && now.getMinutes() === 0) {
processEnvoisAutomatiques();
}
},
60 * 1000 // Vérifier toutes les minutes
);
console.log("[Questionnaires] Scheduler initialisé - vérification quotidienne à 9h00");
return interval;
}