feat: add admin package configuration and automated super admin initialization script
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "prisma generate --schema=../prisma/schema.prisma && next build",
|
"build": "prisma generate --schema=../prisma/schema.prisma && next build",
|
||||||
"start": "node ../scripts/ensure-admin.cjs && next start -p 3000",
|
"start": "(node ../scripts/ensure-admin.cjs || node scripts/ensure-admin.cjs || true) && next start",
|
||||||
"db:init-admin": "node ../scripts/ensure-admin.cjs",
|
"db:init-admin": "node ../scripts/ensure-admin.cjs || node scripts/ensure-admin.cjs",
|
||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
111
admin/scripts/ensure-admin.cjs
Normal file
111
admin/scripts/ensure-admin.cjs
Normal file
@@ -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 (_) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -3,12 +3,39 @@ const bcrypt = require('bcryptjs');
|
|||||||
|
|
||||||
const prisma = new PrismaClient();
|
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() {
|
async function main() {
|
||||||
const email = 'admin@afrohub.com';
|
const email = 'admin@afrohub.com';
|
||||||
const initialPassword = process.env.ADMIN_INITIAL_PASSWORD || 'afrohub2025';
|
const initialPassword = process.env.ADMIN_INITIAL_PASSWORD || 'afrohub2025';
|
||||||
|
|
||||||
console.log(`🔍 Vérification du compte Super Admin (${email})...`);
|
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
|
// Auto-migration: Ensure columns adminRole and adminPermissions exist
|
||||||
try {
|
try {
|
||||||
await prisma.$executeRawUnsafe(`
|
await prisma.$executeRawUnsafe(`
|
||||||
@@ -65,9 +92,13 @@ async function main() {
|
|||||||
|
|
||||||
main()
|
main()
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error("❌ Erreur lors de l'initialisation du Super Admin:", err);
|
console.error("⚠️ Note lors de l'initialisation du Super Admin:", err.message || err);
|
||||||
process.exit(1);
|
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 () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
try {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
} catch (_) {}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user