mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Unify flash messages: replace all legacy session key writes with App::flash()
All admin action files (account, tag, page, edit, visibility, maintenance,
publish, formulaire) now call App::flash('error'|'success', ...) instead of
writing to raw per-page session keys ($_SESSION['error'], 'admin_error',
'edit_error', 'admin_success', 'edit_success', 'form_error').
All admin display pages (add, edit, account, tags, pages, index) now include
templates/partials/flash-messages.php instead of manually reading and
unsetting the legacy session keys and inlining their own alert HTML.
App::consumeFlash() already drained all legacy key variants as a safety net,
so the partial works correctly whether called from pages that were already
migrated or any remaining stragglers. No behaviour change for end users.
This commit is contained in:
2
TODO.md
2
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
|
||||
|
||||
|
||||
@@ -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'])) {
|
||||
<main id="main-content">
|
||||
<h1>Compte administrateur</h1>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<p role="status" data-type="success">✓ <?= htmlspecialchars($success) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<!-- Status info -->
|
||||
<div class="admin-account-status">
|
||||
|
||||
@@ -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 = '<?php' . "\n"
|
||||
$tmpFile = $credentialsFile . '.tmp.' . bin2hex(random_bytes(6));
|
||||
if (file_put_contents($tmpFile, $configContent, LOCK_EX) === false) {
|
||||
@unlink($tmpFile);
|
||||
$_SESSION['error'] = 'Impossible d\'écrire le fichier de configuration. Vérifiez les permissions sur config/.';
|
||||
App::flash('error', 'Impossible d\'écrire le fichier de configuration. Vérifiez les permissions sur config/.');
|
||||
header('Location: /admin/account.php');
|
||||
exit;
|
||||
}
|
||||
if (!rename($tmpFile, $credentialsFile)) {
|
||||
@unlink($tmpFile);
|
||||
$_SESSION['error'] = 'Impossible de mettre à jour le fichier de configuration.';
|
||||
App::flash('error', 'Impossible de mettre à jour le fichier de configuration.');
|
||||
header('Location: /admin/account.php');
|
||||
exit;
|
||||
}
|
||||
@@ -114,9 +114,9 @@ if (!rename($tmpFile, $credentialsFile)) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['admin_authenticated'] = true;
|
||||
|
||||
$_SESSION['success'] = $hasPassword
|
||||
App::flash('success', $hasPassword
|
||||
? 'Mot de passe mis à jour avec succès.'
|
||||
: 'Mot de passe défini avec succès. L\'authentification PHP est maintenant active.';
|
||||
: 'Mot de passe défini avec succès. L\'authentification PHP est maintenant active.');
|
||||
|
||||
header('Location: /admin/account.php');
|
||||
exit;
|
||||
|
||||
@@ -125,7 +125,7 @@ try {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
|
||||
// Flash success and redirect back to edit form
|
||||
$_SESSION['edit_success'] = "TFE mis à jour avec succès!";
|
||||
App::flash('success', "TFE mis à jour avec succès!");
|
||||
header('Location: ../edit.php?id=' . $thesisId);
|
||||
exit();
|
||||
|
||||
@@ -135,7 +135,7 @@ try {
|
||||
}
|
||||
error_log("Edit action error: " . $e->getMessage());
|
||||
|
||||
$_SESSION['edit_error'] = $e->getMessage();
|
||||
App::flash('error', $e->getMessage());
|
||||
header('Location: ../edit.php?id=' . $thesisId);
|
||||
exit();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/');
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
<main id="main-content">
|
||||
<h1>Ajouter un TFE</h1>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<form action="actions/formulaire.php" method="post" enctype="multipart/form-data" class="admin-form">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION["csrf_token"]) ?>">
|
||||
|
||||
@@ -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 {
|
||||
<main id="main-content">
|
||||
<h1>Modifier un TFE</h1>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<p role="status" data-type="success">✓ <?= htmlspecialchars($success) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<form method="post" action="/admin/actions/edit.php" class="admin-form" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||
|
||||
@@ -67,12 +67,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
<main id="main-content">
|
||||
<h1>Liste des TFE</h1>
|
||||
|
||||
<?php if (isset($_SESSION['error'])): ?>
|
||||
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($_SESSION['error']); unset($_SESSION['error']); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_SESSION['success'])): ?>
|
||||
<p role="status" data-type="success">✓ <?= htmlspecialchars($_SESSION['success']); unset($_SESSION['success']); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<!-- Maintenance mode toggle -->
|
||||
<?php $maintenanceOn = file_exists(APP_ROOT . '/storage/maintenance.flag'); ?>
|
||||
|
||||
@@ -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.
|
||||
?>
|
||||
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
|
||||
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||
@@ -24,9 +23,7 @@ unset($_SESSION['success']);
|
||||
<main id="main-content">
|
||||
<h1>Pages statiques</h1>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<p role="status" data-type="success">✓ <?= htmlspecialchars($success) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
@@ -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.
|
||||
?>
|
||||
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
|
||||
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||
@@ -28,12 +26,7 @@ unset($_SESSION['admin_error'], $_SESSION['admin_success']);
|
||||
<main id="main-content">
|
||||
<h1>Mots-clés (<?= count($tags) ?>)</h1>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<p role="status" data-type="success">✓ <?= htmlspecialchars($success) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
Reference in New Issue
Block a user