Feature: add game cover upload with compact thumbnails

This commit is contained in:
Ponte
2026-02-14 22:55:22 +01:00
parent 832004b591
commit 23352d85d0
4 changed files with 98 additions and 7 deletions

View File

@@ -121,6 +121,7 @@ async function runMigrations() {
condition_score NUMERIC(4,2),
loaned_to TEXT,
barcode TEXT,
cover_url TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
@@ -130,6 +131,7 @@ async function runMigrations() {
await pool.query("ALTER TABLE games ADD COLUMN IF NOT EXISTS purchase_price NUMERIC(10,2);");
await pool.query("ALTER TABLE games ADD COLUMN IF NOT EXISTS condition_score NUMERIC(4,2);");
await pool.query("ALTER TABLE games ADD COLUMN IF NOT EXISTS barcode TEXT;");
await pool.query("ALTER TABLE games ADD COLUMN IF NOT EXISTS cover_url TEXT;");
await pool.query(`
CREATE TABLE IF NOT EXISTS backup_snapshots (
@@ -248,6 +250,7 @@ async function getCatalogFull() {
g.condition_score,
g.loaned_to,
g.barcode,
g.cover_url,
g.created_at
FROM games g
JOIN consoles c ON c.id = g.console_id
@@ -280,6 +283,7 @@ async function getCatalogFull() {
condition: row.condition_score != null ? Number(row.condition_score) : null,
loanedTo: row.loaned_to || "",
barcode: row.barcode || "",
coverUrl: row.cover_url || "",
createdAt: row.created_at,
});
}
@@ -320,6 +324,7 @@ async function exportCatalogDumpWithClient(client) {
g.condition_score,
g.loaned_to,
g.barcode,
g.cover_url,
g.created_at,
g.updated_at
FROM games g
@@ -360,6 +365,7 @@ async function exportCatalogDumpWithClient(client) {
condition: row.condition_score != null ? Number(row.condition_score) : null,
loanedTo: row.loaned_to || "",
barcode: row.barcode || "",
coverUrl: row.cover_url || "",
createdAt: row.created_at,
updatedAt: row.updated_at,
})),
@@ -504,6 +510,7 @@ async function restoreCatalogDump(mode, dump) {
const publisher = normalizeText(gameEntry && gameEntry.publisher) || null;
const loanedTo = normalizeText(gameEntry && gameEntry.loanedTo) || null;
const barcode = normalizeText(gameEntry && gameEntry.barcode) || null;
const coverUrl = normalizeText(gameEntry && gameEntry.coverUrl) || null;
const isDuplicate = Boolean(gameEntry && gameEntry.isDuplicate);
const purchasePrice =
gameEntry && gameEntry.purchasePrice != null && gameEntry.purchasePrice !== ""
@@ -518,9 +525,9 @@ async function restoreCatalogDump(mode, dump) {
`
INSERT INTO games(
console_id, title, genre, publisher, game_version, is_duplicate, release_year, purchase_price,
estimated_value, condition_score, loaned_to, created_at
estimated_value, condition_score, loaned_to, barcode, cover_url, created_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, COALESCE($13::timestamptz, NOW()));
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, COALESCE($14::timestamptz, NOW()));
`,
[
consoleId,
@@ -535,6 +542,7 @@ async function restoreCatalogDump(mode, dump) {
condition,
loanedTo,
barcode,
coverUrl,
createdAt,
],
);
@@ -589,6 +597,7 @@ async function createGame(payload) {
const isDuplicate = Boolean(payload.isDuplicate);
const loanedTo = normalizeText(payload.loanedTo) || null;
const barcode = normalizeText(payload.barcode) || null;
const coverUrl = normalizeText(payload.coverUrl) || null;
const year = payload.year != null && payload.year !== "" ? Number(payload.year) : null;
const purchasePrice =
payload.purchasePrice != null && payload.purchasePrice !== "" ? Number(payload.purchasePrice) : null;
@@ -599,9 +608,9 @@ async function createGame(payload) {
`
INSERT INTO games(
console_id, title, genre, publisher, game_version, is_duplicate, release_year, purchase_price,
estimated_value, condition_score, loaned_to, barcode
estimated_value, condition_score, loaned_to, barcode, cover_url
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
RETURNING id::text AS id;
`,
[
@@ -617,6 +626,7 @@ async function createGame(payload) {
condition,
loanedTo,
barcode,
coverUrl,
],
);
@@ -647,6 +657,7 @@ async function updateGame(id, payload) {
const isDuplicate = Boolean(payload.isDuplicate);
const loanedTo = normalizeText(payload.loanedTo) || null;
const barcode = normalizeText(payload.barcode) || null;
const coverUrl = normalizeText(payload.coverUrl) || null;
const year = payload.year != null && payload.year !== "" ? Number(payload.year) : null;
const purchasePrice =
payload.purchasePrice != null && payload.purchasePrice !== "" ? Number(payload.purchasePrice) : null;
@@ -668,7 +679,8 @@ async function updateGame(id, payload) {
estimated_value = $10,
condition_score = $11,
loaned_to = $12,
barcode = $13
barcode = $13,
cover_url = $14
WHERE id = $1::uuid
RETURNING id::text AS id;
`,
@@ -686,6 +698,7 @@ async function updateGame(id, payload) {
condition,
loanedTo,
barcode,
coverUrl,
],
);
@@ -904,6 +917,7 @@ async function importCatalog(payload) {
const publisher = normalizeText(game && game.publisher) || null;
const loanedTo = normalizeText(game && game.loanedTo) || null;
const barcode = normalizeText(game && game.barcode) || null;
const coverUrl = normalizeText(game && game.coverUrl) || null;
const year = game && game.year != null && game.year !== "" ? Number(game.year) : null;
const purchasePrice =
game && game.purchasePrice != null && game.purchasePrice !== "" ? Number(game.purchasePrice) : null;
@@ -931,9 +945,9 @@ async function importCatalog(payload) {
`
INSERT INTO games(
console_id, title, genre, publisher, game_version, is_duplicate, release_year, purchase_price,
estimated_value, condition_score, loaned_to, barcode
estimated_value, condition_score, loaned_to, barcode, cover_url
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
`,
[
consoleId,
@@ -948,6 +962,7 @@ async function importCatalog(payload) {
condition,
loanedTo,
barcode,
coverUrl,
],
);