From 24d68dda598e8b659501ffef0cabca514766e37c Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Thu, 7 May 2026 17:52:46 +0200 Subject: [PATCH] =?UTF-8?q?refactor=20form=20structure=20per=20new=20spec?= =?UTF-8?q?=20+=20fix=20-=20split=20jury=20into=20interne/externe/ULB,=20-?= =?UTF-8?q?=20remove=20president=20from=20student=20form,=20-=20add=20lang?= =?UTF-8?q?uage=5Fautre,=20-=20split=20duration=20into=20pages+minutes+ann?= =?UTF-8?q?exes,=20-=20move=20licence=20to=20degr=C3=A9s=20d'ouverture=20w?= =?UTF-8?q?ith=20CC2r,=20-=20add=20license=5Fcustom,=20-=20filter=20PACS?= =?UTF-8?q?=20from=20student=20AP=20list,=20-=20editable=20g=C3=A9n=C3=A9r?= =?UTF-8?q?alit=C3=A9s=20help=20block,=20-=20Libre=20toggle=20per=20settin?= =?UTF-8?q?gs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: - missing comma after cc4r column in schema.sql - remove duplicate form footer from partage template - remove couverture from student files fieldset; add promoteur ULB conditional disable via JS on Approfondi - promoteur ULB: remove 'si applicable', make required when visible --- TODO.md | 18 ++ app/public/admin/add.php | 6 + app/public/admin/edit.php | 4 + app/public/partage/index.php | 88 ++++-- .../Controllers/ThesisCreateController.php | 69 +++-- app/src/Controllers/ThesisEditController.php | 91 ++++-- app/src/Database.php | 9 +- app/storage/logs/admin.log | 1 + app/storage/schema.sql | 4 +- app/templates/admin/add.php | 50 +++- app/templates/admin/edit.php | 192 ++++++++----- app/templates/partials/form/checkbox-list.php | 2 +- .../partials/form/fieldset-academic.php | 15 +- .../partials/form/fieldset-files.php | 43 +-- .../form/fieldset-licence-explanation.php | 126 ++++++--- .../partials/form/fieldset-metadata.php | 58 ++-- .../partials/form/fieldset-tfe-info.php | 25 +- app/templates/partials/form/file-field.php | 7 +- app/templates/partials/form/jury-fieldset.php | 263 +++++++++++------- app/templates/partials/form/select-field.php | 2 +- app/templates/partials/form/text-field.php | 2 +- 21 files changed, 694 insertions(+), 381 deletions(-) diff --git a/TODO.md b/TODO.md index d54bd5c..dab47a2 100644 --- a/TODO.md +++ b/TODO.md @@ -125,3 +125,21 @@ - [x] StudentEmail: use new jury_lecteurs_internes/externes and jury_promoteurs_ulb columns - [x] Recapitulatif: show promoteur·ice ULB and lecteur·ices interne/externe - [x] Migration: `014_tfe_form_fields.sql` — ALTER + view rebuild + +## Refactor form structure per spec (student vs admin) +- [x] Remove `jury_president` field from student-facing forms (edit keeps it as optional) +- [x] Jury: split into promoteur·ice interne, promoteur·ice ULB, lecteur·ice interne, lecteur·ice externe — each with +add button +- [x] AP filtering: student form hides PACS; admin form shows all APs +- [x] Language: add "autre" text field alongside predefined checkboxes +- [x] Duration: split into pages field + minutes field + annexes checkbox +- [x] Licence: removed from métadonnées fieldset, now only in degrés d'ouverture section +- [x] Degrés d'ouverture: généralités FIRST, then radio choice (Libre/Interne/Interdit), then licence dropdown + custom text + CC2r +- [x] CC4r → CC2r rename in form UI + `cc2r` POST name +- [x] Licence: custom licence text field added (`license_custom` DB column) +- [x] Généralités text editable via form help block (`fieldset_generalites`) +- [x] Libre option: hidden in student form when disabled in settings; always shown in admin +- [x] Contact: `contact_visible` field always present in TFE info; admin gets `contact_public` checkbox separately +- [x] Email confirmation: mandatory in student form, optional in admin +- [x] Fichiers: cover image hint updated to 4:3 ratio +- [x] All three form pages (admin add, admin edit, partage) updated +- [x] Controllers updated: `collectJuryMembers`, `validateAndSanitise`, `buildFileSizeInfo`, `license_custom`, `cc2r`→`cc4r` mapping diff --git a/app/public/admin/add.php b/app/public/admin/add.php index b87325b..3981c81 100644 --- a/app/public/admin/add.php +++ b/app/public/admin/add.php @@ -23,6 +23,12 @@ $formData = $_SESSION['form_data'] ?? []; unset($_SESSION['form_data']); $autofocusField = App::consumeAutofocus(); +// Site settings for licence / access type toggles +$siteSettings = Database::getInstance()->getAllSettings(); +// Form help blocks +$helpBlocks = Database::getInstance()->getAllFormHelpBlocks(); +$helpFn = fn(string $key) => $helpBlocks[$key]['content'] ?? ''; + function withAutofocus(string $fieldName, array $attrs = []): array { global $autofocusField; if ($autofocusField === $fieldName) { diff --git a/app/public/admin/edit.php b/app/public/admin/edit.php index d5bf83c..50ff58e 100644 --- a/app/public/admin/edit.php +++ b/app/public/admin/edit.php @@ -17,6 +17,10 @@ if ($thesisId <= 0) { $autofocusField = App::consumeAutofocus(); +// Form help blocks for editable généralités +$helpBlocks = Database::getInstance()->getAllFormHelpBlocks(); +$helpFn = fn(string $key) => $helpBlocks[$key]['content'] ?? ''; + try { $ctrl = ThesisEditController::create(); $view = $ctrl->load($thesisId); diff --git a/app/public/partage/index.php b/app/public/partage/index.php index 84fbe0f..2afc84d 100644 --- a/app/public/partage/index.php +++ b/app/public/partage/index.php @@ -284,7 +284,6 @@ function renderShareLinkForm(string $slug, array $link): void - - $name, - 'is_external' => !empty($formData["jury_lecteurs_ext:$i"]) ? 1 : 0, - ]; - } - } - $helpContent = $helpFn('fieldset_jury'); - include APP_ROOT . '/templates/partials/form/form-help-block.php'; - require APP_ROOT . '/templates/partials/form/jury-fieldset.php'; - ?> + +
+ Langue(s) + + +
+ + +
+ Format(s) + +
+ + +
+ Mots-clés + +
+ + $n]; + } + for ($i = 0; $i < 10; $i++) { + $n = old($formData, "jury_lecteur_externe:$i"); + if ($n !== '') $lecteursExternes[] = ['name' => $n]; + } + $juryPresident = null; + $showPresident = false; + $showPromoteurUlb = true; + $promoteurUlbConditional = true; + $helpContent = $helpFn('fieldset_jury'); + include APP_ROOT . '/templates/partials/form/form-help-block.php'; + require APP_ROOT . '/templates/partials/form/jury-fieldset.php'; + ?> + - +
@@ -351,7 +381,7 @@ function renderShareLinkForm(string $slug, array $link): void $data['synopsis'], 'file_size_info' => $data['durationInfo'], 'baiu_link' => $data['lien'], - 'license_id' => $data['licenseId'], - 'access_type_id' => $data['accessTypeId'], + 'license_id' => $data['licenseId'], + 'license_custom' => $data['licenseCustom'], + 'access_type_id' => $data['accessTypeId'], 'objet' => $data['objet'], ]); @@ -310,31 +311,65 @@ class ThesisCreateController $subtitle = $this->sanitiseString($post['subtitle'] ?? ''); $synopsis = $this->validateRequired($this->sanitiseString($post['synopsis'] ?? ''), 'Synopsis'); - $durationInfo = $this->sanitiseString($post['duration_info'] ?? ''); - - // Jury members - $juryMembers = []; - if (!empty(trim($post['jury_president'] ?? ''))) { - $juryMembers[] = ['name' => trim($post['jury_president']), 'role' => 'president', 'is_external' => 0]; + $durationInfo = $this->sanitiseString($post['duration_pages'] ?? ''); + $durationMinutes = $this->sanitiseString($post['duration_minutes'] ?? ''); + if ($durationInfo !== '' && $durationMinutes !== '') { + $durationInfo = $durationInfo . ' pages + ' . $durationMinutes . ' minutes'; + } elseif ($durationMinutes !== '') { + $durationInfo = $durationMinutes . ' minutes'; + } elseif ($durationInfo !== '') { + $durationInfo = $durationInfo . ' pages'; } + if (!empty($post['has_annexes'])) { + $durationInfo = $durationInfo ? $durationInfo . ' + annexe(s)' : 'Annexe(s)'; + } + + // Jury members — new structure: separate interne/externe lecteurs + $juryMembers = []; if (!empty(trim($post['jury_promoteur'] ?? ''))) { $juryMembers[] = [ 'name' => trim($post['jury_promoteur']), 'role' => 'promoteur', - 'is_external' => isset($post['jury_promoteur_ext']) ? 1 : 0, - 'is_ulb' => isset($post['jury_promoteur_ulb']) ? 1 : 0, + 'is_external' => 0, + 'is_ulb' => 0, ]; } - foreach ($post['jury_lecteurs'] ?? [] as $i => $name) { + if (!empty(trim($post['jury_promoteur_ulb_name'] ?? ''))) { + $juryMembers[] = [ + 'name' => trim($post['jury_promoteur_ulb_name']), + 'role' => 'promoteur', + 'is_external' => 1, + 'is_ulb' => 1, + ]; + } + foreach ($post['jury_lecteur_interne'] ?? [] as $name) { $name = trim($name); if ($name !== '') { - $juryMembers[] = [ - 'name' => $name, - 'role' => 'lecteur', - 'is_external' => isset($post['jury_lecteurs_ext'][$i]) ? 1 : 0, - ]; + $juryMembers[] = ['name' => $name, 'role' => 'lecteur', 'is_external' => 0]; } } + foreach ($post['jury_lecteur_externe'] ?? [] as $name) { + $name = trim($name); + if ($name !== '') { + $juryMembers[] = ['name' => $name, 'role' => 'lecteur', 'is_external' => 1]; + } + } + // Keep backwards compat with old jury_lecteurs (from old-style forms) + if (empty($juryMembers) || isset($post['jury_lecteurs'])) { + foreach ($post['jury_lecteurs'] ?? [] as $i => $name) { + $name = trim($name); + if ($name !== '') { + $juryMembers[] = [ + 'name' => $name, + 'role' => 'lecteur', + 'is_external' => isset($post['jury_lecteurs_ext'][$i]) ? 1 : 0, + ]; + } + } + } + if (!empty(trim($post['jury_president'] ?? ''))) { + $juryMembers[] = ['name' => trim($post['jury_president']), 'role' => 'president', 'is_external' => 0]; + } // Keywords (max 10) $tagRaw = $this->sanitiseString($post['tag'] ?? ''); @@ -357,6 +392,7 @@ class ThesisCreateController : []; $licenseId = filter_var($post['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null; + $licenseCustom = trim($post['license_custom'] ?? ''); // Access type — must be one of the enabled types; default 2 (Interne) $accessTypeId = filter_var($post['access_type_id'] ?? '', FILTER_VALIDATE_INT); @@ -404,6 +440,7 @@ class ThesisCreateController 'languageIds', 'formatIds', 'licenseId', + 'licenseCustom', 'lien', 'accessTypeId', 'objet' diff --git a/app/src/Controllers/ThesisEditController.php b/app/src/Controllers/ThesisEditController.php index 3c2f36f..9b244bc 100644 --- a/app/src/Controllers/ThesisEditController.php +++ b/app/src/Controllers/ThesisEditController.php @@ -175,7 +175,7 @@ class ThesisEditController 'finality_id' => intval($post['finality'] ?? 0), 'synopsis' => trim($post['synopsis'] ?? ''), 'context_note' => trim($post['context_note'] ?? ''), - 'file_size_info' => trim($post['duration_info'] ?? ''), + 'file_size_info' => $this->buildFileSizeInfo($post), 'baiu_link' => trim($post['lien'] ?? ''), 'license_id' => filter_var($post['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null, 'access_type_id' => filter_var($post['access_type_id'] ?? '', FILTER_VALIDATE_INT) ?: null, @@ -184,7 +184,8 @@ class ThesisEditController 'jury_points' => $post['jury_points'] ?? null, 'exemplaire_baiu' => !empty($post['exemplaire_baiu']), 'exemplaire_erg' => !empty($post['exemplaire_erg']), - 'cc4r' => !empty($post['cc4r']), + 'cc4r' => !empty($post['cc2r']), + 'license_custom' => trim($post['license_custom'] ?? ''), ]); // ── 2. Authors (alphabetically sorted) ───────────────────────────── @@ -545,6 +546,43 @@ class ThesisEditController { $members = []; + // Promoteur interne + if (!empty(trim($post['jury_promoteur'] ?? ''))) { + $members[] = [ + 'name' => trim($post['jury_promoteur']), + 'role' => 'promoteur', + 'is_external' => 0, + 'is_ulb' => 0, + ]; + } + + // Promoteur ULB + if (!empty(trim($post['jury_promoteur_ulb_name'] ?? ''))) { + $members[] = [ + 'name' => trim($post['jury_promoteur_ulb_name']), + 'role' => 'promoteur', + 'is_external' => 1, + 'is_ulb' => 1, + ]; + } + + // Lecteurs internes + foreach ($post['jury_lecteur_interne'] ?? [] as $name) { + $name = trim($name); + if ($name !== '') { + $members[] = ['name' => $name, 'role' => 'lecteur', 'is_external' => 0]; + } + } + + // Lecteurs externes + foreach ($post['jury_lecteur_externe'] ?? [] as $name) { + $name = trim($name); + if ($name !== '') { + $members[] = ['name' => $name, 'role' => 'lecteur', 'is_external' => 1]; + } + } + + // President (optional, admin-only) if (!empty(trim($post['jury_president'] ?? ''))) { $members[] = [ 'name' => trim($post['jury_president']), @@ -553,26 +591,41 @@ class ThesisEditController ]; } - if (!empty(trim($post['jury_promoteur'] ?? ''))) { - $members[] = [ - 'name' => trim($post['jury_promoteur']), - 'role' => 'promoteur', - 'is_external' => isset($post['jury_promoteur_ext']) ? 1 : 0, - 'is_ulb' => isset($post['jury_promoteur_ulb']) ? 1 : 0, - ]; - } - - foreach ($post['jury_lecteurs'] ?? [] as $i => $name) { - $name = trim($name); - if ($name !== '') { - $members[] = [ - 'name' => $name, - 'role' => 'lecteur', - 'is_external' => isset($post['jury_lecteurs_ext'][$i]) ? 1 : 0, - ]; + // Backwards compat: old jury_lecteurs[] + if (isset($post['jury_lecteurs'])) { + foreach ($post['jury_lecteurs'] ?? [] as $i => $name) { + $name = trim($name); + if ($name !== '') { + $members[] = [ + 'name' => $name, + 'role' => 'lecteur', + 'is_external' => isset($post['jury_lecteurs_ext'][$i]) ? 1 : 0, + ]; + } } } return $members; } + + /** + * Build file_size_info from separate duration fields. + */ + private function buildFileSizeInfo(array $post): string + { + $pages = trim($post['duration_pages'] ?? ''); + $minutes = trim($post['duration_minutes'] ?? ''); + $info = ''; + if ($pages !== '' && $minutes !== '') { + $info = $pages . ' pages + ' . $minutes . ' minutes'; + } elseif ($minutes !== '') { + $info = $minutes . ' minutes'; + } elseif ($pages !== '') { + $info = $pages . ' pages'; + } + if (!empty($post['has_annexes'])) { + $info = $info ? $info . ' + annexe(s)' : 'Annexe(s)'; + } + return $info; + } } diff --git a/app/src/Database.php b/app/src/Database.php index 7c5f1bc..666644f 100644 --- a/app/src/Database.php +++ b/app/src/Database.php @@ -1651,7 +1651,7 @@ class Database public function getThesisRawFields(int $thesisId): ?array { $stmt = $this->pdo->prepare( - 'SELECT license_id, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r FROM theses WHERE id = ? LIMIT 1' + 'SELECT license_id, license_custom, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r FROM theses WHERE id = ? LIMIT 1' ); $stmt->execute([$thesisId]); $row = $stmt->fetch(); @@ -1783,6 +1783,7 @@ class Database file_size_info = ?, baiu_link = ?, license_id = ?, + license_custom = ?, access_type_id = ?, is_published = ?, remarks = ?, @@ -1805,6 +1806,7 @@ class Database !empty($data['file_size_info']) ? $data['file_size_info'] : null, !empty($data['baiu_link']) ? $data['baiu_link'] : null, $data['license_id'] ?? null, + !empty($data['license_custom']) ? $data['license_custom'] : null, $data['access_type_id'] ?? null, $data['is_published'] ? 1 : 0, !empty($data['remarks']) ? $data['remarks'] : null, @@ -1847,12 +1849,12 @@ class Database identifier, title, subtitle, year, orientation_id, ap_program_id, finality_id, synopsis, file_size_info, - baiu_link, license_id, + baiu_link, license_id, license_custom, access_type_id, objet, is_published, submitted_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, CURRENT_TIMESTAMP) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, CURRENT_TIMESTAMP) '); $validObjet = ['tfe', 'thèse', 'frart']; @@ -1870,6 +1872,7 @@ class Database !empty($data['file_size_info']) ? $data['file_size_info'] : null, !empty($data['baiu_link']) ? $data['baiu_link'] : null, $data['license_id'] ?? null, + !empty($data['license_custom']) ? $data['license_custom'] : null, isset($data['access_type_id']) ? (int)$data['access_type_id'] : 2, // default: Interne $objet, ]); diff --git a/app/storage/logs/admin.log b/app/storage/logs/admin.log index b68a942..7bbdadb 100644 --- a/app/storage/logs/admin.log +++ b/app/storage/logs/admin.log @@ -10,3 +10,4 @@ {"timestamp":"2026-05-05T16:40:13+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"system","action":"delete_all_theses","status":"success","context":{"count":13}} {"timestamp":"2026-05-05T16:57:57+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"thesis","action":"publish","status":"success","context":{"count":15,"ids":[53,52,51,50,49,48,47,46,45,44,43,42,41,40,39]}} {"timestamp":"2026-05-05T16:58:02+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"thesis","action":"publish","status":"success","context":{"count":25,"ids":[178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154]}} +{"timestamp":"2026-05-07T16:15:27+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"system","action":"files_export","status":"success","context":{"file_count":0,"byte_size":248}} diff --git a/app/storage/schema.sql b/app/storage/schema.sql index d583f72..5c60784 100644 --- a/app/storage/schema.sql +++ b/app/storage/schema.sql @@ -183,6 +183,7 @@ CREATE TABLE IF NOT EXISTS theses ( -- Access and licensing access_type_id INTEGER, license_id INTEGER, + license_custom TEXT, -- free-text licence (if not in predefined list) -- Jury information jury_points DECIMAL(4,2), -- Points out of 20 (backoffice only) @@ -205,7 +206,7 @@ CREATE TABLE IF NOT EXISTS theses ( exemplaire_erg BOOLEAN DEFAULT 0, -- Physical copy at ERG -- CC4r acceptance (collected in student form) - cc4r BOOLEAN DEFAULT 0 + cc4r BOOLEAN DEFAULT 0, -- Timestamps created_at DATETIME DEFAULT CURRENT_TIMESTAMP, @@ -527,6 +528,7 @@ SELECT at.name as access_type, lt.name as license_type, t.license_id, + t.license_custom, t.access_type_id, t.jury_points, t.submitted_at, diff --git a/app/templates/admin/add.php b/app/templates/admin/add.php index c3717c5..3b526bb 100644 --- a/app/templates/admin/add.php +++ b/app/templates/admin/add.php @@ -16,8 +16,30 @@ include APP_ROOT . '/templates/partials/form/fieldset-tfe-info.php'; ?> - - + +
+ Langue(s) + + +
+ + +
+ Format(s) + +
+ + +
+ Mots-clés + +
+ + + @@ -33,12 +68,19 @@ - +
diff --git a/app/templates/admin/edit.php b/app/templates/admin/edit.php index 6d61503..7d619fb 100644 --- a/app/templates/admin/edit.php +++ b/app/templates/admin/edit.php @@ -12,9 +12,7 @@ $currentAuthorShowContact ?? false]); - // Build old()-compatible callable from the already-loaded $thesis data. $editOldFn = function (string $key, string $default = '') use ($thesis, $formData, $currentAuthorEmail) { if (!empty($formData[$key])) return htmlspecialchars($formData[$key]); $map = [ @@ -35,30 +33,56 @@ $oldFn = $editOldFn; $withAutofocusFn = $editWithAutofocusFn; include APP_ROOT . '/templates/partials/form/fieldset-tfe-info.php'; - // Restore $formData to original for downstream partials. $formData = $_SESSION['form_data'] ?? []; ?> - - + +
+ Contact +
+ + L'adresse est toujours conservée en interne comme contact de référence. +
+
+ + +
+ Langue(s) + + +
+ + +
+ Format(s) + +
+ + +
+ Mots-clés + $thesis['keywords'] ?? '']; + $editKwOldFn = fn(string $key, string $default = '') => isset($editKwFormData[$key]) ? htmlspecialchars((string)$editKwFormData[$key]) : $default; + $oldFn = $editKwOldFn; $withAutofocusFn = $editWithAutofocusFn; $formData = $editKwFormData; + $name = 'tag'; $label = 'Mots-clés (max 10) :'; $value = $editKwOldFn('tag'); + $placeholder = 'sociologie, anthropologie, ...'; + $hint = 'Séparez par des virgules. Max 10 mots-clés.'; + include APP_ROOT . '/templates/partials/form/text-field.php'; + ?> +
$thesis['orientation'], 'ap' => $thesis['ap_program'], 'finality' => $thesis['finality_type'], - 'languages' => $currentLanguages, - 'formats' => $currentFormats, - 'tag' => $thesis['keywords'] ?? '', ]; $editAcademicOldFn = function (string $key, string $default = '') use ($editFormData) { return isset($editFormData[$key]) && !is_array($editFormData[$key]) - ? htmlspecialchars((string)$editFormData[$key]) - : $default; + ? htmlspecialchars((string)$editFormData[$key]) : $default; }; $oldFn = $editAcademicOldFn; $withAutofocusFn = $editWithAutofocusFn; @@ -82,6 +102,36 @@ include APP_ROOT . '/templates/partials/form/fieldset-academic.php'; ?> + + +
Fichiers @@ -101,7 +151,7 @@
- + @@ -127,13 +177,9 @@ }; ?>
  • - - - - @@ -144,16 +190,13 @@ MB - -
  • @@ -183,8 +226,7 @@
    - Bannière actuelle + Bannière actuelle @@ -200,24 +242,47 @@ $currentLicenseId, - 'duration_info' => $thesis['file_size_info'] ?? '', - 'lien' => $thesis['baiu_link'] ?? '', - 'access_type_id' => $currentAccessTypeId, + 'duration_pages' => $currentRaw['duration_pages'] ?? '', + 'duration_minutes' => $currentRaw['duration_minutes'] ?? '', + 'lien' => $thesis['baiu_link'] ?? '', ]; $editMetaOldFn = function (string $key, string $default = '') use ($editMetaFormData) { - return isset($editMetaFormData[$key]) - ? htmlspecialchars((string)$editMetaFormData[$key]) - : $default; + return isset($editMetaFormData[$key]) ? htmlspecialchars((string)$editMetaFormData[$key]) : $default; }; - $oldFn = $editMetaOldFn; - $withAutofocusFn = $editWithAutofocusFn; - $formData = $editMetaFormData; - $defaultAccessTypeId = $currentAccessTypeId; - $showDescription = true; + $oldFn = $editMetaOldFn; + $withAutofocusFn = $editWithAutofocusFn; + $formData = $editMetaFormData; include APP_ROOT . '/templates/partials/form/fieldset-metadata.php'; ?> + + + + +
    + Note contextuelle +
    + +
    + + Visible publiquement pour les TFE Interne ou Interdit. Max 1 500 caractères. +
    +
    +
    +
    Backoffice @@ -253,28 +318,6 @@ Case logistique : cocher si un exemplaire physique est disponible à l'ERG.
    - -
    - - Conditions collectives de réutilisation. -
    -
    - - -
    - Note contextuelle -
    - -
    - - Visible publiquement pour les TFE Interne ou Interdit. Max 1 500 caractères. -
    -
    @@ -289,6 +332,5 @@
    - diff --git a/app/templates/partials/form/checkbox-list.php b/app/templates/partials/form/checkbox-list.php index 3f4fcaa..7526a1c 100644 --- a/app/templates/partials/form/checkbox-list.php +++ b/app/templates/partials/form/checkbox-list.php @@ -19,7 +19,7 @@ $checked = $checked ?? []; $required = $required ?? false; ?>
    - + *' : '' ?>
    >
      diff --git a/app/templates/partials/form/fieldset-academic.php b/app/templates/partials/form/fieldset-academic.php index 62935fb..19a27f5 100644 --- a/app/templates/partials/form/fieldset-academic.php +++ b/app/templates/partials/form/fieldset-academic.php @@ -8,9 +8,7 @@ * array $orientations — options for the orientation select. * array $apPrograms — options for the AP select. * array $finalityTypes — options for the finality select. - * array $languages — options for the language checkbox list. - * array $formatTypes — options for the format checkbox list. - * array $formData — raw form data (used for checkbox checked state). + * array $formData — raw form data (used for selected state). */ $oldFn = $oldFn ?? (function_exists('old') ? 'old' : fn($k, $d = '') => $d); @@ -46,17 +44,6 @@ $formData = $formData ?? []; $attrs = $withAutofocusFn('finality'); include APP_ROOT . '/templates/partials/form/select-field.php'; ?> - - - - -
    Fichiers - - + +
    - +
    - Types acceptés : PDF · JPG/PNG/GIF/WEBP · MP4/WebM/MOV (vidéo) · MP3/OGG/WAV/FLAC (audio) · ZIP/TAR (archives) · autres fichiers (téléchargement uniquement). - Max 500 MB par fichier. + Types acceptés : PDF · JPG/PNG/GIF/WEBP · MP4/WebM/MOV (vidéo) · MP3/OGG/WAV/FLAC (audio) · ZIP/TAR (archives). Max 500 MB par fichier. Les fichiers .vtt sont des sous-titres et seront associés automatiquement à la vidéo précédente. @@ -51,4 +51,13 @@

    Aucun fichier sélectionné.

    + +
    diff --git a/app/templates/partials/form/fieldset-licence-explanation.php b/app/templates/partials/form/fieldset-licence-explanation.php index f8c90a2..7521e64 100644 --- a/app/templates/partials/form/fieldset-licence-explanation.php +++ b/app/templates/partials/form/fieldset-licence-explanation.php @@ -1,52 +1,40 @@
    Degrés d'ouverture et licences -
    -

    Je veux que mon TFE soit disponible sous les conditions suivantes :

    - -
    -

    🔓 Libre

    -

    Mon TFE est en libre accès à tout le monde sur la plateforme des TFE ainsi que dans la bibliothèque de l'erg. Je suis conscient·e des responsabilités et obligations légales qui viennent avec une diffusion externe – et acquiesce avoir lu la documentation prévue à cet effet par l'erg, ainsi qu'avoir discuté des enjeux d'une publication avec l'équipe pédagogique. J'accepte de partager mes droits de diffusion avec l'erg, ce uniquement dans le cadre d'une diffusion sur la plateforme xamxam.

    -
      -
    • -
    • -
    -

    Au moins une des deux cases doit être cochée pour le degré Libre.

    -
    - -
    -

    🔒 Interne

    -

    Mon TFE et ma note d'intention ne sont accessibles que sur place en physique ainsi que sur la plateforme xamxam par la communauté erg. Une note descriptive est disponible sur le site à toustes. J'autorise une (ré-)utilisation et diffusion dans un contexte académique et didactique au sein de l'erg.

    -

    La diffusion limitée est protégée par le cadre académique/didactique, le travail pourrait donc être diffusé en interne et être cité par d'autres étudiant·es sans implications légales pour l'auteur·ice ni pour l'école.

    -
      -
    • -
    • -
    -

    Au moins une des deux cases doit être cochée.

    -
    - -
    -

    🚫 Interdit

    -

    Mon TFE n'est pas disponible en physique ni sur le site. Une note descriptive est disponible sur le site.

    -
    -
    - +

    Généralités

    + +
    +
    • L'auteur·ice peut décider entre trois degrés de partage de son travail : libre, interne, interdit.
    • L'auteur·ice peut, à tout moment, décider de restreindre le degré d'accès à son travail. Il ne peut néanmoins pas l'ouvrir davantage.
    • @@ -55,7 +43,69 @@ $formData = $formData ?? [];
    • Dans tous les cas, l'auteur·ice garde les droits d'auteurs, de diffusion, d'utilisation, etc. de son travail – sauf si la licence choisie restreindrait ses droits.
    • La diffusion « xamxam » est indépendante de la diffusion à la BAIU.
    + +
    + + +
    +

    J'autorise l'erg à archiver mon TFE de la manière suivante :

    + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    + +

    L'auteur·ice peut, à tout moment, décider de restreindre son propre choix. Iel ne peut par contre pas l'ouvrir.

    +
    + + +
    - $d); -$withAutofocusFn = $withAutofocusFn ?? fn($field, $attrs = []) => $attrs; -$formData = $formData ?? []; -$defaultAccessTypeId = $defaultAccessTypeId ?? 2; -$showDescription = $showDescription ?? false; - -$accessOptions = array_map(function ($at) use ($showDescription) { - $label = $at['name']; - if ($showDescription && !empty($at['description'])) { - $label .= ' — ' . $at['description']; - } - return ['id' => $at['id'], 'name' => $label]; -}, $enabledAccessTypes); - -$selectedAccessType = isset($formData['access_type_id']) - ? (int) $formData['access_type_id'] - : $defaultAccessTypeId; +$oldFn = $oldFn ?? (function_exists('old') ? 'old' : fn($k, $d = '') => $d); +$withAutofocusFn = $withAutofocusFn ?? fn($field, $attrs = []) => $attrs; +$formData = $formData ?? []; ?>
    Métadonnées complémentaires +
    + +
    + - -
    1 a radio group * is shown; when count === 1 a hidden input is emitted instead. - * Omit or pass [] to suppress the objet selector entirely. - * array $formData — raw form data array (used for contact_public checkbox state). - * string $synopsisExtra — optional HTML block injected after the synopsis label - * (use for student-facing explanations). - * bool $isAdminMode — when true the form uses admin-style helpers; default false. + * array $formData — raw form data array (used for checkbox states). + * string $synopsisExtra — optional HTML block injected after the synopsis label. */ $oldFn = $oldFn ?? (function_exists('old') ? 'old' : fn($k, $d = '') => $d); @@ -45,37 +42,29 @@ $synopsisExtra = $synopsisExtra ?? ''; 'name']); + $hint = 'Séparez les auteur·ices par des virgules.'; include APP_ROOT . '/templates/partials/form/text-field.php'; ?> 'email']; + $hint = 'Ce contact sera visible publiquement sur la fiche du TFE.'; include APP_ROOT . '/templates/partials/form/text-field.php'; ?> -
    - - Si coché, votre contact apparaîtra sur la page publique. L'adresse est toujours conservée en interne. -
    -
    - + diff --git a/app/templates/partials/form/file-field.php b/app/templates/partials/form/file-field.php index 11a4088..dfaf92f 100644 --- a/app/templates/partials/form/file-field.php +++ b/app/templates/partials/form/file-field.php @@ -7,24 +7,27 @@ * string $label — visible label text * string $accept — MIME types / extensions for the accept attribute (e.g. 'image/jpeg,image/png') * string|null $hint — optional hint shown in below the input + * bool $required — whether the field is required; default false * bool $multiple — whether to allow multiple file selection; default false * string|null $id — override the id attribute (defaults to $name) */ $accept = $accept ?? ''; $hint = $hint ?? null; +$required = $required ?? false; $multiple = $multiple ?? false; $id = $id ?? $name; $previewId = 'fp-' . htmlspecialchars($id); ?>
    - +
    + data-preview="">
    @@ -33,4 +36,4 @@ $previewId = 'fp-' . htmlspecialchars($id);
    string, 'is_external' => int] + * $juryPromoteur string|null Promoteur interne name + * $juryPromoteurUlb string|null Promoteur ULB name + * $lecteursInternes array [{name: string}] + * $lecteursExternes array [{name: string}] + * $juryPresident string|null President name (edit-only, optional) + * $showPresident bool Show president field (default: false) + * $showPromoteurUlb bool Show ULB promoteur field (default: true) + * $promoteurUlbConditional bool If true, field is hidden unless finality=Approfondi * - * In "add" mode (no existing jury data), callers should pass nulls/empty arrays and - * may rely on the $formData repopulation helpers (old/wasSelected) defined in add.php. - * When those helpers exist and no explicit values are set, the partial uses them. + * In add-mode repopulation: if old() exists and values are null, populate from it. */ -$juryPresident = $juryPresident ?? null; -$juryPromoteur = $juryPromoteur ?? null; -$juryPromoteurExt = $juryPromoteurExt ?? 0; -$juryPromoteurUlb = $juryPromoteurUlb ?? 0; -$juryLecteurs = $juryLecteurs ?? []; +$juryPromoteur = $juryPromoteur ?? null; +$juryPromoteurUlb = $juryPromoteurUlb ?? null; +$lecteursInternes = $lecteursInternes ?? []; +$lecteursExternes = $lecteursExternes ?? []; +$juryPresident = $juryPresident ?? null; +$showPresident = $showPresident ?? false; +$showPromoteurUlb = $showPromoteurUlb ?? true; +$promoteurUlbConditional = $promoteurUlbConditional ?? false; -// In add-mode, repopulate from flash form data when helpers are available. -$addMode = ($juryPresident === null && $juryPromoteur === null && empty($juryLecteurs)); +// Add-mode repopulation from flash data +$addMode = ($juryPromoteur === null && $juryPromoteurUlb === null && empty($lecteursInternes) && empty($lecteursExternes) && $juryPresident === null); if ($addMode && function_exists('old')) { - $juryPresident = old('jury_president') ?: null; - $juryPromoteur = old('jury_promoteur') ?: null; - $juryPromoteurExt = function_exists('wasSelected') && wasSelected('jury_promoteur_ext', '1') ? 1 : 0; + $juryPromoteur = old('jury_promoteur') ?: null; + $juryPromoteurUlb = old('jury_promoteur_ulb_name') ?: null; + $juryPresident = old('jury_president') ?: null; + for ($i = 0; $i < 10; $i++) { + $n = old("jury_lecteur_interne:$i"); + if ($n !== '') $lecteursInternes[] = ['name' => $n]; + } + for ($i = 0; $i < 10; $i++) { + $n = old("jury_lecteur_externe:$i"); + if ($n !== '') $lecteursExternes[] = ['name' => $n]; + } } - -$juryIdx = max(count($juryLecteurs), 1); ?> - -
    - Composition du jury +
    + Composition du jury - -
    - - -
    + +
    + + +
    - -
    - -
    - - - -
    -
    - - -
    - Lecteur·ices -
    - -
    - - - -
    - - $lm): ?> - -
    - - - -
    - - -
    - -
    -
    - + })(); + + + + + +
    + Lecteur·ice(s) interne +
    + +
    + + +
    + + $lm): ?> +
    + + +
    + + +
    + +
    + + +
    + Lecteur·ice(s) externe +
    + +
    + + +
    + + $lm): ?> +
    + + +
    + + +
    + +
    + + + +
    + + +
    + +
    + + diff --git a/app/templates/partials/form/select-field.php b/app/templates/partials/form/select-field.php index 24ec4b6..f21687a 100644 --- a/app/templates/partials/form/select-field.php +++ b/app/templates/partials/form/select-field.php @@ -23,7 +23,7 @@ $hint = $hint ?? null; $attrs = $attrs ?? []; ?>
    - + $v) { diff --git a/app/templates/partials/form/text-field.php b/app/templates/partials/form/text-field.php index 5a1e1f5..d22975c 100644 --- a/app/templates/partials/form/text-field.php +++ b/app/templates/partials/form/text-field.php @@ -33,7 +33,7 @@ foreach ($attrs as $k => $v) { } ?>
    - +