Files
xamxam/app/templates/admin/recapitulatif.php
T
Pontoporeia 6e1fc6a781 Add admin-only route to open Interdit thesis files from backoffice:
- reliable tab title /favicon wrapper,
- Content-Disposition filename,
- admin media route hardened to thesis-file prefixes only (defense-in-depth)
2026-09-18 16:26:36 +02:00

306 lines
16 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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" class="admin-main--recap">
<?php if ($studentMode): ?>
<!-- ═══════════════════ STUDENT MODE: Thank you page ═══════════════════ -->
<div class="thanks-student-page">
<?php if ($error): ?>
<div class="thanks-error">
<h1>⚠ Oups…</h1>
<p><?= htmlspecialchars($error) ?></p>
<a href="/admin/add.php?mode=student" class="btn btn--primary btn--lg btn-new-form">← Retour au formulaire</a>
</div>
<?php elseif ($thesis): ?>
<div class="thanks-success">
<h1>Merci 🎉</h1>
<p class="thanks-message">
Ton TFE <strong><?= htmlspecialchars($thesis['title']) ?></strong> a bien été soumis.
</p>
<a href="/admin/add.php?mode=student" class="btn btn--primary btn--lg btn-new-form">+ Ajouter un nouveau TFE</a>
</div>
<?php else: ?>
<div class="thanks-error">
<h1>Erreur</h1>
<p>Aucune donnée à afficher.</p>
<a href="/admin/add.php?mode=student" class="btn btn--primary btn--lg btn-new-form">← Retour au formulaire</a>
</div>
<?php endif; ?>
</div>
<?php else: ?>
<!-- ═══════════════════ ADMIN MODE: Recap page ═══════════════════ -->
<h1><a href="/admin/" class="admin-back-btn" title="Retour à la liste"><?= icon('arrow-left-circle') ?></a> Récapitulatif TFE</h1>
<?php if ($error): ?>
<p class="toast" role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
<p><a href="/admin/add.php" class="btn btn--secondary">Retour au formulaire</a></p>
<?php elseif ($thesis): ?>
<!-- ═══════════ Informations du TFE ═══════════ -->
<fieldset>
<legend>Informations du TFE</legend>
<dl class="recap-dl">
<dt>Identifiant</dt><dd><?= htmlspecialchars($thesis['identifier']) ?></dd>
<dt>Titre</dt><dd><?= htmlspecialchars($thesis['title']) ?></dd>
<?php if ($thesis['subtitle']): ?>
<dt>Sous-titre</dt><dd><?= htmlspecialchars($thesis['subtitle']) ?></dd>
<?php endif; ?>
<dt>Auteur·ice(s)</dt><dd><?= htmlspecialchars($thesis['authors']) ?></dd>
<?php if (!empty($thesis['contact_visible'])): ?>
<dt>Contact visible</dt><dd><?= htmlspecialchars($thesis['contact_visible']) ?></dd>
<?php endif; ?>
<?php if (!empty($thesis['contact_interne'])): ?>
<dt>Contact interne (privé)</dt><dd><?= htmlspecialchars($thesis['contact_interne']) ?></dd>
<?php endif; ?>
<dt>Année</dt><dd><?= htmlspecialchars((string)$thesis['year']) ?></dd>
<dt>Objet</dt><dd><?= htmlspecialchars($thesis['objet'] ?? 'tfe') ?></dd>
<?php if ($thesis['is_doctoral']): ?>
<dt>Doctoral</dt><dd>Oui</dd>
<?php endif; ?>
</dl>
</fieldset>
<!-- ═══════════ Cadre académique ═══════════ -->
<fieldset>
<legend>Cadre académique</legend>
<dl class="recap-dl">
<dt>Orientation</dt><dd><?= htmlspecialchars($thesis['orientation'] ?? '–') ?></dd>
<dt>Atelier Pratique</dt><dd><?= htmlspecialchars($thesis['ap_program'] ?? '–') ?></dd>
<dt>Finalité</dt><dd><?= htmlspecialchars($thesis['finality_type'] ?? '–') ?></dd>
</dl>
</fieldset>
<!-- ═══════════ Jury ═══════════ -->
<?php
$hasJury = $thesis['jury_president']
|| $thesis['jury_promoteurs']
|| $thesis['jury_promoteurs_ulb']
|| $thesis['jury_lecteurs_internes']
|| $thesis['jury_lecteurs_externes']
|| $thesis['supervisors'];
?>
<?php if ($hasJury): ?>
<fieldset>
<legend>Jury</legend>
<dl class="recap-dl">
<?php if ($thesis['jury_president']): ?>
<dt>Président·e</dt><dd><?= htmlspecialchars($thesis['jury_president']) ?></dd>
<?php endif; ?>
<?php if ($thesis['jury_promoteurs']): ?>
<dt>Promoteur·ice(s)</dt><dd><?= htmlspecialchars($thesis['jury_promoteurs']) ?></dd>
<?php endif; ?>
<?php if ($thesis['jury_promoteurs_ulb']): ?>
<dt>Promoteur·ice(s) université</dt><dd><?= htmlspecialchars($thesis['jury_promoteurs_ulb']) ?></dd>
<?php endif; ?>
<?php if ($thesis['jury_lecteurs_internes']): ?>
<dt>Lecteur·ice(s) interne</dt><dd><?= htmlspecialchars($thesis['jury_lecteurs_internes']) ?></dd>
<?php endif; ?>
<?php if ($thesis['jury_lecteurs_externes']): ?>
<dt>Lecteur·ice(s) externe</dt><dd><?= htmlspecialchars($thesis['jury_lecteurs_externes']) ?></dd>
<?php endif; ?>
<?php if ($thesis['supervisors'] && !$thesis['jury_promoteurs']): ?>
<dt>Promoteur·ice(s)</dt><dd><?= htmlspecialchars($thesis['supervisors']) ?></dd>
<?php endif; ?>
<?php if ($thesis['jury_points'] !== null): ?>
<dt>Note du jury</dt><dd><?= htmlspecialchars($thesis['jury_points']) ?>/20</dd>
<?php endif; ?>
</dl>
</fieldset>
<?php endif; ?>
<!-- ═══════════ Contenu ═══════════ -->
<fieldset>
<legend>Contenu</legend>
<dl class="recap-dl">
<dt>Synopsis</dt>
<dd class="recap-synopsis"><?= nl2br(htmlspecialchars($thesis['synopsis'] ?? '–')) ?></dd>
<?php if ($thesis['context_note']): ?>
<dt>Note contextuelle relative à soutenance</dt>
<dd class="recap-long-text"><?= nl2br(htmlspecialchars($thesis['context_note'])) ?></dd>
<?php endif; ?>
<?php if ($thesis['languages']): ?>
<dt>Langue(s)</dt><dd><?= htmlspecialchars($thesis['languages']) ?></dd>
<?php endif; ?>
<?php if ($thesis['formats']): ?>
<dt>Format(s)</dt><dd><?= htmlspecialchars($thesis['formats']) ?></dd>
<?php endif; ?>
<?php if ($thesis['keywords']): ?>
<dt>Mots-clés</dt><dd><?= htmlspecialchars($thesis['keywords']) ?></dd>
<?php endif; ?>
<?php
$_hasPages = isset($thesis['duration_pages']) && $thesis['duration_pages'] !== null && $thesis['duration_pages'] !== '';
$_hasMins = isset($thesis['duration_minutes']) && $thesis['duration_minutes'] !== null && $thesis['duration_minutes'] !== '';
$_parts = [];
if ($_hasPages) $_parts[] = $thesis['duration_pages'] . ' pages';
if ($_hasMins) {
$_h = (int)floor((int)$thesis['duration_minutes'] / 60);
$_m = (int)$thesis['duration_minutes'] % 60;
$_parts[] = $_h . 'h' . str_pad((string)$_m, 2, '0', STR_PAD_LEFT);
}
$_duree = $_parts ? htmlspecialchars(implode(', ', $_parts)) : '–';
?>
<dt>Durée</dt><dd><?= $_duree ?></dd>
<dt>Annexes</dt><dd><?= !empty($thesis['has_annexes']) ? 'Oui' : 'Non' ?></dd>
<?php if ($thesis['baiu_link']): ?>
<dt>Lien BAIU</dt><dd><a href="<?= htmlspecialchars($thesis['baiu_link']) ?>" target="_blank" rel="noopener"><?= htmlspecialchars($thesis['baiu_link']) ?></a></dd>
<?php endif; ?>
</dl>
</fieldset>
<!-- ═══════════ Accès et licence ═══════════ -->
<fieldset>
<legend>Accès et licence</legend>
<dl class="recap-dl">
<dt>Degré d'ouverture</dt><dd><?= htmlspecialchars($thesis['access_type'] ?? '–') ?></dd>
<?php if ($thesis['license_type']): ?>
<dt>Licence</dt><dd><?= htmlspecialchars($thesis['license_type']) ?></dd>
<?php endif; ?>
<?php if ($thesis['license_custom']): ?>
<dt>Licence personnalisée</dt><dd><?= htmlspecialchars($thesis['license_custom']) ?></dd>
<?php endif; ?>
<dt>CC2r</dt><dd><?= !empty($thesis['cc2r']) ? 'Acceptée' : 'Non' ?></dd>
<dt>Exemplaire BAIU</dt><dd><?= !empty($thesis['exemplaire_baiu']) ? 'Oui' : 'Non' ?></dd>
<dt>Exemplaire ERG</dt><dd><?= !empty($thesis['exemplaire_erg']) ? 'Oui' : 'Non' ?></dd>
</dl>
</fieldset>
<!-- ═══════════ Dates et publication ═══════════ -->
<fieldset>
<legend>Dates et publication</legend>
<dl class="recap-dl">
<?php if ($thesis['date_depot']): ?>
<dt>Date de dépôt</dt><dd><?= htmlspecialchars(db_datetime($thesis['date_depot'], 'd/m/Y à H:i')) ?></dd>
<?php endif; ?>
<?php if ($thesis['submitted_at']): ?>
<dt>Soumis le</dt><dd><?= htmlspecialchars(db_datetime($thesis['submitted_at'])) ?></dd>
<?php endif; ?>
<?php if ($thesis['defense_date']): ?>
<dt>Date de défense</dt><dd><?= htmlspecialchars(db_datetime($thesis['defense_date'], 'd/m/Y')) ?></dd>
<?php endif; ?>
<?php if ($thesis['published_at']): ?>
<dt>Publié le</dt><dd><?= htmlspecialchars(db_datetime($thesis['published_at'])) ?></dd>
<?php endif; ?>
<dt>Publié</dt><dd><?= !empty($thesis['is_published']) ? 'Oui' : 'Non' ?></dd>
<?php if ($thesis['jury_note_added']): ?>
<dt>Note du jury ajoutée</dt><dd><?= htmlspecialchars(db_datetime($thesis['jury_note_added'], 'd/m/Y')) ?></dd>
<?php endif; ?>
</dl>
</fieldset>
<!-- ═══════════ Remarques ═══════════ -->
<?php if (!empty($thesis['remarks'])): ?>
<fieldset>
<legend>Remarques</legend>
<p class="recap-long-text"><?= nl2br(htmlspecialchars($thesis['remarks'])) ?></p>
</fieldset>
<?php endif; ?>
<!-- ═══════════ Fichiers ═══════════ -->
<?php if (!empty($files)): ?>
<fieldset>
<legend>Fichiers (<?= count($files) ?>)</legend>
<table class="recap-files-table">
<thead>
<tr>
<th></th>
<th>Nom</th>
<th>Type</th>
<th>Taille</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<?php foreach ($files as $f): ?>
<?php
$mime = $f['mime_type'] ?? '';
$filePath = $f['file_path'] ?? '';
$fileName = htmlspecialchars($f['file_name'] ?? basename($filePath));
$fileType = $f['file_type'] ?? 'other';
$displayLabel = $f['display_label'] ?? '';
$fileExt = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
$isImage = str_starts_with($mime, 'image/') || in_array($fileExt, ['jpg','jpeg','png','gif','webp']);
$isPeerTube = str_starts_with($filePath, 'peertube_ids:');
$isExternal = str_starts_with($filePath, 'http://') || str_starts_with($filePath, 'https://');
if ($isPeerTube) {
require_once APP_ROOT . '/src/PeerTubeService.php';
$_ptDb = new Database();
$_ptUuid = substr($filePath, strlen('peertube_ids:'));
$_ptS = PeerTubeService::getSettings($_ptDb);
$mediaUrl = ((int)$_ptS['privacy'] <= 2)
? PeerTubeService::getWatchUrl($_ptDb, $_ptUuid)
: '#';
} elseif ($isExternal) {
$mediaUrl = htmlspecialchars($filePath);
} else {
// Interdit (access_type_id=3): the public /media route returns
// 403 for these. Open them via the dedicated admin viewer
// (/admin/media-viewer.php), served under /admin so the
// administrator's session cookie is sent and the tab title
// shows the file name.
$_isForbidden = ((int)($thesis['access_type_id'] ?? 0) === 3);
$mediaUrl = ($_isForbidden ? '/admin/media-viewer.php' : '/media')
. '?path=' . urlencode($filePath);
}
$typeIcon = match (true) {
$isPeerTube && $fileType === 'video' => '🎬',
$isPeerTube && $fileType === 'audio' => '🔊',
$fileType === 'cover' => '🖼️',
$fileType === 'note_intention' => '📝',
$fileType === 'main' || ($mime === 'application/pdf') || $fileExt === 'pdf' => '📄',
$fileType === 'video' || str_starts_with($mime, 'video/') || in_array($fileExt, ['mp4','webm','mov','ogv']) => '🎬',
$fileType === 'audio' || str_starts_with($mime, 'audio/') || in_array($fileExt, ['mp3','ogg','wav','flac','aac','m4a']) => '🔊',
$isImage => '🖼️',
$fileType === 'caption' || $fileExt === 'vtt' => '💬',
$fileType === 'annex' => '📎',
$fileType === 'website' => '🌐',
default => '📎',
};
?>
<tr>
<td class="recap-files-icon">
<span class="recap-files-icon-emoji"><?= $typeIcon ?></span>
</td>
<td class="recap-files-name">
<a href="<?= $mediaUrl ?>" target="_blank" rel="noopener"><?= $fileName ?></a>
<?php if ($isPeerTube): ?>
<span class="recap-files-peertube-id">ID : <?= htmlspecialchars($_ptUuid) ?></span>
<?php endif; ?>
<?php if ($displayLabel): ?>
<span class="recap-files-label"><?= htmlspecialchars($displayLabel) ?></span>
<?php endif; ?>
</td>
<td class="recap-files-type"><?= htmlspecialchars($fileType) ?></td>
<td class="recap-files-size"><?= !empty($f['file_size']) && $f['file_size'] > 0 ? formatFileSize($f['file_size']) : '–' ?></td>
<td class="recap-files-date"><?= !empty($f['uploaded_at']) ? htmlspecialchars(db_datetime($f['uploaded_at'], 'd/m/Y H:i')) : '–' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</fieldset>
<?php endif; ?>
<div class="admin-action-bar">
<a href="/admin/edit.php?id=<?= $thesisId ?>" class="btn btn--primary">Modifier</a>
<a href="/admin/" class="btn btn--secondary">Retour à la liste</a>
</div>
<?php else: ?>
<p class="admin-muted">Aucune donnée à afficher.</p>
<p><a href="/admin/add.php" class="btn btn--secondary">Retour au formulaire</a></p>
<?php endif; ?>
<?php endif; ?>
</main>