Files
xamxam/app/templates/admin/acces.php

395 lines
22 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.
<main id="main-content">
<h1>Accès</h1>
<!-- ══════════════════════════════════════════════════════════════
LIENS D'ACCÈS ÉTUDIANT·E
══════════════════════════════════════════════════════════════ -->
<section aria-labelledby="acces-liens-title">
<div class="admin-list-toolbar">
<h2 id="acces-liens-title">Accès étudiant·e</h2>
<div class="admin-list-toolbar__right">
<button type="button" class="admin-btn admin-btn--sm" id="open-create-dialog">
Créer un lien
</button>
</div>
</div>
<?php if (empty($links)): ?>
<p class="admin-empty">Aucun lien d'accès créé. Cliquez sur « Créer un lien » pour générer un lien partageable.</p>
<?php else: ?>
<table>
<thead>
<tr>
<th scope="col">Lien</th>
<th scope="col">Objet</th>
<th scope="col">Statut</th>
<th scope="col">Mot de passe</th>
<th scope="col">Utilisations</th>
<th scope="col">Expiration</th>
<th scope="col">Créé le</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($links as $link): ?>
<?php
$isExpired = $link['expires_at'] !== null && strtotime($link['expires_at']) < time();
$isActive = (bool)$link['is_active'] && !$isExpired;
$statusLabel = $isExpired ? 'Expiré' : ($link['is_active'] ? 'Actif' : 'Désactivé');
$fullUrl = $baseUrl . '/partage/' . htmlspecialchars($link['slug']);
$created = date('d/m/Y H:i', strtotime($link['created_at']));
$expires = $link['expires_at'] ? date('d/m/Y', strtotime($link['expires_at'])) : '—';
$hasLinkPassword = !empty($link['password_hash']);
?>
<tr>
<td>
<code style="font-size:var(--step--2);color:var(--text-secondary);"><?= htmlspecialchars($link['slug']) ?></code>
<input type="hidden" id="url-<?= $link['id'] ?>" value="<?= $fullUrl ?>">
</td>
<td>
<?php if ($link['objet_restriction']): ?>
<span class="status-badge"><?= htmlspecialchars($link['objet_restriction']) ?></span>
<?php else: ?>
<span style="color:var(--text-secondary);font-size:var(--step--2);">Tous</span>
<?php endif; ?>
</td>
<td>
<?php if ($isExpired): ?>
<span class="status-badge status-pending"><?= $statusLabel ?></span>
<?php elseif ($link['is_active']): ?>
<span class="status-badge status-published"><?= $statusLabel ?></span>
<?php else: ?>
<span style="display:inline-block;padding:var(--space-3xs) var(--space-2xs);border-radius:3px;font-size:var(--step--2);font-weight:500;letter-spacing:0.04em;background:var(--error-muted-bg);color:var(--error);"><?= $statusLabel ?></span>
<?php endif; ?>
</td>
<td><?= $hasLinkPassword ? '🔒 Oui' : 'Non' ?></td>
<td style="text-align:center;"><?= intval($link['usage_count']) ?></td>
<td><?= $expires ?></td>
<td><?= $created ?></td>
<td>
<div class="admin-actions">
<a href="/partage/<?= urlencode($link['slug']) ?>" target="_blank" rel="noopener"
class="admin-btn-sm admin-btn-visit" title="Visiter le formulaire">
👁 Visiter
</a>
<button type="button" class="admin-btn-sm admin-btn-view"
onclick="copyUrl(<?= $link['id'] ?>)" title="Copier l'URL">
Copier
</button>
<form method="post" action="actions/acces-etudiante.php" class="publish-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="action" value="toggle">
<input type="hidden" name="id" value="<?= $link['id'] ?>">
<button type="submit"
class="admin-btn-sm <?= $link['is_active'] ? 'admin-btn-unpublish' : 'admin-btn-publish' ?>"
title="<?= $link['is_active'] ? 'Désactiver' : 'Activer' ?>">
<?= $link['is_active'] ? '⏸' : '▶' ?>
</button>
</form>
<button type="button" class="admin-btn-sm admin-btn-edit"
onclick="openPasswordDialog(<?= $link['id'] ?>, <?= $hasLinkPassword ? 'true' : 'false' ?>)"
title="Modifier le mot de passe">
🔑
</button>
<form method="post" action="actions/acces-etudiante.php" class="publish-form"
onsubmit="return confirm('Supprimer ce lien ? Les soumissions via ce lien seront bloquées.')">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $link['id'] ?>">
<button type="submit" class="admin-btn-sm admin-btn-delete" title="Supprimer">
🗑
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</section>
<!-- ══════════════════════════════════════════════════════════════
DEMANDES D'ACCÈS AUX FICHIERS
══════════════════════════════════════════════════════════════ -->
<section aria-labelledby="acces-fichiers-title">
<h2 id="acces-fichiers-title">Demandes d'accès aux fichiers</h2>
<div class="access-req-stats">
<div class="access-req-stat-card">
<span class="access-req-stat-number"><?= $pendingCount ?></span>
<span class="access-req-stat-label">En attente</span>
</div>
<div class="access-req-stat-card">
<span class="access-req-stat-number"><?= $approvedCount ?></span>
<span class="access-req-stat-label">Approuvées</span>
</div>
<div class="access-req-stat-card">
<span class="access-req-stat-number"><?= $rejectedCount ?></span>
<span class="access-req-stat-label">Rejetées</span>
</div>
</div>
<nav class="access-req-tabs">
<a href="?status=pending" class="access-req-tab <?= $status === 'pending' ? 'active' : '' ?>">
En attente <?= $pendingCount > 0 ? "({$pendingCount})" : '' ?>
</a>
<a href="?status=approved" class="access-req-tab <?= $status === 'approved' ? 'active' : '' ?>">
Approuvées
</a>
<a href="?status=rejected" class="access-req-tab <?= $status === 'rejected' ? 'active' : '' ?>">
Rejetées
</a>
</nav>
<?php if (empty($requests)): ?>
<div class="access-req-empty">
<p>Aucune demande <?= $status === 'pending' ? 'en attente' : ($status === 'approved' ? 'approuvée' : 'rejetée') ?>.</p>
</div>
<?php else: ?>
<div class="access-req-list">
<?php foreach ($requests as $req): ?>
<div class="access-req-card">
<div class="access-req-card__header">
<div class="access-req-card__thesis">
<h3><?= htmlspecialchars($req['title']) ?></h3>
<p class="access-req-card__authors">
<?php if (!empty($req['authors'])): ?>
par <?= htmlspecialchars($req['authors']) ?>
<?php endif; ?>
<?php if (!empty($req['year'])): ?>
— <?= htmlspecialchars($req['year']) ?>
<?php endif; ?>
</p>
</div>
<div class="access-req-card__meta">
<span class="access-req-badge access-req-badge--<?= $status ?>">
<?= $status === 'pending' ? 'En attente' : ($status === 'approved' ? 'Approuvée' : 'Rejetée') ?>
</span>
</div>
</div>
<div class="access-req-card__body">
<div class="access-req-card__info">
<div>
<strong>Email :</strong>
<a href="mailto:<?= htmlspecialchars($req['email']) ?>">
<?= htmlspecialchars($req['email']) ?>
</a>
</div>
<div>
<strong>Date :</strong>
<?= date('d/m/Y à H:i', strtotime($req['created_at'])) ?>
</div>
<?php if ($status === 'approved' && !empty($req['approved_at'])): ?>
<div>
<strong>Approuvée le :</strong>
<?= date('d/m/Y à H:i', strtotime($req['approved_at'])) ?>
</div>
<?php endif; ?>
<?php if ($status === 'rejected' && !empty($req['approved_at'])): ?>
<div>
<strong>Rejetée le :</strong>
<?= date('d/m/Y à H:i', strtotime($req['approved_at'])) ?>
</div>
<?php endif; ?>
</div>
<?php if (!empty($req['justification'])): ?>
<div class="access-req-card__justification">
<strong>Justification :</strong>
<p><?= nl2br(htmlspecialchars($req['justification'])) ?></p>
</div>
<?php endif; ?>
<?php if ($status === 'rejected' && !empty($req['admin_notes'])): ?>
<div class="access-req-card__admin-notes">
<strong>Note de l'administrateur :</strong>
<p><?= nl2br(htmlspecialchars($req['admin_notes'])) ?></p>
</div>
<?php endif; ?>
<?php if ($status === 'pending'): ?>
<div class="access-req-card__actions">
<button type="button"
class="access-req-btn access-req-btn--approve"
onclick="openApproveDialog(<?= $req['id'] ?>)">
Approuver
</button>
<button type="button"
class="access-req-btn access-req-btn--reject"
onclick="openRejectDialog(<?= $req['id'] ?>)">
Rejeter
</button>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if ($totalPages > 1): ?>
<nav class="access-req-pagination">
<?php if ($page > 1): ?>
<a href="?status=<?= $status ?>&page=<?= $page - 1 ?>" class="access-req-pagination__link">
&larr; Précédent
</a>
<?php endif; ?>
<span class="access-req-pagination__info">
Page <?= $page ?> sur <?= $totalPages ?>
</span>
<?php if ($page < $totalPages): ?>
<a href="?status=<?= $status ?>&page=<?= $page + 1 ?>" class="access-req-pagination__link">
Suivant &rarr;
</a>
<?php endif; ?>
</nav>
<?php endif; ?>
<?php endif; ?>
</section>
</main>
<!-- ═══════════════════════ CREATE DIALOG ═══════════════════════ -->
<dialog id="create-dialog" class="admin-dialog" aria-labelledby="create-dialog-title">
<div class="admin-dialog__header">
<h2 id="create-dialog-title">Créer un lien d'accès</h2>
<button type="button" class="admin-dialog__close" aria-label="Fermer"
onclick="document.getElementById('create-dialog').close()">&#x2715;</button>
</div>
<form method="post" action="actions/acces-etudiante.php" class="admin-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="action" value="create">
<div>
<label for="create-objet">Type d'objet (optionnel)</label>
<select id="create-objet" name="objet_restriction">
<option value="">— Tous les types —</option>
<option value="tfe">TFE</option>
<option value="thèse">Thèse</option>
<option value="frart">Frart</option>
</select>
<small>Restreint ce lien à un seul type de soumission.</small>
</div>
<div>
<label for="create-password">Mot de passe (optionnel)</label>
<input type="password" id="create-password" name="password" autocomplete="new-password">
<small>Laissez vide pour un lien sans mot de passe.</small>
</div>
<div>
<label for="create-expires">Expiration (optionnel)</label>
<input type="datetime-local" id="create-expires" name="expires_at">
<small>Laissez vide pour qu'il n'expire jamais.</small>
</div>
<div class="admin-form-footer">
<button type="submit" class="admin-btn">Créer le lien</button>
<button type="button" class="admin-btn-secondary"
onclick="document.getElementById('create-dialog').close()">Annuler</button>
</div>
</form>
</dialog>
<!-- ═══════════════════════ PASSWORD DIALOG ═══════════════════════ -->
<dialog id="password-dialog" class="admin-dialog" aria-labelledby="password-dialog-title">
<div class="admin-dialog__header">
<h2 id="password-dialog-title">Mot de passe</h2>
<button type="button" class="admin-dialog__close" aria-label="Fermer"
onclick="document.getElementById('password-dialog').close()">&#x2715;</button>
</div>
<form method="post" action="actions/acces-etudiante.php" class="admin-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="action" value="set_password">
<input type="hidden" name="id" id="password-link-id" value="">
<div>
<label for="password-input">Nouveau mot de passe</label>
<input type="password" id="password-input" name="password" autocomplete="new-password">
<small>Laissez vide pour supprimer le mot de passe.</small>
<p id="password-current-info" style="font-size:var(--step--2);color:var(--text-secondary);margin-top:var(--space-2xs);"></p>
</div>
<div class="admin-form-footer">
<button type="submit" class="admin-btn">Enregistrer</button>
<button type="button" class="admin-btn-secondary"
onclick="document.getElementById('password-dialog').close()">Annuler</button>
</div>
</form>
</dialog>
<!-- ═══════════════════════ APPROVE DIALOG ═══════════════════════ -->
<dialog id="approve-dialog" class="admin-dialog">
<div class="admin-dialog__header">
<h2>Approuver la demande</h2>
<button type="button" class="admin-dialog__close"
onclick="document.getElementById('approve-dialog').close()">&times;</button>
</div>
<form method="post" action="/admin/actions/access-request.php">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="request_id" id="approve-request-id">
<input type="hidden" name="action" value="approve">
<label for="approve-notes">Note optionnelle (inclus dans l'email) :</label>
<textarea name="admin_notes" id="approve-notes" rows="3"
placeholder="Message personnalisé pour le demandeur..."></textarea>
<div class="admin-form-footer">
<button type="submit" class="admin-btn">Approuver et envoyer email</button>
<button type="button" class="admin-btn-secondary"
onclick="document.getElementById('approve-dialog').close()">Annuler</button>
</div>
</form>
</dialog>
<!-- ═══════════════════════ REJECT DIALOG ════════════════════════ -->
<dialog id="reject-dialog" class="admin-dialog">
<div class="admin-dialog__header">
<h2>Rejeter la demande</h2>
<button type="button" class="admin-dialog__close"
onclick="document.getElementById('reject-dialog').close()">&times;</button>
</div>
<form method="post" action="/admin/actions/access-request.php">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="request_id" id="reject-request-id">
<input type="hidden" name="action" value="reject">
<label for="reject-notes">Raison du rejet (optionnel) :</label>
<textarea name="admin_notes" id="reject-notes" rows="3"
placeholder="Raison du rejet..."></textarea>
<div class="admin-form-footer">
<button type="submit" class="admin-btn admin-btn--danger">Rejeter</button>
<button type="button" class="admin-btn-secondary"
onclick="document.getElementById('reject-dialog').close()">Annuler</button>
</div>
</form>
</dialog>
<script>
document.getElementById('open-create-dialog').addEventListener('click', () => {
document.getElementById('create-dialog').showModal();
});
function copyUrl(id) {
const input = document.getElementById('url-' + id);
navigator.clipboard.writeText(input.value).then(() => {
const btn = event.target.closest('button');
const orig = btn.textContent;
btn.textContent = '✓ Copié';
setTimeout(() => { btn.textContent = orig; }, 1200);
});
}
function openPasswordDialog(id, hasPassword) {
document.getElementById('password-link-id').value = id;
const info = document.getElementById('password-current-info');
info.textContent = hasPassword
? 'Un mot de passe est actuellement configuré. Entrez-en un nouveau ou laissez vide pour le supprimer.'
: 'Aucun mot de passe configuré.';
document.getElementById('password-dialog').showModal();
}
function openApproveDialog(requestId) {
document.getElementById('approve-request-id').value = requestId;
document.getElementById('approve-dialog').showModal();
}
function openRejectDialog(requestId) {
document.getElementById('reject-request-id').value = requestId;
document.getElementById('reject-dialog').showModal();
}
</script>