From b2673d75bffc5dbe7dfe69d9fdebe0e8fb26aa34 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sun, 5 Dec 2021 11:55:46 -0900 Subject: [PATCH] Feature/shareable recipes (#866) * simplify context menu * move computed to comp-api * feat: :sparkles: create share tokens for recipes for sharing recieps to non-users * feat: :sparkles: shareable recipe links with og tags --- frontend/api/_base.ts | 2 +- .../class-interfaces/recipes/recipe-share.ts | 26 ++ .../api/class-interfaces/recipes/recipe.ts | 11 +- .../components/Domain/Recipe/RecipeCard.vue | 2 +- .../Domain/Recipe/RecipeCardMobile.vue | 2 +- .../Domain/Recipe/RecipeContextMenu.vue | 49 +-- .../Recipe/RecipeDialogExtrasEditor.vue | 88 ---- .../Domain/Recipe/RecipeDialogShare.vue | 181 ++++++++ .../Domain/Recipe/RecipeInstructions.vue | 6 +- frontend/components/Layout/AppHeader.vue | 39 +- frontend/composables/recipes/index.ts | 1 + .../composables/recipes/use-recipe-meta.ts | 50 +++ frontend/layouts/basic.vue | 16 +- frontend/pages/recipe/_slug/index.vue | 63 +-- frontend/pages/shared/recipes/_id.vue | 399 ++++++++++++++++++ .../data_access_layer/access_model_factory.py | 6 + mealie/db/models/recipe/recipe.py | 3 + mealie/db/models/recipe/shared.py | 27 ++ mealie/routes/__init__.py | 2 + mealie/routes/recipe/__init__.py | 11 +- mealie/routes/recipe/shared_routes.py | 21 + mealie/routes/shared/__init__.py | 23 + mealie/schema/recipe/recipe_share_token.py | 34 ++ mealie/services/shared/__init__.py | 0 .../services/shared/recipe_shared_service.py | 51 +++ 25 files changed, 914 insertions(+), 199 deletions(-) create mode 100644 frontend/api/class-interfaces/recipes/recipe-share.ts delete mode 100644 frontend/components/Domain/Recipe/RecipeDialogExtrasEditor.vue create mode 100644 frontend/components/Domain/Recipe/RecipeDialogShare.vue create mode 100644 frontend/composables/recipes/use-recipe-meta.ts create mode 100644 frontend/pages/shared/recipes/_id.vue create mode 100644 mealie/db/models/recipe/shared.py create mode 100644 mealie/routes/recipe/shared_routes.py create mode 100644 mealie/routes/shared/__init__.py create mode 100644 mealie/schema/recipe/recipe_share_token.py create mode 100644 mealie/services/shared/__init__.py create mode 100644 mealie/services/shared/recipe_shared_service.py diff --git a/frontend/api/_base.ts b/frontend/api/_base.ts index e7383434e328..55eacc71847a 100644 --- a/frontend/api/_base.ts +++ b/frontend/api/_base.ts @@ -32,7 +32,7 @@ export abstract class BaseCRUDAPI extends BaseAPI implements CrudAPIInterf abstract baseRoute: string; abstract itemRoute(itemId: string | number): string; - async getAll(start = 0, limit = 9999, params = {}) { + async getAll(start = 0, limit = 9999, params = {} as any) { return await this.requests.get(this.baseRoute, { params: { start, limit, ...params }, }); diff --git a/frontend/api/class-interfaces/recipes/recipe-share.ts b/frontend/api/class-interfaces/recipes/recipe-share.ts new file mode 100644 index 000000000000..be00e53443c1 --- /dev/null +++ b/frontend/api/class-interfaces/recipes/recipe-share.ts @@ -0,0 +1,26 @@ +import { BaseCRUDAPI } from "~/api/_base"; + +const prefix = "/api"; + +const routes = { + shareToken: `${prefix}/shared/recipes`, + shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`, +}; + +export interface RecipeShareTokenCreate { + recipeId: number; + expiresAt?: Date; +} + +export interface RecipeShareToken { + recipeId: number; + id: string; + groupId: number; + expiresAt: string; + createdAt: string; +} + +export class RecipeShareApi extends BaseCRUDAPI { + baseRoute: string = routes.shareToken; + itemRoute = routes.shareTokenId; +} diff --git a/frontend/api/class-interfaces/recipes/recipe.ts b/frontend/api/class-interfaces/recipes/recipe.ts index 170a5a62b85a..7b270daf5c1f 100644 --- a/frontend/api/class-interfaces/recipes/recipe.ts +++ b/frontend/api/class-interfaces/recipes/recipe.ts @@ -1,5 +1,6 @@ import { CreateAsset, ParsedIngredient, Parser, RecipeZipToken, BulkCreatePayload } from "./types"; import { CommentsApi } from "./recipe-comments"; +import { RecipeShareApi } from "./recipe-share"; import { BaseCRUDAPI } from "~/api/_base"; import { Recipe, CreateRecipe } from "~/types/api-types/recipe"; @@ -26,18 +27,22 @@ const routes = { recipesSlugComments: (slug: string) => `${prefix}/recipes/${slug}/comments`, recipesSlugCommentsId: (slug: string, id: number) => `${prefix}/recipes/${slug}/comments/${id}`, + + recipeShareToken: (token: string) => `${prefix}/recipes/shared/${token}`, }; export class RecipeAPI extends BaseCRUDAPI { baseRoute: string = routes.recipesBase; itemRoute = routes.recipesRecipeSlug; - public comments: CommentsApi; + comments: CommentsApi; + share: RecipeShareApi; constructor(requests: ApiRequestInstance) { super(requests); this.comments = new CommentsApi(requests); + this.share = new RecipeShareApi(requests); } async getAllByCategory(categories: string[]) { @@ -116,4 +121,8 @@ export class RecipeAPI extends BaseCRUDAPI { getZipRedirectUrl(recipeSlug: string, token: string) { return `${routes.recipesRecipeSlugExportZip(recipeSlug)}?token=${token}`; } + + async getShared(item_id: string) { + return await this.requests.get(routes.recipeShareToken(item_id)); + } } diff --git a/frontend/components/Domain/Recipe/RecipeCard.vue b/frontend/components/Domain/Recipe/RecipeCard.vue index dde34ed10a63..9f0277a66705 100644 --- a/frontend/components/Domain/Recipe/RecipeCard.vue +++ b/frontend/components/Domain/Recipe/RecipeCard.vue @@ -34,7 +34,7 @@ :name="name" :recipe-id="recipeId" :use-items="{ - delete: true, + delete: false, edit: true, download: true, mealplanner: true, diff --git a/frontend/components/Domain/Recipe/RecipeCardMobile.vue b/frontend/components/Domain/Recipe/RecipeCardMobile.vue index 4d22d548718c..a8dfffafb4f4 100644 --- a/frontend/components/Domain/Recipe/RecipeCardMobile.vue +++ b/frontend/components/Domain/Recipe/RecipeCardMobile.vue @@ -43,7 +43,7 @@ :name="name" :recipe-id="recipeId" :use-items="{ - delete: true, + delete: false, edit: true, download: true, mealplanner: true, diff --git a/frontend/components/Domain/Recipe/RecipeContextMenu.vue b/frontend/components/Domain/Recipe/RecipeContextMenu.vue index 9694956f2e0f..fb1af4c5208d 100644 --- a/frontend/components/Domain/Recipe/RecipeContextMenu.vue +++ b/frontend/components/Domain/Recipe/RecipeContextMenu.vue @@ -1,5 +1,7 @@