diff --git a/api.php b/api.php index 19e9b4e..17a307a 100644 --- a/api.php +++ b/api.php @@ -1,156 +1,117 @@ -/** - * Mon Cinéma - Module d'Administration (admin.js) - * Version synchronisée avec api.php - */ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci" + ]); +} catch (\PDOException $e) { + echo json_encode(["error" => "Erreur BDD : " . $e->getMessage()]); + exit; +} + +function encryptData($data) { + $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); + $encrypted = openssl_encrypt($data, 'aes-256-cbc', ENCRYPTION_KEY, 0, $iv); + return base64_encode($encrypted . '::' . $iv); +} + +function decryptData($data) { + if (!$data) return ''; + $decoded = base64_decode($data); + if (strpos($decoded, '::') === false) return ''; + list($encrypted_data, $iv) = explode('::', $decoded, 2); + return openssl_decrypt($encrypted_data, 'aes-256-cbc', ENCRYPTION_KEY, 0, $iv); +} + +function makeStableId($title, $year) { + $key = strtolower(trim($title)) . '|' . trim($year); + return (abs(crc32($key)) % 2000000000) + 100000000; +} + +function makeNewIdSafe() { + return (abs(crc32(uniqid('', true))) % 2000000000) + 100000000; +} + +function convertRating($rawRating) { + return max(1, min(5, (int)round(floatval($rawRating)))); +} + +function checkAuth($pdo) { + $stmtCheck = $pdo->query("SELECT COUNT(*) as total FROM users"); + if ($stmtCheck->fetch()['total'] == 0) return true; + + $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; + if (empty($token) && function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + $token = $headers['Authorization'] ?? ''; + } + + if ($token !== md5(ENCRYPTION_KEY . 'session')) { + http_response_code(403); + echo json_encode(["error" => "Accès interdit."]); + exit; + } +} + +$method = $_SERVER['REQUEST_METHOD']; +$action = $_GET['action'] ?? ''; + +switch ($method) { + case 'GET': + if ($action === 'get_films') { + $critiques = $pdo->query("SELECT *, 'critique' AS type FROM critiques ORDER BY created_at DESC")->fetchAll(); + $videotheque = $pdo->query("SELECT *, 'videotheque' AS type FROM videotheque ORDER BY created_at DESC")->fetchAll(); + echo json_encode(array_merge($critiques, $videotheque), JSON_UNESCAPED_UNICODE); + } elseif ($action === 'check_security_status') { + $stmt = $pdo->query("SELECT COUNT(*) as total FROM users"); + echo json_encode(["is_blank" => ($stmt->fetch()['total'] == 0)]); + } + break; + + case 'POST': + $data = json_decode(file_get_contents('php://input'), true) ?? []; - const secRes = await fetch(`${API_URL}?action=check_security_status`); - const secData = await secRes.json(); - const banner = document.getElementById('security-banner'); - if (banner) banner.style.display = secData.is_blank ? 'flex' : 'none'; - - renderAdminTable(); - } catch (err) { console.error('Erreur chargement :', err); } -} - -function renderAdminTable() { - const tbody = document.getElementById('admin-table-body'); - if (!tbody) return; - tbody.innerHTML = ''; - const filtered = allItems.filter(item => item.type === currentAdminTab); - document.getElementById('admin-count-label').textContent = `${filtered.length} élément(s)`; - - filtered.forEach(f => { - const tr = document.createElement('tr'); - tr.innerHTML = ` - - ${f.poster ? `` : '-'} - ${f.title} - ${f.year || ''} - ${f.director || ''} - ${currentAdminTab === 'critique' ? (f.rating ? '★'.repeat(f.rating) : '☆') : (f.format || '-')} - - - - `; - tbody.appendChild(tr); - }); -} - -// ── ACTIONS CRUD ── -async function saveFilmForm(e) { - e.preventDefault(); - const payload = { - type: currentAdminTab, - id: document.getElementById('f-id').value, - title: document.getElementById('f-title').value, - year: document.getElementById('f-year').value, - director: document.getElementById('f-director').value, - poster: document.getElementById('f-poster').value, - // Champs conditionnels - rating: document.getElementById('f-rating').value, - review: document.getElementById('f-review').value, - streaming: document.getElementById('f-streaming').value, - format: document.getElementById('f-format').value, - length: document.getElementById('f-length').value, - publisher: document.getElementById('f-publisher').value, - ean_isbn13: document.getElementById('f-ean').value, - number_of_discs: document.getElementById('f-discs').value, - aspect_ratio: document.getElementById('f-aspect').value, - description: document.getElementById('f-description').value - }; - - await fetch(`${API_URL}?action=save_film`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - closeAdminModal(); - loadDashboardData(); -} - -async function deleteSingleFilm(id) { - if (!confirm('Supprimer cette œuvre ?')) return; - await fetch(`${API_URL}?action=delete_film&id=${id}&type=${currentAdminTab}`, { - method: 'DELETE', - headers: { 'Authorization': localStorage.getItem('token') } - }); - loadDashboardData(); -} - -// ── MODALES & UI ── -function switchAdminTab(tabName) { - currentAdminTab = tabName; - document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); - document.getElementById(`btn-tab-${tabName}`).classList.add('active'); - - // Basculer l'affichage des formulaires - document.getElementById('form-critique-fields').style.display = tabName === 'critique' ? 'block' : 'none'; - document.getElementById('form-videotheque-fields').style.display = tabName === 'videotheque' ? 'block' : 'none'; - - renderAdminTable(); -} - -function openAddModal() { - document.getElementById('film-form').reset(); - document.getElementById('f-id').value = ''; - document.getElementById('admin-modal').classList.add('open'); -} - -function openEditModal(id) { - const item = allItems.find(x => String(x.id) === String(id)); - if (!item) return; - // Remplissage formulaire... - document.getElementById('f-id').value = item.id; - document.getElementById('f-title').value = item.title; - document.getElementById('admin-modal').classList.add('open'); -} - -function closeAdminModal() { document.getElementById('admin-modal').classList.remove('open'); } -function openConfigModal() { document.getElementById('config-modal').classList.add('open'); } -function closeConfigModal() { document.getElementById('config-modal').classList.remove('open'); } -function openPasswordModal() { document.getElementById('password-modal').classList.add('open'); } -function closePasswordModal() { document.getElementById('password-modal').classList.remove('open'); } - -function logout() { - localStorage.removeItem('token'); - window.location.href = 'login.html'; -} - -// ── MOT DE PASSE ── -async function saveNewPassword() { - const newPwd = document.getElementById('new-password-input').value; - const confirmPwd = document.getElementById('new-password-confirm').value; - if (newPwd !== confirmPwd) return alert("Les mots de passe ne correspondent pas."); - - const res = await fetch(`${API_URL}?action=update_password`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, - body: JSON.stringify({ new_password: newPwd }) - }); - if (res.ok) { alert("Mot de passe mis à jour."); closePasswordModal(); } -} - -// ── IMPORT CSV ── -async function handleCsvUpload(input) { - if (!input.files[0]) return; - const formData = new FormData(); - formData.append('csv_file', input.files[0]); - await fetch(`${API_URL}?action=import_csv`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token') }, - body: formData - }); - loadDashboardData(); + if ($action === 'login') { + $stmt = $pdo->query("SELECT COUNT(*) as total FROM users"); + if ($stmt->fetch()['total'] == 0) { + echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => true]); + } else { + $stmt = $pdo->prepare("SELECT password_hash FROM users WHERE username = 'admin'"); + $stmt->execute(); + $user = $stmt->fetch(); + if ($user && password_verify($data['password'] ?? '', $user['password_hash'])) { + echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => false]); + } else { + http_response_code(401); + echo json_encode(["error" => "Mot de passe incorrect."]); + } + } + } elseif ($action === 'setup_admin' || $action === 'update_password') { + checkAuth($pdo); + $pwd = $data['password'] ?? $data['new_password'] ?? ''; + $stmt = $pdo->prepare("REPLACE INTO users (id, username, password_hash) VALUES (1, 'admin', :pass)"); + $stmt->execute([':pass' => password_hash($pwd, PASSWORD_BCRYPT)]); + echo json_encode(["success" => true]); + } + break; } \ No newline at end of file