Files
xamxam/app/templates/public/tfe.php
T
Pontoporeia 6e1d54511d fix: remove redundant query= param from filter-specific metadata links on TFE page
Clicking orientation, AP program, finality, year, format, or keyword links
on the TFE page was passing both a dedicated filter param AND a query=
param. The query= text search doesn't look at the filter columns
(orientation, ap_program, etc.), so the AND combination yielded zero
results when the filter value didn't appear in title/authors/etc fields.

Also fix the language link: it was passing language as query= which
searches only title/authors/etc, not the languages column. Now uses
the dedicated language= param (DB layer already supported it, and
collectSearchParams now collects it).
2026-07-10 17:20:21 +02:00

484 lines
25 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 class="tfe-main" id="main-content">
<article class="tfe-content-row">
<div class="tfe-left-column">
<p class="tfe-author"><?= htmlspecialchars(
$data["authors"] ?? "Auteur inconnu",
) ?></p>
<h1 class="tfe-title">
<?= htmlspecialchars($data["title"]) ?>
<?php if (!empty($data["subtitle"])): ?>
<?= htmlspecialchars($data["subtitle"]) ?>
<?php endif; ?>
</h1>
<div class="tfe-meta">
<?php if (!empty($data["orientation"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Orientation&nbsp;:</span>
<a href="/search?orientation=<?= urlencode($data["orientation"]) ?>"><?= htmlspecialchars($data["orientation"]) ?></a>
</p>
<?php endif; ?>
<?php if (!empty($data["ap_program"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Atelier pluridisciplinaire&nbsp;:</span>
<a href="/search?ap_program=<?= urlencode($data["ap_program"]) ?>"><?= htmlspecialchars($data["ap_program"]) ?></a>
</p>
<?php endif; ?>
<?php if (!empty($data["finality_type"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Finalité&nbsp;:</span>
<a href="/search?finality=<?= urlencode($data["finality_type"]) ?>"><?= htmlspecialchars($data["finality_type"]) ?></a>
</p>
<?php endif; ?>
<?php if (!empty($data["year"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Date&nbsp;:</span>
<a href="/search?year=<?= urlencode($data["year"]) ?>"><?= htmlspecialchars($data["year"]) ?></a>
</p>
<?php endif; ?>
<?php
$_hasPages = isset($data["duration_pages"]) && $data["duration_pages"] !== null && $data["duration_pages"] !== '';
$_hasMins = isset($data["duration_minutes"]) && $data["duration_minutes"] !== null && $data["duration_minutes"] !== '';
if ($_hasPages || $_hasMins):
$_parts = [];
if ($_hasPages) $_parts[] = $data['duration_pages'] . ' pages';
if ($_hasMins) {
$_h = (int)floor((int)$data['duration_minutes'] / 60);
$_m = (int)$data['duration_minutes'] % 60;
$_parts[] = $_h . 'h' . str_pad((string)$_m, 2, '0', STR_PAD_LEFT);
}
$_duree = htmlspecialchars(implode(', ', $_parts));
unset($_h, $_m);
?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Durée&nbsp;:</span>
<?= $_duree ?>
</p>
<?php endif; unset($_hasPages, $_hasMins, $_parts, $_duree); ?>
<?php if (!empty($data["languages"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Langue&nbsp;:</span>
<?php
$langs = array_map("trim", explode(",", $data["languages"]));
$langLinks = array_map(
fn($l) => '<a href="/search?language=' . urlencode($l) . '">' . htmlspecialchars(mb_strtolower($l)) . '</a>',
$langs,
);
echo implode(", ", $langLinks);
?>
</p>
<?php endif; ?>
<?php if (!empty($data["formats"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Format&nbsp;:</span>
<?php
$fmts = array_map("trim", explode(",", $data["formats"]));
$fmtLinks = array_map(
fn($f) => '<a href="/search?format=' . urlencode($f) . '">' . htmlspecialchars(mb_strtolower($f)) . '</a>',
$fmts,
);
echo implode(", ", $fmtLinks);
?>
</p>
<?php endif; ?>
<?php if (!empty($data["keywords"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Mots-clés&nbsp;:</span>
<?php
$kws = array_map("trim", explode(",", $data["keywords"]));
$kwLinks = array_map(
fn($k) => '<a href="/search?keyword=' . urlencode($k) . '">' . htmlspecialchars(mb_strtolower($k)) . '</a>',
$kws,
);
echo implode(", ", $kwLinks);
?>
</p>
<?php endif; ?>
<?php if (!empty($promoteursInternes)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Promoteur·ice interne&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$promoteursInternes,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($promoteursExternes)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Promoteur·ice externe&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$promoteursExternes,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($promoteursUlb)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Promoteur·ice université&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$promoteursUlb,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($juryPresidents)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Président·e du jury&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$juryPresidents,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($juryLecteursInternes)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Lecteur·ice(s) interne&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$juryLecteursInternes,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($juryLecteursExternes)): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Lecteur·ice(s) externe&nbsp;:</span>
<?php
$links = array_map(
fn($n) => '<a href="/search?query=' . urlencode($n) . '">' . htmlspecialchars($n) . '</a>',
$juryLecteursExternes,
);
echo implode(", ", $links);
?>
</p>
<?php endif; ?>
<?php if (!empty($data["access_type"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Accès&nbsp;:</span>
<?= htmlspecialchars($data["access_type"]) ?>
</p>
<?php endif; ?>
<?php
$_cc2r = !empty($data["cc2r"]);
$_lic = !empty($data["license_type"]) ? $data["license_type"] : ($data["license_custom"] ?? null);
if ($_cc2r || $_lic): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Licence&nbsp;:</span>
<?= htmlspecialchars(implode(", ", array_filter([$_cc2r ? "CC2r" : null, $_lic]))) ?>
</p>
<?php endif; ?>
<?php if (!empty($data["contact_visible"])): ?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Contact&nbsp;:</span>
<?php
$_contact = $data["contact_visible"];
$_isUrl = filter_var($_contact, FILTER_VALIDATE_URL) !== false;
$_isEmail = !$_isUrl && str_contains($_contact, '@') && !str_starts_with($_contact, '@');
if ($_isUrl):
$_host = parse_url($_contact, PHP_URL_HOST);
$_path = parse_url($_contact, PHP_URL_PATH) ?? '';
$_isInstagram = $_host && str_contains($_host, 'instagram.com');
$_isMastodon = $_path && str_contains($_path, '/@');
if ($_isInstagram):
$_username = trim($_path, '/');
$_display = $_username ? '@' . $_username : preg_replace("#^https?://(www\.)?#i", "", rtrim($_contact, "/"));
elseif ($_isMastodon):
$_username = trim($_path, '/@');
$_display = $_username ? '@' . $_username : preg_replace("#^https?://(www\.)?#i", "", rtrim($_contact, "/"));
else:
$_display = preg_replace("#^https?://(www\.)?#i", "", rtrim($_contact, "/"));
endif; ?>
<a href="<?= htmlspecialchars($_contact) ?>" target="_blank" rel="noopener">
<?= htmlspecialchars($_display) ?>
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
</a>
<?php elseif ($_isEmail): ?>
<a href="<?= EmailObfuscator::mailto($_contact) ?>"><?= htmlspecialchars($_contact) ?></a>
<?php else:
// Bare domain (ex: erg.be) or unrecognised → try to link it
$_looksLikeDomain = !str_contains($_contact, ' ') && preg_match('#\.[a-z]{2,}$#i', $_contact);
if ($_looksLikeDomain): ?>
<a href="https://<?= htmlspecialchars($_contact) ?>" target="_blank" rel="noopener">
<?= htmlspecialchars($_contact) ?>
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
</a>
<?php else: ?>
<?= htmlspecialchars($_contact) ?>
<?php endif; ?>
<?php endif; ?>
</p>
<?php endif; ?>
<?php if (!empty($data["baiu_link"])): ?>
<?php
$_baiuHref = htmlspecialchars($data["baiu_link"]);
$_baiuLabel = parse_url($data["baiu_link"], PHP_URL_HOST) ?: preg_replace("#^https?://(www\\.)?#i", "", rtrim($data["baiu_link"], "/"));
?>
<p class="tfe-meta-item">
<span class="tfe-meta-label">Lien&nbsp;:</span>
<a href="<?= $_baiuHref ?>" target="_blank" rel="noopener">
<?= htmlspecialchars($_baiuLabel) ?>
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
</a>
</p>
<?php endif; ?>
</div>
<?php if (!empty($data["context_note"])): ?>
<p class="tfe-context-note"><em>Note Contextuelle :</em><br><?= nl2br(htmlspecialchars($data["context_note"])) ?></p>
<?php endif; ?>
<?php if (!empty($data["synopsis"])): ?>
<div class="tfe-synopsis-text">
<?= nl2br(htmlspecialchars($data["synopsis"])) ?>
</div>
<?php else: ?>
<div class="tfe-synopsis-text tfe-synopsis-empty"></div>
<?php endif; ?>
</div><!-- /tfe-left-column -->
<div class="tfe-right-column">
<div class="tfe-files">
<?php $_videoIndex = 0; ?>
<?php if ($isInterdit): ?>
<p class="tfe-restricted">
<?= htmlspecialchars(
$forbiddenMessage ??
"Ce TFE n'est pas disponible en ligne.",
) ?>
</p>
<?php elseif ($shouldHideFiles): ?>
<div class="tfe-restricted-access">
<p class="tfe-restricted-message">
<strong>Accès restreint</strong><br>
<?= htmlspecialchars(
$restrictedMessage ??
'Les fichiers attachés à ce TFE sont réservés aux utilisateur·ices autorisé·es.',
) ?>
</p>
<form id="access-request-form" class="tfe-access-request-form"
data-thesis-id="<?= $thesisId ?>">
<input type="hidden" name="csrf_token"
value="<?= htmlspecialchars(
$_SESSION["csrf_token"] ?? "",
) ?>">
<div class="form-group">
<label for="access-email">Votre adresse email :</label>
<input type="email"
id="access-email"
name="email"
required
placeholder="votre@email.com">
</div>
<div id="justification-container" class="form-group" style="display: none;">
<label for="access-justification">Pourquoi souhaitez-vous accéder à ce TFE ?</label>
<textarea id="access-justification"
name="justification"
rows="4"
placeholder="Décrivez brièvement votre motivation (recherche, collaboration, etc.)"></textarea>
</div>
<button type="submit" class="btn btn--primary tfe-btn-request-access">
Demander l'accès
</button>
<div id="access-request-message" class="tfe-access-message" style="display: none;"></div>
</form>
</div>
<?php elseif (!empty($data["files"])): ?>
<?php
// Preload PeerTube instance URL once
$_ptHasAnyPeerTube = false;
foreach ($data['files'] as $_f) {
if (str_starts_with($_f['file_path'] ?? '', 'peertube_ids:')) {
$_ptHasAnyPeerTube = true;
break;
}
}
$_ptInstanceUrl = '';
if ($_ptHasAnyPeerTube) {
require_once APP_ROOT . '/src/PeerTubeService.php';
$_ptSettings = PeerTubeService::getSettings(Database::getInstance());
$_ptInstanceUrl = $_ptSettings['instance_url'] ?? '';
}
?>
<?php foreach ($data["files"] as $file): ?>
<?php
$ext = strtolower(pathinfo($file["file_path"] ?? '', PATHINFO_EXTENSION));
$fileType = $file["file_type"] ?? '';
// Skip helper/internal types
if ($ext === 'vtt' || $fileType === 'caption') continue;
if ($fileType === 'cover') continue;
// Determine display category
$isImage = in_array($ext, ['jpg','jpeg','png','gif','bmp','webp'], true) || $fileType === 'image';
$isVideo = in_array($ext, ['mp4','webm','mov','ogv'], true) || $fileType === 'video';
$isAudio = in_array($ext, ['mp3','ogg','oga','wav','flac','aac','m4a'], true) || $fileType === 'audio';
$isPdf = ($ext === 'pdf') || $fileType === 'main';
$isWebsite = ($fileType === 'website');
$isOther = !($isImage || $isVideo || $isAudio || $isPdf || $isWebsite);
$_vttPath = null;
if ($isVideo) {
$_vttPath = $captionFiles[$_videoIndex] ?? null;
$_videoIndex++;
}
$caption = !empty($file["display_label"]) ? $file["display_label"] : ($file["description"] ?? '');
$filePath = $file['file_path'] ?? '';
$isExternalUrl = str_starts_with($filePath, 'http://') || str_starts_with($filePath, 'https://');
$isPeerTube = str_starts_with($filePath, 'peertube_ids:');
$mediaUrl = $isPeerTube ? '' : ($isExternalUrl ? htmlspecialchars($filePath) : ('/media?path=' . urlencode($filePath)));
$fileName = htmlspecialchars($file["file_name"] ?? basename($filePath));
?>
<div class="tfe-file-item">
<?php if ($isPdf): ?>
<?php
$_pdfLabel = match ($fileType) {
'main' => 'TFE',
'annex' => 'Annexes',
'note_intention' => "Note d'intention",
default => '',
};
?>
<div class="pdf-embed-wrapper"
data-pdf-url="<?= $mediaUrl ?>"
data-pdf-scale="0.85"
data-pdf-label="<?= htmlspecialchars($_pdfLabel) ?>"
tabindex="-1"></div>
<?php elseif ($isWebsite): ?>
<div class="tfe-website-wrapper">
<span class="tfe-website-badge">Site web</span>
<a href="<?= $mediaUrl ?>"
class="tfe-website-open-btn"
target="_blank"
rel="noopener noreferrer"
title="Ouvrir le site web dans un nouvel onglet"
aria-label="Ouvrir le site web">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z"></path></svg>
</a>
<iframe src="<?= $mediaUrl ?>"
class="tfe-file-iframe"
title="<?= $fileName ?>"
sandbox="allow-scripts allow-same-origin"
loading="lazy">
</iframe>
</div>
<?php elseif ($isImage): ?>
<img src="<?= $mediaUrl ?>"
alt="<?= htmlspecialchars($caption !== '' ? $caption : $data['title'] . ' — ' . ($data['authors'] ?? '')) ?>"
draggable="false"
oncontextmenu="return false">
<?php elseif ($isVideo): ?>
<?php if ($isPeerTube): ?>
<?php
$peertubeUuid = substr($filePath, strlen('peertube_ids:'));
$title = $fileName;
$instanceUrl = $_ptInstanceUrl;
include APP_ROOT . '/templates/partials/peertube-embed.php';
?>
<?php else: ?>
<video width="100%" controls
controlsList="nodownload nofullscreen noremoteplayback"
disablepictureinpicture
oncontextmenu="return false">
<source src="<?= $mediaUrl ?>" type="video/<?= htmlspecialchars($ext === 'mov' ? 'mp4' : $ext) ?>">
<?php if ($_vttPath): ?>
<track kind="captions"
src="/media?path=<?= urlencode($_vttPath) ?>"
srclang="fr" label="Sous-titres" default>
<?php endif; ?>
</video>
<?php endif; ?>
<?php elseif ($isAudio): ?>
<?php if ($isPeerTube): ?>
<?php
$peertubeUuid = substr($filePath, strlen('peertube_ids:'));
$title = $fileName;
$instanceUrl = $_ptInstanceUrl;
$width = 560;
$height = 150;
include APP_ROOT . '/templates/partials/peertube-embed.php';
?>
<?php else: ?>
<audio controls class="tfe-audio"
controlsList="nodownload noremoteplayback"
oncontextmenu="return false">
<source src="<?= $mediaUrl ?>" type="audio/<?= htmlspecialchars(match($ext) {
'mp3' => 'mpeg',
'ogg', 'oga' => 'ogg',
'wav' => 'wav',
'flac' => 'flac',
'aac' => 'aac',
'm4a' => 'mp4',
default => $ext,
}) ?>">
Votre navigateur ne supporte pas la lecture audio.
</audio>
<?php endif; ?>
<?php else: /* other — not previewable, skip */ ?>
<?php continue; ?>
<?php endif; ?>
<?php if ($caption !== '' && !$isOther): ?>
<figcaption><?= htmlspecialchars($caption) ?></figcaption>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="tfe-no-files">Aucun fichier disponible pour ce TFE.</p>
<?php endif; ?>
</div>
</div><!-- /tfe-right-column -->
</article>
</main>
<?php if (!$isInterdit && !$shouldHideFiles && !empty($data["files"])): ?>
<?php $_hasPdf = false; foreach ($data["files"] as $_f) { $_ext = strtolower(pathinfo($_f["file_path"] ?? '', PATHINFO_EXTENSION)); $_type = $_f['file_type'] ?? ''; if ($_ext === 'pdf' || $_type === 'main') { $_hasPdf = true; break; } } ?>
<?php if ($_hasPdf): ?>
<script type="module" src="/assets/js/vendor/pdf.min.mjs" async></script>
<?php endif; ?>
<?php endif; ?>