diff --git a/TODO.md b/TODO.md index 9126b2d..e59f103 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,10 @@ # TODO +## CSV importer AP/orientation standardisation +- [x] Migration 014: add `Récits et expérimentation` (RE) and `PACS` AP programs; set code `NS` on `Narration Spéculative` +- [x] Importer: replace code-only AP lookup with `resolveAP()` — handles full names, aliases (`L.I.E.N.S.`, case variants), code fallback +- [x] Importer: replace `orientationMap` code-only lookup with `resolveOrientation()` — handles full names, aliases (`Installation/Performance`, `Arts numériques`, `Design numérique`), legacy 2-letter codes, case-insensitive DB fallback + ## Répertoire page fixes - [x] Fix AP and orientation columns returning empty results when clicked - [x] Fix multi-select being blocked (only one entry selectable at a time) diff --git a/app/public/admin/index.php b/app/public/admin/index.php index aa986a1..b307ffc 100644 --- a/app/public/admin/index.php +++ b/app/public/admin/index.php @@ -38,7 +38,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { fgetcsv($handle, 0, ',', '"', ''); fgetcsv($handle, 0, ',', '"', ''); // skip 4 header rows - $orientationMap = [ + // Code → canonical name (legacy short-code CSV format) + $orientationCodeMap = [ 'SC'=>'Sculpture','VI'=>'Vidéographie','CA'=>"Cinéma d'animation", 'IP'=>'Installation-Performance','PE'=>'Peinture','PH'=>'Photographie', 'DE'=>'Dessin','AN'=>'Arts Numériques','GR'=>'Graphisme', @@ -46,6 +47,91 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { 'BD'=>'Bande-Dessinée','SE'=>'Sérigraphie','GV'=>'Gravure', ]; + // Alias map: normalise known variant spellings → canonical DB name. + // Keys are lowercased+stripped for comparison. + $orientationAliases = [ + 'arts numériques' => 'Arts Numériques', + 'design numérique' => 'Design Numérique', + 'installation/performance' => 'Installation-Performance', + 'installation performance' => 'Installation-Performance', + 'cinema d\'animation' => "Cinéma d'animation", + 'cinéma d\'animation' => "Cinéma d'animation", + 'bande dessinée' => 'Bande-Dessinée', + ]; + + // Resolve an orientation string (code or full name) → canonical DB name. + $resolveOrientation = function(string $raw) use ($orientationCodeMap, $orientationAliases, $importPdo): ?int { + $raw = trim($raw); + if ($raw === '') return null; + + // 1. Try legacy short code + if (isset($orientationCodeMap[$raw])) { + $raw = $orientationCodeMap[$raw]; + } + + // 2. Try alias map (lowercase key) + $key = mb_strtolower($raw, 'UTF-8'); + if (isset($orientationAliases[$key])) { + $raw = $orientationAliases[$key]; + } + + // 3. Exact DB match + $s = $importPdo->prepare("SELECT id FROM orientations WHERE name = ?"); + $s->execute([$raw]); + $r = $s->fetch(); + if ($r) return (int)$r['id']; + + // 4. Case-insensitive DB match + $s = $importPdo->prepare("SELECT id FROM orientations WHERE LOWER(name) = LOWER(?)"); + $s->execute([$raw]); + $r = $s->fetch(); + return $r ? (int)$r['id'] : null; + }; + + // AP alias map: variant spellings → canonical DB name. + $apAliases = [ + 'l.i.e.n.s.' => 'Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', + 'liens' => 'Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', + 'lieux, interdisciplinarités, écologie, nécessité, systèmes' + => 'Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', + 'récits et expérimentation' => 'Récits et expérimentation', + 'recits et experimentation' => 'Récits et expérimentation', + 'atelier pratiques situées' => 'Atelier Pratiques Situées', + 'design et politique du multiple' => 'Design et Politique du Multiple', + 'narration spéculative' => 'Narration Spéculative', + 'pacs' => 'PACS', + ]; + + // Resolve an AP string (code or full name) → ap_program id. + $resolveAP = function(string $raw) use ($apAliases, $importPdo): ?int { + $raw = trim($raw); + if ($raw === '') return null; + + // 1. Try alias map (lowercase key) + $key = mb_strtolower($raw, 'UTF-8'); + if (isset($apAliases[$key])) { + $raw = $apAliases[$key]; + } + + // 2. Exact name match + $s = $importPdo->prepare("SELECT id FROM ap_programs WHERE name = ?"); + $s->execute([$raw]); + $r = $s->fetch(); + if ($r) return (int)$r['id']; + + // 3. Code match (legacy) + $s = $importPdo->prepare("SELECT id FROM ap_programs WHERE code = ?"); + $s->execute([$raw]); + $r = $s->fetch(); + if ($r) return (int)$r['id']; + + // 4. Case-insensitive name match + $s = $importPdo->prepare("SELECT id FROM ap_programs WHERE LOWER(name) = LOWER(?)"); + $s->execute([$raw]); + $r = $s->fetch(); + return $r ? (int)$r['id'] : null; + }; + $lineNumber = 5; while (($row = fgetcsv($handle, 0, ',', '"', '')) !== false) { $lineNumber++; @@ -77,20 +163,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { if (empty($title) || empty($year)) throw new Exception("Titre et année requis."); - $orientationName = $orientationMap[$orientationCode] ?? null; - $orientationId = null; - if ($orientationName) { - $s = $importPdo->prepare("SELECT id FROM orientations WHERE name = ?"); - $s->execute([$orientationName]); - $r = $s->fetch(); $orientationId = $r ? $r['id'] : null; - } - - $apProgramId = null; - if (!empty($apCode)) { - $s = $importPdo->prepare("SELECT id FROM ap_programs WHERE code = ?"); - $s->execute([$apCode]); - $r = $s->fetch(); $apProgramId = $r ? $r['id'] : null; - } + $orientationId = $resolveOrientation($orientationCode); + $apProgramId = $resolveAP($apCode); $finalityId = null; if (!empty($finalityName)) { diff --git a/app/storage/.~lock.Database_TFE_test.csv# b/app/storage/.~lock.Database_TFE_test.csv# new file mode 100644 index 0000000..4a0c540 --- /dev/null +++ b/app/storage/.~lock.Database_TFE_test.csv# @@ -0,0 +1 @@ +,padlock,archlinux,21.04.2026 19:12,file:///home/padlock/.config/libreoffice/4; \ No newline at end of file diff --git a/app/storage/migrations/014_ap_programs_seed.sql b/app/storage/migrations/014_ap_programs_seed.sql new file mode 100644 index 0000000..f8b42b7 --- /dev/null +++ b/app/storage/migrations/014_ap_programs_seed.sql @@ -0,0 +1,9 @@ +-- Migration 014: seed missing AP programs and fix codes +-- Adds programs present in real CSV data but absent from the initial seed. + +-- Fill in missing code for Narration Spéculative +UPDATE ap_programs SET code = 'NS' WHERE name = 'Narration Spéculative' AND (code IS NULL OR code = ''); + +-- Add missing AP programs (INSERT OR IGNORE is safe to re-run) +INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Récits et expérimentation', 'RE'); +INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('PACS', 'PACS'); diff --git a/app/storage/posterg.db b/app/storage/posterg.db index b66f21a..db4042c 100644 Binary files a/app/storage/posterg.db and b/app/storage/posterg.db differ diff --git a/app/storage/test.db b/app/storage/test.db index 6e84cee..6f52264 100644 Binary files a/app/storage/test.db and b/app/storage/test.db differ