mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
The file had accumulated severe corruption in its lower half (garbled selector text, variable names spliced into property values, orphaned declarations, broken nesting) alongside hardcoded hex colours throughout. Rewrote the entire file cleanly: - Every colour is now a var() referencing a token defined in variables.css: --accent-primary/secondary/foreground, --accent-blue/green/yellow/red, --bg-secondary/tertiary, --border-primary, --text-primary/secondary/tertiary, --error, --warning, --success, --accent-muted. - Zero raw hex values remain in admin.css. - Removed the corrupted/dead CSS from the bottom half and reconstructed all selectors from what the templates actually use (audited via grep). - Fixed structural issues: broken border shorthand, nested rules that were not valid CSS, orphaned declaration blocks. - New/restored rules: .admin-maintenance-bar (was corrupted), .status-access variants (was corrupted), .admin-section-title--danger, .admin-danger-zone, .admin-account-status (all reconstructed cleanly). - .admin-btn--warning and .admin-btn--danger now use var(--accent-yellow) and var(--accent-red) instead of hardcoded dark hex values. - .admin-btn-remove hover now uses var(--error) instead of #e55. - .admin-btn-unpublish now uses var(--bg-secondary)/var(--text-tertiary) instead of hardcoded grey hex values. - select option background colours removed (browser chrome, not styleable cross-platform). Templates: replace 4 inline var(--admin-text-muted) with var(--text-secondary) in index.php, thanks.php, import.php.
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" role="toolbar" aria-label="Actions groupées">
|
|
<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(--text-secondary);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(--text-secondary);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'; ?>
|