diff --git a/TODO.md b/TODO.md index fc35e1e..f327347 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,29 @@ ## Completed +- [x] PDF 100 MB limit + bentopdf mention + - [x] `ThesisCreateController`: `MAX_PDF_SIZE = 100 MB`; PDFs checked against it, other files still 500 MB + - [x] `ThesisEditController`: same per-PDF limit applied + - [x] `fichiers-fragment.php`: note d'intention and TFE hints mention 100 MB PDF limit + bentopdf.com link + - [x] `form.php` edit-mode new-files hint updated + - [x] `file-field.php`: added `$hintRaw` flag to allow HTML in hints + +- [x] Format types: reorder, rename, add Image/Écriture + - [x] Migration 019: add Écriture + - [x] Migration 020: add `sort_order` column, rename Autre → Etc. / Autre, add Image, set display order (Écriture · Image · Audio · Vidéo · Site web · Performance · Objet éditorial · Installation · Etc. / Autre) + - [x] `Database.php` format_types query uses `ORDER BY sort_order, id` + - [x] `fichiers-fragment.php` uses `ORDER BY sort_order, id`; Image/Vidéo/Audio IDs resolved via name map + - [ ] TODO: Vidéo + Audio — PeerTube API upload (notice shown in form for now) + +- [x] Combined Format + Fichiers into HTMX-swappable block + - [x] `partage/fichiers-fragment.php` — new combined fragment: format checkboxes + fichiers fieldset that adapts based on selected formats (upload inputs / URL fields / both) + - [x] Route `/partage/fichiers-fragment` added to `partage/index.php` + - [x] `admin/fichiers-fragment.php` — admin-gated wrapper for the same fragment (sets `admin_mode=1`) + - [x] `admin/format-website-fragment.php` — admin-gated fragment for edit-mode website URL fieldset toggle + - [x] `form.php` — add/partage mode: replaced separate Format + Fichiers + website-url-fieldset with single `#format-fichiers-block` server-rendered via shared fragment + - [x] `form.php` — edit mode: Format checkboxes wire to `admin/format-website-fragment.php` → `#edit-website-url-fieldset` (existing-file management untouched) + - [x] `checkbox-list.php` — added `$hxInclude` variable (defaults to `'this, #website-url-fieldset'`) so callers can customise included fields + - [x] TDD analysis + new test suites - [x] **Bug fixed**: `SearchController::handleSearch()` — `$coverMap` undefined variable + never populated for search results - [x] `ShareLinkTest` (13 tests) — `generateSlug`, all `validateLink` branches, `verifyPassword`, `incrementUsage`, `objet_restriction` diff --git a/app/migrations/applied/019_add_ecriture_format.sql b/app/migrations/applied/019_add_ecriture_format.sql new file mode 100644 index 0000000..55d565e --- /dev/null +++ b/app/migrations/applied/019_add_ecriture_format.sql @@ -0,0 +1,2 @@ +-- Migration 019: Add "Écriture" format type +INSERT INTO format_types (name) VALUES ('Écriture'); diff --git a/app/migrations/applied/020_format_types_sort_and_rename.sql b/app/migrations/applied/020_format_types_sort_and_rename.sql new file mode 100644 index 0000000..fd84387 --- /dev/null +++ b/app/migrations/applied/020_format_types_sort_and_rename.sql @@ -0,0 +1,13 @@ +-- Migration 020: Add sort_order to format_types, rename/reorder entries, add Image +ALTER TABLE format_types ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 99; + +UPDATE format_types SET sort_order = 1 WHERE name = 'Écriture'; +UPDATE format_types SET sort_order = 3 WHERE name = 'Audio'; +UPDATE format_types SET sort_order = 4 WHERE name = 'Vidéo'; +UPDATE format_types SET sort_order = 5 WHERE name = 'Site web'; +UPDATE format_types SET sort_order = 6 WHERE name = 'Performance'; +UPDATE format_types SET sort_order = 7 WHERE name = 'Objet éditorial'; +UPDATE format_types SET sort_order = 8 WHERE name = 'Installation'; +UPDATE format_types SET sort_order = 9 WHERE name = 'Autre'; + +INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Image', 2); diff --git a/app/public/admin/fichiers-fragment.php b/app/public/admin/fichiers-fragment.php new file mode 100644 index 0000000..9cb52d1 --- /dev/null +++ b/app/public/admin/fichiers-fragment.php @@ -0,0 +1,17 @@ +getConnection(); + +$stmt = $db->prepare('SELECT id FROM format_types WHERE name = ? LIMIT 1'); +$stmt->execute(['Site web']); +$websiteFormatId = $stmt->fetchColumn(); + +if (!$websiteFormatId) { + echo '
'; + exit; +} + +$selectedFormats = isset($_POST['formats']) && is_array($_POST['formats']) + ? array_map('intval', $_POST['formats']) + : []; + +if (!in_array((int)$websiteFormatId, $selectedFormats, true)) { + echo ''; + exit; +} + +$websiteUrl = htmlspecialchars($_POST['website_url'] ?? ''); +$websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); +?> + diff --git a/app/public/partage/fichiers-fragment.php b/app/public/partage/fichiers-fragment.php new file mode 100644 index 0000000..bc8f198 --- /dev/null +++ b/app/public/partage/fichiers-fragment.php @@ -0,0 +1,205 @@ +getConnection(); + +// Load all format types in display order +$allFormats = $db->query('SELECT id, name FROM format_types ORDER BY sort_order, id') + ->fetchAll(PDO::FETCH_ASSOC); + +// Build name→id map for format logic +$formatIdByName = []; +foreach ($allFormats as $f) { + $formatIdByName[$f['name']] = (int)$f['id']; +} + +$siteWebId = $formatIdByName['Site web'] ?? null; +$videoId = $formatIdByName['Vidéo'] ?? null; +$audioId = $formatIdByName['Audio'] ?? null; +$imageId = $formatIdByName['Image'] ?? null; + +$selectedFormats = isset($_POST['formats']) && is_array($_POST['formats']) + ? array_map('intval', $_POST['formats']) + : []; + +$adminMode = ($_POST['admin_mode'] ?? '0') === '1'; + +$hasSiteWeb = $siteWebId && in_array($siteWebId, $selectedFormats, true); +$hasVideo = $videoId && in_array($videoId, $selectedFormats, true); +$hasAudio = $audioId && in_array($audioId, $selectedFormats, true); +$hasImage = $imageId && in_array($imageId, $selectedFormats, true); + +// Show standard file inputs unless *only* Site web is selected +$hasNonWebFormat = !empty(array_filter( + $selectedFormats, + fn($id) => $id !== $siteWebId +)); +$showUploadBlock = $hasNonWebFormat || !$hasSiteWeb; + +$websiteUrl = htmlspecialchars($_POST['website_url'] ?? ''); +$websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); + +$hxPost = $adminMode ? '/admin/fichiers-fragment.php' : '/partage/fichiers-fragment'; +?> +Aucun fichier sélectionné.
++ 🚧 À venir : l'upload vidéo sera géré directement via l'API PeerTube. + La vidéo sera hébergée sur l'instance PeerTube de l'école et intégrée + comme lecteur embarqué sur la page du TFE. +
++ En attendant, déposez votre vidéo dans le champ TFE ci-dessus (ZIP si besoin). +
++ 🚧 À venir : l'upload audio sera géré via l'API PeerTube. + Le fichier audio sera hébergé sur l'instance PeerTube de l'école et + intégré comme lecteur embarqué sur la page du TFE. +
++ En attendant, déposez votre fichier audio dans le champ TFE ci-dessus (ZIP si besoin). +
+Aucun nouveau fichier sélectionné.
- -