From bf4109d8eca3541d58e43a42999b2a9587673ee8 Mon Sep 17 00:00:00 2001 From: seb Date: Sun, 18 Oct 2026 14:07:01 +0200 Subject: [PATCH] u --- src/store/article/addImage.js | 10 +++- src/store/article/deleteImage.js | 40 +++++++++++----- src/store/article/orderImages.js | 13 +++++- src/store/articlehistory/record.js | 75 ++++++++++++++++++++++++++++++ test/article.test.js | 6 +++ 5 files changed, 130 insertions(+), 14 deletions(-) diff --git a/src/store/article/addImage.js b/src/store/article/addImage.js index 067f068..7f31f17 100644 --- a/src/store/article/addImage.js +++ b/src/store/article/addImage.js @@ -11,6 +11,7 @@ import { CREATE as SQLITE_CREATE_PIC } from '../../providers/sqlite3/queries/pic import processAvifImage from '../../util/processAvifImage.js'; import newFullHash from '../../util/newFullHash.js'; import resolveArticleBySku from './resolveArticleBySku.js'; +import { recordImageAddHistory } from '../articlehistory/record.js'; import makeRunner from '../runner.js'; export default function addImage(provider) { @@ -39,7 +40,7 @@ export default function addImage(provider) { const fullHash = newFullHash(processed.full.buffer); const runAdd = async (runner) => { - const { articleId } = await resolve(googleAuthId, sku, runner); + const { articleId, companyuserId } = await resolve(googleAuthId, sku, runner); const sortResult = await runner.query(getSortSql, { articleId }); const sort = sortResult.rows[0].sort; @@ -96,6 +97,13 @@ export default function addImage(provider) { picId, sort, }); + + await recordImageAddHistory(runner, { + articleId, + companyuserId, + fullHash, + sort: effectiveSort, + }); } return { diff --git a/src/store/article/deleteImage.js b/src/store/article/deleteImage.js index b1c2387..34b52bd 100644 --- a/src/store/article/deleteImage.js +++ b/src/store/article/deleteImage.js @@ -1,6 +1,7 @@ import { DELETE_BY_ARTICLE_AND_HASH as MSSQL_QUERY } from '../../providers/mssql/queries/pic.js'; import { DELETE_BY_ARTICLE_AND_HASH as SQLITE_QUERY } from '../../providers/sqlite3/queries/pic.js'; import resolveArticleBySku from './resolveArticleBySku.js'; +import { recordImageDeleteHistory } from '../articlehistory/record.js'; import makeRunner from '../runner.js'; export default function deleteImage(provider) { @@ -21,21 +22,36 @@ export default function deleteImage(provider) { * await store.article.deleteImage(42, 'SKU-1', 'abc123'); */ return async (googleAuthId, sku, fullHash, tx) => { - const { articleId } = await resolve(googleAuthId, sku, tx); - const runner = makeRunner(provider, tx); - const result = await runner.query(sql, { articleId, fullHash }); + const runDelete = async (runner) => { + const { articleId, companyuserId } = await resolve(googleAuthId, sku, runner); + const result = await runner.query(sql, { articleId, fullHash }); - if (!result.rowsAffected) { - throw new Error('Image not found'); - } - - if (provider?.dialect === 'sqlite3') { - if (runner.deletePic) { - await runner.deletePic(fullHash); - } else if (provider?.deletePic) { - await provider.deletePic(fullHash); + if (!result.rowsAffected) { + throw new Error('Image not found'); } + + if (provider?.dialect === 'sqlite3') { + if (runner.deletePic) { + await runner.deletePic(fullHash); + } else if (provider?.deletePic) { + await provider.deletePic(fullHash); + } + } + + await recordImageDeleteHistory(runner, { + articleId, + companyuserId, + fullHash, + }); + }; + + if (tx) { + return runDelete(makeRunner(provider, tx)); } + if (typeof provider?.transaction === 'function') { + return provider.transaction(runDelete); + } + return runDelete(makeRunner(provider)); }; } diff --git a/src/store/article/orderImages.js b/src/store/article/orderImages.js index 68751c3..7888989 100644 --- a/src/store/article/orderImages.js +++ b/src/store/article/orderImages.js @@ -1,6 +1,7 @@ import * as mssqlPic from '../../providers/mssql/queries/articlepic.js'; import * as sqlitePic from '../../providers/sqlite3/queries/articlepic.js'; import resolveArticleBySku from './resolveArticleBySku.js'; +import { recordImageOrderHistory } from '../articlehistory/record.js'; import makeRunner from '../runner.js'; export default function orderImages(provider) { @@ -29,7 +30,7 @@ export default function orderImages(provider) { } const runOrder = async (runner) => { - const { articleId } = await resolve(googleAuthId, sku, runner); + const { articleId, companyuserId } = await resolve(googleAuthId, sku, runner); const current = await runner.query(queries.LIST_HASHES_BY_ARTICLE, { articleId }); const existing = new Set(current.rows.map((r) => r.fullHash)); @@ -60,6 +61,16 @@ export default function orderImages(provider) { } } + const oldOrder = current.rows.map((r) => r.fullHash); + const isSameOrder = oldOrder.length === fullHashes.length && oldOrder.every((h, i) => h === fullHashes[i]); + if (!isSameOrder) { + await recordImageOrderHistory(runner, { + articleId, + companyuserId, + fullHashes, + }); + } + return { fullHashes }; }; diff --git a/src/store/articlehistory/record.js b/src/store/articlehistory/record.js index c63fb7f..8df7952 100644 --- a/src/store/articlehistory/record.js +++ b/src/store/articlehistory/record.js @@ -1018,3 +1018,78 @@ export async function recordOptionsListChangeHistory(runner, { meta, }); } + +/** + * Records image addition to an article. + */ +export async function recordImageAddHistory(runner, { + articleId, + companyuserId, + date, + fullHash, + sort, +}) { + const text = typeof sort === 'number' + ? `Bild hinzugefügt (Position ${sort + 1})` + : 'Bild hinzugefügt'; + const meta = { + type: 'image_add', + fullHash, + sort, + }; + return recordArticleHistory(runner, { + articleId, + companyuserId, + date, + text, + meta, + }); +} + +/** + * Records image deletion from an article. + */ +export async function recordImageDeleteHistory(runner, { + articleId, + companyuserId, + date, + fullHash, +}) { + const text = 'Bild gelöscht'; + const meta = { + type: 'image_delete', + fullHash, + }; + return recordArticleHistory(runner, { + articleId, + companyuserId, + date, + text, + meta, + }); +} + +/** + * Records image reordering for an article. + */ +export async function recordImageOrderHistory(runner, { + articleId, + companyuserId, + date, + fullHashes, +}) { + const count = Array.isArray(fullHashes) ? fullHashes.length : 0; + const text = `Bildreihenfolge geändert (${count} Bilder)`; + const meta = { + type: 'image_order', + fullHashes, + }; + return recordArticleHistory(runner, { + articleId, + companyuserId, + date, + text, + meta, + }); +} + diff --git a/test/article.test.js b/test/article.test.js index 3e69b4b..c646d2c 100644 --- a/test/article.test.js +++ b/test/article.test.js @@ -626,6 +626,12 @@ describe('store.article', () => { () => store.article.deleteImage(gid, art.sku, img2.fullHash), { message: 'Image not found' }, ); + + const history = await store.article.getHistoryBySku(gid, art.sku); + const texts = history.map((h) => h.text); + assert.ok(texts.some((t) => t.includes('Bild hinzugefügt'))); + assert.ok(texts.some((t) => t.includes('Bildreihenfolge geändert'))); + assert.ok(texts.some((t) => t.includes('Bild gelöscht'))); }); });