Files
varlog/templates/admin.php
T
2026-05-12 10:04:58 +02:00

395 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
ob_start();
$now = time();
function adminStatusBadge(array $a, int $now): string
{
if (!$a['published']) {
return '<span class="badge bg-secondary">Brouillon</span>';
}
if (strtotime((string)($a['published_at'] ?? '')) > $now) {
return '<span class="badge bg-warning text-dark">Avant-première</span>';
}
return '<span class="badge bg-success">Publié</span>';
}
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0">Administration</h1>
<a href="/new" class="btn btn-primary btn-sm">+ Nouvel article</a>
</div>
<!-- Onglets -->
<ul class="nav nav-tabs mb-4">
<?php if (isAdmin()): ?>
<li class="nav-item">
<a class="nav-link <?= $tab === 'dashboard' ? 'active' : '' ?>"
href="/admin/dashboard">Tableau de bord</a>
</li>
<?php endif; ?>
<li class="nav-item">
<a class="nav-link <?= $tab === 'articles' ? 'active' : '' ?>"
href="/admin/articles"><?= isAdmin() ? 'Articles' : 'Mes articles' ?></a>
</li>
<?php if (isAdmin()): ?>
<li class="nav-item">
<a class="nav-link <?= $tab === 'users' ? 'active' : '' ?>"
href="/admin/users">Utilisateurs</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $tab === 'roles' ? 'active' : '' ?>"
href="/admin/roles">Rôles</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/categories">Catégories</a>
</li>
<?php endif; ?>
</ul>
<!-- ─────────────────────────── DASHBOARD ─────────────────────────── -->
<?php if ($tab === 'dashboard' && isAdmin()): ?>
<div class="row g-3 mb-4">
<?php
$stats = [
['label' => 'Publiés', 'value' => $adminData['published'], 'color' => 'success'],
['label' => 'Avant-premières', 'value' => $adminData['previews'], 'color' => 'warning'],
['label' => 'Brouillons', 'value' => $adminData['drafts'], 'color' => 'secondary'],
['label' => 'Total', 'value' => $adminData['total'], 'color' => 'primary'],
];
foreach ($stats as $s): ?>
<div class="col-6 col-md-3">
<div class="card text-center">
<div class="card-body">
<div class="display-6 fw-bold text-<?= $s['color'] ?>"><?= $s['value'] ?></div>
<div class="text-muted small"><?= $s['label'] ?></div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<h5>Activité récente</h5>
<table class="table table-sm table-hover">
<thead>
<tr>
<th>Titre</th>
<th>Auteur</th>
<th>Statut</th>
<th>Modifié le</th>
</tr>
</thead>
<tbody>
<?php foreach ($adminData['recent'] as $a): ?>
<tr>
<td>
<a href="/post/<?= htmlspecialchars($a['slug'] ?? '') ?>">
<?= htmlspecialchars($a['title']) ?>
</a>
</td>
<td class="text-muted small"><?= htmlspecialchars($a['author'] ?? '') ?></td>
<td><?= adminStatusBadge($a, $now) ?></td>
<td class="text-muted small">
<?= htmlspecialchars(date('d/m/Y H:i', strtotime((string)($a['updated_at'] ?? $a['created_at'] ?? '')))) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- ─────────────────────────── ARTICLES ─────────────────────────── -->
<?php elseif ($tab === 'articles'): ?>
<?php if (empty($adminData['articles'])): ?>
<p class="text-muted">Aucun article.</p>
<?php else: ?>
<table class="table table-sm table-hover align-middle">
<thead>
<tr>
<th>Titre</th>
<?php if (isAdmin()): ?><th>Auteur</th><?php endif; ?>
<th>Catégorie</th>
<th>Statut</th>
<th>Date</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($adminData['articles'] as $a): ?>
<tr>
<td>
<a href="/post/<?= htmlspecialchars($a['slug'] ?? '') ?>">
<?= htmlspecialchars($a['title']) ?>
</a>
</td>
<?php if (isAdmin()): ?>
<td class="text-muted small"><?= htmlspecialchars($a['author'] ?? '') ?></td>
<?php endif; ?>
<td class="text-muted small"><?= htmlspecialchars($a['category'] ?? '') ?></td>
<td><?= adminStatusBadge($a, $now) ?></td>
<td class="text-muted small text-nowrap">
<?= htmlspecialchars(date('d/m/Y', strtotime((string)($a['published_at'] ?? $a['created_at'] ?? '')))) ?>
</td>
<td class="text-end text-nowrap">
<a href="/edit/<?= htmlspecialchars($a['uuid']) ?>"
class="btn btn-outline-secondary btn-sm">Modifier</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<!-- ─────────────────────────── UTILISATEURS ─────────────────────────── -->
<?php elseif ($tab === 'users' && isAdmin()): ?>
<!-- Ajouter / attribuer un rôle -->
<div class="card mb-4">
<div class="card-header">Attribuer un rôle</div>
<div class="card-body">
<form method="post" action="/?action=admin_grant_role" class="row g-2 align-items-end">
<div class="col-md-5">
<label class="form-label small">Email</label>
<input type="email" name="email" class="form-control form-control-sm"
placeholder="utilisateur@exemple.fr" required>
</div>
<div class="col-md-4">
<label class="form-label small">Rôle</label>
<select name="role" class="form-select form-select-sm" required>
<?php foreach ($adminData['roles'] as $r): ?>
<option value="<?= htmlspecialchars($r['name']) ?>">
<?= htmlspecialchars($r['label']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary btn-sm w-100">Attribuer</button>
</div>
</form>
</div>
</div>
<!-- Liste des utilisateurs -->
<?php if (empty($adminData['users'])): ?>
<p class="text-muted">Aucun utilisateur.</p>
<?php else: ?>
<table class="table table-sm table-hover align-middle">
<thead>
<tr>
<th>Email</th>
<th>Statut</th>
<th>Rôles</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($adminData['users'] as $u): ?>
<tr>
<td class="small"><?= htmlspecialchars($u['email']) ?></td>
<td>
<?php if ($u['is_active'] === null): ?>
<span class="badge bg-light text-muted">Pré-inscrit</span>
<?php elseif ($u['is_active']): ?>
<span class="badge bg-success">Actif</span>
<?php else: ?>
<span class="badge bg-danger">Inactif</span>
<?php endif; ?>
</td>
<td>
<?php foreach ($u['roles'] as $roleName): ?>
<span class="badge bg-primary me-1"><?= htmlspecialchars($roleName) ?></span>
<form method="post" action="/?action=admin_revoke_role"
class="d-inline"
data-confirm="Retirer le rôle <?= htmlspecialchars($roleName) ?> à <?= htmlspecialchars($u['email']) ?> ?">
<input type="hidden" name="email" value="<?= htmlspecialchars($u['email']) ?>">
<input type="hidden" name="role" value="<?= htmlspecialchars($roleName) ?>">
<button type="submit" class="btn btn-link btn-sm p-0 text-danger" title="Retirer">×</button>
</form>
<?php endforeach; ?>
<?php if (empty($u['roles'])): ?>
<span class="text-muted small"></span>
<?php endif; ?>
</td>
<td class="text-end">
<!-- Ajout rapide d'un rôle existant -->
<?php
$currentRoles = $u['roles'];
$missing = array_filter($adminData['roles'], fn ($r) => !in_array($r['name'], $currentRoles, true));
?>
<?php if ($missing): ?>
<form method="post" action="/?action=admin_grant_role" class="d-inline-flex gap-1">
<input type="hidden" name="email" value="<?= htmlspecialchars($u['email']) ?>">
<select name="role" class="form-select form-select-sm" style="width:auto">
<?php foreach ($missing as $r): ?>
<option value="<?= htmlspecialchars($r['name']) ?>">
<?= htmlspecialchars($r['label']) ?>
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="btn btn-outline-primary btn-sm">+</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<!-- ─────────────────────────── RÔLES ─────────────────────────── -->
<?php elseif ($tab === 'roles' && isAdmin()): ?>
<div class="row g-4">
<!-- Liste des rôles existants -->
<div class="col-lg-8">
<h5 class="mb-3">Rôles existants</h5>
<?php if (empty($adminData['roles'])): ?>
<p class="text-muted">Aucun rôle défini.</p>
<?php else: ?>
<table class="table table-sm table-hover align-middle">
<thead>
<tr>
<th style="width:160px">Nom technique</th>
<th>Label affiché</th>
<th class="text-center" style="width:90px">Utilisateurs</th>
<th style="width:100px"></th>
</tr>
</thead>
<tbody>
<?php foreach ($adminData['roles'] as $r): ?>
<tr>
<td><code class="text-body"><?= htmlspecialchars($r['name']) ?></code></td>
<td>
<form method="post" action="/?action=admin_update_role"
class="d-flex gap-2 align-items-center">
<input type="hidden" name="id" value="<?= (int)$r['id'] ?>">
<input type="text" name="label"
value="<?= htmlspecialchars($r['label']) ?>"
class="form-control form-control-sm" required>
<button type="submit" class="btn btn-outline-secondary btn-sm text-nowrap">
Sauver
</button>
</form>
</td>
<td class="text-center">
<span class="badge bg-secondary"><?= (int)$r['user_count'] ?></span>
</td>
<td class="text-end">
<form method="post" action="/?action=admin_delete_role"
data-confirm="Supprimer le rôle «<?= htmlspecialchars($r['name']) ?>» ?<?= (int)$r['user_count'] > 0 ? ' ' . (int)$r['user_count'] . ' utilisateur(s) perdront ce rôle.' : '' ?>">
<input type="hidden" name="id" value="<?= (int)$r['id'] ?>">
<button type="submit" class="btn btn-outline-danger btn-sm">
Supprimer
</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<!-- Créer un rôle -->
<div class="col-lg-4">
<div class="card">
<div class="card-header">Nouveau rôle</div>
<div class="card-body">
<form method="post" action="/?action=admin_create_role">
<div class="mb-3">
<label class="form-label small fw-semibold">Nom technique</label>
<input type="text" name="name" class="form-control form-control-sm"
placeholder="ex : moderator"
pattern="[a-z0-9_-]+"
title="Lettres minuscules, chiffres, tirets et underscores uniquement"
required>
<div class="form-text">Utilisé dans le code — ne change pas.</div>
</div>
<div class="mb-3">
<label class="form-label small fw-semibold">Label affiché</label>
<input type="text" name="label" class="form-control form-control-sm"
placeholder="ex : Modérateur" required>
</div>
<button type="submit" class="btn btn-primary btn-sm w-100">Créer</button>
</form>
</div>
</div>
</div>
<!-- Permissions par rôle -->
<?php if (!empty($adminData['roles'])): ?>
<div class="col-12 mt-2">
<h5 class="mb-3">Permissions par rôle</h5>
<p class="text-muted small mb-3">Le rôle <code>admin</code> a toutes les permissions implicitement.</p>
<div class="row g-3">
<?php foreach ($adminData['roles'] as $r):
if ($r['name'] === 'admin') {
continue;
} ?>
<div class="col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-header py-2 d-flex align-items-center justify-content-between">
<span class="fw-semibold"><?= htmlspecialchars($r['label']) ?></span>
<code class="text-muted small"><?= htmlspecialchars($r['name']) ?></code>
</div>
<div class="card-body py-3">
<form method="post" action="/?action=admin_update_role_caps">
<input type="hidden" name="role_id" value="<?= (int)$r['id'] ?>">
<?php foreach (CAPABILITY_GROUPS as $group): ?>
<?php if (isset($group['single'])): ?>
<?php $cap = $group['single']; ?>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox"
name="caps[]" value="<?= htmlspecialchars($cap) ?>"
id="cap_<?= (int)$r['id'] ?>_<?= htmlspecialchars($cap) ?>"
<?= in_array($cap, $r['capabilities'], true) ? 'checked' : '' ?>>
<label class="form-check-label small fw-semibold"
for="cap_<?= (int)$r['id'] ?>_<?= htmlspecialchars($cap) ?>">
<?= htmlspecialchars($group['label']) ?>
</label>
</div>
<?php else: ?>
<div class="mb-3">
<div class="small fw-semibold mb-1"><?= htmlspecialchars($group['label']) ?></div>
<div class="d-flex gap-3 ps-1">
<?php foreach (['own' => 'Propres articles', 'all' => 'Tous'] as $scope => $scopeLabel):
$cap = $group[$scope]; ?>
<div class="form-check">
<input class="form-check-input" type="checkbox"
name="caps[]" value="<?= htmlspecialchars($cap) ?>"
id="cap_<?= (int)$r['id'] ?>_<?= htmlspecialchars($cap) ?>"
<?= in_array($cap, $r['capabilities'], true) ? 'checked' : '' ?>>
<label class="form-check-label small"
for="cap_<?= (int)$r['id'] ?>_<?= htmlspecialchars($cap) ?>">
<?= $scopeLabel ?>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<button type="submit" class="btn btn-outline-secondary btn-sm mt-1 w-100">
Enregistrer
</button>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<?php
$content = ob_get_clean();
$title = 'Administration — varlog';
include __DIR__ . '/layout.php';