feat: use checksummed filenames for recipe images and clean up old files
All checks were successful
CI / update (push) Successful in 1m13s
All checks were successful
CI / update (push) Successful in 1m13s
Updated recipe image handling to use checksummed filenames for proper cache busting. When uploading a new image during recipe edit, old image files (both hashed and unhashed versions) are now properly deleted from all directories (full, thumb, placeholder). Changes: - CardAdd.svelte: Use checksummed filename from upload response - Edit page server: Add deleteRecipeImage() helper to remove old images - Edit page server: Delete old images when new image is uploaded
This commit is contained in:
@@ -113,7 +113,7 @@ export async function show_local_image(){
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
uploaded_image_filename = result.unhashedFilename;
|
||||
uploaded_image_filename = result.filename;
|
||||
upload_error = "";
|
||||
|
||||
} catch (error: any) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Recipe } from '$models/Recipe';
|
||||
import { dbConnect } from '$utils/db';
|
||||
import { invalidateRecipeCaches } from '$lib/server/cache';
|
||||
import { IMAGE_DIR } from '$env/static/private';
|
||||
import { rename, access } from 'fs/promises';
|
||||
import { rename, access, unlink } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { constants } from 'fs';
|
||||
import {
|
||||
@@ -14,6 +14,43 @@ import {
|
||||
detectChangedFields
|
||||
} from '$utils/recipeFormHelpers';
|
||||
|
||||
/**
|
||||
* Delete recipe image files from all directories (full, thumb, placeholder)
|
||||
* Handles both hashed and unhashed versions for backward compatibility
|
||||
*/
|
||||
async function deleteRecipeImage(filename: string): Promise<void> {
|
||||
if (!filename) return;
|
||||
|
||||
const imageDirectories = ['full', 'thumb', 'placeholder'];
|
||||
|
||||
// Extract basename to handle both hashed and unhashed versions
|
||||
const basename = filename
|
||||
.replace(/\.[a-f0-9]{8}\.webp$/, '') // Remove hash if present
|
||||
.replace(/\.webp$/, ''); // Remove extension
|
||||
|
||||
const unhashedFilename = basename + '.webp';
|
||||
|
||||
for (const dir of imageDirectories) {
|
||||
// Delete hashed version (if it's the hashed filename that was passed in)
|
||||
if (filename !== unhashedFilename) {
|
||||
try {
|
||||
await unlink(join(IMAGE_DIR, 'rezepte', dir, filename));
|
||||
console.log(`Deleted hashed image: ${dir}/${filename}`);
|
||||
} catch (err) {
|
||||
console.warn(`Could not delete hashed image ${dir}/${filename}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete unhashed version
|
||||
try {
|
||||
await unlink(join(IMAGE_DIR, 'rezepte', dir, unhashedFilename));
|
||||
console.log(`Deleted unhashed image: ${dir}/${unhashedFilename}`);
|
||||
} catch (err) {
|
||||
console.warn(`Could not delete unhashed image ${dir}/${unhashedFilename}:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch, params, locals}) => {
|
||||
// Edit is German-only - redirect to German version
|
||||
if (params.recipeLang === 'recipes') {
|
||||
@@ -79,7 +116,11 @@ export const actions = {
|
||||
const existingImagePath = formData.get('existing_image_path')?.toString();
|
||||
|
||||
if (uploadedImage) {
|
||||
// New image uploaded - use it
|
||||
// New image uploaded - delete old image files and use new one
|
||||
if (existingImagePath && existingImagePath !== uploadedImage) {
|
||||
await deleteRecipeImage(existingImagePath);
|
||||
}
|
||||
|
||||
recipeData.images = [{
|
||||
mediapath: uploadedImage,
|
||||
alt: existingImagePath ? (recipeData.images?.[0]?.alt || '') : '',
|
||||
|
||||
Reference in New Issue
Block a user