fixed test + added api doc for new search

This commit is contained in:
vabene1111 2021-04-18 15:01:39 +02:00
parent e676b4bac3
commit 4ad5d6ef2f
5 changed files with 59 additions and 40 deletions

View File

@ -17,7 +17,6 @@ def search_recipes(queryset, params):
search_books_or = params.get('books_or', True) search_books_or = params.get('books_or', True)
search_internal = params.get('internal', None) search_internal = params.get('internal', None)
search_limit = params.get('limit', None)
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']: if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']:
queryset = queryset.annotate(similarity=TrigramSimilarity('name', search_string), ).filter(Q(similarity__gt=0.1) | Q(name__unaccent__icontains=search_string)).order_by('-similarity') queryset = queryset.annotate(similarity=TrigramSimilarity('name', search_string), ).filter(Q(similarity__gt=0.1) | Q(name__unaccent__icontains=search_string)).order_by('-similarity')
@ -50,7 +49,4 @@ def search_recipes(queryset, params):
if search_internal == 'true': if search_internal == 'true':
queryset = queryset.filter(internal=True) queryset = queryset.filter(internal=True)
# if search_limit:
# queryset = queryset[:int(search_limit)]
return queryset return queryset

View File

@ -517,7 +517,7 @@
} }
this.$http.get(url).then((response) => { this.$http.get(url).then((response) => {
this.recipes = response.data; this.recipes = response.data.results;
}).catch((err) => { }).catch((err) => {
console.log("getRecipes error: ", err); console.log("getRecipes error: ", err);
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger') this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')
@ -530,7 +530,7 @@
} }
this.$http.get(url).then((response) => { this.$http.get(url).then((response) => {
this.recipes = response.data; this.recipes = response.data.results;
}).catch((err) => { }).catch((err) => {
console.log("getRecipes error: ", err); console.log("getRecipes error: ", err);
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger') this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')

View File

@ -834,7 +834,7 @@
} }
this.$http.get(url).then((response) => { this.$http.get(url).then((response) => {
this.recipes = response.data; this.recipes = response.data.results;
}).catch((err) => { }).catch((err) => {
console.log("getRecipes error: ", err); console.log("getRecipes error: ", err);
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger') this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')

View File

@ -22,15 +22,15 @@ def test_list_permission(arg, request):
def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2): def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2):
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1 assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 1
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0 assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 0
with scopes_disabled(): with scopes_disabled():
recipe_1_s1.space = space_2 recipe_1_s1.space = space_2
recipe_1_s1.save() recipe_1_s1.save()
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 0 assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 0
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1 assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1
@pytest.mark.parametrize("arg", [ @pytest.mark.parametrize("arg", [

View File

@ -4,13 +4,11 @@ import re
import uuid import uuid
import requests import requests
import yaml
from PIL import Image from PIL import Image
from annoying.decorators import ajax_request from annoying.decorators import ajax_request
from annoying.functions import get_object_or_None from annoying.functions import get_object_or_None
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import management
from django.core.exceptions import FieldError, ValidationError from django.core.exceptions import FieldError, ValidationError
from django.core.files import File from django.core.files import File
from django.db.models import Q from django.db.models import Q
@ -18,19 +16,21 @@ from django.http import FileResponse, HttpResponse, JsonResponse
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from icalendar import Calendar, Event from icalendar import Calendar, Event
from rest_framework import decorators, viewsets, status from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode
from rest_framework.exceptions import APIException, PermissionDenied, NotFound, MethodNotAllowed from rest_framework import decorators, viewsets
from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination from rest_framework.exceptions import APIException, PermissionDenied
from rest_framework.pagination import PageNumberPagination
from rest_framework.parsers import MultiPartParser from rest_framework.parsers import MultiPartParser
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.schemas import AutoSchema from rest_framework.schemas.openapi import AutoSchema
from rest_framework.schemas.utils import is_list_view
from rest_framework.viewsets import ViewSetMixin from rest_framework.viewsets import ViewSetMixin
from cookbook.helper.ingredient_parser import parse from cookbook.helper.ingredient_parser import parse
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
CustomIsOwner, CustomIsShare, CustomIsOwner, CustomIsShare,
CustomIsShared, CustomIsUser, CustomIsShared, CustomIsUser,
group_required, share_link_valid) group_required)
from cookbook.helper.recipe_search import search_recipes from cookbook.helper.recipe_search import search_recipes
from cookbook.helper.recipe_url_import import get_from_html, get_from_scraper, find_recipe_json from cookbook.helper.recipe_url_import import get_from_html, get_from_scraper, find_recipe_json
from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan, from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan,
@ -55,7 +55,6 @@ from cookbook.serializer import (FoodSerializer, IngredientSerializer,
ViewLogSerializer, CookLogSerializer, RecipeBookEntrySerializer, ViewLogSerializer, CookLogSerializer, RecipeBookEntrySerializer,
RecipeOverviewSerializer, SupermarketSerializer, ImportLogSerializer) RecipeOverviewSerializer, SupermarketSerializer, ImportLogSerializer)
from recipes.settings import DEMO from recipes.settings import DEMO
from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode
class StandardFilterMixin(ViewSetMixin): class StandardFilterMixin(ViewSetMixin):
@ -281,34 +280,58 @@ class RecipePagination(PageNumberPagination):
max_page_size = 100 max_page_size = 100
from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator # TODO move to separate class to cleanup
class RecipeSchema(AutoSchema): class RecipeSchema(AutoSchema):
def get_path_parameters(self, path, method): def get_path_parameters(self, path, method):
if not is_list_view(path, method, self.view):
return []
parameters = super().get_path_parameters(path, method) parameters = super().get_path_parameters(path, method)
parameters.append( parameters.append({
{ "name": 'query', "in": "query", "required": False,
"name": 'query', "description": 'Query string matched (fuzzy) against recipe name. In the future also fulltext search.',
"in": "path", 'schema': {'type': 'string', },
"required": True, })
"description": 'description', parameters.append({
'schema': { "name": 'keywords', "in": "query", "required": False,
'type': 'string', # TODO: integer, pattern, ... "description": 'Id of keyword a recipe should have. For multiple repeat parameter.',
}, 'schema': {'type': 'string', },
} })
) parameters.append({
"name": 'foods', "in": "query", "required": False,
"description": 'Id of food a recipe should have. For multiple repeat parameter.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'books', "in": "query", "required": False,
"description": 'Id of book a recipe should have. For multiple repeat parameter.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'keywords_or', "in": "query", "required": False,
"description": 'If recipe should have all (AND) or any (OR) of the provided keywords.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'foods_or', "in": "query", "required": False,
"description": 'If recipe should have all (AND) or any (OR) any of the provided foods.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'books_or', "in": "query", "required": False,
"description": 'If recipe should be in all (AND) or any (OR) any of the provided books.',
'schema': {'type': 'string', },
})
parameters.append({
"name": 'internal', "in": "query", "required": False,
"description": 'true or false. If only internal recipes should be returned or not.',
'schema': {'type': 'string', },
})
return parameters return parameters
class RecipeViewSet(viewsets.ModelViewSet): class RecipeViewSet(viewsets.ModelViewSet):
"""
list:
optional parameters
- **query**: search recipes for a string contained in the recipe name (case in-sensitive)
- **limit**: limits the amount of returned results
"""
queryset = Recipe.objects queryset = Recipe.objects
serializer_class = RecipeSerializer serializer_class = RecipeSerializer
# TODO split read and write permission for meal plan guest # TODO split read and write permission for meal plan guest
@ -316,7 +339,7 @@ class RecipeViewSet(viewsets.ModelViewSet):
pagination_class = RecipePagination pagination_class = RecipePagination
# schema = RecipeSchema schema = RecipeSchema()
def get_queryset(self): def get_queryset(self):
share = self.request.query_params.get('share', None) share = self.request.query_params.get('share', None)