diff --git a/TODO.md b/TODO.md index 14371b8..9a5fe5a 100644 --- a/TODO.md +++ b/TODO.md @@ -45,7 +45,7 @@ PHP has no component system, but `include`/`require` with variable scoping works ### Shared UI partials — `templates/partials/` - [x] **`pagination.php`** — pagination nav is duplicated between `index.php` and `search.php` with minor variations; unify into one partial accepting `$page`, `$totalPages`, `$baseParams[]` - [x] **`status-badge.php`** — the published/pending badge + access badge pattern is repeated in `index.php` admin table rows; extract into a partial -- [ ] **`admin-alert.php`** — rename/merge `flash-messages.php` to also handle the 3 different legacy flash key patterns (`$_SESSION['error']`, `$_SESSION['admin_error']`, `$_SESSION['edit_error']`, etc.) that pages still consume manually instead of via `App::consumeFlash()` +- [x] **`admin-alert.php`** — unified flash system: all action files now call `App::flash('error'|'success', ...)` instead of writing raw legacy session keys; all display pages (`edit.php`, `account.php`, `tags.php`, `pages.php`, `add.php`, `index.php`) replaced manual session reads with `include flash-messages.php` partial; `App::consumeFlash()` still drains any surviving legacy keys as a safety net ## System Page Caching — Database-Backed Status Cache diff --git a/public/admin/account.php b/public/admin/account.php index 783a225..7285249 100644 --- a/public/admin/account.php +++ b/public/admin/account.php @@ -8,9 +8,7 @@ $pageTitle = "Compte administrateur"; $credentialsFile = APP_ROOT . '/config/admin_credentials.php'; $hasPassword = defined('ADMIN_PASSWORD_HASH'); -$success = $_SESSION['success'] ?? null; -$error = $_SESSION['error'] ?? null; -unset($_SESSION['success'], $_SESSION['error']); +// Flash messages are consumed by the flash-messages partial below. if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); @@ -22,12 +20,7 @@ if (empty($_SESSION['csrf_token'])) {

Compte administrateur

- -

- - -

- +
diff --git a/public/admin/actions/account.php b/public/admin/actions/account.php index 4fe5b6f..52a19ab 100644 --- a/public/admin/actions/account.php +++ b/public/admin/actions/account.php @@ -24,13 +24,13 @@ $action = $_POST['action'] ?? 'change_password'; // ── Remove credentials ──────────────────────────────────────────────────────── if ($action === 'remove_credentials') { if (!$hasPassword) { - $_SESSION['error'] = 'Aucun fichier de mot de passe à supprimer.'; + App::flash('error', 'Aucun fichier de mot de passe à supprimer.'); header('Location: /admin/account.php'); exit; } if (!is_writable($credentialsFile) && !is_writable(dirname($credentialsFile))) { - $_SESSION['error'] = 'Le fichier de configuration n\'est pas accessible en écriture.'; + App::flash('error', 'Le fichier de configuration n\'est pas accessible en écriture.'); header('Location: /admin/account.php'); exit; } @@ -41,7 +41,7 @@ if ($action === 'remove_credentials') { header('Location: /admin/login.php'); exit; } else { - $_SESSION['error'] = 'Impossible de supprimer le fichier de configuration.'; + App::flash('error', 'Impossible de supprimer le fichier de configuration.'); header('Location: /admin/account.php'); exit; } @@ -53,7 +53,7 @@ if ($action === 'remove_credentials') { if ($hasPassword) { $currentPassword = $_POST['current_password'] ?? ''; if (!AdminAuth::login($currentPassword)) { - $_SESSION['error'] = 'Mot de passe actuel incorrect.'; + App::flash('error', 'Mot de passe actuel incorrect.'); header('Location: /admin/account.php'); exit; } @@ -64,13 +64,13 @@ $newPassword = $_POST['new_password'] ?? ''; $confirmPassword = $_POST['confirm_password'] ?? ''; if (strlen($newPassword) < 12) { - $_SESSION['error'] = 'Le nouveau mot de passe doit contenir au moins 12 caractères.'; + App::flash('error', 'Le nouveau mot de passe doit contenir au moins 12 caractères.'); header('Location: /admin/account.php'); exit; } if ($newPassword !== $confirmPassword) { - $_SESSION['error'] = 'Les mots de passe ne correspondent pas.'; + App::flash('error', 'Les mots de passe ne correspondent pas.'); header('Location: /admin/account.php'); exit; } @@ -78,7 +78,7 @@ if ($newPassword !== $confirmPassword) { // 3. Generate bcrypt hash (cost 12). $hash = password_hash($newPassword, PASSWORD_BCRYPT, ['cost' => 12]); if ($hash === false) { - $_SESSION['error'] = 'Erreur lors du hachage du mot de passe.'; + App::flash('error', 'Erreur lors du hachage du mot de passe.'); header('Location: /admin/account.php'); exit; } @@ -99,13 +99,13 @@ $configContent = 'getMessage()); - $_SESSION['edit_error'] = $e->getMessage(); + App::flash('error', $e->getMessage()); header('Location: ../edit.php?id=' . $thesisId); exit(); } diff --git a/public/admin/actions/formulaire.php b/public/admin/actions/formulaire.php index a9e9145..5e2ac4e 100644 --- a/public/admin/actions/formulaire.php +++ b/public/admin/actions/formulaire.php @@ -312,7 +312,7 @@ try { error_log("Form processing error: " . $e->getMessage()); // Save error message and form data to session - $_SESSION['form_error'] = $e->getMessage(); + App::flash('error', $e->getMessage()); $_SESSION['form_data'] = $_POST; // Redirect back to form with preserved data diff --git a/public/admin/actions/maintenance.php b/public/admin/actions/maintenance.php index 9199b95..c318bb7 100644 --- a/public/admin/actions/maintenance.php +++ b/public/admin/actions/maintenance.php @@ -14,14 +14,14 @@ $action = $_POST['action'] ?? ''; if ($action === 'enable_maintenance') { file_put_contents(MAINTENANCE_FLAG, date('c')); - $_SESSION['success'] = "Mode maintenance activé."; + App::flash('success', "Mode maintenance activé."); } elseif ($action === 'disable_maintenance') { if (file_exists(MAINTENANCE_FLAG)) { unlink(MAINTENANCE_FLAG); } - $_SESSION['success'] = "Mode maintenance désactivé."; + App::flash('success', "Mode maintenance désactivé."); } else { - $_SESSION['error'] = "Action inconnue."; + App::flash('error', "Action inconnue."); } header('Location: /admin/'); diff --git a/public/admin/actions/page.php b/public/admin/actions/page.php index d157674..22fede9 100644 --- a/public/admin/actions/page.php +++ b/public/admin/actions/page.php @@ -25,7 +25,7 @@ require_once __DIR__ . '/../../../src/Database.php'; try { $db = new Database(); $db->savePage($slug, $content); - $_SESSION['success'] = "Page «" . $slug . "» mise à jour avec succès."; + App::flash('success', "Page «" . $slug . "» mise à jour avec succès."); } catch (Exception $e) { error_log("Page save error: " . $e->getMessage()); die("Erreur lors de la sauvegarde : " . htmlspecialchars($e->getMessage())); diff --git a/public/admin/actions/publish.php b/public/admin/actions/publish.php index fdde8fd..fb7ed8a 100644 --- a/public/admin/actions/publish.php +++ b/public/admin/actions/publish.php @@ -13,7 +13,7 @@ require_once __DIR__ . '/../../../src/Database.php'; // Verify CSRF token if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { - $_SESSION['error'] = "Erreur de sécurité : token invalide."; + App::flash('error', "Erreur de sécurité : token invalide."); header('Location: ../index.php'); exit; } @@ -22,7 +22,7 @@ $action = isset($_POST['action']) ? $_POST['action'] : ''; $isBulk = isset($_POST['bulk']) && $_POST['bulk'] == '1'; if (!in_array($action, ['publish', 'unpublish'])) { - $_SESSION['error'] = "Action invalide."; + App::flash('error', "Action invalide."); header('Location: ../index.php'); exit; } @@ -38,7 +38,7 @@ try { $thesisIds = isset($_POST['selected_theses']) ? $_POST['selected_theses'] : []; if (empty($thesisIds)) { - $_SESSION['error'] = "Aucun TFE sélectionné."; + App::flash('error', "Aucun TFE sélectionné."); header('Location: ../index.php'); exit; } @@ -48,7 +48,7 @@ try { $thesisIds = array_filter($thesisIds, fn($id) => $id > 0); if (empty($thesisIds)) { - $_SESSION['error'] = "IDs invalides."; + App::flash('error', "IDs invalides."); header('Location: ../index.php'); exit; } @@ -63,9 +63,9 @@ try { $count = count($thesisIds); if ($action === 'publish') { - $_SESSION['success'] = "$count TFE(s) publié(s) avec succès!"; + App::flash('success', "$count TFE(s) publié(s) avec succès!"); } else { - $_SESSION['success'] = "$count TFE(s) retiré(s) de la publication."; + App::flash('success', "$count TFE(s) retiré(s) de la publication."); } } else { @@ -73,7 +73,7 @@ try { $thesisId = isset($_POST['thesis_id']) ? intval($_POST['thesis_id']) : 0; if ($thesisId <= 0) { - $_SESSION['error'] = "ID invalide."; + App::flash('error', "ID invalide."); header('Location: ../index.php'); exit; } @@ -82,15 +82,15 @@ try { $stmt->execute([$isPublished, $thesisId]); if ($action === 'publish') { - $_SESSION['success'] = "TFE publié avec succès!"; + App::flash('success', "TFE publié avec succès!"); } else { - $_SESSION['success'] = "TFE retiré de la publication."; + App::flash('success', "TFE retiré de la publication."); } } } catch (Exception $e) { error_log("Publish error: " . $e->getMessage()); - $_SESSION['error'] = "Erreur lors de la modification: " . $e->getMessage(); + App::flash('error', "Erreur lors de la modification: " . $e->getMessage()); } // Regenerate CSRF token diff --git a/public/admin/actions/tag.php b/public/admin/actions/tag.php index 012ffee..8f34bef 100644 --- a/public/admin/actions/tag.php +++ b/public/admin/actions/tag.php @@ -41,9 +41,9 @@ try { throw new Exception("Action inconnue."); } - $_SESSION['admin_success'] = "Opération effectuée."; + App::flash('success', "Opération effectuée."); } catch (Exception $e) { - $_SESSION['admin_error'] = $e->getMessage(); + App::flash('error', $e->getMessage()); } header('Location: /admin/tags.php'); diff --git a/public/admin/actions/visibility.php b/public/admin/actions/visibility.php index 73e3650..2ad19f7 100644 --- a/public/admin/actions/visibility.php +++ b/public/admin/actions/visibility.php @@ -5,7 +5,7 @@ AdminAuth::requireLogin(); if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { - $_SESSION['error'] = "Erreur de sécurité : token invalide."; + App::flash('error', "Erreur de sécurité : token invalide."); header('Location: /admin/'); exit; } @@ -18,7 +18,7 @@ $isBulk = !empty($_POST['bulk']); $validAccess = [null, 1, 2, 3]; if (!in_array($accessTypeId, $validAccess, true)) { - $_SESSION['error'] = "Valeur de visibilité invalide."; + App::flash('error', "Valeur de visibilité invalide."); header('Location: /admin/'); exit; } @@ -29,25 +29,25 @@ try { if ($isBulk) { $ids = array_filter(array_map('intval', $_POST['selected_theses'] ?? []), fn($id) => $id > 0); if (empty($ids)) { - $_SESSION['error'] = "Aucun TFE sélectionné."; + App::flash('error', "Aucun TFE sélectionné."); header('Location: /admin/'); exit; } $db->bulkSetVisibility($ids, $accessTypeId); - $_SESSION['success'] = count($ids) . " TFE(s) mis à jour."; + App::flash('success', count($ids) . " TFE(s) mis à jour."); } else { $thesisId = filter_var($_POST['thesis_id'] ?? '', FILTER_VALIDATE_INT); if (!$thesisId) { - $_SESSION['error'] = "ID invalide."; + App::flash('error', "ID invalide."); header('Location: /admin/'); exit; } $db->setVisibility($thesisId, $accessTypeId); - $_SESSION['success'] = "Visibilité mise à jour."; + App::flash('success', "Visibilité mise à jour."); } } catch (Exception $e) { error_log("visibility.php error: " . $e->getMessage()); - $_SESSION['error'] = "Erreur : " . $e->getMessage(); + App::flash('error', "Erreur : " . $e->getMessage()); } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); diff --git a/public/admin/add.php b/public/admin/add.php index 153cc2b..6374070 100644 --- a/public/admin/add.php +++ b/public/admin/add.php @@ -24,9 +24,9 @@ try { die("Erreur lors du chargement du formulaire."); } -$error = $_SESSION["form_error"] ?? null; -$formData = $_SESSION["form_data"] ?? []; -unset($_SESSION["form_error"], $_SESSION["form_data"]); +$formData = $_SESSION["form_data"] ?? []; +unset($_SESSION["form_data"]); +// Flash error consumed by the flash-messages partial below. function old($key, $default = "") { global $formData; @@ -45,9 +45,7 @@ function wasSelected($key, $value) {

Ajouter un TFE

- -

- +
"> diff --git a/public/admin/edit.php b/public/admin/edit.php index c5a75c0..94a5005 100644 --- a/public/admin/edit.php +++ b/public/admin/edit.php @@ -19,10 +19,7 @@ if ($thesisId <= 0) { die("ID invalide"); } -// Consume flash messages from the edit action -$error = $_SESSION['edit_error'] ?? null; -$success = $_SESSION['edit_success'] ?? null; -unset($_SESSION['edit_error'], $_SESSION['edit_success']); +// Flash messages are consumed by the flash-messages partial below. try { $db = new Database(); @@ -67,12 +64,7 @@ try {

Modifier un TFE

- -

- - -

- + diff --git a/public/admin/index.php b/public/admin/index.php index d3c1f1e..ee3d59c 100644 --- a/public/admin/index.php +++ b/public/admin/index.php @@ -67,12 +67,7 @@ document.addEventListener('DOMContentLoaded', () => {

Liste des TFE

- -

- - -

- + diff --git a/public/admin/pages.php b/public/admin/pages.php index 70edc75..d19fc5a 100644 --- a/public/admin/pages.php +++ b/public/admin/pages.php @@ -15,8 +15,7 @@ try { die("Erreur lors du chargement des pages."); } -$success = $_SESSION['success'] ?? null; -unset($_SESSION['success']); +// Flash messages are consumed by the flash-messages partial below. ?> @@ -24,9 +23,7 @@ unset($_SESSION['success']);

Pages statiques

- -

- + diff --git a/public/admin/tags.php b/public/admin/tags.php index 0a13906..0ff370d 100644 --- a/public/admin/tags.php +++ b/public/admin/tags.php @@ -18,9 +18,7 @@ try { die("Erreur : " . htmlspecialchars($e->getMessage())); } -$error = $_SESSION['admin_error'] ?? null; -$success = $_SESSION['admin_success'] ?? null; -unset($_SESSION['admin_error'], $_SESSION['admin_success']); +// Flash messages are consumed by the flash-messages partial below. ?> @@ -28,12 +26,7 @@ unset($_SESSION['admin_error'], $_SESSION['admin_success']);

Mots-clés ()

- -

- - -

- +