Checkpoint: Ajout d'une interface d'administration complète pour personnaliser les templates d'emails avec prévisualisation en temps réel, stockage en base de données et intégration avec le service d'envoi
This commit is contained in:
137
server/db.ts
137
server/db.ts
@@ -18,7 +18,10 @@ import {
|
||||
Sequence,
|
||||
DateFormation,
|
||||
Apprenant,
|
||||
Formation
|
||||
Formation,
|
||||
emailTemplates,
|
||||
EmailTemplate,
|
||||
InsertEmailTemplate
|
||||
} from "../drizzle/schema";
|
||||
import { ENV } from './_core/env';
|
||||
|
||||
@@ -467,3 +470,135 @@ export async function deleteExpiredTokens() {
|
||||
await db.delete(passwordResetTokens)
|
||||
.where(sql`${passwordResetTokens.expiresAt} < ${now}`);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Email Templates Management
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Récupère tous les templates d'emails
|
||||
*/
|
||||
export async function getAllEmailTemplates() {
|
||||
const db = await getDb();
|
||||
if (!db) return [];
|
||||
|
||||
return await db.select().from(emailTemplates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère un template par son type
|
||||
*/
|
||||
export async function getEmailTemplateByType(type: string) {
|
||||
const db = await getDb();
|
||||
if (!db) return undefined;
|
||||
|
||||
const results = await db.select().from(emailTemplates).where(eq(emailTemplates.type, type)).limit(1);
|
||||
return results.length > 0 ? results[0] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée ou met à jour un template d'email
|
||||
*/
|
||||
export async function upsertEmailTemplate(template: InsertEmailTemplate) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
const existing = await getEmailTemplateByType(template.type);
|
||||
|
||||
if (existing) {
|
||||
// Mise à jour
|
||||
await db.update(emailTemplates)
|
||||
.set({
|
||||
name: template.name,
|
||||
logoUrl: template.logoUrl,
|
||||
primaryColor: template.primaryColor,
|
||||
headerBgColor: template.headerBgColor,
|
||||
headerTextColor: template.headerTextColor,
|
||||
headerTitle: template.headerTitle,
|
||||
footerText: template.footerText,
|
||||
active: template.active,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(emailTemplates.type, template.type));
|
||||
|
||||
return await getEmailTemplateByType(template.type);
|
||||
} else {
|
||||
// Création
|
||||
await db.insert(emailTemplates).values(template);
|
||||
return await getEmailTemplateByType(template.type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un template d'email
|
||||
*/
|
||||
export async function deleteEmailTemplate(type: string) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
await db.delete(emailTemplates).where(eq(emailTemplates.type, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les templates par défaut si la table est vide
|
||||
*/
|
||||
export async function initializeDefaultEmailTemplates() {
|
||||
const db = await getDb();
|
||||
if (!db) return;
|
||||
|
||||
const existing = await getAllEmailTemplates();
|
||||
if (existing.length > 0) return; // Déjà initialisé
|
||||
|
||||
const defaultTemplates: InsertEmailTemplate[] = [
|
||||
{
|
||||
type: "inscription",
|
||||
name: "Confirmation d'inscription",
|
||||
logoUrl: null,
|
||||
primaryColor: "#2563eb",
|
||||
headerBgColor: "#2563eb",
|
||||
headerTextColor: "#ffffff",
|
||||
headerTitle: "Formation Manager Itinova",
|
||||
footerText: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
type: "teaser",
|
||||
name: "Email teaser",
|
||||
logoUrl: null,
|
||||
primaryColor: "#2563eb",
|
||||
headerBgColor: "#2563eb",
|
||||
headerTextColor: "#ffffff",
|
||||
headerTitle: "Formation Manager Itinova",
|
||||
footerText: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
type: "rappel",
|
||||
name: "Rappel J-7",
|
||||
logoUrl: null,
|
||||
primaryColor: "#2563eb",
|
||||
headerBgColor: "#2563eb",
|
||||
headerTextColor: "#ffffff",
|
||||
headerTitle: "Formation Manager Itinova",
|
||||
footerText: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
type: "reset_password",
|
||||
name: "Réinitialisation de mot de passe",
|
||||
logoUrl: null,
|
||||
primaryColor: "#2563eb",
|
||||
headerBgColor: "#2563eb",
|
||||
headerTextColor: "#ffffff",
|
||||
headerTitle: "Formation Manager Itinova",
|
||||
footerText: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.",
|
||||
active: true,
|
||||
},
|
||||
];
|
||||
|
||||
for (const template of defaultTemplates) {
|
||||
await db.insert(emailTemplates).values(template);
|
||||
}
|
||||
|
||||
console.log("[DB] Templates d'emails par défaut initialisés");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user