diff --git a/client/src/pages/SolutionsLogicielles.tsx b/client/src/pages/SolutionsLogicielles.tsx index 7c3f81f..a39efe4 100644 --- a/client/src/pages/SolutionsLogicielles.tsx +++ b/client/src/pages/SolutionsLogicielles.tsx @@ -195,8 +195,8 @@ export default function SolutionsLogicielles() { className="flex-1 flex items-center justify-between px-5 py-4 text-left hover:bg-muted/30 transition-colors" >
-
- +
0 ? 'bg-green-500/10' : 'bg-blue-500/10'}`}> + 0 ? 'text-green-600' : 'text-blue-600'} />
{sol.solutionNom}
@@ -312,7 +312,7 @@ export default function SolutionsLogicielles() { <>
- + 0 ? 'text-green-600 flex-shrink-0' : 'text-blue-500 flex-shrink-0'} /> {sol.solutionNom}
diff --git a/export_sandbox_data.mjs b/export_sandbox_data.mjs new file mode 100644 index 0000000..89aa41f --- /dev/null +++ b/export_sandbox_data.mjs @@ -0,0 +1,98 @@ +/** + * Export des données de la base Sandbox SONUM vers un script SQL d'injection. + * Tables exportées : blocs_fonctionnels, editeurs, etablissements, solutions, + * logiciels_etablissements, consultations, demandes_contact, user_etablissements + * Tables exclues : users, local_credentials, __drizzle_migrations + */ +import mysql from 'mysql2/promise'; +import fs from 'fs'; + +const TABLES_TO_EXPORT = [ + 'blocs_fonctionnels', + 'editeurs', + 'etablissements', + 'solutions', + 'logiciels_etablissements', + 'consultations', + 'demandes_contact', + 'user_etablissements', +]; + +const conn = await mysql.createConnection(process.env.DATABASE_URL); + +let sql = `-- Export données SONUM Sandbox → VPS +-- Généré le ${new Date().toISOString()} +-- Tables : ${TABLES_TO_EXPORT.join(', ')} +-- ATTENTION : exclut users, local_credentials, __drizzle_migrations + +SET FOREIGN_KEY_CHECKS = 0; +SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'; + +`; + +for (const table of TABLES_TO_EXPORT) { + console.log(`Exporting table: ${table}...`); + + // Récupérer la structure de la table + const [[createResult]] = await conn.execute(`SHOW CREATE TABLE \`${table}\``); + const createSQL = createResult['Create Table']; + + // Récupérer les données + const [rows] = await conn.execute(`SELECT * FROM \`${table}\``); + + sql += `-- ─────────────────────────────────────────────────────────────────\n`; + sql += `-- Table: ${table} (${rows.length} lignes)\n`; + sql += `-- ─────────────────────────────────────────────────────────────────\n`; + sql += `TRUNCATE TABLE \`${table}\`;\n\n`; + + if (rows.length === 0) { + sql += `-- (aucune donnée)\n\n`; + continue; + } + + // Générer les INSERT par lots de 50 + const columns = Object.keys(rows[0]); + const colList = columns.map(c => `\`${c}\``).join(', '); + + const BATCH_SIZE = 50; + for (let i = 0; i < rows.length; i += BATCH_SIZE) { + const batch = rows.slice(i, i + BATCH_SIZE); + const values = batch.map(row => { + const vals = columns.map(col => { + const v = row[col]; + if (v === null || v === undefined) return 'NULL'; + if (typeof v === 'number' || typeof v === 'bigint') return String(v); + if (typeof v === 'boolean') return v ? '1' : '0'; + if (v instanceof Date) return `'${v.toISOString().slice(0, 19).replace('T', ' ')}'`; + // Escape string + const escaped = String(v) + .replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\0/g, '\\0'); + return `'${escaped}'`; + }); + return `(${vals.join(', ')})`; + }); + sql += `INSERT INTO \`${table}\` (${colList}) VALUES\n${values.join(',\n')};\n`; + } + sql += `\n`; +} + +sql += `SET FOREIGN_KEY_CHECKS = 1;\n`; +sql += `-- Fin de l'export\n`; + +await conn.end(); + +const outputPath = '/home/ubuntu/sonum_data_export.sql'; +fs.writeFileSync(outputPath, sql, 'utf8'); + +const stats = fs.statSync(outputPath); +console.log(`\nExport terminé : ${outputPath}`); +console.log(`Taille : ${(stats.size / 1024).toFixed(1)} KB`); +console.log(`\nRésumé par table :`); +for (const table of TABLES_TO_EXPORT) { + const matches = sql.match(new RegExp(`-- Table: ${table} \\((\\d+) lignes\\)`)); + if (matches) console.log(` ${table}: ${matches[1]} lignes`); +} diff --git a/seed-admin.mjs b/seed-admin.mjs index 18d8655..95835fb 100644 --- a/seed-admin.mjs +++ b/seed-admin.mjs @@ -4,22 +4,33 @@ */ import mysql from 'mysql2/promise'; import bcrypt from 'bcrypt'; +import { randomUUID } from 'crypto'; const conn = await mysql.createConnection(process.env.DATABASE_URL); // Vérifier si adminItinova existe déjà -const [rows] = await conn.execute("SELECT id FROM users WHERE login = 'adminItinova' LIMIT 1"); +const [rows] = await conn.execute("SELECT id, openId FROM users WHERE login = 'adminItinova' LIMIT 1"); if (rows.length > 0) { - console.log('Compte adminItinova déjà existant, seed ignoré.'); + const existing = rows[0]; + // Si openId est null, le corriger pour permettre la connexion JWT + if (!existing.openId) { + const openId = `local:adminItinova:${randomUUID()}`; + await conn.execute("UPDATE users SET openId = ? WHERE id = ?", [openId, existing.id]); + console.log(`Compte adminItinova : openId corrigé (id=${existing.id})`); + } else { + console.log('Compte adminItinova déjà existant, seed ignoré.'); + } await conn.end(); process.exit(0); } -// Créer l'utilisateur adminItinova +// Créer l'utilisateur adminItinova avec un openId local unique +const openId = `local:adminItinova:${randomUUID()}`; + const [result] = await conn.execute( - `INSERT INTO users (login, email, firstName, lastName, name, role, sonumRole, isActive, loginMethod, cguAccepted, lastSignedIn, createdAt, updatedAt) - VALUES (?, ?, ?, ?, ?, 'admin', 'gestionnaire', 1, 'local', 1, NOW(), NOW(), NOW())`, - ['adminItinova', 'adminItinova@santinova-soft.org', 'Admin', 'SONUM', 'Admin SONUM'] + `INSERT INTO users (login, email, firstName, lastName, name, openId, role, sonumRole, isActive, loginMethod, cguAccepted, lastSignedIn, createdAt, updatedAt) + VALUES (?, ?, ?, ?, ?, ?, 'admin', 'gestionnaire', 1, 'local', 1, NOW(), NOW(), NOW())`, + ['adminItinova', 'adminItinova@santinova-soft.org', 'Admin', 'SONUM', 'Admin SONUM', openId] ); const userId = result.insertId; @@ -31,5 +42,5 @@ await conn.execute( [userId, hash] ); -console.log(`Compte adminItinova créé avec succès (id=${userId})`); +console.log(`Compte adminItinova créé avec succès (id=${userId}, openId=${openId})`); await conn.end();