mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-02 20:59:28 -05:00
remove facets and treeselect
This commit is contained in:
@@ -3,7 +3,6 @@ import io
|
||||
import json
|
||||
import mimetypes
|
||||
import pathlib
|
||||
import random
|
||||
import re
|
||||
import threading
|
||||
import traceback
|
||||
@@ -15,7 +14,6 @@ from zipfile import ZipFile
|
||||
|
||||
import requests
|
||||
import validators
|
||||
from PIL import UnidentifiedImageError
|
||||
from annoying.decorators import ajax_request
|
||||
from annoying.functions import get_object_or_None
|
||||
from django.contrib import messages
|
||||
@@ -24,7 +22,7 @@ from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.core.cache import caches
|
||||
from django.core.exceptions import FieldError, ValidationError
|
||||
from django.core.files import File
|
||||
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When, Avg, Max
|
||||
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When
|
||||
from django.db.models.fields.related import ForeignObjectRel
|
||||
from django.db.models.functions import Coalesce, Lower
|
||||
from django.db.models.signals import post_save
|
||||
@@ -36,6 +34,7 @@ from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from icalendar import Calendar, Event
|
||||
from oauth2_provider.models import AccessToken
|
||||
from PIL import UnidentifiedImageError
|
||||
from recipe_scrapers import scrape_me
|
||||
from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
|
||||
from requests.exceptions import MissingSchema
|
||||
@@ -58,35 +57,41 @@ from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.image_processing import handle_image
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.open_data_importer import OpenDataImporter
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
|
||||
CustomIsOwnerReadOnly, CustomIsShared,
|
||||
CustomIsSpaceOwner, CustomIsUser, group_required,
|
||||
is_space_owner, switch_user_active_space, above_space_limit,
|
||||
CustomRecipePermission, CustomUserPermission,
|
||||
CustomTokenHasReadWriteScope, CustomTokenHasScope, has_group_permission, IsReadOnlyDRF)
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup, clean_dict
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner, CustomIsOwnerReadOnly,
|
||||
CustomIsShared, CustomIsSpaceOwner, CustomIsUser,
|
||||
CustomRecipePermission, CustomTokenHasReadWriteScope,
|
||||
CustomTokenHasScope, CustomUserPermission,
|
||||
IsReadOnlyDRF, above_space_limit, group_required,
|
||||
has_group_permission, is_space_owner,
|
||||
switch_user_active_space)
|
||||
from cookbook.helper.recipe_search import RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import (clean_dict, get_from_youtube_scraper,
|
||||
get_images_from_soup)
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
|
||||
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, ExportLog, Food,
|
||||
FoodInheritField, ImportLog, Ingredient, InviteLink, Keyword, MealPlan,
|
||||
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, PropertyType, Property)
|
||||
MealType, Property, PropertyType, Recipe, RecipeBook, RecipeBookEntry,
|
||||
ShareLink, ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space,
|
||||
Step, Storage, Supermarket, SupermarketCategory,
|
||||
SupermarketCategoryRelation, Sync, SyncLog, Unit, UnitConversion,
|
||||
UserFile, UserPreference, UserSpace, ViewLog)
|
||||
from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.local import Local
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
|
||||
from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSerializer,
|
||||
from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer,
|
||||
AutoMealPlanSerializer, BookmarkletImportListSerializer,
|
||||
BookmarkletImportSerializer, CookLogSerializer,
|
||||
CustomFilterSerializer, ExportLogSerializer,
|
||||
FoodInheritFieldSerializer, FoodSerializer,
|
||||
FoodShoppingUpdateSerializer, GroupSerializer, ImportLogSerializer,
|
||||
IngredientSerializer, IngredientSimpleSerializer,
|
||||
InviteLinkSerializer, KeywordSerializer, MealPlanSerializer,
|
||||
MealTypeSerializer, RecipeBookEntrySerializer,
|
||||
RecipeBookSerializer, RecipeFromSourceSerializer,
|
||||
FoodShoppingUpdateSerializer, FoodSimpleSerializer,
|
||||
GroupSerializer, ImportLogSerializer, IngredientSerializer,
|
||||
IngredientSimpleSerializer, InviteLinkSerializer,
|
||||
KeywordSerializer, MealPlanSerializer, MealTypeSerializer,
|
||||
PropertySerializer, PropertyTypeSerializer,
|
||||
RecipeBookEntrySerializer, RecipeBookSerializer,
|
||||
RecipeExportSerializer, RecipeFromSourceSerializer,
|
||||
RecipeImageSerializer, RecipeOverviewSerializer, RecipeSerializer,
|
||||
RecipeShoppingUpdateSerializer, RecipeSimpleSerializer,
|
||||
ShoppingListAutoSyncSerializer, ShoppingListEntrySerializer,
|
||||
@@ -94,11 +99,9 @@ from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSeri
|
||||
SpaceSerializer, StepSerializer, StorageSerializer,
|
||||
SupermarketCategoryRelationSerializer,
|
||||
SupermarketCategorySerializer, SupermarketSerializer,
|
||||
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
||||
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
||||
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer,
|
||||
RecipeExportSerializer, UnitConversionSerializer, PropertyTypeSerializer,
|
||||
PropertySerializer, AutoMealPlanSerializer)
|
||||
SyncLogSerializer, SyncSerializer, UnitConversionSerializer,
|
||||
UnitSerializer, UserFileSerializer, UserPreferenceSerializer,
|
||||
UserSerializer, UserSpaceSerializer, ViewLogSerializer)
|
||||
from cookbook.views.import_export import get_integration
|
||||
from recipes import settings
|
||||
|
||||
@@ -186,7 +189,8 @@ class FuzzyFilterMixin(ViewSetMixin, ExtendedRecipeMixin):
|
||||
if query is not None and query not in ["''", '']:
|
||||
if fuzzy and (settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||
'django.db.backends.postgresql']):
|
||||
if self.request.user.is_authenticated and any([self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
||||
if self.request.user.is_authenticated and any(
|
||||
[self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name__unaccent', query))
|
||||
else:
|
||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name', query))
|
||||
@@ -367,7 +371,7 @@ class TreeMixin(MergeMixin, FuzzyFilterMixin, ExtendedRecipeMixin):
|
||||
child.move(parent, f'{node_location}-child')
|
||||
content = {'msg': _(f'{child.name} was moved successfully to parent {parent.name}')}
|
||||
return Response(content, status=status.HTTP_200_OK)
|
||||
except (PathOverflow, InvalidMoveToDescendant, InvalidPosition) as e:
|
||||
except (PathOverflow, InvalidMoveToDescendant, InvalidPosition):
|
||||
content = {'error': True, 'msg': _('An error occurred attempting to move ') + child.name}
|
||||
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -775,8 +779,7 @@ class StepViewSet(viewsets.ModelViewSet):
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
query_params = [
|
||||
QueryParam(name='recipe', description=_('ID of recipe a step is part of. For multiple repeat parameter.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='recipe', description=_('ID of recipe a step is part of. For multiple repeat parameter.'), qtype='int'),
|
||||
QueryParam(name='query', description=_('Query string matched (fuzzy) against object name.'), qtype='string'),
|
||||
]
|
||||
schema = QueryParamAutoSchema()
|
||||
@@ -799,7 +802,6 @@ class RecipePagination(PageNumberPagination):
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
if queryset is None:
|
||||
raise Exception
|
||||
self.facets = RecipeFacet(request, queryset=queryset)
|
||||
return super().paginate_queryset(queryset, request, view)
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
@@ -808,7 +810,6 @@ class RecipePagination(PageNumberPagination):
|
||||
('next', self.get_next_link()),
|
||||
('previous', self.get_previous_link()),
|
||||
('results', data),
|
||||
('facets', self.facets.get_facets(from_cache=True))
|
||||
]))
|
||||
|
||||
|
||||
@@ -820,63 +821,33 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
pagination_class = RecipePagination
|
||||
|
||||
query_params = [
|
||||
QueryParam(name='query', description=_(
|
||||
'Query string matched (fuzzy) against recipe name. In the future also fulltext search.')),
|
||||
QueryParam(name='keywords', description=_(
|
||||
'ID of keyword a recipe should have. For multiple repeat parameter. Equivalent to keywords_or'),
|
||||
qtype='int'),
|
||||
QueryParam(name='keywords_or',
|
||||
description=_('Keyword IDs, repeat for multiple. Return recipes with any of the keywords'),
|
||||
qtype='int'),
|
||||
QueryParam(name='keywords_and',
|
||||
description=_('Keyword IDs, repeat for multiple. Return recipes with all of the keywords.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='keywords_or_not',
|
||||
description=_('Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='keywords_and_not',
|
||||
description=_('Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='foods', description=_('ID of food a recipe should have. For multiple repeat parameter.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='foods_or',
|
||||
description=_('Food IDs, repeat for multiple. Return recipes with any of the foods'), qtype='int'),
|
||||
QueryParam(name='foods_and',
|
||||
description=_('Food IDs, repeat for multiple. Return recipes with all of the foods.'), qtype='int'),
|
||||
QueryParam(name='foods_or_not',
|
||||
description=_('Food IDs, repeat for multiple. Exclude recipes with any of the foods.'), qtype='int'),
|
||||
QueryParam(name='foods_and_not',
|
||||
description=_('Food IDs, repeat for multiple. Exclude recipes with all of the foods.'), qtype='int'),
|
||||
QueryParam(name='query', description=_('Query string matched (fuzzy) against recipe name. In the future also fulltext search.')),
|
||||
QueryParam(name='keywords', description=_('ID of keyword a recipe should have. For multiple repeat parameter. Equivalent to keywords_or'), qtype='int'),
|
||||
QueryParam(name='keywords_or', description=_('Keyword IDs, repeat for multiple. Return recipes with any of the keywords'), qtype='int'),
|
||||
QueryParam(name='keywords_and', description=_('Keyword IDs, repeat for multiple. Return recipes with all of the keywords.'), qtype='int'),
|
||||
QueryParam(name='keywords_or_not', description=_('Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords.'), qtype='int'),
|
||||
QueryParam(name='keywords_and_not', description=_('Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords.'), qtype='int'),
|
||||
QueryParam(name='foods', description=_('ID of food a recipe should have. For multiple repeat parameter.'), qtype='int'),
|
||||
QueryParam(name='foods_or', description=_('Food IDs, repeat for multiple. Return recipes with any of the foods'), qtype='int'),
|
||||
QueryParam(name='foods_and', description=_('Food IDs, repeat for multiple. Return recipes with all of the foods.'), qtype='int'),
|
||||
QueryParam(name='foods_or_not', description=_('Food IDs, repeat for multiple. Exclude recipes with any of the foods.'), qtype='int'),
|
||||
QueryParam(name='foods_and_not', description=_('Food IDs, repeat for multiple. Exclude recipes with all of the foods.'), qtype='int'),
|
||||
QueryParam(name='units', description=_('ID of unit a recipe should have.'), qtype='int'),
|
||||
QueryParam(name='rating', description=_(
|
||||
'Rating a recipe should have or greater. [0 - 5] Negative value filters rating less than.'), qtype='int'),
|
||||
QueryParam(name='rating', description=_('Rating a recipe should have or greater. [0 - 5] Negative value filters rating less than.'), qtype='int'),
|
||||
QueryParam(name='books', description=_('ID of book a recipe should be in. For multiple repeat parameter.')),
|
||||
QueryParam(name='books_or',
|
||||
description=_('Book IDs, repeat for multiple. Return recipes with any of the books'), qtype='int'),
|
||||
QueryParam(name='books_and',
|
||||
description=_('Book IDs, repeat for multiple. Return recipes with all of the books.'), qtype='int'),
|
||||
QueryParam(name='books_or_not',
|
||||
description=_('Book IDs, repeat for multiple. Exclude recipes with any of the books.'), qtype='int'),
|
||||
QueryParam(name='books_and_not',
|
||||
description=_('Book IDs, repeat for multiple. Exclude recipes with all of the books.'), qtype='int'),
|
||||
QueryParam(name='internal',
|
||||
description=_('If only internal recipes should be returned. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='random',
|
||||
description=_('Returns the results in randomized order. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='new',
|
||||
description=_('Returns new results first in search results. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='timescooked', description=_(
|
||||
'Filter recipes cooked X times or more. Negative values returns cooked less than X times'), qtype='int'),
|
||||
QueryParam(name='cookedon', description=_(
|
||||
'Filter recipes last cooked on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='createdon', description=_(
|
||||
'Filter recipes created on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='updatedon', description=_(
|
||||
'Filter recipes updated on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='viewedon', description=_(
|
||||
'Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='makenow',
|
||||
description=_('Filter recipes that can be made with OnHand food. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='books_or', description=_('Book IDs, repeat for multiple. Return recipes with any of the books'), qtype='int'),
|
||||
QueryParam(name='books_and', description=_('Book IDs, repeat for multiple. Return recipes with all of the books.'), qtype='int'),
|
||||
QueryParam(name='books_or_not', description=_('Book IDs, repeat for multiple. Exclude recipes with any of the books.'), qtype='int'),
|
||||
QueryParam(name='books_and_not', description=_('Book IDs, repeat for multiple. Exclude recipes with all of the books.'), qtype='int'),
|
||||
QueryParam(name='internal', description=_('If only internal recipes should be returned. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='random', description=_('Returns the results in randomized order. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='new', description=_('Returns new results first in search results. [''true''/''<b>false</b>'']')),
|
||||
QueryParam(name='timescooked', description=_('Filter recipes cooked X times or more. Negative values returns cooked less than X times'), qtype='int'),
|
||||
QueryParam(name='cookedon', description=_('Filter recipes last cooked on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='createdon', description=_('Filter recipes created on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='updatedon', description=_('Filter recipes updated on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='viewedon', description=_('Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending ''-'' filters on or before date.')),
|
||||
QueryParam(name='makenow', description=_('Filter recipes that can be made with OnHand food. [''true''/''<b>false</b>'']')),
|
||||
]
|
||||
schema = QueryParamAutoSchema()
|
||||
|
||||
@@ -1095,17 +1066,10 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = ShoppingListEntrySerializer
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
query_params = [
|
||||
QueryParam(name='id',
|
||||
description=_('Returns the shopping list entry with a primary key of id. Multiple values allowed.'),
|
||||
qtype='int'),
|
||||
QueryParam(
|
||||
name='checked',
|
||||
description=_(
|
||||
'Filter shopping list entries on checked. [''true'', ''false'', ''both'', ''<b>recent</b>'']<br> - ''recent'' includes unchecked items and recently completed items.')
|
||||
),
|
||||
QueryParam(name='supermarket',
|
||||
description=_('Returns the shopping list entries sorted by supermarket category order.'),
|
||||
qtype='int'),
|
||||
QueryParam(name='id', description=_('Returns the shopping list entry with a primary key of id. Multiple values allowed.'), qtype='int'),
|
||||
QueryParam(name='checked', description=_('Filter shopping list entries on checked. [''true'', ''false'', ''both'', ''<b>recent</b>'']<br> - ''recent'' includes unchecked items and recently completed items.')
|
||||
),
|
||||
QueryParam(name='supermarket', description=_('Returns the shopping list entries sorted by supermarket category order.'), qtype='int'),
|
||||
]
|
||||
schema = QueryParamAutoSchema()
|
||||
|
||||
@@ -1344,12 +1308,10 @@ def recipe_from_source(request):
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
elif url and not data:
|
||||
if re.match('^(https?://)?(www\.youtube\.com|youtu\.be)/.+$', url):
|
||||
if re.match('^(https?://)?(www\\.youtube\\.com|youtu\\.be)/.+$', url):
|
||||
if validators.url(url, public=True):
|
||||
return Response({
|
||||
'recipe_json': get_from_youtube_scraper(url, request),
|
||||
# 'recipe_tree': '',
|
||||
# 'recipe_html': '',
|
||||
'recipe_images': [],
|
||||
}, status=status.HTTP_200_OK)
|
||||
if re.match(
|
||||
@@ -1412,8 +1374,6 @@ def recipe_from_source(request):
|
||||
if scrape:
|
||||
return Response({
|
||||
'recipe_json': helper.get_from_scraper(scrape, request),
|
||||
# 'recipe_tree': recipe_tree,
|
||||
# 'recipe_html': recipe_html,
|
||||
'recipe_images': list(dict.fromkeys(get_images_from_soup(scrape.soup, url))),
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
@@ -1437,7 +1397,7 @@ def reset_food_inheritance(request):
|
||||
try:
|
||||
Food.reset_inheritance(space=request.space)
|
||||
return Response({'message': 'success', }, status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -1457,7 +1417,7 @@ def switch_active_space(request, space_id):
|
||||
return Response(UserSpaceSerializer().to_representation(instance=user_space), status=status.HTTP_200_OK)
|
||||
else:
|
||||
return Response("not found", status=status.HTTP_404_NOT_FOUND)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -1482,7 +1442,7 @@ def download_file(request, file_id):
|
||||
response['Content-Disposition'] = 'attachment; filename="' + uf.name + '.zip"'
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -1707,25 +1667,3 @@ def ingredient_from_string(request):
|
||||
},
|
||||
status=200
|
||||
)
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def get_facets(request):
|
||||
key = request.GET.get('hash', None)
|
||||
food = request.GET.get('food', None)
|
||||
keyword = request.GET.get('keyword', None)
|
||||
facets = RecipeFacet(request, hash_key=key)
|
||||
|
||||
if food:
|
||||
results = facets.add_food_children(food)
|
||||
elif keyword:
|
||||
results = facets.add_keyword_children(keyword)
|
||||
else:
|
||||
results = facets.get_facets()
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
'facets': results,
|
||||
},
|
||||
status=200
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user