mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
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.
216 lines
10 KiB
PHP
216 lines
10 KiB
PHP
<?php
|
|
require_once __DIR__ . "/../../config/bootstrap.php";
|
|
require_once __DIR__ . '/../../src/AdminAuth.php';
|
|
AdminAuth::requireLogin();
|
|
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
}
|
|
|
|
$pageTitle = "Liste des TFE";
|
|
require_once __DIR__ . '/../../src/Database.php';
|
|
|
|
try {
|
|
$db = new Database();
|
|
$searchQuery = isset($_GET['search']) ? trim($_GET['search']) : '';
|
|
$yearFilter = isset($_GET['year']) ? intval($_GET['year']) : null;
|
|
$orientationFilter = isset($_GET['orientation']) ? intval($_GET['orientation']) : null;
|
|
|
|
$filters = [];
|
|
if ($searchQuery) $filters['search'] = $searchQuery;
|
|
if ($yearFilter) $filters['year'] = $yearFilter;
|
|
if ($orientationFilter) $filters['orientation'] = $orientationFilter;
|
|
|
|
$theses = $db->getThesesList($filters);
|
|
$stats = $db->getThesesStats();
|
|
$years = $db->getAllYears();
|
|
$orientations = $db->getAllOrientations();
|
|
} catch (Exception $e) {
|
|
error_log("Error loading theses list: " . $e->getMessage());
|
|
die("Erreur lors du chargement de la liste.");
|
|
}
|
|
?>
|
|
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
|
|
<?php include APP_ROOT . '/templates/header.php'; ?>
|
|
|
|
<script>
|
|
function toggleAll(src) {
|
|
document.querySelectorAll('input[name="selected_theses[]"]').forEach(cb => cb.checked = src.checked);
|
|
updateBulk();
|
|
}
|
|
function updateBulk() {
|
|
const checked = document.querySelectorAll('input[name="selected_theses[]"]:checked');
|
|
const bulk = document.getElementById('bulk-actions');
|
|
document.getElementById('selected-count').textContent = checked.length;
|
|
bulk.style.display = checked.length > 0 ? 'flex' : 'none';
|
|
}
|
|
function bulkAction(action) {
|
|
const checked = document.querySelectorAll('input[name="selected_theses[]"]:checked');
|
|
if (!checked.length) { alert('Sélectionnez au moins un TFE.'); return; }
|
|
const word = action === 'publish' ? 'publier' : 'dépublier';
|
|
if (!confirm(`${word.charAt(0).toUpperCase()+word.slice(1)} ${checked.length} TFE(s) ?`)) return;
|
|
document.getElementById('bulk-action-input').value = action;
|
|
const container = document.getElementById('bulk-checkboxes');
|
|
container.innerHTML = '';
|
|
checked.forEach(cb => {
|
|
const inp = document.createElement('input');
|
|
inp.type = 'hidden'; inp.name = 'selected_theses[]'; inp.value = cb.value;
|
|
container.appendChild(inp);
|
|
});
|
|
document.getElementById('bulk-form').submit();
|
|
}
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.querySelectorAll('input[name="selected_theses[]"]').forEach(cb => cb.addEventListener('change', updateBulk));
|
|
});
|
|
</script>
|
|
|
|
<main id="main-content">
|
|
<h1>Liste des TFE</h1>
|
|
|
|
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
|
|
|
<!-- Maintenance mode toggle -->
|
|
<?php $maintenanceOn = file_exists(APP_ROOT . '/storage/maintenance.flag'); ?>
|
|
<div class="admin-maintenance-bar <?= $maintenanceOn ? 'admin-maintenance-bar--active' : '' ?>">
|
|
<?php if ($maintenanceOn): ?>
|
|
<span>⚠ Mode maintenance <strong>activé</strong> — le site public est inaccessible.</span>
|
|
<form method="post" action="actions/maintenance.php" style="display:inline;">
|
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
<input type="hidden" name="action" value="disable_maintenance">
|
|
<button type="submit" class="admin-btn admin-btn--sm">Désactiver la maintenance</button>
|
|
</form>
|
|
<?php else: ?>
|
|
<span>Site public : <strong>en ligne</strong></span>
|
|
<form method="post" action="actions/maintenance.php" style="display:inline;">
|
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
<input type="hidden" name="action" value="enable_maintenance">
|
|
<button type="submit" class="admin-btn admin-btn--sm admin-btn--warning"
|
|
onclick="return confirm('Mettre le site en maintenance ? Les visiteurs verront une page 503.')">
|
|
Activer la maintenance
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Stats (always reflects full DB, independent of active filters) -->
|
|
<dl class="admin-stats">
|
|
<div class="admin-stat">
|
|
<dt class="admin-stat__label">TFE total</dt>
|
|
<dd class="admin-stat__number"><?= $stats['total'] ?></dd>
|
|
</div>
|
|
<div class="admin-stat">
|
|
<dt class="admin-stat__label">Publiés</dt>
|
|
<dd class="admin-stat__number"><?= $stats['published'] ?></dd>
|
|
</div>
|
|
<div class="admin-stat">
|
|
<dt class="admin-stat__label">En attente</dt>
|
|
<dd class="admin-stat__number"><?= $stats['pending'] ?></dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<!-- Filters -->
|
|
<form class="admin-filters" method="get" action="/admin/">
|
|
<input type="text" name="search" placeholder="Titre, auteur..."
|
|
value="<?= htmlspecialchars($searchQuery) ?>">
|
|
<select name="year">
|
|
<option value="">Toutes les années</option>
|
|
<?php foreach ($years as $y): ?>
|
|
<option value="<?= $y ?>" <?= $yearFilter == $y ? 'selected' : '' ?>><?= $y ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<select name="orientation">
|
|
<option value="">Toutes les orientations</option>
|
|
<?php foreach ($orientations as $o): ?>
|
|
<option value="<?= $o['id'] ?>" <?= $orientationFilter == $o['id'] ? 'selected' : '' ?>>
|
|
<?= htmlspecialchars($o['name']) ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<button type="submit" class="admin-filters-btn">Filtrer</button>
|
|
<?php if ($searchQuery || $yearFilter || $orientationFilter): ?>
|
|
<a href="/admin/" class="admin-filters-reset"><span aria-hidden="true">✕ </span>Réinitialiser</a>
|
|
<?php endif; ?>
|
|
</form>
|
|
|
|
<!-- Bulk actions bar -->
|
|
<div id="bulk-actions" class="admin-bulk-actions">
|
|
<strong><span id="selected-count">0</span> TFE(s) sélectionné(s)</strong>
|
|
<div class="admin-bulk-btns">
|
|
<button type="button" class="admin-btn-sm admin-btn-publish" onclick="bulkAction('publish')">Publier</button>
|
|
<button type="button" class="admin-btn-sm admin-btn-unpublish" onclick="bulkAction('unpublish')">Dépublier</button>
|
|
</div>
|
|
</div>
|
|
|
|
<form id="bulk-form" method="post" action="actions/publish.php">
|
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
<input type="hidden" id="bulk-action-input" name="action" value="">
|
|
<input type="hidden" name="bulk" value="1">
|
|
<div id="bulk-checkboxes"></div>
|
|
</form>
|
|
|
|
<!-- Table -->
|
|
<?php if (empty($theses)): ?>
|
|
<p style="color:var(--admin-text-muted);padding:1rem 0;">Aucun TFE trouvé.</p>
|
|
<?php else: ?>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th scope="col"><input type="checkbox" onchange="toggleAll(this)"></th>
|
|
<th scope="col">ID</th>
|
|
<th scope="col">Titre</th>
|
|
<th scope="col">Auteur(s)</th>
|
|
<th scope="col">Année</th>
|
|
<th scope="col">Orientation</th>
|
|
<th scope="col">AP</th>
|
|
<th scope="col">Statut</th>
|
|
<th scope="col">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($theses as $thesis): ?>
|
|
<tr>
|
|
<td><input type="checkbox" name="selected_theses[]" value="<?= $thesis['id'] ?>"></td>
|
|
<td style="color:var(--admin-text-muted);font-size:.8rem;"><?= htmlspecialchars($thesis['identifier'] ?? $thesis['id']) ?></td>
|
|
<td>
|
|
<div class="thesis-title"><?= htmlspecialchars($thesis['title']) ?></div>
|
|
<?php if ($thesis['subtitle']): ?>
|
|
<div class="thesis-subtitle"><?= htmlspecialchars($thesis['subtitle']) ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><?= htmlspecialchars($thesis['authors'] ?? 'N/A') ?></td>
|
|
<td><?= $thesis['year'] ?></td>
|
|
<td><?= htmlspecialchars($thesis['orientation'] ?? 'N/A') ?></td>
|
|
<td><?= htmlspecialchars($thesis['ap_program'] ?? 'N/A') ?></td>
|
|
<td>
|
|
<?php $badgeType = 'publish'; $badgeValue = $thesis['is_published']; include APP_ROOT . '/templates/partials/status-badge.php'; ?>
|
|
<?php if (!empty($thesis['access_type'])): ?>
|
|
<br><?php $badgeType = 'access'; $badgeValue = $thesis['access_type']; include APP_ROOT . '/templates/partials/status-badge.php'; ?>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<div class="admin-actions">
|
|
<a href="/admin/thanks.php?id=<?= $thesis['id'] ?>" class="admin-btn-sm admin-btn-view">Voir</a>
|
|
<a href="/admin/edit.php?id=<?= $thesis['id'] ?>" class="admin-btn-sm admin-btn-edit">Éditer</a>
|
|
<form method="post" action="actions/publish.php" class="publish-form">
|
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
<input type="hidden" name="thesis_id" value="<?= $thesis['id'] ?>">
|
|
<?php if ($thesis['is_published']): ?>
|
|
<input type="hidden" name="action" value="unpublish">
|
|
<button type="submit" class="admin-btn-sm admin-btn-unpublish"
|
|
onclick="return confirm('Retirer de la publication ?')">Dépublier</button>
|
|
<?php else: ?>
|
|
<input type="hidden" name="action" value="publish">
|
|
<button type="submit" class="admin-btn-sm admin-btn-publish">Publier</button>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
</main>
|
|
|
|
<?php require_once APP_ROOT . '/templates/admin/footer.php'; ?>
|