refactor form structure per new spec + fix

- split jury into interne/externe/ULB,
- remove president from student form,
- add language_autre,
- split duration into pages+minutes+annexes,
- move licence to degrés d'ouverture with CC2r,
- add license_custom,
- filter PACS from student AP list,
- editable généralités help block,
- Libre toggle per settings

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
This commit is contained in:
Pontoporeia
2026-05-07 17:52:46 +02:00
parent dce0e0b301
commit 24d68dda59
21 changed files with 694 additions and 381 deletions

View File

@@ -183,8 +183,9 @@ class ThesisCreateController
'synopsis' => $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'

View File

@@ -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;
}
}

View File

@@ -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,
]);