diff --git a/TODO.md b/TODO.md index ad96266..a7d7dcd 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,10 @@ # TODO +- [x] Improve recapitulatif.php (partage): bottom margin/padding, center .thanks-success +- [x] Display ALL submitted info in recapitulatif page + email recap +- [x] Add "validate your info / contact xamxam@erg.be" note on recap page +- [x] Fix CSV import: lecteur interne/externe + promoteurice ULB not imported with correct role/is_external/is_ulb flags + - [x] Replace HTMX+PHP file upload queues with client-side JS - [x] Fix submit button on all forms — add JS/PHP debug logging - [x] Fix file-upload-queue.js: redirect detection broken due to opaque redirect (switched from fetch to XHR for reliable responseURL) diff --git a/app/public/admin/index.php b/app/public/admin/index.php index a1964de..3cdc5fa 100644 --- a/app/public/admin/index.php +++ b/app/public/admin/index.php @@ -42,7 +42,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { $headerRowNum = 0; $knownHeaders = [ 'identifiant', 'titre', 'sous-titre', 'auteur', 'contact', - 'promoteur', 'format', 'année', 'ap', 'orientation', 'finalité', + 'promoteur', 'lecteur', 'ulb', 'externe', 'format', 'année', 'ap', 'orientation', 'finalité', 'mots-clés', 'synopsis', 'contexte', 'remarques', 'langue', 'autorisation', 'licence', 'license', 'points', 'lien baiu', ]; @@ -68,10 +68,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { // Avoid short prefixes matching unrelated words if ($hlen >= 5 || $cell === $h) { $hits++; $map[$h] = $pos; $used[$pos] = true; break; } } + // Substring match for short distinguishers (ulb, externe) + if ($hlen >= 3 && $hlen <= 7 && str_contains($cell, $h)) { + $hits++; $map[$h] = $pos; $used[$pos] = true; break; + } } } - // Require at least 8 known headers to trust the row. - if ($hits >= 8) { $colIdx = $map; break; } + // Require at least 11 known headers to trust the row. + if ($hits >= 11) { $colIdx = $map; break; } } // If no header row found, rewind and fall back to positional (skip 4 rows). if ($colIdx === null) { @@ -238,27 +242,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { if ($contact !== '' && in_array(strtoupper(trim($contact)), ['NON', 'OUI'], true)) { $contact = ''; } - $supervisorsRaw = $cell($row, 'promoteur', 5); - $formatsRaw = $cell($row, 'format', 6); - $yearRaw = $cell($row, 'année', 7); + $supervisorsRaw = $cell($row, 'promoteur', 5); + $lecteursInternesRaw = $cell($row, 'lecteur', 6); // first "lecteur" col = interne + $lecteursExternesRaw = $cell($row, 'externe', 7); // contains "externe" + $promoteursUlbRaw = $cell($row, 'ulb', 8); // contains "ulb" + $formatsRaw = $cell($row, 'format', 9); + $yearRaw = $cell($row, 'année', 10); $year = $yearRaw !== '' ? intval($yearRaw) : 0; // Fallback: derive year from identifier (e.g. "2024-003" → 2024) if ($year === 0 && $identifier !== '' && preg_match('/^(\d{4})-/', $identifier, $m)) { $year = (int)$m[1]; } - $apCode = $cell($row, 'ap', 8); - $orientationCode = $cell($row, 'orientation', 9); - $finalityName = $cell($row, 'finalité', 10); - $keywordsRaw = $cell($row, 'mots-clés', 11); - $synopsis = $cell($row, 'synopsis', 12); - $context = $cell($row, 'contexte', 13); - $remarks = $cell($row, 'remarques', 14); - $languageRaw = $cell($row, 'langue', 15); - $access = $cell($row, 'autorisation', 16); - $license = $cell($row, 'license', 17); - $juryPointsRaw = $cell($row, 'points', 18); + $apCode = $cell($row, 'ap', 11); + $orientationCode = $cell($row, 'orientation', 12); + $finalityName = $cell($row, 'finalité', 13); + $keywordsRaw = $cell($row, 'mots-clés', 14); + $synopsis = $cell($row, 'synopsis', 15); + $context = $cell($row, 'contexte', 16); + $remarks = $cell($row, 'remarques', 17); + $languageRaw = $cell($row, 'langue', 18); + $access = $cell($row, 'autorisation', 19); + $license = $cell($row, 'license', 20); + $juryPointsRaw = $cell($row, 'points', 21); $juryPoints = $juryPointsRaw !== '' ? floatval($juryPointsRaw) : null; - $baiuLink = $cell($row, 'lien baiu', 19); + $baiuLink = $cell($row, 'lien baiu', 22); if ($title === '' || $year === 0) { $missing = []; @@ -328,12 +335,49 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { } } } + // Insert supervisors with proper role/is_external/is_ulb flags + $juryOrder = 0; + // Promoteurs internes if (!empty($supervisorsRaw)) { - foreach (array_map('trim', explode(',', $supervisorsRaw)) as $idx => $name) { + foreach (array_map('trim', explode(',', $supervisorsRaw)) as $name) { if ($name) { + $juryOrder++; $sId = $importDb->findOrCreateSupervisor($name); - $s = $importPdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, supervisor_order) VALUES (?,?,?)"); - $s->execute([$thesisId, $sId, $idx + 1]); + $stmt = $importPdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, role, is_external, is_ulb, supervisor_order) VALUES (?,?,?,?,?,?)"); + $stmt->execute([$thesisId, $sId, 'promoteur', 0, 0, $juryOrder]); + } + } + } + // Lecteurs internes + if (!empty($lecteursInternesRaw)) { + foreach (array_map('trim', explode(',', $lecteursInternesRaw)) as $name) { + if ($name) { + $juryOrder++; + $sId = $importDb->findOrCreateSupervisor($name); + $stmt = $importPdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, role, is_external, is_ulb, supervisor_order) VALUES (?,?,?,?,?,?)"); + $stmt->execute([$thesisId, $sId, 'lecteur', 0, 0, $juryOrder]); + } + } + } + // Lecteurs externes + if (!empty($lecteursExternesRaw)) { + foreach (array_map('trim', explode(',', $lecteursExternesRaw)) as $name) { + if ($name) { + $juryOrder++; + $sId = $importDb->findOrCreateSupervisor($name); + $stmt = $importPdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, role, is_external, is_ulb, supervisor_order) VALUES (?,?,?,?,?,?)"); + $stmt->execute([$thesisId, $sId, 'lecteur', 1, 0, $juryOrder]); + } + } + } + // Promoteurs ULB + if (!empty($promoteursUlbRaw)) { + foreach (array_map('trim', explode(',', $promoteursUlbRaw)) as $name) { + if ($name) { + $juryOrder++; + $sId = $importDb->findOrCreateSupervisor($name); + $stmt = $importPdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, role, is_external, is_ulb, supervisor_order) VALUES (?,?,?,?,?,?)"); + $stmt->execute([$thesisId, $sId, 'promoteur', 1, 1, $juryOrder]); } } } diff --git a/app/public/assets/css/form.css b/app/public/assets/css/form.css index 4ab566c..3d3f8be 100644 --- a/app/public/assets/css/form.css +++ b/app/public/assets/css/form.css @@ -797,12 +797,41 @@ a.recap-file-name:hover { .partage-recap { display: flex; flex-direction: column; + align-items: center; gap: var(--space-l); + padding-bottom: var(--space-3xl); + margin-bottom: var(--space-2xl); +} + +.partage-recap .thanks-success { + text-align: center; +} + +.recap-validate-notice { + text-align: center; + font-size: var(--step--1); + color: var(--text-secondary); + background: color-mix(in srgb, var(--accent-primary) 8%, transparent); + border: 1px solid color-mix(in srgb, var(--accent-primary) 20%, transparent); + border-radius: 8px; + padding: var(--space-s) var(--space-m); + max-width: 560px; +} + +.recap-validate-notice p { + margin: 0; +} + +.recap-validate-notice a { + color: var(--accent-primary); + font-weight: 600; } .recap-section { border-top: 1px solid var(--border-primary); padding-top: var(--space-m); + width: 100%; + max-width: 620px; } .recap-section h2 { diff --git a/app/public/partage/recapitulatif.php b/app/public/partage/recapitulatif.php index 7011faf..a0e02f6 100644 --- a/app/public/partage/recapitulatif.php +++ b/app/public/partage/recapitulatif.php @@ -8,6 +8,8 @@ if (!defined('APP_ROOT')) { App::boot(); } +require_once APP_ROOT . '/src/EmailObfuscator.php'; + $thesisId = isset($_GET['id']) ? (int)$_GET['id'] : 0; if ($thesisId <= 0) { @@ -69,9 +71,18 @@ $pageTitle = 'Merci — TFE enregistré'; +
Veuillez vérifier les informations ci-dessous. Si vous constatez une erreur, contactez-nous à = EmailObfuscator::email('xamxam@erg.be') ?>.
+- Voici un récapitulatif de ta soumission. Tu n'as pas besoin de répondre à cet e-mail. + Voici un récapitulatif de ta soumission. Vérifie bien toutes les informations ci-dessous. + Si tu constates une erreur, écris à xamxam@erg.be.