the-tip-top-backend/scripts/verify-admin-endpoints.js
2025-11-17 23:47:54 +01:00

239 lines
7.6 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Script de vérification des endpoints admin
* Teste que tous les endpoints sont accessibles et répondent correctement
*/
import 'dotenv/config';
const API_URL = process.env.API_URL || 'http://localhost:5000';
// Codes couleur pour terminal
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
cyan: '\x1b[36m',
};
const log = {
success: (msg) => console.log(`${colors.green}${msg}${colors.reset}`),
error: (msg) => console.log(`${colors.red}${msg}${colors.reset}`),
info: (msg) => console.log(`${colors.blue} ${msg}${colors.reset}`),
warn: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`),
section: (msg) => console.log(`\n${colors.cyan}${'='.repeat(60)}${colors.reset}\n${colors.cyan}${msg}${colors.reset}\n${colors.cyan}${'='.repeat(60)}${colors.reset}`),
};
/**
* Vérifie qu'un endpoint répond (sans authentification)
*/
async function checkEndpoint(method, path, description) {
try {
const response = await fetch(`${API_URL}${path}`, {
method,
headers: { 'Content-Type': 'application/json' },
});
const statusOk = response.status >= 200 && response.status < 500;
if (statusOk) {
log.success(`${method} ${path} - ${response.status} - ${description}`);
return { success: true, status: response.status, path };
} else {
log.error(`${method} ${path} - ${response.status} - ${description}`);
return { success: false, status: response.status, path };
}
} catch (error) {
log.error(`${method} ${path} - NETWORK ERROR - ${error.message}`);
return { success: false, error: error.message, path };
}
}
/**
* Teste les routes publiques
*/
async function testPublicRoutes() {
log.section('🌍 Routes Publiques');
const routes = [
{ method: 'GET', path: '/', desc: 'API status' },
{ method: 'GET', path: '/db-check', desc: 'Database connection' },
{ method: 'GET', path: '/metrics', desc: 'Prometheus metrics' },
];
const results = [];
for (const route of routes) {
const result = await checkEndpoint(route.method, route.path, route.desc);
results.push(result);
}
return results;
}
/**
* Teste les routes d'authentification
*/
async function testAuthRoutes() {
log.section('🔐 Routes Authentification');
const routes = [
{ method: 'POST', path: '/api/auth/register', desc: 'Register endpoint' },
{ method: 'POST', path: '/api/auth/login', desc: 'Login endpoint' },
{ method: 'POST', path: '/api/auth/oauth/google', desc: 'Google OAuth endpoint' },
{ method: 'POST', path: '/api/auth/oauth/facebook', desc: 'Facebook OAuth endpoint' },
];
const results = [];
for (const route of routes) {
const result = await checkEndpoint(route.method, route.path, route.desc);
results.push(result);
}
return results;
}
/**
* Teste les routes admin (doivent retourner 401/403 sans token)
*/
async function testAdminRoutes() {
log.section('👑 Routes Admin (protected)');
const routes = [
{ method: 'GET', path: '/api/admin/statistics', desc: 'Dashboard statistics' },
{ method: 'GET', path: '/api/admin/users', desc: 'Get all users' },
{ method: 'GET', path: '/api/admin/tickets', desc: 'Get all tickets' },
{ method: 'POST', path: '/api/admin/generate-tickets', desc: 'Generate tickets' },
{ method: 'GET', path: '/api/game/prizes', desc: 'Get prizes' },
];
log.info('Ces routes doivent retourner 401 (Unauthorized) sans token - c\'est normal!');
const results = [];
for (const route of routes) {
const result = await checkEndpoint(route.method, route.path, route.desc);
// Pour les routes protégées, 401 est un succès (route existe et est protégée)
if (result.status === 401 || result.status === 403) {
result.isProtected = true;
log.info(` → Route correctement protégée`);
}
results.push(result);
}
return results;
}
/**
* Teste les routes de tirage au sort
*/
async function testDrawRoutes() {
log.section('🎲 Routes Tirage au Sort (protected)');
const routes = [
{ method: 'GET', path: '/api/draw/eligible-participants', desc: 'Get eligible participants' },
{ method: 'GET', path: '/api/draw/check-existing', desc: 'Check existing draw' },
{ method: 'POST', path: '/api/draw/conduct', desc: 'Conduct draw' },
{ method: 'GET', path: '/api/draw/history', desc: 'Draw history' },
];
log.info('Ces routes doivent retourner 401 (Unauthorized) sans token - c\'est normal!');
const results = [];
for (const route of routes) {
const result = await checkEndpoint(route.method, route.path, route.desc);
if (result.status === 401 || result.status === 403) {
result.isProtected = true;
log.info(` → Route correctement protégée`);
}
results.push(result);
}
return results;
}
/**
* Résumé final
*/
function printSummary(allResults) {
log.section('📊 Résumé de la Vérification');
const total = allResults.length;
const reachable = allResults.filter(r => r.success).length;
const protectedRoutes = allResults.filter(r => r.isProtected).length;
const errors = allResults.filter(r => !r.success && !r.isProtected).length;
console.log(`Total endpoints testés: ${total}`);
console.log(`${colors.green}✅ Endpoints accessibles: ${reachable}${colors.reset}`);
console.log(`${colors.blue}🔒 Endpoints protégés: ${protectedRoutes}${colors.reset}`);
console.log(`${colors.red}❌ Erreurs: ${errors}${colors.reset}`);
const successRate = Math.round(((reachable + protectedRoutes) / total) * 100);
console.log(`\n${colors.cyan}Taux de succès: ${successRate}%${colors.reset}`);
if (successRate === 100) {
log.success('Tous les endpoints sont opérationnels! 🎉');
} else if (successRate >= 90) {
log.warn('Quelques endpoints ont des problèmes mineurs');
} else {
log.error('Plusieurs endpoints ne fonctionnent pas correctement');
}
// Afficher les erreurs
const failed = allResults.filter(r => !r.success && !r.isProtected);
if (failed.length > 0) {
console.log(`\n${colors.red}Endpoints en erreur:${colors.reset}`);
failed.forEach(f => {
console.log(` - ${f.path} (${f.status || 'NETWORK ERROR'})`);
});
}
}
/**
* Fonction principale
*/
async function main() {
console.log(`${colors.cyan}`);
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ VÉRIFICATION DES ENDPOINTS ADMIN - THÉ TIP TOP ║');
console.log('╚════════════════════════════════════════════════════════════╝');
console.log(`${colors.reset}\n`);
log.info(`API URL: ${API_URL}`);
log.info('Démarrage des tests...\n');
try {
const allResults = [];
// Test routes publiques
const publicResults = await testPublicRoutes();
allResults.push(...publicResults);
// Test routes auth
const authResults = await testAuthRoutes();
allResults.push(...authResults);
// Test routes admin
const adminResults = await testAdminRoutes();
allResults.push(...adminResults);
// Test routes tirage
const drawResults = await testDrawRoutes();
allResults.push(...drawResults);
// Résumé
printSummary(allResults);
// Exit code
const hasErrors = allResults.some(r => !r.success && !r.isProtected);
process.exit(hasErrors ? 1 : 0);
} catch (error) {
log.error(`Erreur critique: ${error.message}`);
console.error(error);
process.exit(1);
}
}
// Lancer le script
main();