merge banners into covers: remove banner field, migrate files, add covers to search/home/repertoire cards

This commit is contained in:
Pontoporeia
2026-05-08 10:46:02 +02:00
parent e3896811c4
commit f3d9615562
15 changed files with 198 additions and 407 deletions

View File

@@ -0,0 +1,130 @@
<?php
/**
* Migration 016 — merge banners into covers
*
* 1. For every thesis that has a banner_path:
* a. Copy the file from storage/banners/<file> to storage/covers/<file>
* b. Insert a thesis_files row with file_type='cover'
* c. Clear theses.banner_path
* 2. Remove the now-empty storage/banners/ directory (best-effort).
*
* Safe to re-run: if a cover record already exists for a thesis, the banner
* migration for that thesis is skipped.
*/
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');
$coverDir = STORAGE_ROOT . '/covers/';
$bannerDir = STORAGE_ROOT . '/banners/';
if (!is_dir($coverDir)) {
mkdir($coverDir, 0755, true);
echo "Created covers/ directory.\n";
}
// Fetch all theses with a non-null banner_path
$stmt = $pdo->query("SELECT id, banner_path FROM theses WHERE banner_path IS NOT NULL");
$rows = $stmt->fetchAll();
if (empty($rows)) {
echo "No banners to migrate.\n";
} else {
foreach ($rows as $row) {
$thesisId = (int)$row['id'];
$bannerPath = $row['banner_path']; // e.g. "banners/abc123.png"
// Skip if a cover record already exists for this thesis
$check = $pdo->prepare("SELECT id FROM thesis_files WHERE thesis_id = ? AND file_type = 'cover' LIMIT 1");
$check->execute([$thesisId]);
if ($check->fetch()) {
echo " Thesis $thesisId: cover record already exists — skipping banner migration.\n";
// Still clear banner_path so UI stays clean
$pdo->prepare("UPDATE theses SET banner_path = NULL WHERE id = ?")->execute([$thesisId]);
continue;
}
$srcAbs = STORAGE_ROOT . '/' . $bannerPath;
$filename = basename($bannerPath);
$dstAbs = $coverDir . $filename;
$dstRel = 'covers/' . $filename;
if (!file_exists($srcAbs)) {
echo " Thesis $thesisId: source file missing ($srcAbs) — inserting DB record with new path anyway, skipping file copy.\n";
} else {
if (!copy($srcAbs, $dstAbs)) {
echo " ERROR: could not copy $srcAbs$dstAbs — skipping thesis $thesisId.\n";
continue;
}
chmod($dstAbs, 0644);
echo " Thesis $thesisId: copied $bannerPath$dstRel\n";
}
// Determine MIME from extension
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$mime = match($ext) {
'jpg', 'jpeg' => 'image/jpeg',
'png' => 'image/png',
'webp' => 'image/webp',
default => 'image/jpeg',
};
// Get file size
$size = file_exists($dstAbs) ? filesize($dstAbs) : 0;
// Insert cover record
$ins = $pdo->prepare(
"INSERT INTO thesis_files (thesis_id, file_type, file_path, file_name, file_size, mime_type, sort_order)
VALUES (?, 'cover', ?, ?, ?, ?, 0)"
);
$ins->execute([$thesisId, $dstRel, $filename, $size, $mime]);
echo " Thesis $thesisId: inserted cover record → $dstRel\n";
// Clear banner_path
$pdo->prepare("UPDATE theses SET banner_path = NULL WHERE id = ?")->execute([$thesisId]);
echo " Thesis $thesisId: cleared banner_path.\n";
}
}
// Remove old banner files that were successfully copied
$remaining = glob($bannerDir . '*') ?: [];
$allClear = true;
foreach ($remaining as $f) {
$basename = basename($f);
if (file_exists($coverDir . $basename)) {
@unlink($f);
echo "Removed migrated banner file: banners/$basename\n";
} else {
echo "WARNING: banners/$basename has no corresponding cover — leaving in place.\n";
$allClear = false;
}
}
// Remove the now-empty banners/ directory (best-effort, ignoring .gitkeep)
if ($allClear && is_dir($bannerDir)) {
$leftovers = array_diff(scandir($bannerDir), ['.', '..', '.gitkeep']);
if (empty($leftovers)) {
// Remove .gitkeep if present, then the dir
$gitkeep = $bannerDir . '.gitkeep';
if (file_exists($gitkeep)) {
@unlink($gitkeep);
}
@rmdir($bannerDir);
echo "Removed banners/ directory.\n";
} else {
echo "WARNING: banners/ directory still has files after migration — leaving in place.\n";
}
}
echo "\nMigration 016 complete.\n";