Class_generator/test-digitalocean.html
StillHammer fe7153d28b Fix compatibility system and improve UX
- Add intelligent content-game compatibility system with visual badges
- Fix Adventure Reader to work with Dragon's Pearl content structure
- Implement multi-column games grid for faster navigation
- Add pronunciation display for Chinese vocabulary and sentences
- Fix navigation breadcrumb to show proper hierarchy (Home > Levels > Content)
- Add back buttons to all navigation pages
- Improve JSONContentLoader to preserve story structure
- Add comprehensive debugging and diagnostic tools

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-18 19:29:21 +08:00

374 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test DigitalOcean Spaces Connection</title>
<style>
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
h1 {
color: #333;
border-bottom: 3px solid #667eea;
padding-bottom: 10px;
}
.test-section {
margin: 20px 0;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #667eea;
}
.test-result {
margin: 10px 0;
padding: 15px;
border-radius: 5px;
font-family: 'Courier New', monospace;
font-size: 14px;
white-space: pre-wrap;
word-break: break-all;
}
.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.warning {
background: #fff3cd;
border: 1px solid #ffeeba;
color: #856404;
}
.info {
background: #d1ecf1;
border: 1px solid #bee5eb;
color: #0c5460;
}
button {
background: #667eea;
color: white;
border: none;
padding: 12px 24px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 5px;
transition: all 0.3s;
}
button:hover {
background: #5a67d8;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
button:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
}
.spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.config-display {
background: #2d3748;
color: #48bb78;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
font-family: 'Courier New', monospace;
}
.test-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.test-card {
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-card h3 {
margin-top: 0;
color: #4a5568;
}
.status-indicator {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
}
.status-indicator.success { background: #48bb78; }
.status-indicator.error { background: #f56565; }
.status-indicator.pending { background: #ed8936; }
</style>
</head>
<body>
<div class="container">
<h1>🔧 Test de Connexion DigitalOcean Spaces</h1>
<div class="test-section">
<h2>📋 Configuration Actuelle</h2>
<div id="config" class="config-display">Chargement...</div>
</div>
<div class="test-section">
<h2>🧪 Tests de Connexion</h2>
<div>
<button onclick="runAllTests()">🚀 Lancer Tous les Tests</button>
<button onclick="testPublicAccess()">🌐 Test Accès Public</button>
<button onclick="testWithAuth()">🔐 Test avec Authentification</button>
<button onclick="testCORS()">🔄 Test CORS</button>
<button onclick="clearResults()">🗑️ Effacer Résultats</button>
</div>
</div>
<div class="test-grid" id="testGrid"></div>
<div class="test-section">
<h2>📊 Résultats Détaillés</h2>
<div id="results"></div>
</div>
<div class="test-section">
<h2>💡 Recommandations</h2>
<div id="recommendations" class="info">
Les recommandations apparaîtront après les tests...
</div>
</div>
</div>
<!-- Charger les scripts nécessaires -->
<script src="js/core/env-config.js"></script>
<script>
// Désactiver temporairement les logs pour éviter les erreurs
if (typeof logSh === 'undefined') {
window.logSh = function(msg, level) {
console.log(`[${level}] ${msg}`);
};
}
// Afficher la configuration
function displayConfig() {
const config = window.envConfig.getDiagnostics();
document.getElementById('config').innerHTML = JSON.stringify(config, null, 2);
}
// Fonction pour ajouter un résultat
function addResult(message, type = 'info') {
const resultsDiv = document.getElementById('results');
const resultDiv = document.createElement('div');
resultDiv.className = `test-result ${type}`;
resultDiv.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
resultsDiv.appendChild(resultDiv);
}
// Fonction pour ajouter une carte de test
function addTestCard(title, status, details) {
const grid = document.getElementById('testGrid');
const card = document.createElement('div');
card.className = 'test-card';
card.innerHTML = `
<h3><span class="status-indicator ${status}"></span>${title}</h3>
<div>${details}</div>
`;
grid.appendChild(card);
}
// Test d'accès public (sans auth)
async function testPublicAccess() {
addResult('Test d\'accès public sans authentification...', 'info');
try {
const url = window.envConfig.getRemoteContentUrl() + 'test.json';
addResult(`URL testée: ${url}`, 'info');
const response = await fetch(url, {
method: 'HEAD',
mode: 'cors'
});
if (response.ok) {
addResult('✅ Accès public réussi!', 'success');
addTestCard('Accès Public', 'success', 'Le bucket est accessible publiquement');
} else if (response.status === 403) {
addResult('🔒 Accès refusé (403) - Le bucket est privé', 'warning');
addTestCard('Accès Public', 'error', 'Bucket privé - Authentification requise');
} else {
addResult(`❌ Erreur: Status ${response.status}`, 'error');
addTestCard('Accès Public', 'error', `Status HTTP: ${response.status}`);
}
} catch (error) {
addResult(`❌ Erreur réseau: ${error.message}`, 'error');
if (error.message.includes('CORS')) {
addResult('⚠️ Problème CORS détecté - Vérifiez la configuration CORS du bucket', 'warning');
addTestCard('Accès Public', 'error', 'Erreur CORS');
} else {
addTestCard('Accès Public', 'error', error.message);
}
}
}
// Test avec authentification
async function testWithAuth() {
addResult('Test avec authentification AWS Signature v4...', 'info');
try {
const testUrl = window.envConfig.getRemoteContentUrl() + 'test.json';
const authHeaders = await window.envConfig.getAuthHeaders('GET', testUrl);
addResult('Headers d\'authentification générés:', 'info');
addResult(JSON.stringify(authHeaders, null, 2), 'info');
const response = await fetch(testUrl, {
method: 'GET',
headers: authHeaders,
mode: 'cors'
});
if (response.ok) {
addResult('✅ Authentification réussie!', 'success');
const data = await response.text();
addResult(`Contenu reçu: ${data.substring(0, 200)}...`, 'success');
addTestCard('Authentification', 'success', 'Connexion authentifiée réussie');
} else {
addResult(`❌ Authentification échouée: Status ${response.status}`, 'error');
addResult(`Message: ${response.statusText}`, 'error');
addTestCard('Authentification', 'error', `Status: ${response.status}`);
}
} catch (error) {
addResult(`❌ Erreur: ${error.message}`, 'error');
addTestCard('Authentification', 'error', error.message);
}
}
// Test CORS
async function testCORS() {
addResult('Test de la configuration CORS...', 'info');
try {
const url = window.envConfig.getRemoteContentUrl();
// Test OPTIONS (preflight)
const response = await fetch(url, {
method: 'OPTIONS',
headers: {
'Origin': window.location.origin,
'Access-Control-Request-Method': 'GET',
'Access-Control-Request-Headers': 'authorization'
}
});
const corsHeaders = {
'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers')
};
addResult('Headers CORS reçus:', 'info');
addResult(JSON.stringify(corsHeaders, null, 2), 'info');
if (corsHeaders['Access-Control-Allow-Origin']) {
addResult('✅ CORS configuré', 'success');
addTestCard('Configuration CORS', 'success', 'Headers CORS présents');
} else {
addResult('⚠️ Headers CORS manquants', 'warning');
addTestCard('Configuration CORS', 'error', 'Headers CORS non configurés');
}
} catch (error) {
addResult(`❌ Test CORS échoué: ${error.message}`, 'error');
addTestCard('Configuration CORS', 'error', 'Test échoué');
}
}
// Lancer tous les tests
async function runAllTests() {
clearResults();
addResult('🚀 Démarrage de la suite de tests complète...', 'info');
await testPublicAccess();
await new Promise(resolve => setTimeout(resolve, 1000));
await testWithAuth();
await new Promise(resolve => setTimeout(resolve, 1000));
await testCORS();
// Test de connexion via EnvConfig
addResult('Test via EnvConfig.testRemoteConnection()...', 'info');
const result = await window.envConfig.testRemoteConnection();
addResult(`Résultat: ${JSON.stringify(result, null, 2)}`, result.success ? 'success' : 'error');
generateRecommendations();
}
// Générer des recommandations
function generateRecommendations() {
const recoDiv = document.getElementById('recommendations');
let recommendations = [];
const results = document.getElementById('results').textContent;
if (results.includes('403')) {
recommendations.push('🔐 Le bucket est privé. Assurez-vous que les clés d\'API sont correctes.');
}
if (results.includes('CORS')) {
recommendations.push('🔄 Configurez CORS sur votre bucket DigitalOcean Spaces:');
recommendations.push(' - Allez dans les paramètres du bucket');
recommendations.push(' - Ajoutez une règle CORS pour autoriser votre origine');
recommendations.push(' - Origine: * ou file:// pour les fichiers locaux');
}
if (results.includes('Authentification échouée')) {
recommendations.push('🔑 Vérifiez vos clés d\'accès DigitalOcean dans env-config.js');
}
if (recommendations.length === 0) {
recommendations.push('✅ Tout semble fonctionner correctement!');
}
recoDiv.innerHTML = recommendations.join('<br>');
}
// Effacer les résultats
function clearResults() {
document.getElementById('results').innerHTML = '';
document.getElementById('testGrid').innerHTML = '';
document.getElementById('recommendations').innerHTML = 'Les recommandations apparaîtront après les tests...';
}
// Initialisation
displayConfig();
addResult('Page de test prête. Cliquez sur "Lancer Tous les Tests" pour commencer.', 'info');
</script>
</body>
</html>