af7970b069
* fix(preview): generate lightbox previews for external/reference photos (#1078) ensurePreviewImage() resolved its source only via resolvePhotoStorageKey(), which returns null for external/reference photos by design — those live on a media mount outside the managed storage tree. The null went straight into withLocalCopy(), which throws ("LocalFsStorage: invalid relative path: null"), so the preview route fell back to redirecting at the full-size original. A gallery whose photos are all external got no benefit from the preview tier (#492) at all: guests paid 5-12 MB on every lightbox open, with nothing surfaced in the admin UI. Add the external branch ensureThumbnail() has had since #423: resolve via resolvePhotoFilePath() and feed the mount path to generatePreviewImage() directly, with an ext<id>_ output basename so two events referencing the same NAS filename can't clobber each other's preview. Also close the adjacent hole that made the failure a throw rather than the documented null: a row with no source_origin in a reference-mode event takes its mode from the event, so resolvePhotoStorageKey returns null for it too. Return null instead of handing that to withLocalCopy. Claude-Session: https://claude.ai/code/session_01Ra4hcsYiKuQLbbRsg6EjAc * fix(preview): select the columns the external branch needs on bulk regenerate POST /api/admin/thumbnails/regenerate-previews selected only id, event_id, path, media_type, mime_type and preview_path, so photo.source_origin was undefined by the time ensurePreviewImage branched on it. Every external row in a reference gallery took the managed path, resolvePhotoStorageKey returned null for it, and the endpoint reported success while generating nothing. Add source_origin, external_relpath and filename to the select, plus a source-inspection test pinning the caller contract and a service-level test showing a column-starved row is indistinguishable from a managed one. Claude-Session: https://claude.ai/code/session_01Ra4hcsYiKuQLbbRsg6EjAc * style(test): single-quote the source-inspection needles Matches the repo eslint quotes rule (no avoidEscape) by dropping the nested quotes from the search strings rather than escaping them. Claude-Session: https://claude.ai/code/session_01Ra4hcsYiKuQLbbRsg6EjAc --------- Co-authored-by: Paul Nothaft <paul@MacStudio-von-Paul.local>
43 lines
1.6 KiB
JavaScript
43 lines
1.6 KiB
JavaScript
/**
|
|
* Source-inspection contract test for #1078.
|
|
*
|
|
* POST /api/admin/thumbnails/regenerate-previews hands its selected rows to
|
|
* ensurePreviewImage, which branches on `source_origin` (and then reads
|
|
* `external_relpath` / `filename`) to reach an external/reference photo on its
|
|
* media mount. When the select list omitted those columns, every external row
|
|
* looked managed, resolvePhotoStorageKey returned null, and the endpoint
|
|
* reported success while silently generating nothing for reference galleries.
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
describe('regenerate-previews selects the columns ensurePreviewImage branches on (#1078)', () => {
|
|
const src = fs.readFileSync(
|
|
path.join(__dirname, '..', '..', 'src', 'routes', 'adminThumbnails.js'),
|
|
'utf8',
|
|
);
|
|
|
|
// The select feeding the regenerate-previews handler, from the route
|
|
// declaration to the end of that statement.
|
|
const selectStatement = (() => {
|
|
const routeIdx = src.indexOf('/regenerate-previews');
|
|
expect(routeIdx).toBeGreaterThan(-1);
|
|
const selectIdx = src.indexOf('.select(', routeIdx);
|
|
expect(selectIdx).toBeGreaterThan(-1);
|
|
return src.slice(selectIdx, src.indexOf(';', selectIdx));
|
|
})();
|
|
|
|
it.each(['source_origin', 'external_relpath', 'filename'])(
|
|
'selects %s',
|
|
(column) => {
|
|
expect(selectStatement).toContain(`'${column}'`);
|
|
}
|
|
);
|
|
|
|
it('still selects the columns the managed path needs', () => {
|
|
for (const column of ['id', 'event_id', 'path', 'media_type', 'mime_type', 'preview_path']) {
|
|
expect(selectStatement).toContain(`'${column}'`);
|
|
}
|
|
});
|
|
});
|