Checkpoint: Implémentation de la synchronisation automatique entre table users (role=formateur) et table formateurs : auto-création dans createUser/updateUser + script de migration pour les formateurs existants
This commit is contained in:
40
server/db.ts
40
server/db.ts
@@ -563,6 +563,16 @@ export async function createUser(data: InsertUser) {
|
|||||||
data.password = await bcrypt.hash(data.password, 10);
|
data.password = await bcrypt.hash(data.password, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si le rôle est formateur et qu'il n'y a pas de formateurId, créer une entrée dans la table formateurs
|
||||||
|
if (data.role === 'formateur' && !data.formateurId && data.name && data.email) {
|
||||||
|
const formateurResult = await db.insert(formateurs).values({
|
||||||
|
nom: data.name,
|
||||||
|
email: data.email,
|
||||||
|
});
|
||||||
|
// Récupérer l'ID du formateur créé
|
||||||
|
data.formateurId = Number(formateurResult[0].insertId);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await db.insert(users).values(data);
|
const result = await db.insert(users).values(data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -592,6 +602,36 @@ export async function updateUser(id: number, data: Partial<InsertUser>) {
|
|||||||
data.password = await bcrypt.hash(data.password, 10);
|
data.password = await bcrypt.hash(data.password, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Récupérer l'utilisateur actuel
|
||||||
|
const currentUser = await getUserById(id);
|
||||||
|
if (!currentUser) throw new Error("User not found");
|
||||||
|
|
||||||
|
// Si le rôle change vers formateur et qu'il n'y a pas de formateurId
|
||||||
|
if (data.role === 'formateur' && !currentUser.formateurId && !data.formateurId) {
|
||||||
|
const name = data.name || currentUser.name;
|
||||||
|
const email = data.email || currentUser.email;
|
||||||
|
if (name && email) {
|
||||||
|
const formateurResult = await db.insert(formateurs).values({
|
||||||
|
nom: name,
|
||||||
|
email: email,
|
||||||
|
});
|
||||||
|
data.formateurId = Number(formateurResult[0].insertId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si l'utilisateur est formateur et a un formateurId, synchroniser les modifications
|
||||||
|
if (currentUser.formateurId && (data.name || data.email)) {
|
||||||
|
const formateurUpdate: any = {};
|
||||||
|
if (data.name) formateurUpdate.nom = data.name;
|
||||||
|
if (data.email) formateurUpdate.email = data.email;
|
||||||
|
|
||||||
|
if (Object.keys(formateurUpdate).length > 0) {
|
||||||
|
await db.update(formateurs)
|
||||||
|
.set(formateurUpdate)
|
||||||
|
.where(eq(formateurs.id, currentUser.formateurId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await db.update(users).set(data).where(eq(users.id, id));
|
await db.update(users).set(data).where(eq(users.id, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
91
server/migrate-formateurs.mjs
Normal file
91
server/migrate-formateurs.mjs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { drizzle } from "drizzle-orm/mysql2";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { users, formateurs } from "../drizzle/schema.ts";
|
||||||
|
import * as dotenv from "dotenv";
|
||||||
|
|
||||||
|
// Charger les variables d'environnement
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script de migration pour synchroniser les utilisateurs avec role='formateur'
|
||||||
|
* qui n'ont pas encore d'entrée dans la table formateurs
|
||||||
|
*/
|
||||||
|
async function migrateFormateurs() {
|
||||||
|
console.log("[Migration] Démarrage de la synchronisation des formateurs...");
|
||||||
|
|
||||||
|
if (!process.env.DATABASE_URL) {
|
||||||
|
console.error("[Migration] DATABASE_URL non définie");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = drizzle(process.env.DATABASE_URL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Récupérer tous les utilisateurs avec role='formateur'
|
||||||
|
const formateurUsers = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.role, 'formateur'));
|
||||||
|
|
||||||
|
console.log(`[Migration] ${formateurUsers.length} utilisateur(s) avec role='formateur' trouvé(s)`);
|
||||||
|
|
||||||
|
let created = 0;
|
||||||
|
let updated = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
|
||||||
|
for (const user of formateurUsers) {
|
||||||
|
// Si l'utilisateur a déjà un formateurId, vérifier qu'il existe
|
||||||
|
if (user.formateurId) {
|
||||||
|
const existingFormateur = await db
|
||||||
|
.select()
|
||||||
|
.from(formateurs)
|
||||||
|
.where(eq(formateurs.id, user.formateurId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (existingFormateur.length > 0) {
|
||||||
|
console.log(`[Migration] ✓ Utilisateur "${user.name}" (${user.email}) déjà lié au formateur ID ${user.formateurId}`);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier si l'utilisateur a un nom et un email
|
||||||
|
if (!user.name || !user.email) {
|
||||||
|
console.log(`[Migration] ⚠ Utilisateur ID ${user.id} ignoré (nom ou email manquant)`);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer une entrée dans la table formateurs
|
||||||
|
const formateurResult = await db.insert(formateurs).values({
|
||||||
|
nom: user.name,
|
||||||
|
email: user.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
const newFormateurId = Number(formateurResult[0].insertId);
|
||||||
|
|
||||||
|
// Mettre à jour l'utilisateur avec le formateurId
|
||||||
|
await db
|
||||||
|
.update(users)
|
||||||
|
.set({ formateurId: newFormateurId })
|
||||||
|
.where(eq(users.id, user.id));
|
||||||
|
|
||||||
|
console.log(`[Migration] ✓ Créé formateur "${user.name}" (${user.email}) avec ID ${newFormateurId}`);
|
||||||
|
created++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n[Migration] Résumé:");
|
||||||
|
console.log(` - Créés: ${created}`);
|
||||||
|
console.log(` - Mis à jour: ${updated}`);
|
||||||
|
console.log(` - Ignorés: ${skipped}`);
|
||||||
|
console.log("[Migration] Terminé avec succès !");
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[Migration] Erreur:", error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
migrateFormateurs();
|
||||||
17
todo.md
17
todo.md
@@ -1205,17 +1205,26 @@
|
|||||||
|
|
||||||
- [x] Identifier les procédures backend concernées (exports PDF/Excel, feuille de présence)
|
- [x] Identifier les procédures backend concernées (exports PDF/Excel, feuille de présence)
|
||||||
- [x] Modifier les restrictions pour autoriser les formateurs
|
- [x] Modifier les restrictions pour autoriser les formateurs
|
||||||
- [ ] Tester les modifications
|
- [x] Tester les modifications
|
||||||
- [ ] Déployer sur le VPS
|
- [x] Déployer sur le VPS
|
||||||
|
|
||||||
## Corriger l'accès des formateurs à la liste des inscrits
|
## Corriger l'accès des formateurs à la liste des inscrits
|
||||||
|
|
||||||
- [x] Identifier les procédures concernées (listBySequence, getWithDates)
|
- [x] Identifier les procédures concernées (listBySequence, getWithDates)
|
||||||
- [x] Remplacer adminProcedure par protectedProcedure
|
- [x] Remplacer adminProcedure par protectedProcedure
|
||||||
- [ ] Déployer sur le VPS
|
- [x] Déployer sur le VPS
|
||||||
|
|
||||||
## Masquer le menu "Gestion technique" pour les formateurs
|
## Masquer le menu "Gestion technique" pour les formateurs
|
||||||
|
|
||||||
- [x] Identifier le composant DashboardLayout où le menu est défini
|
- [x] Identifier le composant DashboardLayout où le menu est défini
|
||||||
- [x] Ajouter une condition isAdmin pour masquer la section Gestion technique
|
- [x] Ajouter une condition isAdmin pour masquer la section Gestion technique
|
||||||
- [ ] Tester et déployer sur le VPS
|
- [x] Tester et déployer sur le VPS
|
||||||
|
|
||||||
|
## Synchronisation entre table users (rôle formateur) et table formateurs
|
||||||
|
|
||||||
|
- [x] Analyser la structure des deux tables
|
||||||
|
- [x] Comprendre la relation entre users.role='formateur' et la table formateurs
|
||||||
|
- [x] Proposer une solution pour synchroniser ou clarifier l'usage
|
||||||
|
- [x] Implémenter la solution (auto-création dans createUser et updateUser)
|
||||||
|
- [x] Créer un script de migration pour les formateurs existants
|
||||||
|
- [ ] Déployer sur le VPS
|
||||||
|
|||||||
Reference in New Issue
Block a user