diff --git a/admin/package.json b/admin/package.json index 3d68faa..2613e31 100644 --- a/admin/package.json +++ b/admin/package.json @@ -5,8 +5,8 @@ "scripts": { "dev": "next dev", "build": "prisma generate --schema=../prisma/schema.prisma && next build", - "start": "node ../scripts/ensure-admin.cjs && next start -p 3000", - "db:init-admin": "node ../scripts/ensure-admin.cjs", + "start": "(node ../scripts/ensure-admin.cjs || node scripts/ensure-admin.cjs || true) && next start", + "db:init-admin": "node ../scripts/ensure-admin.cjs || node scripts/ensure-admin.cjs", "lint": "eslint" }, "dependencies": { diff --git a/admin/scripts/ensure-admin.cjs b/admin/scripts/ensure-admin.cjs new file mode 100644 index 0000000..0fd9177 --- /dev/null +++ b/admin/scripts/ensure-admin.cjs @@ -0,0 +1,111 @@ +const path = require('path'); +const fs = require('fs'); + +// Si le script racine existe (monorepo), on peut le déléguer directement +const rootScript = path.resolve(__dirname, '../../scripts/ensure-admin.cjs'); +if (fs.existsSync(rootScript)) { + require(rootScript); +} else { + // Sinon exécution autonome dans admin + const { PrismaClient } = require('@prisma/client'); + const bcrypt = require('bcryptjs'); + + const prisma = new PrismaClient(); + + async function waitForDatabase(prismaClient, maxRetries = 30, delayMs = 2000) { + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + await prismaClient.$executeRawUnsafe('SELECT 1;'); + console.log('✅ Base de données prête et accessible.'); + return true; + } catch (err) { + const msg = err.message || ''; + const isStartingUp = msg.includes('the database system is starting up') || + msg.includes('57P03') || + msg.includes('ConnectionRefused') || + msg.includes("Can't reach database server"); + + const info = isStartingUp ? 'PostgreSQL est en cours de démarrage...' : msg.split('\n')[0].substring(0, 80); + console.log(`⏳ En attente de la base de données (${attempt}/${maxRetries}) : ${info}`); + + if (attempt === maxRetries) { + throw new Error(`Délai dépassé en attendant la base de données après ${maxRetries} tentatives (${maxRetries * (delayMs / 1000)}s): ${msg}`); + } + await new Promise(resolve => setTimeout(resolve, delayMs)); + } + } + } + + async function main() { + const email = 'admin@afrohub.com'; + const initialPassword = process.env.ADMIN_INITIAL_PASSWORD || 'afrohub2025'; + + console.log(`🔍 Vérification du compte Super Admin (${email})...`); + + await waitForDatabase(prisma); + + try { + await prisma.$executeRawUnsafe(` + ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "adminRole" TEXT DEFAULT 'ADMIN'; + `); + await prisma.$executeRawUnsafe(` + ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "adminPermissions" TEXT[] DEFAULT ARRAY[]::TEXT[]; + `); + console.log(`✅ Structure des colonnes vérifiée / mise à jour.`); + } catch (err) { + console.warn(`⚠️ Note sur la mise à jour des colonnes:`, err.message); + } + + const existing = await prisma.user.findFirst({ + where: { email: { equals: email, mode: 'insensitive' } } + }); + + if (existing) { + if (existing.adminRole !== 'SUPER_ADMIN' || existing.role !== 'ADMIN' || existing.isSuspended) { + await prisma.user.update({ + where: { id: existing.id }, + data: { + role: 'ADMIN', + adminRole: 'SUPER_ADMIN', + isSuspended: false + } + }); + console.log(`✅ Compte existant mis à jour en SUPER_ADMIN (${email}).`); + } else { + console.log(`✅ Le compte Super Admin (${email}) est déjà présent et actif.`); + } + return; + } + + const hashedPassword = await bcrypt.hash(initialPassword, 10); + + const created = await prisma.user.create({ + data: { + name: 'Admin Afrohub', + email: email, + password: hashedPassword, + role: 'ADMIN', + adminRole: 'SUPER_ADMIN', + adminPermissions: [], + emailVerified: true + } + }); + + console.log(`🎉 Compte Super Admin créé avec succès !`); + console.log(` Email: ${created.email}`); + console.log(` Rôle: ${created.adminRole}`); + console.log(` Mot de passe initial: ${process.env.ADMIN_INITIAL_PASSWORD ? '(défini via ADMIN_INITIAL_PASSWORD)' : 'afrohub2025'}`); + } + + main() + .catch(err => { + console.error("⚠️ Note lors de l'initialisation du Super Admin:", err.message || err); + console.warn("⚠️ Poursuite du démarrage de l'application Next.js..."); + process.exit(0); + }) + .finally(async () => { + try { + await prisma.$disconnect(); + } catch (_) {} + }); +} diff --git a/scripts/ensure-admin.cjs b/scripts/ensure-admin.cjs index 150f552..9fa10fb 100644 --- a/scripts/ensure-admin.cjs +++ b/scripts/ensure-admin.cjs @@ -3,12 +3,39 @@ const bcrypt = require('bcryptjs'); const prisma = new PrismaClient(); +async function waitForDatabase(prismaClient, maxRetries = 30, delayMs = 2000) { + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + await prismaClient.$executeRawUnsafe('SELECT 1;'); + console.log('✅ Base de données prête et accessible.'); + return true; + } catch (err) { + const msg = err.message || ''; + const isStartingUp = msg.includes('the database system is starting up') || + msg.includes('57P03') || + msg.includes('ConnectionRefused') || + msg.includes("Can't reach database server"); + + const info = isStartingUp ? 'PostgreSQL est en cours de démarrage...' : msg.split('\n')[0].substring(0, 80); + console.log(`⏳ En attente de la base de données (${attempt}/${maxRetries}) : ${info}`); + + if (attempt === maxRetries) { + throw new Error(`Délai dépassé en attendant la base de données après ${maxRetries} tentatives (${maxRetries * (delayMs / 1000)}s): ${msg}`); + } + await new Promise(resolve => setTimeout(resolve, delayMs)); + } + } +} + async function main() { const email = 'admin@afrohub.com'; const initialPassword = process.env.ADMIN_INITIAL_PASSWORD || 'afrohub2025'; console.log(`🔍 Vérification du compte Super Admin (${email})...`); + // Attente que la base de données soit prête à accepter les requêtes + await waitForDatabase(prisma); + // Auto-migration: Ensure columns adminRole and adminPermissions exist try { await prisma.$executeRawUnsafe(` @@ -65,9 +92,13 @@ async function main() { main() .catch(err => { - console.error("❌ Erreur lors de l'initialisation du Super Admin:", err); - process.exit(1); + console.error("⚠️ Note lors de l'initialisation du Super Admin:", err.message || err); + console.warn("⚠️ Poursuite du démarrage de l'application Next.js..."); + // Ne pas crasher le conteneur en production si le script de vérification échoue + process.exit(0); }) .finally(async () => { - await prisma.$disconnect(); + try { + await prisma.$disconnect(); + } catch (_) {} });