mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 08:09:18 +02:00
Added EmailObfuscator class (src/EmailObfuscator.php) that converts email addresses to HTML decimal entities (e.g. foo@...) so browsers render them correctly but bots and scrapers see gibberish. Methods: - email($addr): obfuscate for display in HTML content - mailto($addr): return obfuscated mailto: href - obfuscateHtml($html): post-process rendered HTML to obfuscate all mailto: links (used after Parsedown/Markdown rendering) Applied to: - partage/index.php: mailto link at top + error scenarios via _flash_contact flag rendered in form.php (outside htmlspecialchars to avoid double-escape) - admin/acces.php: request email mailto links - admin/file-access.php: request email mailto links - public/about.php: contact email mailto links - public/tfe.php: author contact mailto links - AboutController: Parsedown output post-processing - LicenceController: Parsedown output post-processing - Dispatcher::render(): require_once EmailObfuscator for all public views Also fixed _flash_contact session flag in form.php partial to show contact email line on share link validation errors (separate from flash_error/warning to bypass htmlspecialchars double-escaping).
198 lines
9.1 KiB
PHP
198 lines
9.1 KiB
PHP
<main id="main-content">
|
|
<h1>Demandes d'accès aux fichiers</h1>
|
|
|
|
<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="<?= EmailObfuscator::mailto($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="btn btn--primary access-req-btn access-req-btn--approve"
|
|
onclick="openApproveDialog(<?= $req['id'] ?>)">
|
|
Approuver
|
|
</button>
|
|
<button type="button"
|
|
class="btn btn--danger 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">
|
|
← 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 →
|
|
</a>
|
|
<?php endif; ?>
|
|
</nav>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</main>
|
|
|
|
<!-- 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()">×</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="btn btn--primary">Approuver et envoyer email</button>
|
|
<button type="button" class="btn 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()">×</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="btn btn--danger">Rejeter</button>
|
|
<button type="button" class="btn btn--secondary"
|
|
onclick="document.getElementById('reject-dialog').close()">Annuler</button>
|
|
</div>
|
|
</form>
|
|
</dialog>
|
|
|
|
<script>
|
|
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>
|
|
|
|
|