Checkpoint: Ajout d'un template d'email personnalisable pour l'envoi des attestations de formation. Le template utilise des variables dynamiques ({{prenomApprenant}}, {{nomApprenant}}, {{nomFormation}}) et peut être modifié depuis l'interface de gestion des templates. Déployé sur le VPS avec migration SQL.
This commit is contained in:
37
.manus/db/db-query-1769705480755.json
Normal file
37
.manus/db/db-query-1769705480755.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"query": "SELECT type FROM emailTemplates;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT type FROM emailTemplates;",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"type": "inscription"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "teaser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappelJ1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappel3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappel4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappel5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rappel6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "reset_password"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "type\ninscription\nteaser\nrappel\nrappelJ1\nrappel3\nrappel4\nrappel5\nrappel6\nreset_password\n",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 51
|
||||||
|
}
|
||||||
9
.manus/db/db-query-1769705553295.json
Normal file
9
.manus/db/db-query-1769705553295.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"query": "ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel','rappelJ1','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel','rappelJ1','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"rows": [],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 536
|
||||||
|
}
|
||||||
9
.manus/db/db-query-1769705570074.json
Normal file
9
.manus/db/db-query-1769705570074.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"query": "INSERT INTO emailTemplates (type, titre, bodyContent, couleurPrincipale, couleurSecondaire, piedDePage) \nVALUES (\n 'attestation',\n 'Votre attestation de formation',\n '<h2>Votre attestation de formation</h2>\\n\\n<p>Bonjour {{prenomApprenant}} {{nomApprenant}},</p>\\n\\n<p>Nous avons le plaisir de vous transmettre votre attestation de formation pour :</p>\\n\\n<div class=\"info-box\" style=\"background-color: #dbeafe; border-left-color: #3b82f6;\">\\n <h3>{{nomFormation}}</h3>\\n</div>\\n\\n<p>Vous trouverez votre attestation en pièce jointe de cet email.</p>\\n\\n<p>Cette attestation certifie votre participation à la formation et peut être utilisée pour votre dossier professionnel.</p>\\n\\n<p>Nous vous remercions pour votre participation et vous souhaitons une excellente continuation.</p>\\n\\n<p>Cordialement,<br/>L''équipe Formation</p>',\n '#283581',\n '#0578BE',\n NULL\n);",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute INSERT INTO emailTemplates (type, titre, bodyContent, couleurPrincipale, couleurSecondaire, piedDePage) \nVALUES (\n 'attestation',\n 'Votre attestation de formation',\n '<h2>Votre attestation de formation</h2>\\n\\n<p>Bonjour {{prenomApprenant}} {{nomApprenant}},</p>\\n\\n<p>Nous avons le plaisir de vous transmettre votre attestation de formation pour :</p>\\n\\n<div class=\"info-box\" style=\"background-color: #dbeafe; border-left-color: #3b82f6;\">\\n <h3>{{nomFormation}}</h3>\\n</div>\\n\\n<p>Vous trouverez votre attestation en pièce jointe de cet email.</p>\\n\\n<p>Cette attestation certifie votre participation à la formation et peut être utilisée pour votre dossier professionnel.</p>\\n\\n<p>Nous vous remercions pour votre participation et vous souhaitons une excellente continuation.</p>\\n\\n<p>Cordialement,<br/>L''équipe Formation</p>',\n '#283581',\n '#0578BE',\n NULL\n);",
|
||||||
|
"rows": [],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 66
|
||||||
|
}
|
||||||
8
.manus/db/db-query-error-1769705465473.json
Normal file
8
.manus/db/db-query-error-1769705465473.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"query": "ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"returncode": 1,
|
||||||
|
"logs": [
|
||||||
|
"ERROR 1265 (01000) at line 1: Data truncated for column 'type', value is 'rappel'"
|
||||||
|
]
|
||||||
|
}
|
||||||
8
.manus/db/db-query-error-1769705523703.json
Normal file
8
.manus/db/db-query-error-1769705523703.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"query": "ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE `emailTemplates` MODIFY COLUMN `type` enum('inscription','teaser','rappel','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password','attestation') NOT NULL;",
|
||||||
|
"returncode": 1,
|
||||||
|
"logs": [
|
||||||
|
"ERROR 1265 (01000) at line 1: Data truncated for column 'type', value is 'rappelJ1'"
|
||||||
|
]
|
||||||
|
}
|
||||||
2269
drizzle/meta/0010_snapshot.json
Normal file
2269
drizzle/meta/0010_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2269
drizzle/meta/0011_snapshot.json
Normal file
2269
drizzle/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2269
drizzle/meta/0012_snapshot.json
Normal file
2269
drizzle/meta/0012_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,27 @@
|
|||||||
"when": 1769704162958,
|
"when": 1769704162958,
|
||||||
"tag": "0009_nervous_nomad",
|
"tag": "0009_nervous_nomad",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 10,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1769705449970,
|
||||||
|
"tag": "0010_fixed_slipstream",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1769705509311,
|
||||||
|
"tag": "0011_lucky_the_liberteens",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 12,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1769705546694,
|
||||||
|
"tag": "0012_puzzling_baron_zemo",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ export type InsertEmailConfig = typeof emailConfig.$inferInsert;
|
|||||||
export const emailTemplates = mysqlTable("emailTemplates", {
|
export const emailTemplates = mysqlTable("emailTemplates", {
|
||||||
id: int("id").autoincrement().primaryKey(),
|
id: int("id").autoincrement().primaryKey(),
|
||||||
/** Type de template (inscription, teaser, rappel1, rappel2, rappel3, rappel4, rappel5, rappel6, reset_password) */
|
/** Type de template (inscription, teaser, rappel1, rappel2, rappel3, rappel4, rappel5, rappel6, reset_password) */
|
||||||
type: mysqlEnum("type", ["inscription", "teaser", "rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]).notNull().unique(),
|
type: mysqlEnum("type", ["inscription", "teaser", "rappel", "rappelJ1", "rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password", "attestation"]).notNull().unique(),
|
||||||
titre: varchar("titre", { length: 255 }).notNull(),
|
titre: varchar("titre", { length: 255 }).notNull(),
|
||||||
/** Corps du message avec variables dynamiques */
|
/** Corps du message avec variables dynamiques */
|
||||||
bodyContent: text("bodyContent").notNull(),
|
bodyContent: text("bodyContent").notNull(),
|
||||||
|
|||||||
@@ -1158,25 +1158,28 @@ export async function sendAttestationEmail(params: {
|
|||||||
formationNom: string;
|
formationNom: string;
|
||||||
pdfUrl: string;
|
pdfUrl: string;
|
||||||
}): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
const content = `
|
// Récupérer le template attestation depuis la base de données
|
||||||
<h2>Votre attestation de formation</h2>
|
const { getDb } = await import('./db');
|
||||||
|
const { emailTemplates } = await import('../drizzle/schema');
|
||||||
|
const { eq } = await import('drizzle-orm');
|
||||||
|
|
||||||
<p>Bonjour ${params.apprenantPrenom} ${params.apprenantNom},</p>
|
const db = await getDb();
|
||||||
|
if (!db) {
|
||||||
|
throw new Error('Database not available');
|
||||||
|
}
|
||||||
|
|
||||||
<p>Nous avons le plaisir de vous transmettre votre attestation de formation pour :</p>
|
const templates = await db.select().from(emailTemplates).where(eq(emailTemplates.type, 'attestation')).limit(1);
|
||||||
|
if (templates.length === 0) {
|
||||||
|
throw new Error('Template attestation not found');
|
||||||
|
}
|
||||||
|
|
||||||
<div class="info-box" style="background-color: #dbeafe; border-left-color: #3b82f6;">
|
const template = templates[0];
|
||||||
<h3>${params.formationNom}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>Vous trouverez votre attestation en pièce jointe de cet email.</p>
|
// Remplacer les variables dans le template
|
||||||
|
let content = template.bodyContent;
|
||||||
<p>Cette attestation certifie votre participation à la formation et peut être utilisée pour votre dossier professionnel.</p>
|
content = content.replace(/{{prenomApprenant}}/g, params.apprenantPrenom);
|
||||||
|
content = content.replace(/{{nomApprenant}}/g, params.apprenantNom);
|
||||||
<p>Nous vous remercions pour votre participation et vous souhaitons une excellente continuation.</p>
|
content = content.replace(/{{nomFormation}}/g, params.formationNom);
|
||||||
|
|
||||||
<p>Cordialement,<br/>L'équipe Formation</p>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Récupérer le PDF (depuis URL ou chemin local)
|
// Récupérer le PDF (depuis URL ou chemin local)
|
||||||
let pdfBuffer: Buffer;
|
let pdfBuffer: Buffer;
|
||||||
|
|||||||
9
todo.md
9
todo.md
@@ -1451,3 +1451,12 @@
|
|||||||
- [x] Modifier DashboardLayout pour masquer Configuration aux super formateurs
|
- [x] Modifier DashboardLayout pour masquer Configuration aux super formateurs
|
||||||
- [x] Déployer sur VPS
|
- [x] Déployer sur VPS
|
||||||
- [x] Créer un checkpoint
|
- [x] Créer un checkpoint
|
||||||
|
|
||||||
|
## Template email attestations
|
||||||
|
|
||||||
|
- [x] Analyser le système actuel d'envoi des attestations
|
||||||
|
- [x] Ajouter le template "attestation" dans la table emailTemplates
|
||||||
|
- [x] Créer le template par défaut avec variables dynamiques
|
||||||
|
- [x] Intégrer le template dans le code d'envoi des attestations
|
||||||
|
- [x] Déployer sur VPS (migration SQL + fichiers)
|
||||||
|
- [x] Créer un checkpoint
|
||||||
|
|||||||
Reference in New Issue
Block a user