mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
feat: migration 038 to fix thesis identifiers mismatched with their year
This commit is contained in:
6
TODO.md
6
TODO.md
@@ -7,5 +7,7 @@
|
||||
- [x] Fix #5: "Contact public : non" partout, non modifiable, sans impact
|
||||
- [x] Fix #6: Investiguer "libre → interne" impossible — aucune restriction trouvée dans le code admin
|
||||
- [x] Hotfix: contact_visible manquant dans le SQL de updateThesis (l'edit matchait createThesis à la place)
|
||||
- [x] Fix #7: Options de licence non persistées en edit — HTMX load trigger perdait les valeurs (pas de hidden inputs pour license_id/license_custom/cc2r/want_license dans fieldset-licence-explanation.php)
|
||||
- [x] Commit + jj new
|
||||
- [x] Fix #7: Options de licence non persistées en edit — HTMX load trigger perdait les valeurs
|
||||
- [x] Fix #3 (v2): findOrCreateAuthor avec cascade ID → nom → email, setThesisAuthors passe les IDs existants
|
||||
- [x] Migration 038: corriger les identifiers theses qui ne matchent pas leur année
|
||||
- [ ] Commit + jj new
|
||||
|
||||
85
app/migrations/applied/038_fix_mismatched_identifiers.php
Normal file
85
app/migrations/applied/038_fix_mismatched_identifiers.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Migration 038 — fix thesis identifiers that don't match their year.
|
||||
*
|
||||
* Some entries have identifiers like "2024-026" with year=2025 (or vice-versa),
|
||||
* typically because the year was corrected after initial creation. When editing
|
||||
* a thesis and changing its year, the identifier is now auto-regenerated via
|
||||
* ThesisEditController::save(), but pre-existing wrong identifiers need a
|
||||
* one-off fix.
|
||||
*
|
||||
* Logic: for each thesis whose identifier year-prefix does NOT match its `year`
|
||||
* column, assign a new identifier <year>-<NNN> using the next available sequence
|
||||
* number for that year. Entries are ordered by id within each year so the
|
||||
* numbering is deterministic and roughly chronological.
|
||||
*
|
||||
* Safe to re-run: only updates identifiers that are already mismatched.
|
||||
*/
|
||||
|
||||
defined('APP_ROOT') || define('APP_ROOT', dirname(__DIR__, 2));
|
||||
defined('STORAGE_ROOT') || define('STORAGE_ROOT', APP_ROOT . '/storage');
|
||||
|
||||
$dbPath = APP_ROOT . '/storage/xamxam.db';
|
||||
if (!file_exists($dbPath)) {
|
||||
echo "ERROR: database not found at $dbPath\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$pdo = new PDO('sqlite:' . $dbPath);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
$pdo->exec('PRAGMA foreign_keys = ON');
|
||||
|
||||
// ── 1. Identify mismatched rows ──────────────────────────────────────────
|
||||
$stmt = $pdo->query(
|
||||
"SELECT id, year, identifier
|
||||
FROM theses
|
||||
WHERE deleted_at IS NULL
|
||||
AND CAST(SUBSTR(identifier, 1, 4) AS INTEGER) != year"
|
||||
);
|
||||
$mismatched = $stmt->fetchAll();
|
||||
|
||||
if (empty($mismatched)) {
|
||||
echo "No mismatched identifiers found. Nothing to fix.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
echo "Found " . count($mismatched) . " thesis(es) with mismatched identifiers.\n";
|
||||
|
||||
// Group by year, ordered by id within each year (deterministic renumbering)
|
||||
$byYear = [];
|
||||
foreach ($mismatched as $row) {
|
||||
$year = (int)$row['year'];
|
||||
$byYear[$year][] = $row;
|
||||
}
|
||||
|
||||
$fixed = 0;
|
||||
foreach ($byYear as $year => $rows) {
|
||||
// Sort by id for deterministic sequencing
|
||||
usort($rows, fn($a, $b) => (int)$a['id'] <=> (int)$b['id']);
|
||||
|
||||
// Find the max existing sequence for CORRECT identifiers of this year
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT COALESCE(MAX(CAST(SUBSTR(identifier, 6) AS INTEGER)), 0)
|
||||
FROM theses
|
||||
WHERE year = ?
|
||||
AND deleted_at IS NULL
|
||||
AND CAST(SUBSTR(identifier, 1, 4) AS INTEGER) = ?"
|
||||
);
|
||||
$stmt->execute([$year, $year]);
|
||||
$maxSeq = (int)$stmt->fetchColumn();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$maxSeq++;
|
||||
$newIdentifier = sprintf('%d-%03d', $year, $maxSeq);
|
||||
|
||||
echo " Thesis {$row['id']}: {$row['identifier']} → {$newIdentifier} (year={$year})\n";
|
||||
|
||||
$pdo->prepare("UPDATE theses SET identifier = ? WHERE id = ?")
|
||||
->execute([$newIdentifier, $row['id']]);
|
||||
$fixed++;
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nFixed $fixed identifier(s).\n";
|
||||
echo "Migration 038 complete.\n";
|
||||
@@ -5,3 +5,4 @@
|
||||
{"timestamp":"2026-06-09T10:34:25+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","resource":"thesis","action":"edit","status":"success","context":{"thesis_id":26,"title":"DepNum"}}
|
||||
{"timestamp":"2026-06-09T10:34:45+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","resource":"thesis","action":"edit","status":"success","context":{"thesis_id":26,"title":"DepNum"}}
|
||||
{"timestamp":"2026-06-09T10:34:52+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","resource":"thesis","action":"edit","status":"success","context":{"thesis_id":26,"title":"DepNum"}}
|
||||
{"timestamp":"2026-06-09T10:42:57+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","resource":"thesis","action":"edit","status":"success","context":{"thesis_id":26,"title":"DepNum"}}
|
||||
|
||||
@@ -14,3 +14,5 @@
|
||||
{"timestamp":"2026-06-09T10:34:45+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","actor":"127.0.0.1","action":"DELETE","table":"thesis_files","record_id":6,"old_data":{"id":6,"thesis_id":26,"file_type":"website","file_path":"https://depnum.happyngreen.fr/","file_name":"depnum.happyngreen.fr","file_size":0,"mime_type":"text/html","description":null,"uploaded_at":"2026-06-09 10:34:25","sort_order":1,"display_label":null,"file_hash":null}}
|
||||
{"timestamp":"2026-06-09T10:34:52+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","actor":"127.0.0.1","action":"UPDATE","table":"theses","record_id":26,"old_data":{"id":26,"identifier":"2024-026","title":"DepNum","subtitle":null,"year":2024,"is_doctoral":0,"objet":"tfe","orientation_id":1,"ap_program_id":3,"finality_id":3,"synopsis":"Mon mémoire de Master à l'ERG est un blog autobiographique sur ma dépendance numérique. Chaque post mêle vécu personnel, questions et recherche. J'explore les dynamiques complexes de notre dépendance collective aux technologies numériques, en croisant expérience individuelle et réflexion systémique. JLKJLKJLKJ","context_note":"blposqujdfmlkqshjd mfglkqjhzmdslkf qsdmlkfj mlqskjdf mqskdjf mlqksdjf mlqksdjf mlqksjd fmlkjqsd","remarks":null,"access_type_id":2,"license_id":3,"jury_points":17.5,"jury_note_added":0,"submitted_at":"2026-06-08 08:33:14","defense_date":null,"published_at":null,"is_published":1,"baiu_link":"https://ils.bib.uclouvain.be/global/documents/3830452","created_at":"2026-06-08 08:33:14","updated_at":"2026-06-09 10:34:45","exemplaire_baiu":0,"exemplaire_erg":0,"cc2r":1,"license_custom":null,"deleted_at":null,"contact_visible":null}}
|
||||
{"timestamp":"2026-06-09T10:34:52+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","actor":"127.0.0.1","action":"DELETE","table":"thesis_files","record_id":7,"old_data":{"id":7,"thesis_id":26,"file_type":"website","file_path":"https://depnum.happyngreen.fr/","file_name":"depnum.happyngreen.fr","file_size":0,"mime_type":"text/html","description":null,"uploaded_at":"2026-06-09 10:34:45","sort_order":1,"display_label":null,"file_hash":null}}
|
||||
{"timestamp":"2026-06-09T10:42:57+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","actor":"127.0.0.1","action":"UPDATE","table":"theses","record_id":26,"old_data":{"id":26,"identifier":"2024-026","title":"DepNum","subtitle":null,"year":2024,"is_doctoral":0,"objet":"tfe","orientation_id":1,"ap_program_id":3,"finality_id":3,"synopsis":"Mon mémoire de Master à l'ERG est un blog autobiographique sur ma dépendance numérique. Chaque post mêle vécu personnel, questions et recherche. J'explore les dynamiques complexes de notre dépendance collective aux technologies numériques, en croisant expérience individuelle et réflexion systémique. JLKJLKJLKJ","context_note":"blposqujdfmlkqshjd mfglkqjhzmdslkf qsdmlkfj mlqskjdf mqskdjf mlqksdjf mlqksdjf mlqksjd fmlkjqsd","remarks":null,"access_type_id":2,"license_id":3,"jury_points":17.5,"jury_note_added":0,"submitted_at":"2026-06-08 08:33:14","defense_date":null,"published_at":null,"is_published":1,"baiu_link":"https://ils.bib.uclouvain.be/global/documents/3830452","created_at":"2026-06-08 08:33:14","updated_at":"2026-06-09 10:34:52","exemplaire_baiu":0,"exemplaire_erg":0,"cc2r":1,"license_custom":null,"deleted_at":null,"contact_visible":null}}
|
||||
{"timestamp":"2026-06-09T10:42:57+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0","actor":"127.0.0.1","action":"DELETE","table":"thesis_files","record_id":8,"old_data":{"id":8,"thesis_id":26,"file_type":"website","file_path":"https://depnum.happyngreen.fr/","file_name":"depnum.happyngreen.fr","file_size":0,"mime_type":"text/html","description":null,"uploaded_at":"2026-06-09 10:34:52","sort_order":1,"display_label":null,"file_hash":null}}
|
||||
|
||||
Reference in New Issue
Block a user