Files
homepage/src/routes/[recipeLang=recipeLang]/add/+page.server.ts
T
Alexander 4a931c7e30
CI / update (push) Successful in 1m54s
fix: resolve all 1008 svelte-check type errors across codebase
Add type annotations, JSDoc types, null checks, and proper generics
to eliminate all svelte-check errors. Key changes include:
- Type $state(null) variables to avoid 'never' inference
- Add JSDoc typedefs for plain <script> components
- Fix mongoose model typing with Model<any> to avoid union complexity
- Add App.Error/App.PageState interfaces in app.d.ts
- Fix tuple types to array types in types.ts
- Type catch block errors and API handler params
- Add null safety for DOM queries and optional chaining
- Add standard line-clamp property alongside -webkit- prefix
2026-03-02 08:40:18 +01:00

155 lines
4.5 KiB
TypeScript

import { redirect, fail } from "@sveltejs/kit";
import type { Actions, PageServerLoad } from './$types';
import { Recipe } from '$models/Recipe';
import { dbConnect } from '$utils/db';
import { invalidateRecipeCaches } from '$lib/server/cache';
import { IMAGE_DIR } from '$env/static/private';
import { processAndSaveRecipeImage } from '$utils/imageProcessing';
import {
extractRecipeFromFormData,
validateRecipeData,
serializeRecipeForDatabase
} from '$utils/recipeFormHelpers';
export const load: PageServerLoad = async ({locals, params}) => {
// Add is German-only - redirect to German version
if (params.recipeLang === 'recipes') {
throw redirect(301, '/rezepte/add');
}
const session = await locals.auth();
return {
user: session?.user
};
};
export const actions = {
default: async ({ request, locals, params }) => {
// Check authentication
const auth = await locals.auth();
if (!auth) {
return fail(401, {
error: 'You must be logged in to add recipes',
requiresAuth: true
});
}
try {
const formData = await request.formData();
console.log('[RecipeAdd] Form data received');
// Extract recipe data from FormData
const recipeData = extractRecipeFromFormData(formData);
console.log('[RecipeAdd] Recipe data extracted:', {
short_name: recipeData.short_name,
name: recipeData.name
});
// Validate required fields
const validationErrors = validateRecipeData(recipeData);
if (validationErrors.length > 0) {
console.error('[RecipeAdd] Validation errors:', validationErrors);
return fail(400, {
error: validationErrors.join(', '),
errors: validationErrors,
values: Object.fromEntries(formData)
});
}
// Handle optional image upload
const recipeImage = formData.get('recipe_image') as File | null;
console.log('[RecipeAdd] Recipe image from form:', {
hasImage: !!recipeImage,
size: recipeImage?.size,
name: recipeImage?.name,
type: recipeImage?.type
});
if (recipeImage && recipeImage.size > 0) {
try {
console.log('[RecipeAdd] Starting image processing...');
// Process and save the image
const { filename, color } = await processAndSaveRecipeImage(
recipeImage,
recipeData.short_name,
IMAGE_DIR
);
console.log('[RecipeAdd] Image processed successfully, filename:', filename);
recipeData.images = [{
mediapath: filename,
alt: '',
caption: '',
color
}];
} catch (imageError: any) {
console.error('[RecipeAdd] Image processing error:', imageError);
return fail(400, {
error: `Failed to process image: ${imageError.message}`,
errors: ['Image processing failed'],
values: Object.fromEntries(formData)
});
}
} else {
console.log('[RecipeAdd] No image uploaded, using placeholder');
// No image uploaded - use placeholder based on short_name
recipeData.images = [{
mediapath: `${recipeData.short_name}.webp`,
alt: '',
caption: ''
}];
}
// Serialize for database
const recipe_json = serializeRecipeForDatabase(recipeData);
// Connect to database and create recipe
await dbConnect();
try {
await Recipe.create(recipe_json);
// Invalidate recipe caches after successful creation
await invalidateRecipeCaches();
// Redirect to the new recipe page
throw redirect(303, `/${params.recipeLang}/${recipeData.short_name}`);
} catch (dbError: any) {
// Re-throw redirects (they're not errors)
if (dbError?.status >= 300 && dbError?.status < 400) {
throw dbError;
}
console.error('Database error creating recipe:', dbError);
// Check for duplicate key error
if (dbError.code === 11000) {
return fail(400, {
error: `A recipe with the short name "${recipeData.short_name}" already exists. Please choose a different short name.`,
errors: ['Duplicate short_name'],
values: Object.fromEntries(formData)
});
}
return fail(500, {
error: `Failed to create recipe: ${dbError.message || 'Unknown database error'}`,
errors: [dbError.message],
values: Object.fromEntries(formData)
});
}
} catch (error: any) {
// Re-throw redirects (they're not errors)
if (error?.status >= 300 && error?.status < 400) {
throw error;
}
console.error('Error processing recipe submission:', error);
return fail(500, {
error: `Failed to process recipe: ${error.message || 'Unknown error'}`,
errors: [error.message]
});
}
}
} satisfies Actions;