mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
SQLite performance (Database::__construct): - PRAGMA journal_mode = WAL: eliminates full-DB read locks on write, safe for concurrent PHP-FPM workers - PRAGMA synchronous = NORMAL: durable on commit without full fsync per write - PRAGMA cache_size = -8000: ~8 MB page cache per connection Accessibility foundation (WCAG 2.1 AA): - common.css: add .sr-only utility, .skip-link (hidden until focused), global :focus-visible (2px purple outline, 2px offset), prefers-reduced-motion guard; remove bare outline:none from .site-search__input - admin.css: same :focus-visible, skip-link, and motion guard scoped to admin purple; remove outline:none from .admin-input/.admin-select/ .admin-textarea and .admin-filters select (both had :focus border rules already, so focus is still visually communicated) - search.css: remove outline:none from .search-filter-select (already has :focus border-color rule) - All 5 public pages (index, search, tfe, apropos, licence): add <a href="#main-content" class="skip-link"> as first child of <body>; add id="main-content" to <main> - templates/admin/head.php: same skip link; aria-label="Navigation admin" on <nav>; id="main-content" on all 10 admin <main> elements All 4 test suites pass (unit, integration, security, rate-limit).
227 lines
10 KiB
PHP
227 lines
10 KiB
PHP
<?php
|
||
require_once __DIR__ . '/../config/bootstrap.php';
|
||
require_once APP_ROOT . '/src/Database.php';
|
||
|
||
if (isset($_GET['id'])) {
|
||
$thesisId = intval($_GET['id']);
|
||
try {
|
||
$db = Database::getInstance();
|
||
$data = $db->getThesisById($thesisId);
|
||
if (!$data) { header('Location: index.php'); exit; }
|
||
} catch (Exception $e) {
|
||
error_log("Error loading thesis: " . $e->getMessage());
|
||
header('Location: index.php'); exit;
|
||
}
|
||
} else {
|
||
header('Location: index.php'); exit;
|
||
}
|
||
|
||
$currentNav = '';
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title><?= htmlspecialchars($data['title']) ?> – Posterg</title>
|
||
<link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg">
|
||
<link rel="stylesheet" href="assets/modern-normalize.min.css">
|
||
<link rel="stylesheet" href="assets/common.css">
|
||
<link rel="stylesheet" href="assets/tfe.css">
|
||
<?php if (php_sapi_name() === 'cli-server'): ?>
|
||
<script>
|
||
(function poll(){
|
||
fetch('/live-reload.php').then(r=>r.json()).then(d=>{
|
||
if(d.changed) location.reload(); else setTimeout(poll,1000);
|
||
}).catch(()=>setTimeout(poll,2000));
|
||
})();
|
||
</script>
|
||
<?php endif; ?>
|
||
</head>
|
||
<body class="tfe-body">
|
||
<a href="#main-content" class="skip-link">Aller au contenu principal</a>
|
||
|
||
<?php include APP_ROOT . '/templates/nav.php'; ?>
|
||
<?php include APP_ROOT . '/templates/search-bar.php'; ?>
|
||
|
||
<main class="tfe-main" id="main-content">
|
||
<div class="tfe-layout">
|
||
|
||
<!-- LEFT: info -->
|
||
<div class="tfe-left">
|
||
<h1 class="tfe-author"><?= htmlspecialchars($data['authors'] ?? 'Auteur inconnu') ?></h1>
|
||
|
||
<h2 class="tfe-title">
|
||
<?= htmlspecialchars($data['title']) ?>
|
||
<?php if (!empty($data['subtitle'])): ?>
|
||
– <?= htmlspecialchars($data['subtitle']) ?>
|
||
<?php endif; ?>
|
||
</h2>
|
||
|
||
<div class="tfe-meta-list">
|
||
<?php if (!empty($data['orientation'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Orientation :</span>
|
||
<span class="value"><?= htmlspecialchars($data['orientation']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['ap_program'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Atelier pluridisciplinaire :</span>
|
||
<span class="value"><?= htmlspecialchars($data['ap_program']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['year'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Date :</span>
|
||
<span class="value"><?= htmlspecialchars($data['year']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['languages'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Langue :</span>
|
||
<span class="value"><?= htmlspecialchars($data['languages']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['formats'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Format :</span>
|
||
<span class="value"><?= htmlspecialchars($data['formats']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['file_size_info'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Durée :</span>
|
||
<span class="value"><?= htmlspecialchars($data['file_size_info']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['keywords'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Mots-clés :</span>
|
||
<span class="value"><?= htmlspecialchars($data['keywords']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['jury_president'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Président·e du jury :</span>
|
||
<span class="value"><?= htmlspecialchars($data['jury_president']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['jury_promoteurs'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Promoteur·ice :</span>
|
||
<span class="value"><?= htmlspecialchars($data['jury_promoteurs']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['jury_lecteurs'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Lecteur·ices :</span>
|
||
<span class="value"><?= htmlspecialchars($data['jury_lecteurs']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['access_type'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Accès :</span>
|
||
<span class="value"><?= htmlspecialchars($data['access_type']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['license_type'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Licence :</span>
|
||
<span class="value"><?= htmlspecialchars($data['license_type']) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['context_note'])): ?>
|
||
<div class="tfe-meta-item" style="align-items:start;">
|
||
<span class="label">Note :</span>
|
||
<span class="value" style="font-style:italic;"><?= nl2br(htmlspecialchars($data['context_note'])) ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($data['baiu_link'])): ?>
|
||
<div class="tfe-meta-item">
|
||
<span class="label">Contact :</span>
|
||
<span class="value">
|
||
<a href="<?= htmlspecialchars($data['baiu_link']) ?>" target="_blank" rel="noopener">
|
||
<?= htmlspecialchars($data['baiu_link']) ?>
|
||
</a>
|
||
</span>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<?php if (!empty($data['synopsis'])): ?>
|
||
<div class="tfe-synopsis-text">
|
||
<?= nl2br(htmlspecialchars($data['synopsis'])) ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div style="margin-top:1.5rem;">
|
||
<a href="index.php" style="font-size:.88rem;color:#666;text-decoration:underline;text-underline-offset:2px;">
|
||
← Retour
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RIGHT: media -->
|
||
<div class="tfe-right">
|
||
<?php
|
||
// Determine effective access: need raw access_type_id
|
||
// The view exposes 'access_type' (name string). Fetch raw id for gate.
|
||
$accessTypeId = null;
|
||
try {
|
||
$accessStmt = $db->getConnection()->prepare(
|
||
"SELECT access_type_id FROM theses WHERE id = ?"
|
||
);
|
||
$accessStmt->execute([$thesisId]);
|
||
$accessTypeId = (int)($accessStmt->fetchColumn() ?? 1);
|
||
} catch (\Throwable $e) {}
|
||
$isInterdit = ($accessTypeId === 3);
|
||
?>
|
||
<?php if ($isInterdit): ?>
|
||
<p class="tfe-no-files" style="color:#999;font-style:italic;">
|
||
Ce TFE n'est pas disponible en ligne.
|
||
</p>
|
||
<?php elseif (!empty($data['files'])): ?>
|
||
<?php foreach ($data['files'] as $file): ?>
|
||
<?php $ext = strtolower(pathinfo($file['file_path'], PATHINFO_EXTENSION)); ?>
|
||
<div class="tfe-media-block">
|
||
<?php if ($ext === 'pdf'): ?>
|
||
<embed src="/media.php?path=<?= urlencode($file['file_path']) ?>"
|
||
type="application/pdf" width="100%" height="700px">
|
||
<?php elseif (in_array($ext, ['jpg','jpeg','png','gif','bmp','webp'])): ?>
|
||
<img src="/media.php?path=<?= urlencode($file['file_path']) ?>"
|
||
alt="<?= htmlspecialchars($file['file_name']) ?>">
|
||
<?php elseif ($ext === 'mp4'): ?>
|
||
<video width="100%" controls>
|
||
<source src="/media.php?path=<?= urlencode($file['file_path']) ?>" type="video/mp4">
|
||
</video>
|
||
<?php endif; ?>
|
||
<?php if (!empty($file['description'])): ?>
|
||
<p class="tfe-file-caption"><?= htmlspecialchars($file['description']) ?></p>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<p class="tfe-no-files">Aucun fichier disponible pour ce TFE.</p>
|
||
<?php endif; // end !$isInterdit ?>
|
||
</div>
|
||
|
||
</div>
|
||
</main>
|
||
|
||
</body>
|
||
</html>
|