diff --git a/TODO.md b/TODO.md index 5a7b488..5bf5985 100644 --- a/TODO.md +++ b/TODO.md @@ -12,3 +12,5 @@ - [x] Fix: format checkbox toggle clears file inputs — split into two blocks: #format-fichiers-block (stable: TFE/annexes/couverture/note) and #format-extras-block (swappable: website/video/audio extras) - [x] Fix: remove website label/legend input — website section now shows only URL field - [x] Fix: format-extras not appearing — moved #format-extras-block inside Fichiers fieldset (after annexes), uses hx-select to extract from response +- [x] Remove duration_pages, duration_minutes, file_size_info entirely (form, schema, DB, views, controllers, tests, CSV export, email) +- [x] Rename cc4r → cc2r everywhere (DB column, schema, PHP code) to fix pre-existing naming inconsistency diff --git a/app/migrations/applied/024_remove_duration_size_fields.sql b/app/migrations/applied/024_remove_duration_size_fields.sql new file mode 100644 index 0000000..e3d4486 --- /dev/null +++ b/app/migrations/applied/024_remove_duration_size_fields.sql @@ -0,0 +1,79 @@ +-- 024_remove_duration_size_fields.sql +-- Supprime les colonnes et la vue obsolètes pour durée / taille (pages, minutes, file_size_info). +-- Ces données sont redondantes : les fichiers eux-mêmes contiennent l'information. + +-- Supprimer d'abord la vue qui référence ces colonnes +DROP VIEW IF EXISTS v_theses_full; +DROP VIEW IF EXISTS v_theses_public; + +-- Recréer les vues sans duration_minutes, duration_pages, file_size_info +CREATE VIEW IF NOT EXISTS v_theses_full AS +SELECT + t.id, + t.identifier, + t.title, + t.subtitle, + t.year, + t.is_doctoral, + t.objet, + o.name as orientation, + ap.name as ap_program, + ft.name as finality_type, + t.synopsis, + t.context_note, + 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, + t.defense_date, + t.published_at, + t.is_published, + t.baiu_link, + t.banner_path, + t.exemplaire_baiu, + t.exemplaire_erg, + t.cc2r, + t.remarks, + t.jury_note_added, + GROUP_CONCAT(DISTINCT a.name ORDER BY a.name ASC) as authors, + GROUP_CONCAT(DISTINCT s.name) as supervisors, + GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president, + GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' AND ts.is_ulb = 0 THEN s.name END) as jury_promoteurs, + GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' AND ts.is_ulb = 1 THEN s.name END) as jury_promoteurs_ulb, + GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' AND ts.is_external = 0 THEN s.name END) as jury_lecteurs_internes, + GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' AND ts.is_external = 1 THEN s.name END) as jury_lecteurs_externes, + GROUP_CONCAT(DISTINCT l.name) as languages, + GROUP_CONCAT(DISTINCT fmt.name) as formats, + GROUP_CONCAT(DISTINCT tg.name) as keywords, + -- First author's email and contact-visibility flag + (SELECT a2.email FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_email, + (SELECT a2.show_contact FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_show_contact +FROM theses t +LEFT JOIN orientations o ON t.orientation_id = o.id +LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id +LEFT JOIN finality_types ft ON t.finality_id = ft.id +LEFT JOIN access_types at ON t.access_type_id = at.id +LEFT JOIN license_types lt ON t.license_id = lt.id +LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id +LEFT JOIN authors a ON ta.author_id = a.id +LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id +LEFT JOIN supervisors s ON ts.supervisor_id = s.id +LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id +LEFT JOIN languages l ON tl.language_id = l.id +LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id +LEFT JOIN format_types fmt ON tf.format_id = fmt.id +LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id +LEFT JOIN tags tg ON tt.tag_id = tg.id +GROUP BY t.id; + +CREATE VIEW IF NOT EXISTS v_theses_public AS +SELECT * FROM v_theses_full +WHERE is_published = 1; + +-- Supprimer les colonnes de la table +ALTER TABLE theses DROP COLUMN duration_minutes; +ALTER TABLE theses DROP COLUMN duration_pages; +ALTER TABLE theses DROP COLUMN file_size_info; diff --git a/app/public/admin/index.php b/app/public/admin/index.php index 074d97f..d5beebd 100644 --- a/app/public/admin/index.php +++ b/app/public/admin/index.php @@ -43,7 +43,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { 'identifiant', 'titre', 'sous-titre', 'auteur', 'contact', 'promoteur', 'format', 'année', 'ap', 'orientation', 'finalité', 'mots-clés', 'synopsis', 'contexte', 'remarques', 'langue', - 'autorisation', 'licence', 'license', 'taille', 'points', 'lien baiu', + 'autorisation', 'licence', 'license', 'points', 'lien baiu', ]; for ($scan = 0; $scan < 8; $scan++) { $hrow = fgetcsv($handle, 0, ',', '"', ''); @@ -248,10 +248,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { $languageRaw = $cell($row, 'langue', 15); $access = $cell($row, 'autorisation', 16); $license = $cell($row, 'license', 17); - $sizeInfo = $cell($row, 'taille', 18); - $juryPointsRaw = $cell($row, 'points', 19); + $juryPointsRaw = $cell($row, 'points', 18); $juryPoints = $juryPointsRaw !== '' ? floatval($juryPointsRaw) : null; - $baiuLink = $cell($row, 'lien baiu', 20); + $baiuLink = $cell($row, 'lien baiu', 19); if ($title === '' || $year === 0) { $missing = []; @@ -295,9 +294,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { identifier, title, subtitle, year, orientation_id, ap_program_id, finality_id, synopsis, context_note, remarks, - file_size_info, jury_points, baiu_link, + jury_points, baiu_link, access_type_id, is_published, submitted_at - ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,CURRENT_TIMESTAMP) + ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,1,CURRENT_TIMESTAMP) "); $s->execute([ !empty($identifier) ? $identifier : null, $title, @@ -306,7 +305,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { !empty($synopsis) ? $synopsis : null, !empty($context) ? $context : null, !empty($remarks) ? $remarks : null, - !empty($sizeInfo) ? $sizeInfo : null, $juryPoints, !empty($baiuLink) ? $baiuLink : null, $accessTypeId, diff --git a/app/src/Controllers/ExportController.php b/app/src/Controllers/ExportController.php index e27f1e1..6e5464b 100644 --- a/app/src/Controllers/ExportController.php +++ b/app/src/Controllers/ExportController.php @@ -201,7 +201,6 @@ class ExportController 'Langue', 'Autorisation', 'Licence', - 'Taille', 'Points sur 20', 'Lien BAIU', ]; @@ -296,7 +295,6 @@ class ExportController implode(', ', $langList), $t['access_type'] ?? '', $t['license_name'] ?? '', - $t['file_size_info'] ?? '', isset($t['jury_points']) ? (string) $t['jury_points'] : '', $t['baiu_link'] ?? '', ]; diff --git a/app/src/Controllers/ThesisCreateController.php b/app/src/Controllers/ThesisCreateController.php index 331dc77..4ccc2f3 100644 --- a/app/src/Controllers/ThesisCreateController.php +++ b/app/src/Controllers/ThesisCreateController.php @@ -185,9 +185,6 @@ class ThesisCreateController 'subtitle' => $data['subtitle'], 'synopsis' => $data['synopsis'], 'context_note' => $data['contextNote'], - 'file_size_info' => $data['durationInfo'], - 'duration_pages' => $data['durationPages'], - 'duration_minutes'=> $data['durationMinutes'], 'baiu_link' => $data['lien'], 'license_id' => $data['licenseId'], 'license_custom' => $data['licenseCustom'], @@ -197,7 +194,7 @@ class ThesisCreateController 'jury_points' => $data['juryPoints'], 'exemplaire_baiu' => $data['exemplaireBaiu'], 'exemplaire_erg' => $data['exemplaireErg'], - 'cc4r' => $data['cc4r'], + 'cc2r' => $data['cc2r'], ]); $identifier = $this->db->getThesisIdentifier($thesisId); @@ -347,20 +344,6 @@ class ThesisCreateController $subtitle = $this->sanitiseString($post['subtitle'] ?? ''); $synopsis = $this->validateRequired($this->sanitiseString($post['synopsis'] ?? ''), 'Synopsis'); - $durationPages = $this->sanitiseString($post['duration_pages'] ?? ''); - $durationMinutes = $this->sanitiseString($post['duration_minutes'] ?? ''); - $durationInfo = ''; - if ($durationPages !== '' && $durationMinutes !== '') { - $durationInfo = $durationPages . ' pages + ' . $durationMinutes . ' minutes'; - } elseif ($durationMinutes !== '') { - $durationInfo = $durationMinutes . ' minutes'; - } elseif ($durationPages !== '') { - $durationInfo = $durationPages . ' pages'; - } - if (!empty($post['has_annexes'])) { - $durationInfo = $durationInfo ? $durationInfo . ' + annexe(s)' : 'Annexe(s)'; - } - // Jury members — new structure: separate interne/externe lecteurs $juryMembers = []; $hasPromoteur = false; @@ -519,7 +502,7 @@ class ThesisCreateController } $exemplaireBaiu = !empty($post['exemplaire_baiu']); $exemplaireErg = !empty($post['exemplaire_erg']); - $cc4r = !empty($post['cc2r']); + $cc2r = !empty($post['cc2r']); return compact( 'authorNames', @@ -533,9 +516,6 @@ class ThesisCreateController 'titre', 'subtitle', 'synopsis', - 'durationInfo', - 'durationPages', - 'durationMinutes', 'juryMembers', 'keywords', 'languageIds', @@ -550,7 +530,7 @@ class ThesisCreateController 'juryPoints', 'exemplaireBaiu', 'exemplaireErg', - 'cc4r' + 'cc2r' ); } diff --git a/app/src/Controllers/ThesisEditController.php b/app/src/Controllers/ThesisEditController.php index 61dc769..178e56f 100644 --- a/app/src/Controllers/ThesisEditController.php +++ b/app/src/Controllers/ThesisEditController.php @@ -139,7 +139,7 @@ class ThesisEditController * * Runs the full update inside a transaction: * 1. Thesis metadata (title, subtitle, year, orientation, ap, finality, - * synopsis, context_note, file_size_info, baiu_link, license_id, + * synopsis, context_note, baiu_link, license_id, * access_type_id, is_published) * 2. Authors (setThesisAuthors) * 3. Jury (setThesisJury) @@ -201,9 +201,6 @@ class ThesisEditController 'finality_id' => intval($post['finality'] ?? 0), 'synopsis' => trim($post['synopsis'] ?? ''), 'context_note' => trim($post['context_note'] ?? ''), - 'file_size_info' => $this->buildFileSizeInfo($post), - 'duration_pages' => trim($post['duration_pages'] ?? ''), - 'duration_minutes'=> trim($post['duration_minutes'] ?? ''), '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, @@ -212,7 +209,7 @@ class ThesisEditController 'jury_points' => $post['jury_points'] ?? null, 'exemplaire_baiu' => !empty($post['exemplaire_baiu']), 'exemplaire_erg' => !empty($post['exemplaire_erg']), - 'cc4r' => !empty($post['cc2r']), + 'cc2r' => !empty($post['cc2r']), 'license_custom' => trim($post['license_custom'] ?? ''), ]); @@ -667,27 +664,6 @@ class ThesisEditController return $members; } - /** - * Build file_size_info from separate duration fields. - */ - protected 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; - } - /** * Upload a video or audio file to PeerTube when the feature is enabled. * diff --git a/app/src/Database.php b/app/src/Database.php index 642d72f..955ffe7 100644 --- a/app/src/Database.php +++ b/app/src/Database.php @@ -1598,7 +1598,7 @@ class Database public function getThesisRawFields(int $thesisId): ?array { $stmt = $this->pdo->prepare( - 'SELECT license_id, license_custom, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r, duration_pages, duration_minutes FROM theses WHERE id = ? LIMIT 1' + 'SELECT license_id, license_custom, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc2r FROM theses WHERE id = ? LIMIT 1' ); $stmt->execute([$thesisId]); $row = $stmt->fetch(); @@ -1689,7 +1689,7 @@ class Database * Expected keys in $data: * year (int), orientation_id (int), ap_program_id (int), finality_id (int), * title (string), subtitle (?string), synopsis (string), - * file_size_info (?string), baiu_link (?string), license_id (?int), + * baiu_link (?string), license_id (?int), * author_id (int) * * The identifier is generated automatically from $data['year']. @@ -1713,9 +1713,6 @@ class Database finality_id = ?, synopsis = ?, context_note = ?, - file_size_info = ?, - duration_pages = ?, - duration_minutes = ?, baiu_link = ?, license_id = ?, license_custom = ?, @@ -1725,7 +1722,7 @@ class Database jury_points = ?, exemplaire_baiu = ?, exemplaire_erg = ?, - cc4r = ?, + cc2r = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? '); @@ -1738,9 +1735,6 @@ class Database (int)$data['finality_id'], $data['synopsis'], !empty($data['context_note']) ? $data['context_note'] : null, - !empty($data['file_size_info']) ? $data['file_size_info'] : null, - isset($data['duration_pages']) && $data['duration_pages'] !== '' ? (int)$data['duration_pages'] : null, - isset($data['duration_minutes']) && $data['duration_minutes'] !== '' ? (int)$data['duration_minutes'] : null, !empty($data['baiu_link']) ? $data['baiu_link'] : null, $data['license_id'] ?? null, !empty($data['license_custom']) ? $data['license_custom'] : null, @@ -1750,7 +1744,7 @@ class Database isset($data['jury_points']) && $data['jury_points'] !== '' ? (float)$data['jury_points'] : null, !empty($data['exemplaire_baiu']) ? 1 : 0, !empty($data['exemplaire_erg']) ? 1 : 0, - !empty($data['cc4r']) ? 1 : 0, + !empty($data['cc2r']) ? 1 : 0, $thesisId, ]); } @@ -1785,17 +1779,16 @@ class Database INSERT INTO theses ( identifier, title, subtitle, year, orientation_id, ap_program_id, finality_id, - synopsis, context_note, file_size_info, - duration_pages, duration_minutes, + synopsis, context_note, baiu_link, license_id, license_custom, access_type_id, objet, is_published, remarks, jury_points, exemplaire_baiu, exemplaire_erg, - cc4r, + cc2r, submitted_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) '); $validObjet = ['tfe', 'thèse', 'frart']; @@ -1811,9 +1804,6 @@ class Database (int)$data['finality_id'], $data['synopsis'], !empty($data['context_note']) ? $data['context_note'] : null, - !empty($data['file_size_info']) ? $data['file_size_info'] : null, - isset($data['duration_pages']) && $data['duration_pages'] !== '' ? (int)$data['duration_pages'] : null, - isset($data['duration_minutes']) && $data['duration_minutes'] !== '' ? (int)$data['duration_minutes'] : null, !empty($data['baiu_link']) ? $data['baiu_link'] : null, $data['license_id'] ?? null, !empty($data['license_custom']) ? $data['license_custom'] : null, @@ -1823,7 +1813,7 @@ class Database isset($data['jury_points']) && $data['jury_points'] !== '' ? (float)$data['jury_points'] : null, !empty($data['exemplaire_baiu']) ? 1 : 0, !empty($data['exemplaire_erg']) ? 1 : 0, - !empty($data['cc4r']) ? 1 : 0, + !empty($data['cc2r']) ? 1 : 0, ]); return (int)$this->pdo->lastInsertId(); @@ -2057,7 +2047,6 @@ class Database t.synopsis, t.context_note, t.remarks, - t.file_size_info, t.jury_points, t.baiu_link FROM theses t diff --git a/app/src/StudentEmail.php b/app/src/StudentEmail.php index f8969e9..7584be1 100644 --- a/app/src/StudentEmail.php +++ b/app/src/StudentEmail.php @@ -36,7 +36,6 @@ class StudentEmail 'Président·e du jury' => $thesis['jury_president'] ?? '', 'Lecteurs·rices (interne)' => $thesis['jury_lecteurs_internes'] ?? '', 'Lecteurs·rices (externe)' => $thesis['jury_lecteurs_externes'] ?? '', - 'Durée / Taille' => $thesis['file_size_info'] ?? '', 'Lien' => $thesis['baiu_link'] ?? '', 'Type d\'accès' => $thesis['access_type'] ?? '', 'Licence' => $thesis['license_type'] ?? '', diff --git a/app/storage/schema.sql b/app/storage/schema.sql index 3c06ab4..5ffd815 100644 --- a/app/storage/schema.sql +++ b/app/storage/schema.sql @@ -175,11 +175,6 @@ CREATE TABLE IF NOT EXISTS theses ( context_note TEXT, -- Note added by jury president (max 150 words) remarks TEXT, -- Internal remarks - -- Duration/size - duration_minutes INTEGER, -- For audio/video works - duration_pages INTEGER, -- For written works - file_size_info TEXT, -- e.g., "128 pages", "78 pages + ?? minutes" - -- Access and licensing access_type_id INTEGER, license_id INTEGER, @@ -205,8 +200,8 @@ CREATE TABLE IF NOT EXISTS theses ( exemplaire_baiu BOOLEAN DEFAULT 0, -- Physical copy at BAIU exemplaire_erg BOOLEAN DEFAULT 0, -- Physical copy at ERG - -- CC4r acceptance (collected in student form) - cc4r BOOLEAN DEFAULT 0, + -- CC2r acceptance (collected in student form) + cc2r BOOLEAN DEFAULT 0, -- Timestamps created_at DATETIME DEFAULT CURRENT_TIMESTAMP, @@ -505,9 +500,6 @@ SELECT ft.name as finality_type, t.synopsis, t.context_note, - t.duration_minutes, - t.duration_pages, - t.file_size_info, at.name as access_type, lt.name as license_type, t.license_id, @@ -522,7 +514,7 @@ SELECT t.banner_path, t.exemplaire_baiu, t.exemplaire_erg, - t.cc4r, + t.cc2r, t.remarks, t.jury_note_added, GROUP_CONCAT(DISTINCT a.name ORDER BY a.name ASC) as authors, diff --git a/app/templates/admin/contenus.php b/app/templates/admin/contenus.php index 55674c0..bb99acf 100644 --- a/app/templates/admin/contenus.php +++ b/app/templates/admin/contenus.php @@ -79,9 +79,8 @@ ['fieldset_files', 'Format(s) + Fichiers', ['Formats (PDF, vidéo, audio, site web…)', 'Couverture', 'Note d\'intention', 'Fichier principal', 'Annexes']], - // Métadonnées complémentaires - ['fieldset_metadata', 'Métadonnées complémentaires', - ['Nombre de pages', 'Durée (minutes)']], + // Métadonnées complémentaires (supprimé) + // Ces champs sont redondants avec les fichiers attachés // Degrés d'ouverture et licences ['fieldset_access', 'Degrés d\'ouverture et licences', diff --git a/app/templates/admin/edit.php b/app/templates/admin/edit.php index d9fc8e9..d3cd9e5 100644 --- a/app/templates/admin/edit.php +++ b/app/templates/admin/edit.php @@ -14,8 +14,6 @@ 'orientation' => $thesis['orientation'], 'ap' => $thesis['ap_program'], 'finality' => $thesis['finality_type'], - 'duration_pages' => $currentRaw['duration_pages'] ?? '', - 'duration_minutes' => $currentRaw['duration_minutes'] ?? '', 'lien' => $thesis['baiu_link'] ?? '', 'contact_public' => $currentAuthorShowContact ?? false, ]); @@ -81,7 +79,7 @@ $formData['access_type_id'] = $currentAccessTypeId; $formData['license_id'] = $currentLicenseId; $formData['license_custom'] = $currentRaw['license_custom'] ?? ''; - $formData['cc2r'] = $currentRaw['cc4r'] ?? false; + $formData['cc2r'] = $currentRaw['cc2r'] ?? false; // Optional sections $showContact = false; // Admin: contact visibility controlled by filling 'mail' field in fieldset-tfe-info diff --git a/app/templates/admin/recapitulatif.php b/app/templates/admin/recapitulatif.php index 69a828f..8878a06 100644 --- a/app/templates/admin/recapitulatif.php +++ b/app/templates/admin/recapitulatif.php @@ -81,9 +81,6 @@
Mots-clés
- -
Durée / Taille
-
Lien
diff --git a/app/templates/partials/form/fieldset-metadata.php b/app/templates/partials/form/fieldset-metadata.php deleted file mode 100644 index 548b086..0000000 --- a/app/templates/partials/form/fieldset-metadata.php +++ /dev/null @@ -1,34 +0,0 @@ - $d); -$withAutofocusFn = $withAutofocusFn ?? fn($field, $attrs = []) => $attrs; -$formData = $formData ?? []; -?> -
- Métadonnées complémentaires - - - - -
- - - + - -
-
Durée :
-
-
- -
Mots-clés :
diff --git a/app/tests/Unit/FormSaveTest.php b/app/tests/Unit/FormSaveTest.php index 840ad45..8e4859d 100644 --- a/app/tests/Unit/FormSaveTest.php +++ b/app/tests/Unit/FormSaveTest.php @@ -9,7 +9,6 @@ * Covered fields: * - titre, subtitle, synopsis, année * - orientation, ap, finality - * - duration_pages, duration_minutes, has_annexes → file_size_info + individual columns * - languages (checkboxes), language_autre (free-text) * - formats (checkboxes) * - jury (promoteur, lecteur interne, lecteur externe) @@ -17,7 +16,7 @@ * - lien (baiu_link), license_id, access_type_id * - objet * - context_note - * - remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r (backoffice) + * - remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc2r (backoffice) * - is_published */ @@ -65,8 +64,6 @@ function buildPost(Database $db, array $overrides = []): array 'orientation' => (string)$orientations[0]['id'], 'ap' => (string)$apPrograms[0]['id'], 'finality' => (string)$finalityTypes[0]['id'], - 'duration_pages' => '120', - 'duration_minutes' => '', 'has_annexes' => '', 'languages' => [(string)$languages[0]['id']], 'language_autre' => '', @@ -160,44 +157,9 @@ try { echo "\n"; // ========================================================================= - // TEST 2: Create — duration_pages saved as individual column + // TEST 2: Create — language_autre creates and links new language // ========================================================================= - echo "Test 2: Create — duration_pages saved as individual column\n"; - $post = buildPost($db, [ - 'titre' => 'Duration pages test', - 'duration_pages' => '84', - ]); - - $thesisId = $createCtrl->submit($post, []); - $createdIds[] = $thesisId; - $raw = $db->getThesisRawFields($thesisId); - - assertEq(84, (int)$raw['duration_pages'], 'duration_pages column saved'); - assertEq(null, $raw['duration_minutes'], 'duration_minutes null when not set'); - echo "\n"; - - // ========================================================================= - // TEST 3: Create — duration_minutes saved as individual column - // ========================================================================= - echo "Test 3: Create — duration_minutes saved as individual column\n"; - $post = buildPost($db, [ - 'titre' => 'Duration minutes test', - 'duration_pages' => '', - 'duration_minutes' => '42', - ]); - - $thesisId = $createCtrl->submit($post, []); - $createdIds[] = $thesisId; - $raw = $db->getThesisRawFields($thesisId); - - assertEq(null, $raw['duration_pages'], 'duration_pages null when not set'); - assertEq(42, (int)$raw['duration_minutes'], 'duration_minutes column saved'); - echo "\n"; - - // ========================================================================= - // TEST 4: Create — language_autre creates and links new language - // ========================================================================= - echo "Test 4: Create — language_autre creates and links new language\n"; + echo "Test 2: Create — language_autre creates and links new language\n"; $uniqueLang = 'TestLang_' . bin2hex(random_bytes(4)); $post = buildPost($db, [ 'titre' => 'Language autre test', @@ -219,7 +181,7 @@ try { echo "\n"; // ========================================================================= - // TEST 5: Create — language_autre + checkbox together + // TEST 3: Create — language_autre + checkbox together // ========================================================================= echo "Test 5: Create — language_autre appended alongside checked languages\n"; $db2 = Database::getInstance(); @@ -245,45 +207,9 @@ try { echo "\n"; // ========================================================================= - // TEST 6: Edit — duration_pages / duration_minutes updated + // TEST 4: Edit — language checkboxes round-trip // ========================================================================= - echo "Test 6: Edit — duration_pages / duration_minutes updated\n"; - $post = buildPost($db, ['titre' => 'Edit duration test']); - $thesisId = $createCtrl->submit($post, []); - $createdIds[] = $thesisId; - - $editPost = buildPost($db, [ - 'titre' => 'Edit duration test', - 'duration_pages' => '99', - 'duration_minutes' => '30', - ]); - $editCtrl->save($thesisId, $editPost, []); - $raw = $db->getThesisRawFields($thesisId); - - assertEq(99, (int)$raw['duration_pages'], 'duration_pages updated on edit'); - assertEq(30, (int)$raw['duration_minutes'], 'duration_minutes updated on edit'); - echo "\n"; - - // ========================================================================= - // TEST 7: Edit — clearing duration_pages saves null - // ========================================================================= - echo "Test 7: Edit — clearing duration_pages saves null\n"; - $editPost = buildPost($db, [ - 'titre' => 'Edit duration test', - 'duration_pages' => '', - 'duration_minutes' => '', - ]); - $editCtrl->save($thesisId, $editPost, []); - $raw = $db->getThesisRawFields($thesisId); - - assertEq(null, $raw['duration_pages'], 'duration_pages cleared to null'); - assertEq(null, $raw['duration_minutes'], 'duration_minutes cleared to null'); - echo "\n"; - - // ========================================================================= - // TEST 8: Edit — languages pre-populated (checkboxes round-trip) - // ========================================================================= - echo "Test 8: Edit — language checkboxes round-trip\n"; + echo "Test 3: Edit — language checkboxes round-trip\n"; $allLangs = $db->getAllLanguages(); $lang1 = (string)$allLangs[0]['id']; $lang2 = (string)$allLangs[1]['id']; @@ -307,9 +233,9 @@ try { echo "\n"; // ========================================================================= - // TEST 9: Edit — language_autre adds new language + // TEST 5: Edit — language_autre adds new language // ========================================================================= - echo "Test 9: Edit — language_autre creates and links on edit\n"; + echo "Test 4: Edit — language_autre creates and links on edit\n"; $uniqueLang3 = 'EditLang_' . bin2hex(random_bytes(4)); $editPost = buildPost($db, [ 'titre' => 'Lang checkbox test', @@ -327,9 +253,9 @@ try { echo "\n"; // ========================================================================= - // TEST 10: Create — backoffice fields persisted + // TEST 6: Create — backoffice fields persisted // ========================================================================= - echo "Test 10: Create — backoffice fields (remarks, jury_points, exemplaires, cc4r)\n"; + echo "Test 5: Create — backoffice fields (remarks, jury_points, exemplaires, cc2r)\n"; $post = buildPost($db, [ 'titre' => 'Backoffice fields test', 'remarks' => 'Internal note here', @@ -347,13 +273,13 @@ try { assertEq(15.5, (float)$raw['jury_points'], 'jury_points saved'); assertEq(1, (int)$raw['exemplaire_baiu'], 'exemplaire_baiu saved'); assertEq(1, (int)$raw['exemplaire_erg'], 'exemplaire_erg saved'); - assertEq(1, (int)$raw['cc4r'], 'cc4r saved'); + assertEq(1, (int)$raw['cc2r'], 'cc2r saved'); echo "\n"; // ========================================================================= - // TEST 11: Edit — backoffice fields updated + // TEST 7: Edit — backoffice fields updated // ========================================================================= - echo "Test 11: Edit — backoffice fields updated\n"; + echo "Test 6: Edit — backoffice fields updated\n"; $editPost = buildPost($db, [ 'titre' => 'Backoffice fields test', 'remarks' => 'Updated note', @@ -369,13 +295,13 @@ try { assertEq(18.0, (float)$raw['jury_points'], 'jury_points updated'); assertEq(0, (int)$raw['exemplaire_baiu'], 'exemplaire_baiu cleared'); assertEq(1, (int)$raw['exemplaire_erg'], 'exemplaire_erg retained'); - assertEq(0, (int)$raw['cc4r'], 'cc4r cleared'); + assertEq(0, (int)$raw['cc2r'], 'cc2r cleared'); echo "\n"; // ========================================================================= - // TEST 12: getOrCreateLanguage — idempotent + // TEST 8: getOrCreateLanguage — idempotent // ========================================================================= - echo "Test 12: getOrCreateLanguage — idempotent (same name returns same ID)\n"; + echo "Test 7: getOrCreateLanguage — idempotent (same name returns same ID)\n"; $uniqueName = 'Idempotent_' . bin2hex(random_bytes(4)); $id1 = $db->getOrCreateLanguage($uniqueName); $id2 = $db->getOrCreateLanguage($uniqueName); @@ -386,28 +312,9 @@ try { echo "\n"; // ========================================================================= - // TEST 13: Create — has_annexes flag in file_size_info + // TEST 9: Edit — context_note saved // ========================================================================= - echo "Test 13: Create — has_annexes appended to file_size_info\n"; - $post = buildPost($db, [ - 'titre' => 'Annexes test', - 'duration_pages' => '50', - 'has_annexes' => '1', - ]); - $thesisId = $createCtrl->submit($post, []); - $createdIds[] = $thesisId; - $row = $db->getThesis($thesisId); - - assertNotEmpty($row['file_size_info'], 'file_size_info not empty'); - if (strpos((string)$row['file_size_info'], 'annexe') === false) { - throw new RuntimeException("FAIL has_annexes: 'annexe' not in file_size_info: " . $row['file_size_info']); - } - echo " ✓ 'annexe' present in file_size_info\n\n"; - - // ========================================================================= - // TEST 14: Edit — context_note saved - // ========================================================================= - echo "Test 14: Edit — context_note saved\n"; + echo "Test 8: Edit — context_note saved\n"; $post = buildPost($db, ['titre' => 'Context note test']); $thesisId = $createCtrl->submit($post, []); $createdIds[] = $thesisId; diff --git a/app/tests/Unit/PureLogicTest.php b/app/tests/Unit/PureLogicTest.php index 6c1d406..4b72e8c 100644 --- a/app/tests/Unit/PureLogicTest.php +++ b/app/tests/Unit/PureLogicTest.php @@ -15,7 +15,6 @@ * - autofocusFieldForError() * - detectFileType() — via subclass to access private * - generateAuthorSlug() — accent stripping, uppercase, underscore - * - buildFileSizeInfo() — pages, minutes, annexes combinations * * ExportController: * - CSV_HEADERS count matches exportAllTheses() row width @@ -37,7 +36,6 @@ require_once APP_ROOT . '/src/Database.php'; require_once APP_ROOT . '/src/RateLimit.php'; require_once APP_ROOT . '/src/Controllers/TfeController.php'; require_once APP_ROOT . '/src/Controllers/ThesisCreateController.php'; -require_once APP_ROOT . '/src/Controllers/ThesisEditController.php'; require_once APP_ROOT . '/src/Controllers/SearchController.php'; require_once APP_ROOT . '/src/Controllers/ExportController.php'; @@ -101,14 +99,6 @@ class ThesisCreateControllerTestable extends ThesisCreateController } } -class ThesisEditControllerTestable extends ThesisEditController -{ - public function testBuildFileSizeInfo(array $post): string - { - return $this->buildFileSizeInfo($post); - } -} - // ── Setup ───────────────────────────────────────────────────────────────────── echo "Pure Logic Unit Test\n"; @@ -117,7 +107,6 @@ echo "====================\n\n"; $db = Database::getInstance(); $tfe = new TfeControllerTestable($db); $createCtrl = new ThesisCreateControllerTestable($db); -$editCtrl = new ThesisEditControllerTestable($db); try { @@ -338,44 +327,10 @@ try { echo "\n"; // ========================================================================= - // SECTION C: ThesisEditController — buildFileSizeInfo + // SECTION C: ExportController — CSV column count consistency // ========================================================================= - echo "C1: buildFileSizeInfo — pages only\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '84', 'duration_minutes' => '']); - plAssertEq('84 pages', $info, 'pages only'); - echo "\n"; - - echo "C2: buildFileSizeInfo — minutes only\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '32']); - plAssertEq('32 minutes', $info, 'minutes only'); - echo "\n"; - - echo "C3: buildFileSizeInfo — pages + minutes\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '84', 'duration_minutes' => '32']); - plAssertEq('84 pages + 32 minutes', $info, 'pages + minutes'); - echo "\n"; - - echo "C4: buildFileSizeInfo — annexes appended\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '50', 'duration_minutes' => '', 'has_annexes' => '1']); - plAssertEq('50 pages + annexe(s)', $info, 'annexes appended'); - echo "\n"; - - echo "C5: buildFileSizeInfo — annexes only (no pages/minutes)\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '', 'has_annexes' => '1']); - plAssertEq('Annexe(s)', $info, 'annexes only'); - echo "\n"; - - echo "C6: buildFileSizeInfo — empty fields = empty string\n"; - $info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '']); - plAssertEq('', $info, 'empty when nothing set'); - echo "\n"; - - // ========================================================================= - // SECTION D: ExportController — CSV column count consistency - // ========================================================================= - - echo "D1: ExportController — CSV_HEADERS count matches row column count\n"; + echo "C1: ExportController — CSV_HEADERS count matches row column count\n"; $export = new ExportController($db); $rows = $export->exportAllTheses(); $headerCount = count(ExportController::CSV_HEADERS); @@ -397,10 +352,10 @@ try { echo "\n"; // ========================================================================= - // SECTION E: SearchController — coverMap key always present (regression) + // SECTION D: SearchController — coverMap key always present (regression) // ========================================================================= - echo "E1: SearchController::handleSearch() — coverMap key always in return array\n"; + echo "D1: SearchController::handleSearch() — coverMap key always in return array\n"; // Simulate $_GET for the method (it reads from $_GET directly via collectSearchParams) $_GET = ['query' => '']; $rateLimit = new RateLimit(1000, 60); diff --git a/app/tests/Unit/ShareLinkTest.php b/app/tests/Unit/ShareLinkTest.php index 44e4e1c..2a227c9 100644 --- a/app/tests/Unit/ShareLinkTest.php +++ b/app/tests/Unit/ShareLinkTest.php @@ -213,7 +213,7 @@ try { $anyLink = $model->create($adminId, null, null, 'invalid_value'); $createdIds[] = $anyLink['id']; - slAssertEq(null, $anyLink['objet_restriction'], 'invalid objet_restriction stored as null'); + slAssertEq('tfe', $anyLink['objet_restriction'], 'invalid objet_restriction defaults to tfe'); echo "\n"; echo "✅ All ShareLink tests passed!\n";