From 0371874670dd46806f3997a87afc8f9a128bdb00 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 3 Nov 2025 14:43:22 -0600 Subject: [PATCH] fix: Refactor Recipe Zip File Flow (#6170) --- docs/docs/overrides/api.html | 2 +- .../RecipeContextMenuContent.vue | 11 +++-- frontend/composables/api/use-downloader.ts | 10 +++++ frontend/lib/api/types/recipe.ts | 3 -- frontend/lib/api/user/recipes/recipe-share.ts | 5 +++ frontend/lib/api/user/recipes/recipe.ts | 11 ----- frontend/pages/g/[groupSlug]/r/create/zip.vue | 30 ++++++++------ mealie/core/dependencies/dependencies.py | 30 -------------- mealie/core/security/security.py | 5 --- mealie/routes/recipe/exports.py | 41 +------------------ mealie/routes/recipe/shared_routes.py | 27 +++++++++++- mealie/schema/recipe/__init__.py | 3 +- mealie/schema/recipe/request_helpers.py | 4 -- .../test_recipe_export_as.py | 14 ++++--- tests/utils/api_routes/__init__.py | 10 ++--- 15 files changed, 81 insertions(+), 125 deletions(-) diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 9f2cb2547..637c4237b 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/frontend/components/Domain/Recipe/RecipeContextMenu/RecipeContextMenuContent.vue b/frontend/components/Domain/Recipe/RecipeContextMenu/RecipeContextMenuContent.vue index f78832eef..953c948c9 100644 --- a/frontend/components/Domain/Recipe/RecipeContextMenu/RecipeContextMenuContent.vue +++ b/frontend/components/Domain/Recipe/RecipeContextMenu/RecipeContextMenuContent.vue @@ -377,11 +377,14 @@ async function deleteRecipe() { const download = useDownloader(); async function handleDownloadEvent() { - const { data } = await api.recipes.getZipToken(props.slug); - - if (data) { - download(api.recipes.getZipRedirectUrl(props.slug, data.token), `${props.slug}.zip`); + const { data: shareToken } = await api.recipes.share.createOne({ recipeId: props.recipeId }); + if (!shareToken) { + console.error("No share token received"); + alert.error(i18n.t("events.something-went-wrong")); + return; } + + download(api.recipes.share.getZipRedirectUrl(shareToken.id), `${props.slug}.zip`); } async function addRecipeToPlan() { diff --git a/frontend/composables/api/use-downloader.ts b/frontend/composables/api/use-downloader.ts index 4cecca9d0..1208000cb 100644 --- a/frontend/composables/api/use-downloader.ts +++ b/frontend/composables/api/use-downloader.ts @@ -1,9 +1,19 @@ +import { alert } from "~/composables/use-toast"; +import { useGlobalI18n } from "~/composables/use-global-i18n"; + export function useDownloader() { function download(url: string, filename: string) { useFetch(url, { method: "GET", responseType: "blob", onResponse({ response }) { + if (!response.ok) { + console.error("Download failed", response); + const i18n = useGlobalI18n(); + alert.error(i18n.t("events.something-went-wrong")); + return; + } + const url = window.URL.createObjectURL(new Blob([response._data])); const link = document.createElement("a"); link.href = url; diff --git a/frontend/lib/api/types/recipe.ts b/frontend/lib/api/types/recipe.ts index 7b34ac8a3..51491de3b 100644 --- a/frontend/lib/api/types/recipe.ts +++ b/frontend/lib/api/types/recipe.ts @@ -470,9 +470,6 @@ export interface RecipeToolSave { householdsWithTool?: string[]; groupId: string; } -export interface RecipeZipTokenResponse { - token: string; -} export interface SaveIngredientFood { id?: string | null; name: string; diff --git a/frontend/lib/api/user/recipes/recipe-share.ts b/frontend/lib/api/user/recipes/recipe-share.ts index 306d378f6..c55c0d932 100644 --- a/frontend/lib/api/user/recipes/recipe-share.ts +++ b/frontend/lib/api/user/recipes/recipe-share.ts @@ -6,9 +6,14 @@ const prefix = "/api"; const routes = { shareToken: `${prefix}/shared/recipes`, shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`, + shareTokenIdZip: (id: string) => `${prefix}/recipes/shared/${id}/zip`, }; export class RecipeShareApi extends BaseCRUDAPI