fix: corriger le flux de réinitialisation par e-mail
Some checks failed
Validation applicative / TypeScript, tests et build (push) Failing after 2m22s
Some checks failed
Validation applicative / TypeScript, tests et build (push) Failing after 2m22s
This commit is contained in:
44
server/db.ts
44
server/db.ts
@@ -23,6 +23,8 @@ import {
|
||||
Apprenant,
|
||||
Formation,
|
||||
EmailTemplate,
|
||||
EmailTemplateType,
|
||||
isEmailTemplateType,
|
||||
InsertEmailTemplate,
|
||||
formateurs,
|
||||
InsertFormateur,
|
||||
@@ -451,7 +453,14 @@ export async function updateApprenant(id: number, data: Partial<InsertApprenant>
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
await db.update(apprenants).set(data).where(eq(apprenants.id, id));
|
||||
try {
|
||||
await db.update(apprenants).set(data).where(eq(apprenants.id, id));
|
||||
} catch (error: any) {
|
||||
if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
|
||||
throw new Error("Cet email est déjà utilisé par un autre apprenant.");
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteApprenant(id: number) {
|
||||
@@ -676,22 +685,14 @@ export async function deleteUser(id: number) {
|
||||
|
||||
// ==================== GESTION DES TOKENS DE RÉINITIALISATION ====================
|
||||
|
||||
export async function createPasswordResetToken(email: string, token: string) {
|
||||
export async function createPasswordResetToken(userId: number, token: string) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setHours(expiresAt.getHours() + 24); // Token valide 24h
|
||||
// Un Date est converti par Drizzle avec le fuseau du serveur sans manipulation de chaîne.
|
||||
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
||||
|
||||
// Convertir la date au format MySQL DATETIME (YYYY-MM-DD HH:MM:SS)
|
||||
const mysqlDate = expiresAt.toISOString().slice(0, 19).replace('T', ' ');
|
||||
|
||||
// Utiliser une requête SQL brute pour éviter les problèmes avec Drizzle
|
||||
const result = await db.execute(sql`
|
||||
INSERT INTO passwordResetTokens (email, token, expiresAt)
|
||||
VALUES (${email}, ${token}, ${mysqlDate})
|
||||
`);
|
||||
return result;
|
||||
return db.insert(passwordResetTokens).values({ userId, token, expiresAt });
|
||||
}
|
||||
|
||||
export async function getPasswordResetToken(token: string) {
|
||||
@@ -744,6 +745,10 @@ export async function getAllEmailTemplates() {
|
||||
export async function getEmailTemplateByType(type: string) {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
|
||||
// Les services de notification peuvent demander un template non persistant.
|
||||
// Dans ce cas, le générateur retombe volontairement sur son HTML de secours.
|
||||
if (!isEmailTemplateType(type)) return null;
|
||||
|
||||
const results = await db.select().from(emailTemplates).where(eq(emailTemplates.type, type)).limit(1);
|
||||
return results.length > 0 ? results[0] : null;
|
||||
@@ -785,6 +790,10 @@ export async function upsertEmailTemplate(template: InsertEmailTemplate) {
|
||||
export async function deleteEmailTemplate(type: string) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
if (!isEmailTemplateType(type)) {
|
||||
throw new Error("Type de template email invalide");
|
||||
}
|
||||
|
||||
await db.delete(emailTemplates).where(eq(emailTemplates.type, type));
|
||||
}
|
||||
@@ -958,7 +967,14 @@ export async function initializeDefaultEmailTemplates() {
|
||||
{
|
||||
type: "reset_password",
|
||||
titre: "Réinitialisation de mot de passe",
|
||||
bodyContent: "<p>Contenu par défaut</p>",
|
||||
// Le lien doit rester une variable : chaque demande génère un token différent.
|
||||
bodyContent: `<p>Bonjour {{prenomApprenant}} {{nomApprenant}},</p>
|
||||
<p>Vous avez demandé la réinitialisation de votre mot de passe pour votre compte Manager Itinova.</p>
|
||||
<p>Cliquez sur le bouton ci-dessous pour choisir un nouveau mot de passe :</p>
|
||||
<p style="text-align: center;"><a href="{{lienReinitialisation}}" class="button">Réinitialiser mon mot de passe</a></p>
|
||||
<p>Si le bouton ne fonctionne pas, copiez ce lien dans votre navigateur :</p>
|
||||
<p style="word-break: break-all;">{{lienReinitialisation}}</p>
|
||||
<p>Ce lien est valide pendant 24 heures et ne peut être utilisé qu’une seule fois.</p>`,
|
||||
couleurPrincipale: "#283581",
|
||||
couleurSecondaire: "#0578BE",
|
||||
piedDePage: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.",
|
||||
|
||||
Reference in New Issue
Block a user