// Configuration API const API_URL = 'http://localhost:4001/api'; // State let currentUser = null; let isAuthenticated = false; // Initialisation document.addEventListener('DOMContentLoaded', () => { checkAuth(); }); // Vérifier l'authentification async function checkAuth() { try { const response = await fetch(`${API_URL}/auth/check`, { credentials: 'include' }); const data = await response.json(); if (data.authenticated) { currentUser = data.user; isAuthenticated = true; showDashboard(); } else { showLoginPage(); } } catch (e) { console.error('Erreur vérification auth:', e); showLoginPage(); } } // Afficher la page de connexion function showLoginPage() { document.getElementById('app').innerHTML = `

🎮 NationsGlory Admin

Connexion

Pas encore de compte? Créer un compte
`; // Par défaut, montrer le formulaire de connexion const regForm = document.getElementById('registerForm'); const loginForm = document.getElementById('loginForm'); if (regForm && loginForm) { regForm.style.display = 'none'; loginForm.style.display = 'block'; } } // Connexion async function handleLogin() { const username = document.getElementById('username').value; const password = document.getElementById('password').value; if (!username || !password) { showMessage('Veuillez remplir tous les champs', 'error', 'loginMessage'); return; } try { const response = await fetch(`${API_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ username, password }) }); const data = await response.json(); if (response.ok) { currentUser = data.user; isAuthenticated = true; showDashboard(); } else { showMessage(data.error || 'Erreur de connexion', 'error', 'loginMessage'); } } catch (e) { console.error('Erreur connexion:', e); showMessage('Erreur serveur', 'error', 'loginMessage'); } } // Enregistrement async function handleRegister() { const username = document.getElementById('regUsername').value; const password = document.getElementById('regPassword').value; const mcUsername = document.getElementById('mcUsername').value; if (!username || !password || !mcUsername) { showMessage('Veuillez remplir tous les champs', 'error', 'loginMessage'); return; } try { const response = await fetch(`${API_URL}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ username, password, mcUsername }) }); const data = await response.json(); if (response.ok) { showMessage('Compte créé! Connectez-vous maintenant.', 'success', 'loginMessage'); setTimeout(() => { document.getElementById('registerForm').style.display = 'none'; document.getElementById('loginForm').style.display = 'block'; document.getElementById('username').value = username; document.getElementById('password').value = ''; }, 1000); } else { showMessage(data.error || 'Erreur d\'enregistrement', 'error', 'loginMessage'); } } catch (e) { console.error('Erreur enregistrement:', e); showMessage('Erreur serveur', 'error', 'loginMessage'); } } // Basculer vers le formulaire de connexion function toggleToLogin(event) { event.preventDefault(); const regForm = document.getElementById('registerForm'); const loginForm = document.getElementById('loginForm'); if (regForm && loginForm) { regForm.style.display = 'none'; loginForm.style.display = 'block'; document.getElementById('loginMessage').innerHTML = ''; // Effacer les champs document.getElementById('username').value = ''; document.getElementById('password').value = ''; } } // Basculer vers le formulaire d'enregistrement function toggleToRegister(event) { event.preventDefault(); const regForm = document.getElementById('registerForm'); const loginForm = document.getElementById('loginForm'); if (regForm && loginForm) { loginForm.style.display = 'none'; regForm.style.display = 'block'; document.getElementById('loginMessage').innerHTML = ''; // Effacer les champs document.getElementById('regUsername').value = ''; document.getElementById('regPassword').value = ''; document.getElementById('mcUsername').value = ''; } } // Afficher le dashboard function showDashboard() { document.getElementById('app').innerHTML = `

🎮 NationsGlory Admin Panel

${getDashboardHTML()}
${getConsoleHTML()}
${getLogsHTML()}
${getPlayersHTML()}
${getWhitelistHTML()}
${getBackupsHTML()}
${getSettingsHTML()}
`; // Charger les données loadDashboardData(); } // Changer d'onglet function switchTab(tabName) { // Masquer tous les onglets document.querySelectorAll('.content-section').forEach(el => { el.classList.remove('active'); }); // Afficher l'onglet sélectionné document.getElementById(tabName).classList.add('active'); // Mettre à jour les boutons document.querySelectorAll('.nav-tabs button').forEach(btn => { btn.classList.remove('active'); }); event.target.classList.add('active'); // Charger les données spécifiques if (tabName === 'console') loadConsoleData(); if (tabName === 'logs') loadLogsData(); if (tabName === 'players') loadPlayersData(); if (tabName === 'whitelist') loadWhitelistData(); if (tabName === 'backups') loadBackupsData(); if (tabName === 'settings') loadSettingsData(); } // ========== DASHBOARD ========== function getDashboardHTML() { return `

🎮 Contrôle du Serveur

État Serveur

En ligne

Joueurs Connectés

0/20

Version Forge

1.6.4

📊 Informations Rapides

Chargement...
`; } async function loadDashboardData() { try { // Charger les joueurs en ligne await window.loadOnlinePlayers(); const response = await fetch(`${API_URL}/server`, { credentials: 'include' }); const data = await response.json(); if (data.properties) { const table = document.getElementById('quickInfoTable'); table.innerHTML = ` Nom Serveur${data.properties['motd'] || 'NationsGlory'} Mode Jeu${data.properties['gamemode'] || 'Survival'} Difficulté${data.properties['difficulty'] || '2'} PvP${data.properties['pvp'] === 'true' ? 'Activé' : 'Désactivé'} Port${data.properties['server-port'] || '25565'} Max Joueurs${data.properties['max-players'] || '20'} `; } // Mettre à jour le nombre de joueurs const onlineResponse = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'list' }) }); if (onlineResponse.ok) { const rconData = await onlineResponse.json(); const output = rconData.response || ''; const cleanOutput = output.replace(/§[0-9a-fk-or]/gi, ''); const match = cleanOutput.match(/There are (\d+) out of maximum (\d+) players online/i); if (match) { const onlineCount = parseInt(match[1]); const maxPlayers = parseInt(match[2]); document.getElementById('playerCount').textContent = `${onlineCount}/${maxPlayers}`; } } } catch (e) { console.error('Erreur chargement dashboard:', e); } } // ========== CONSOLE RCON ========== function getConsoleHTML() { return `

⌨️ Console RCON

Exécutez des commandes directement sur le serveur

admin@nationsglory:~$

�️ Actions Rapides

📜 Historique des Commandes

`; } async function loadConsoleData() { try { const search = document.getElementById('historySearch')?.value || ''; const url = new URL(`${API_URL}/rcon/history`); url.searchParams.set('limit', '50'); if (search) url.searchParams.set('search', search); const response = await fetch(url, { credentials: 'include' }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const data = await response.json(); const container = document.getElementById('historyContainer'); if (data.history && data.history.length > 0) { container.innerHTML = data.history.map(h => { const timestamp = new Date(h.timestamp).toLocaleString('fr-FR'); const statusIcon = h.success ? '✓' : '✗'; const statusColor = h.success ? '#28a745' : '#dc3545'; return `
${h.command}
${timestamp}
${statusIcon}
${h.response ? `
${h.response}
` : ''} ${h.error ? `
Erreur: ${h.error}
` : ''}
`; }).join(''); } else { container.innerHTML = '

Aucun historique

'; } } catch (e) { console.error('Erreur historique:', e); const container = document.getElementById('historyContainer'); container.innerHTML = `

Erreur lors du chargement: ${e.message}

`; } } async function clearRconHistory() { if (!confirm('Êtes-vous sûr de vouloir supprimer tout l\'historique?')) return; try { const response = await fetch(`${API_URL}/rcon/history`, { method: 'DELETE', credentials: 'include' }); if (response.ok) { showMessage('Historique supprimé', 'success', 'dashboardMessage'); loadConsoleData(); } else { showMessage('Erreur lors de la suppression', 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur suppression historique:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function sendRconCommand() { const commandInput = document.getElementById('commandInput'); const command = commandInput.value.trim(); if (!command) return; const output = document.getElementById('consoleOutput'); output.textContent += `admin@nationsglory:~$ ${command}\n`; commandInput.value = ''; try { const response = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command }) }); const data = await response.json(); if (response.ok) { const responseText = data.response || '(pas de réponse)'; output.textContent += `${responseText}\n`; showMessage('Commande exécutée ✓', 'success', 'dashboardMessage'); loadConsoleData(); // Rafraîchir l'historique } else { output.textContent += `Erreur: ${data.error}\n`; showMessage(data.error, 'error', 'dashboardMessage'); } output.scrollTop = output.scrollHeight; } catch (e) { console.error('Erreur envoi commande:', e); output.textContent += `Erreur serveur: ${e.message}\n`; showMessage('Erreur serveur', 'error', 'dashboardMessage'); output.scrollTop = output.scrollHeight; } } // Variables globales pour gérer l'arrêt du serveur let shutdownInProgress = false; let shutdownCancelToken = null; window.openSayModal = function() { document.getElementById('sayModal').style.display = 'flex'; }; window.sendSayCommand = async function() { const message = document.getElementById('sayInput').value.trim(); if (!message) { alert('Entrez un message'); return; } try { const response = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: `say ${message}` }) }); if (response.ok) { showMessage('Message envoyé ✓', 'success', 'dashboardMessage'); document.getElementById('sayInput').value = ''; document.getElementById('sayModal').style.display = 'none'; loadConsoleData(); } else { showMessage('Erreur lors de l\'envoi du message', 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur envoi message:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } }; window.openShutdownModal = function() { document.getElementById('shutdownModal').style.display = 'flex'; }; window.shutdownServer = async function() { const cooldown = parseInt(document.getElementById('shutdownCooldown').value); const message = document.getElementById('shutdownMessage').value.trim(); if (cooldown < 10 || cooldown > 600) { alert('Le cooldown doit être entre 10 et 600 secondes'); return; } if (!message) { alert('Entrez un message d\'avertissement'); return; } if (!confirm(`Êtes-vous sûr de vouloir arrêter le serveur dans ${cooldown} secondes?`)) { return; } try { shutdownInProgress = true; shutdownCancelToken = {}; document.getElementById('cancelShutdownBtn').style.display = 'block'; document.getElementById('shutdownModal').style.display = 'none'; showMessage(`⏳ Arrêt du serveur dans ${cooldown} secondes...`, 'warning', 'dashboardMessage'); let secondsRemaining = cooldown; while (secondsRemaining > 0 && shutdownInProgress && shutdownCancelToken) { if (secondsRemaining % 10 === 0 || secondsRemaining <= 10) { // Envoyer un avertissement tous les 10 secondes (ou chaque seconde dans les 10 dernières) const warningMsg = message.replace('{cooldown}', secondsRemaining); await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: `say ${warningMsg}` }) }).catch(() => {}); } await new Promise(resolve => setTimeout(resolve, 1000)); secondsRemaining--; } if (!shutdownInProgress || !shutdownCancelToken) { // Envoyer un message dans le chat pour informer de l'annulation await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'say Arrêt du serveur annulé!' }) }).catch(() => {}); showMessage('❌ Arrêt annulé', 'warning', 'dashboardMessage'); document.getElementById('cancelShutdownBtn').style.display = 'none'; document.getElementById('cancelShutdownBtnDash').style.display = 'none'; return; } // Envoyer la commande d'arrêt const response = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'stop' }) }); if (response.ok) { showMessage('✓ Serveur arrêté', 'success', 'dashboardMessage'); } else { showMessage('Erreur lors de l\'arrêt du serveur', 'error', 'dashboardMessage'); } shutdownInProgress = false; shutdownCancelToken = null; document.getElementById('cancelShutdownBtn').style.display = 'none'; document.getElementById('cancelShutdownBtnDash').style.display = 'none'; loadConsoleData(); } catch (e) { console.error('Erreur arrêt serveur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); shutdownInProgress = false; shutdownCancelToken = null; document.getElementById('cancelShutdownBtn').style.display = 'none'; } }; window.cancelShutdown = function() { if (shutdownInProgress) { shutdownInProgress = false; shutdownCancelToken = null; document.getElementById('cancelShutdownBtn').style.display = 'none'; document.getElementById('cancelShutdownBtnDash').style.display = 'none'; showMessage('❌ Arrêt annulé', 'warning', 'dashboardMessage'); } }; // Variables globales pour gérer le redémarrage du serveur let restartInProgress = false; let restartCancelToken = null; window.openRestartModal = function() { document.getElementById('restartModal').style.display = 'flex'; }; window.restartServer = async function() { const cooldown = parseInt(document.getElementById('restartCooldown').value); const message = document.getElementById('restartMessage').value.trim(); if (cooldown < 10 || cooldown > 600) { alert('Le cooldown doit être entre 10 et 600 secondes'); return; } if (!message) { alert('Entrez un message d\'avertissement'); return; } if (!confirm(`Êtes-vous sûr de vouloir redémarrer le serveur dans ${cooldown} secondes?`)) { return; } try { restartInProgress = true; restartCancelToken = {}; document.getElementById('cancelRestartBtn').style.display = 'block'; document.getElementById('restartModal').style.display = 'none'; showMessage(`⏳ Redémarrage du serveur dans ${cooldown} secondes...`, 'warning', 'dashboardMessage'); let secondsRemaining = cooldown; while (secondsRemaining > 0 && restartInProgress && restartCancelToken) { if (secondsRemaining % 10 === 0 || secondsRemaining <= 10) { // Envoyer un avertissement tous les 10 secondes (ou chaque seconde dans les 10 dernières) const warningMsg = message.replace('{cooldown}', secondsRemaining); await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: `say ${warningMsg}` }) }).catch(() => {}); } await new Promise(resolve => setTimeout(resolve, 1000)); secondsRemaining--; } if (!restartInProgress || !restartCancelToken) { // Envoyer un message dans le chat pour informer de l'annulation await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'say Redémarrage du serveur annulé!' }) }).catch(() => {}); showMessage('❌ Redémarrage annulé', 'warning', 'dashboardMessage'); document.getElementById('cancelRestartBtn').style.display = 'none'; return; } // Envoyer la commande de redémarrage const response = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'stop' }) }); if (response.ok) { showMessage('✓ Serveur redémarré', 'success', 'dashboardMessage'); } else { showMessage('Erreur lors du redémarrage du serveur', 'error', 'dashboardMessage'); } restartInProgress = false; restartCancelToken = null; document.getElementById('cancelRestartBtn').style.display = 'none'; loadDashboardData(); } catch (e) { console.error('Erreur redémarrage serveur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); restartInProgress = false; restartCancelToken = null; document.getElementById('cancelRestartBtn').style.display = 'none'; } }; window.cancelRestart = function() { if (restartInProgress) { restartInProgress = false; restartCancelToken = null; document.getElementById('cancelRestartBtn').style.display = 'none'; showMessage('❌ Redémarrage annulé', 'warning', 'dashboardMessage'); } }; // ========== LOGS ========== function getLogsHTML() { return `

📜 Logs

`; } async function loadLogsData() { try { const response = await fetch(`${API_URL}/logs?lines=200`, { credentials: 'include' }); const data = await response.json(); const container = document.getElementById('logsContainer'); container.innerHTML = data.logs.map((line, idx) => { let className = ''; if (line.includes('ERROR')) className = 'error'; else if (line.includes('WARN')) className = 'warning'; return `
${escapeHtml(line)}
`; }).join(''); container.scrollTop = container.scrollHeight; } catch (e) { console.error('Erreur chargement logs:', e); document.getElementById('logsContainer').innerHTML = '
Erreur chargement
'; } } async function reloadLogs() { showMessage('Rechargement...', 'success', 'dashboardMessage'); await loadLogsData(); showMessage('Logs rechargés', 'success', 'dashboardMessage'); } function openSearchLogsModal() { const query = prompt('Chercher dans les logs:'); if (query) searchLogs(query); } async function searchLogs(query) { try { const response = await fetch(`${API_URL}/logs/search?query=${encodeURIComponent(query)}`, { credentials: 'include' }); const data = await response.json(); const container = document.getElementById('logsContainer'); container.innerHTML = data.results.map((r, idx) => `
[${r.index}] ${escapeHtml(r.line)}
`).join(''); } catch (e) { console.error('Erreur recherche:', e); } } // ========== JOUEURS ========== function getPlayersHTML() { return `

👥 Joueurs en Ligne

Chargement...

📋 Tous les Joueurs

Liste des joueurs qui se sont connectés au serveur

Nom UUID Dernière Connexion
Chargement...
`; } async function loadPlayersData() { // Charger les joueurs en ligne await window.loadOnlinePlayers(); // Charger tous les joueurs try { const response = await fetch(`${API_URL}/players`, { credentials: 'include' }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); const table = document.getElementById('playersTable'); if (data.players && data.players.length > 0) { table.innerHTML = data.players.map(p => ` ${p.name} ${p.uuid} ${new Date(p.lastPlayed).toLocaleString()} `).join(''); } else { table.innerHTML = 'Aucun joueur'; } } catch (e) { console.error('Erreur joueurs:', e); document.getElementById('playersTable').innerHTML = `Erreur: ${e.message}`; } } window.loadOnlinePlayers = async function() { console.log('Chargement des joueurs en ligne...'); const infoDiv = document.getElementById('onlinePlayersInfo'); const listDiv = document.getElementById('onlinePlayersList'); if (!infoDiv || !listDiv) { console.error('Éléments DOM non trouvés'); return; } try { infoDiv.innerHTML = '

⏳ Chargement...

'; const response = await fetch(`${API_URL}/rcon/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ command: 'list' }) }); console.log('Réponse RCON reçue:', response.status); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const data = await response.json(); const output = data.response || data.output || ''; console.log('Données reçues:', data); console.log('Output RCON:', output); // Supprimer les codes de couleur Minecraft (§X) const cleanOutput = output.replace(/§[0-9a-fk-or]/gi, ''); console.log('Output nettoyé:', cleanOutput); // Parser différents formats possibles: // Format moderne: "There are 1/20 players online: player1, player2" // Format 1.6.4: "There are 1 out of maximum 20 players online. Connected players: player1" let match = cleanOutput.match(/There are (\d+)\/(\d+) players online:?\s*(.*)/i); if (!match) { // Essayer le format 1.6.4 match = cleanOutput.match(/There are (\d+) out of maximum (\d+) players online/i); if (match) { const onlineCount = parseInt(match[1]); const maxPlayers = parseInt(match[2]); // Chercher les noms de joueurs après "Connected players:" const playersMatch = cleanOutput.match(/Connected players[:\s]+(.+)/i); const playerNames = playersMatch ? playersMatch[1].split(',').map(n => n.trim().replace(/\[AFK\]/gi, '').trim()).filter(n => n) : []; match = [cleanOutput, onlineCount.toString(), maxPlayers.toString(), playerNames.join(', ')]; } } if (match) { const onlineCount = parseInt(match[1]); const maxPlayers = parseInt(match[2]); const playerNames = match[3] ? match[3].split(',').map(n => n.trim()).filter(n => n) : []; console.log(`Joueurs: ${onlineCount}/${maxPlayers}`, playerNames); infoDiv.innerHTML = `

${onlineCount} joueur${onlineCount !== 1 ? 's' : ''} en ligne sur ${maxPlayers}

${onlineCount > 0 ? '🟢' : '⚪'}
`; if (onlineCount > 0 && playerNames.length > 0) { listDiv.innerHTML = `
${playerNames.map(name => `
🎮 ${name}
`).join('')}
`; } else { listDiv.innerHTML = ''; } } else { infoDiv.innerHTML = `

Aucun joueur en ligne

`; listDiv.innerHTML = ''; } } catch (e) { console.error('Erreur chargement joueurs en ligne:', e); infoDiv.innerHTML = `

Erreur: ${e.message}

`; listDiv.innerHTML = ''; } } // ========== WHITELIST ========== function getWhitelistHTML() { return `

✅ Whitelist

Joueur Actions
Chargement...
`; } async function loadWhitelistData() { try { const response = await fetch(`${API_URL}/whitelist`, { credentials: 'include' }); const data = await response.json(); const table = document.getElementById('whitelistTable'); if (data.whitelist && data.whitelist.length > 0) { const players = data.whitelist.map(w => typeof w === 'string' ? w : w.name); table.innerHTML = players.map(p => ` ${p} `).join(''); } else { table.innerHTML = 'Whitelist vide'; } } catch (e) { console.error('Erreur whitelist:', e); document.getElementById('whitelistTable').innerHTML = 'Erreur'; } } function openAddWhitelistModal() { const username = prompt('Nom du joueur à ajouter:'); if (username) addToWhitelist(username); } async function addToWhitelist(username) { try { const response = await fetch(`${API_URL}/whitelist/add`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ username }) }); const data = await response.json(); if (response.ok) { showMessage(`${username} ajouté à la whitelist`, 'success', 'dashboardMessage'); loadWhitelistData(); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function removeFromWhitelist(username) { if (!confirm(`Confirmer la suppression de ${username}?`)) return; try { const response = await fetch(`${API_URL}/whitelist/remove`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ username }) }); const data = await response.json(); if (response.ok) { showMessage(`${username} retiré de la whitelist`, 'success', 'dashboardMessage'); loadWhitelistData(); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function reloadWhitelist() { showMessage('Rechargement...', 'success', 'dashboardMessage'); await loadWhitelistData(); showMessage('Whitelist rechargée', 'success', 'dashboardMessage'); } // ========== BACKUPS ========== function getBackupsHTML() { return `

💾 Backups

Nom Taille Date Actions
Chargement...
`; } async function loadBackupsData() { try { const response = await fetch(`${API_URL}/backup`, { credentials: 'include' }); const data = await response.json(); const table = document.getElementById('backupsTable'); if (Array.isArray(data) && data.length > 0) { table.innerHTML = data.map(b => ` ${b.name} ${b.size} ${new Date(b.created).toLocaleString()} `).join(''); } else { table.innerHTML = 'Aucun backup'; } } catch (e) { console.error('Erreur backups:', e); document.getElementById('backupsTable').innerHTML = 'Erreur'; } } async function createBackup() { if (!confirm('Créer un nouveau backup? (cela peut prendre du temps)')) return; showMessage('Création du backup en cours...', 'success', 'dashboardMessage'); try { const response = await fetch(`${API_URL}/backup/create`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({}) }); const data = await response.json(); if (response.ok) { showMessage(data.message, 'success', 'dashboardMessage'); setTimeout(() => loadBackupsData(), 2000); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function deleteBackup(filename) { if (!confirm(`Confirmer la suppression du backup ${filename}?`)) return; try { const response = await fetch(`${API_URL}/backup/delete/${filename}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({}) }); const data = await response.json(); if (response.ok) { showMessage('Backup supprimé', 'success', 'dashboardMessage'); loadBackupsData(); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function reloadBackups() { showMessage('Rechargement...', 'success', 'dashboardMessage'); await loadBackupsData(); showMessage('Backups rechargés', 'success', 'dashboardMessage'); } // ========== PARAMÈTRES ========== function getSettingsHTML() { return `

⚙️ Paramètres du Serveur

Modifiez les paramètres du serveur en temps réel

Paramètre Valeur
Chargement...
`; } async function loadSettingsData() { try { const response = await fetch(`${API_URL}/server`, { credentials: 'include' }); const data = await response.json(); const table = document.getElementById('settingsTable'); const tbody = table.querySelector('tbody'); if (data.properties) { const keys = Object.keys(data.properties).sort(); tbody.innerHTML = keys.map(k => { const isPassword = k.toLowerCase().includes('password') || k.toLowerCase().includes('rcon'); const inputType = isPassword ? 'password' : 'text'; const value = data.properties[k]; return ` ${k} `; }).join(''); } } catch (e) { console.error('Erreur paramètres:', e); } } async function updateSetting(input) { const key = input.getAttribute('data-key'); const newValue = input.value; try { const response = await fetch(`${API_URL}/server/settings`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ key, value: newValue }) }); if (response.ok) { showMessage(`✓ Paramètre ${key} modifié`, 'success', 'dashboardMessage'); } else { const error = await response.json(); showMessage(`Erreur: ${error.error}`, 'error', 'dashboardMessage'); await loadSettingsData(); // Recharger pour annuler la modification } } catch (e) { console.error('Erreur modification paramètre:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } // ========== ACTIONS ========== async function restartServer() { if (!confirm('⚠️ Redémarrer le serveur? Les joueurs seront déconnectés.')) return; showMessage('Redémarrage du serveur...', 'success', 'dashboardMessage'); try { const response = await fetch(`${API_URL}/rcon/restart`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({}) }); const data = await response.json(); if (response.ok) { showMessage(data.message, 'success', 'dashboardMessage'); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } async function saveServer() { showMessage('Sauvegarde du serveur...', 'success', 'dashboardMessage'); try { const response = await fetch(`${API_URL}/rcon/save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({}) }); const data = await response.json(); if (response.ok) { showMessage(data.message, 'success', 'dashboardMessage'); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } function openChangeRconPasswordModal() { const oldPassword = prompt('Ancien mot de passe RCON:'); if (!oldPassword) return; const newPassword = prompt('Nouveau mot de passe RCON:'); if (!newPassword) return; changeRconPassword(oldPassword, newPassword); } async function changeRconPassword(oldPassword, newPassword) { try { const response = await fetch(`${API_URL}/auth/change-rcon-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ oldPassword, newPassword }) }); const data = await response.json(); if (response.ok) { showMessage(data.message, 'success', 'dashboardMessage'); } else { showMessage(data.error, 'error', 'dashboardMessage'); } } catch (e) { console.error('Erreur:', e); showMessage('Erreur serveur', 'error', 'dashboardMessage'); } } // ========== UTILITAIRES ========== function showMessage(text, type, elementId) { const element = document.getElementById(elementId); if (element) { element.textContent = text; element.className = `message show ${type}`; setTimeout(() => { element.classList.remove('show'); }, 4000); } } function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, m => map[m]); } // Déconnexion async function handleLogout() { try { await fetch(`${API_URL}/auth/logout`, { method: 'POST', credentials: 'include' }); checkAuth(); } catch (e) { console.error('Erreur:', e); } }