added ability to mark recipes as private
This commit is contained in:
parent
51076d4ced
commit
e91790f5ac
@ -299,6 +299,27 @@ class CustomIsShare(permissions.BasePermission):
|
||||
return False
|
||||
|
||||
|
||||
class CustomRecipePermission(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission class for recipe api endpoint
|
||||
"""
|
||||
message = _('You do not have the required permissions to view this page!')
|
||||
|
||||
def has_permission(self, request, view): # user is either at least a guest or a share link is given and the request is safe
|
||||
share = request.query_params.get('share', None)
|
||||
return has_group_permission(request.user, ['guest']) or (share and request.method in SAFE_METHODS and 'pk' in view.kwargs)
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
share = request.query_params.get('share', None)
|
||||
if share:
|
||||
return share_link_valid(obj, share)
|
||||
else:
|
||||
if obj.private:
|
||||
return ((obj.created_by == request.user) or (request.user in obj.shared.all())) and obj.space == request.space
|
||||
else:
|
||||
return has_group_permission(request.user, ['guest']) and obj.space == request.space
|
||||
|
||||
|
||||
def above_space_limit(space): # TODO add file storage limit
|
||||
"""
|
||||
Test if the space has reached any limit (e.g. max recipes, users, ..)
|
||||
|
25
cookbook/migrations/0179_recipe_private_recipe_shared.py
Normal file
25
cookbook/migrations/0179_recipe_private_recipe_shared.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-13 10:53
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0178_remove_userpreference_search_style_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='recipe',
|
||||
name='private',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='recipe',
|
||||
name='shared',
|
||||
field=models.ManyToManyField(blank=True, related_name='recipe_shared_with', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
@ -738,6 +738,8 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
|
||||
internal = models.BooleanField(default=False)
|
||||
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
||||
show_ingredient_overview = models.BooleanField(default=True)
|
||||
private = models.BooleanField(default=False)
|
||||
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
||||
|
||||
source_url = models.CharField(max_length=1024, default=None, blank=True, null=True)
|
||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||
|
@ -5,7 +5,7 @@ from gettext import gettext as _
|
||||
from html import escape
|
||||
from smtplib import SMTPException
|
||||
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.auth.models import Group, User, AnonymousUser
|
||||
from django.core.mail import send_mail
|
||||
from django.db.models import Avg, Q, QuerySet, Sum
|
||||
from django.http import BadHeaderError
|
||||
@ -124,6 +124,9 @@ class SpaceFilterSerializer(serializers.ListSerializer):
|
||||
# if query is sliced it came from api request not nested serializer
|
||||
return super().to_representation(data)
|
||||
if self.child.Meta.model == User:
|
||||
if type(self.context['request'].user) == AnonymousUser:
|
||||
data = []
|
||||
else:
|
||||
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
|
||||
else:
|
||||
data = data.filter(**{'__'.join(data.model.get_space_key()): self.context['request'].space})
|
||||
@ -732,6 +735,7 @@ class RecipeSerializer(RecipeBaseSerializer):
|
||||
keywords = KeywordSerializer(many=True)
|
||||
rating = serializers.SerializerMethodField('get_recipe_rating')
|
||||
last_cooked = serializers.SerializerMethodField('get_recipe_last_cooked')
|
||||
shared = UserNameSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
@ -739,6 +743,7 @@ class RecipeSerializer(RecipeBaseSerializer):
|
||||
'id', 'name', 'description', 'image', 'keywords', 'steps', 'working_time',
|
||||
'waiting_time', 'created_by', 'created_at', 'updated_at', 'source_url',
|
||||
'internal', 'show_ingredient_overview', 'nutrition', 'servings', 'file_path', 'servings_text', 'rating', 'last_cooked',
|
||||
'private', 'shared',
|
||||
)
|
||||
read_only_fields = ['image', 'created_by', 'created_at']
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
@ -30,6 +31,7 @@ def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
|
||||
# test for space filter
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.space = space_2
|
||||
recipe_1_s1.save()
|
||||
@ -37,8 +39,23 @@ def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
|
||||
# test for private recipe filter
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.save()
|
||||
|
||||
def test_share_permission(recipe_1_s1, u1_s1, u1_s2, a_u):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s2)
|
||||
recipe_1_s1.save()
|
||||
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
|
||||
|
||||
def test_share_permission(recipe_1_s1, u1_s1, u1_s2, u2_s1, a_u):
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 200
|
||||
assert u1_s2.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 404
|
||||
|
||||
@ -52,6 +69,15 @@ def test_share_permission(recipe_1_s1, u1_s1, u1_s2, a_u):
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u1_s2.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 404 # TODO fix in https://github.com/TandoorRecipes/recipes/issues/1238
|
||||
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.save()
|
||||
|
||||
assert a_u.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u2_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u2_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
@ -80,6 +106,22 @@ def test_update(arg, request, recipe_1_s1):
|
||||
validate_recipe(j, json.loads(r.content))
|
||||
|
||||
|
||||
def test_update_private_recipe(u1_s1, u2_s1, recipe_1_s1):
|
||||
r = u1_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test1'}, content_type='application/json')
|
||||
assert r.status_code == 200
|
||||
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.save()
|
||||
|
||||
r = u1_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test2'}, content_type='application/json')
|
||||
assert r.status_code == 200
|
||||
|
||||
r = u2_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test3'}, content_type='application/json')
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 201],
|
||||
@ -107,22 +149,22 @@ def test_add(arg, request, u1_s2):
|
||||
x += 1
|
||||
|
||||
|
||||
def test_delete(u1_s1, u1_s2, recipe_1_s1):
|
||||
def test_delete(u1_s1, u1_s2, u2_s1, recipe_1_s1, recipe_2_s1):
|
||||
with scopes_disabled():
|
||||
r = u1_s2.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={recipe_1_s1.id}
|
||||
)
|
||||
)
|
||||
r = u1_s2.delete(reverse(DETAIL_URL, args={recipe_1_s1.id}))
|
||||
assert r.status_code == 404
|
||||
|
||||
r = u1_s1.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={recipe_1_s1.id}
|
||||
)
|
||||
)
|
||||
r = u1_s1.delete(reverse(DETAIL_URL, args={recipe_1_s1.id}))
|
||||
|
||||
assert r.status_code == 204
|
||||
assert not Recipe.objects.filter(pk=recipe_1_s1.id).exists()
|
||||
|
||||
recipe_2_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_2_s1.private = True
|
||||
recipe_2_s1.save()
|
||||
|
||||
r = u2_s1.delete(reverse(DETAIL_URL, args={recipe_2_s1.id}))
|
||||
assert r.status_code == 403
|
||||
|
||||
r = u1_s1.delete(reverse(DETAIL_URL, args={recipe_2_s1.id}))
|
||||
assert r.status_code == 204
|
||||
|
@ -53,7 +53,7 @@ from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, CustomIsOwner,
|
||||
CustomIsOwnerReadOnly, CustomIsShare, CustomIsShared,
|
||||
CustomIsSpaceOwner, CustomIsUser, group_required,
|
||||
is_space_owner, switch_user_active_space, above_space_limit)
|
||||
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission)
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
@ -715,7 +715,7 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
queryset = Recipe.objects
|
||||
serializer_class = RecipeSerializer
|
||||
# TODO split read and write permission for meal plan guest
|
||||
permission_classes = [CustomIsShare | CustomIsGuest]
|
||||
permission_classes = [CustomRecipePermission]
|
||||
pagination_class = RecipePagination
|
||||
|
||||
query_params = [
|
||||
@ -782,13 +782,14 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
def get_queryset(self):
|
||||
share = self.request.query_params.get('share', None)
|
||||
|
||||
if self.detail:
|
||||
if not share:
|
||||
if self.detail: # if detail request and not list, private condition is verified by permission class
|
||||
if not share: # filter for space only if not shared
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
return super().get_queryset()
|
||||
|
||||
if not (share and self.detail):
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
self.queryset = self.queryset.filter(space=self.request.space).filter(
|
||||
Q(private=False) | (Q(private=True) & (Q(created_by=self.request.user) | Q(shared=self.request.user)))
|
||||
)
|
||||
|
||||
params = {x: self.request.GET.get(x) if len({**self.request.GET}[x]) == 1 else self.request.GET.getlist(x) for x
|
||||
in list(self.request.GET)}
|
||||
@ -803,8 +804,6 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
})
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
# TODO write extensive tests for permissions
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'list':
|
||||
return RecipeOverviewSerializer
|
||||
|
@ -188,10 +188,31 @@
|
||||
</b-form-checkbox>
|
||||
|
||||
<br/>
|
||||
<label for="id_name"> {{ $t("Imported_From") }}</label>
|
||||
<label> {{ $t("Imported_From") }}</label>
|
||||
<b-form-input v-model="recipe.source_url">
|
||||
|
||||
</b-form-input>
|
||||
|
||||
<br/>
|
||||
<label> {{ $t("Private_Recipe") }}</label>
|
||||
<b-form-checkbox v-model="recipe.private">
|
||||
{{ $t('Private_Recipe_Help') }}
|
||||
</b-form-checkbox>
|
||||
|
||||
<br/>
|
||||
<label> {{ $t("Share") }}</label>
|
||||
<generic-multiselect
|
||||
@change="recipe.shared = $event.val"
|
||||
parent_variable="recipe.shared"
|
||||
:initial_selection="recipe.shared"
|
||||
:label="'username'"
|
||||
:model="Models.USER_NAME"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
v-bind:placeholder="$t('Share')"
|
||||
:limit="25"
|
||||
></generic-multiselect>
|
||||
|
||||
|
||||
</b-collapse>
|
||||
</div>
|
||||
</div>
|
||||
@ -723,6 +744,7 @@ import GenericModalForm from "@/components/Modals/GenericModalForm"
|
||||
import mavonEditor from 'mavon-editor'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import _debounce from "lodash/debounce";
|
||||
import GenericMultiselect from "@/components/GenericMultiselect";
|
||||
// use
|
||||
Vue.use(mavonEditor)
|
||||
|
||||
@ -731,7 +753,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: "RecipeEditView",
|
||||
mixins: [ResolveUrlMixin, ApiMixin],
|
||||
components: {Multiselect, LoadingSpinner, draggable, GenericModalForm},
|
||||
components: {Multiselect, LoadingSpinner, draggable, GenericModalForm, GenericMultiselect},
|
||||
data() {
|
||||
return {
|
||||
recipe_id: window.RECIPE_ID,
|
||||
|
@ -68,6 +68,10 @@
|
||||
"Enable_Amount": "Enable Amount",
|
||||
"Disable_Amount": "Disable Amount",
|
||||
"Ingredient Editor": "Ingredient Editor",
|
||||
|
||||
"Private_Recipe": "Private Recipe",
|
||||
"Private_Recipe_Help": "Recipe is only shown to you and people its shared with.",
|
||||
|
||||
"Add_Step": "Add Step",
|
||||
"Keywords": "Keywords",
|
||||
"Books": "Books",
|
||||
|
@ -8,7 +8,7 @@ axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
|
||||
|
||||
export function apiLoadRecipe(recipe_id) {
|
||||
let url = resolveDjangoUrl('api:recipe-detail', recipe_id)
|
||||
if (window.SHARE_UID !== undefined) {
|
||||
if (window.SHARE_UID !== undefined && window.SHARE_UID !== 'None') {
|
||||
url += '?share=' + window.SHARE_UID
|
||||
}
|
||||
|
||||
|
@ -2023,6 +2023,12 @@ export interface RecipeBookFilter {
|
||||
* @interface RecipeFile
|
||||
*/
|
||||
export interface RecipeFile {
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof RecipeFile
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
@ -2031,16 +2037,16 @@ export interface RecipeFile {
|
||||
name: string;
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @type {string}
|
||||
* @memberof RecipeFile
|
||||
*/
|
||||
file?: any;
|
||||
file_download?: string;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {string}
|
||||
* @memberof RecipeFile
|
||||
*/
|
||||
id?: number;
|
||||
preview?: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
@ -3540,18 +3546,6 @@ export interface UserPreference {
|
||||
* @memberof UserPreference
|
||||
*/
|
||||
use_kj?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserPreference
|
||||
*/
|
||||
search_style?: UserPreferenceSearchStyleEnum;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof UserPreference
|
||||
*/
|
||||
show_recent?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {Array<CustomFilterShared>}
|
||||
@ -3690,15 +3684,6 @@ export enum UserPreferenceDefaultPageEnum {
|
||||
Plan = 'PLAN',
|
||||
Books = 'BOOKS'
|
||||
}
|
||||
/**
|
||||
* @export
|
||||
* @enum {string}
|
||||
*/
|
||||
export enum UserPreferenceSearchStyleEnum {
|
||||
Small = 'SMALL',
|
||||
Large = 'LARGE',
|
||||
New = 'NEW'
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
@ -4713,7 +4698,40 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
|
||||
};
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json, original html,json and images
|
||||
* function to handle files passed by application importer
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createimportFiles: async (body?: any, options: any = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/api/import/`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json and images
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
@ -11014,7 +11032,17 @@ export const ApiApiFp = function(configuration?: Configuration) {
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json, original html,json and images
|
||||
* function to handle files passed by application importer
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async createimportFiles(body?: any, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<any>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.createimportFiles(body, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json and images
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
@ -13042,7 +13070,16 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
|
||||
return localVarFp.createViewLog(viewLog, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json, original html,json and images
|
||||
* function to handle files passed by application importer
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createimportFiles(body?: any, options?: any): AxiosPromise<any> {
|
||||
return localVarFp.createimportFiles(body, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json and images
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
@ -14958,7 +14995,18 @@ export class ApiApi extends BaseAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json, original html,json and images
|
||||
* function to handle files passed by application importer
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiApi
|
||||
*/
|
||||
public createimportFiles(body?: any, options?: any) {
|
||||
return ApiApiFp(this.configuration).createimportFiles(body, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* function to retrieve a recipe from a given url or source string :param request: standard request with additional post parameters - url: url to use for importing recipe - data: if no url is given recipe is imported from provided source data - (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes :return: JsonResponse containing the parsed json and images
|
||||
* @param {any} [body]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
|
Loading…
Reference in New Issue
Block a user