fix: gallery thumbnails not loading (404 errors) #96

The gallery thumbnail endpoint was returning 404 when thumbnail_path
was null or the file didn't exist, unlike the admin endpoint which
generates thumbnails on demand using ensureThumbnail().

- Import ensureThumbnail from imageProcessor
- Use ensureThumbnail() in gallery thumbnail route to generate
  thumbnails on demand if they don't exist
- This matches the admin endpoint behavior

Fixes #96
This commit is contained in:
Paul Nothaft
2026-01-15 11:22:13 +01:00
parent 0e3b50d1b6
commit e3c3c4c951
+18 -17
View File
@@ -12,6 +12,7 @@ const { resolvePhotoFilePath } = require('../services/photoResolver');
const { getEventShareToken, resolveShareIdentifier, buildShareLinkVariants } = require('../services/shareLinkService');
const { handleAsync } = require('../utils/routeHelpers');
const { NotFoundError } = require('../utils/errors');
const { ensureThumbnail } = require('../services/imageProcessor');
// Get storage path from environment or default
const getStoragePath = () => process.env.STORAGE_PATH || path.join(__dirname, '../../storage');
@@ -787,30 +788,30 @@ router.get('/:slug/photo/:photoId',
);
// Serve thumbnail
router.get('/:slug/thumbnail/:photoId',
verifyGalleryAccess,
router.get('/:slug/thumbnail/:photoId',
verifyGalleryAccess,
async (req, res) => {
try {
const { photoId } = req.params;
const photo = await db('photos')
.where({ id: photoId, event_id: req.event.id })
.first();
if (!photo || !photo.thumbnail_path) {
return res.status(404).json({ error: 'Thumbnail not found' });
if (!photo) {
return res.status(404).json({ error: 'Photo not found' });
}
const thumbPath = path.join(getStoragePath(), photo.thumbnail_path);
// Check if file exists
const fs = require('fs').promises;
try {
await fs.access(thumbPath);
} catch (error) {
return res.status(404).json({ error: 'Thumbnail file not found' });
// Ensure thumbnail exists and is valid, regenerate if needed
const thumbnailPath = await ensureThumbnail(photo);
if (!thumbnailPath) {
logger.error(`Failed to generate thumbnail for photo ${photoId}`);
return res.status(404).json({ error: 'Thumbnail generation failed' });
}
const thumbPath = path.join(getStoragePath(), thumbnailPath);
// Log thumbnail access
await secureImageService.logImageAccess(
photoId,
@@ -818,7 +819,7 @@ router.get('/:slug/thumbnail/:photoId',
req.clientInfo,
'thumbnail'
);
// Set appropriate headers with enhanced security
res.set({
'Content-Type': 'image/jpeg',
@@ -827,7 +828,7 @@ router.get('/:slug/thumbnail/:photoId',
'X-Content-Type-Options': 'nosniff',
'X-Protected-Thumbnail': 'true'
});
// Send file
res.sendFile(path.resolve(thumbPath));
} catch (error) {