Merge branch 'develop' into url_import_recipes

# Conflicts:
#	cookbook/helper/recipe_url_import.py
#	cookbook/tests/api/test_api_keyword.py
#	cookbook/tests/other/test_edits_recipe.py
#	cookbook/views/api.py
#	requirements.txt
This commit is contained in:
vabene1111
2021-03-18 20:38:51 +01:00
137 changed files with 10564 additions and 6777 deletions

View File

@@ -0,0 +1,8 @@
from django.test.runner import DiscoverRunner
from django_scopes import scopes_disabled
class CustomTestRunner(DiscoverRunner):
def run_tests(self, *args, **kwargs):
with scopes_disabled():
return super().run_tests(*args, **kwargs)

View File

@@ -10,7 +10,7 @@ class BaseAutocomplete(autocomplete.Select2QuerySetView):
if not self.request.user.is_authenticated:
return self.model.objects.none()
qs = self.model.objects.all()
qs = self.model.objects.filter(space=self.request.space).all()
if self.q:
qs = qs.filter(name__icontains=self.q)

View File

@@ -1,6 +1,9 @@
"""
Source: https://djangosnippets.org/snippets/1703/
"""
from django.views.generic.detail import SingleObjectTemplateResponseMixin
from django.views.generic.edit import ModelFormMixin
from cookbook.models import ShareLink
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
@@ -40,8 +43,7 @@ def has_group_permission(user, groups):
return False
groups_allowed = get_allowed_groups(groups)
if user.is_authenticated:
if (user.is_superuser
| bool(user.groups.filter(name__in=groups_allowed))):
if bool(user.groups.filter(name__in=groups_allowed)):
return True
return False
@@ -56,19 +58,12 @@ def is_object_owner(user, obj):
:param obj any object that should be tested
:return: true if user is owner of object, false otherwise
"""
# TODO this could be improved/cleaned up by adding
# get_owner methods to all models that allow owner checks
if not user.is_authenticated:
return False
if user.is_superuser:
return True
if owner := getattr(obj, 'created_by', None):
return owner == user
if owner := getattr(obj, 'user', None):
return owner == user
if getattr(obj, 'get_owner', None):
try:
return obj.get_owner() == user
return False
except:
return False
def is_object_shared(user, obj):
@@ -84,9 +79,7 @@ def is_object_shared(user, obj):
# share checks for relevant objects
if not user.is_authenticated:
return False
if user.is_superuser:
return True
return user in obj.shared.all()
return user in obj.get_shared()
def share_link_valid(recipe, share):
@@ -97,11 +90,7 @@ def share_link_valid(recipe, share):
:return: true if a share link with the given recipe and uuid exists
"""
try:
return (
True
if ShareLink.objects.filter(recipe=recipe, uuid=share).exists()
else False
)
return True if ShareLink.objects.filter(recipe=recipe, uuid=share).exists() else False
except ValidationError:
return False
@@ -119,7 +108,7 @@ def group_required(*groups_required):
def in_groups(u):
return has_group_permission(u, groups_required)
return user_passes_test(in_groups, login_url='view_no_group')
return user_passes_test(in_groups, login_url='view_no_perm')
class GroupRequiredMixin(object):
@@ -131,13 +120,17 @@ class GroupRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
if not has_group_permission(request.user, self.groups_required):
messages.add_message(
request,
messages.ERROR,
_('You do not have the required permissions to view this page!') # noqa: E501
)
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
return HttpResponseRedirect(reverse_lazy('index'))
try:
obj = self.get_object()
if obj.get_space() != request.space:
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
return HttpResponseRedirect(reverse_lazy('index'))
except AttributeError:
pass
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
@@ -145,25 +138,22 @@ class OwnerRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
messages.add_message(
request,
messages.ERROR,
_('You are not logged in and therefore cannot view this page!')
)
return HttpResponseRedirect(
reverse_lazy('account_login') + '?next=' + request.path
)
messages.add_message(request, messages.ERROR, _('You are not logged in and therefore cannot view this page!'))
return HttpResponseRedirect(reverse_lazy('account_login') + '?next=' + request.path)
else:
if not is_object_owner(request.user, self.get_object()):
messages.add_message(
request,
messages.ERROR,
_('You cannot interact with this object as it is not owned by you!') # noqa: E501
)
messages.add_message(request, messages.ERROR, _('You cannot interact with this object as it is not owned by you!'))
return HttpResponseRedirect(reverse('index'))
return super(OwnerRequiredMixin, self) \
.dispatch(request, *args, **kwargs)
try:
obj = self.get_object()
if obj.get_space() != request.space:
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
return HttpResponseRedirect(reverse_lazy('index'))
except AttributeError:
pass
return super(OwnerRequiredMixin, self).dispatch(request, *args, **kwargs)
# Django Rest Framework Permission classes

View File

@@ -13,7 +13,7 @@ from django.utils.translation import gettext as _
from recipe_scrapers import _utils
def get_from_html(html_text, url):
def get_from_html(html_text, url, space):
soup = BeautifulSoup(html_text, "html.parser")
# first try finding ld+json as its most common
@@ -32,7 +32,7 @@ def get_from_html(html_text, url):
if ('@type' in ld_json_item
and ld_json_item['@type'] == 'Recipe'):
return JsonResponse(find_recipe_json(ld_json_item, url))
return JsonResponse(find_recipe_json(ld_json_item, url, space))
except JSONDecodeError:
return JsonResponse(
{
@@ -46,7 +46,7 @@ def get_from_html(html_text, url):
for i in items:
md_json = json.loads(i.json())
if 'schema.org/Recipe' in str(md_json['type']):
return JsonResponse(find_recipe_json(md_json['properties'], url))
return JsonResponse(find_recipe_json(md_json['properties'], url, space))
return JsonResponse(
{
@@ -56,7 +56,7 @@ def get_from_html(html_text, url):
status=400)
def find_recipe_json(ld_json, url):
def find_recipe_json(ld_json, url, space):
if type(ld_json['name']) == list:
try:
ld_json['name'] = ld_json['name'][0]
@@ -85,6 +85,7 @@ def find_recipe_json(ld_json, url):
for x in ld_json['recipeIngredient']:
if x.replace(' ', '') != '':
x = x.replace('½', "0.5").replace('¼', "0.25").replace('¾', "0.75")
try:
amount, unit, ingredient, note = parse_ingredient(x)
if ingredient:

View File

@@ -0,0 +1,33 @@
from django.shortcuts import redirect
from django.urls import reverse
from django_scopes import scope, scopes_disabled
from cookbook.views import views
class ScopeMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
if request.path.startswith('/admin/'):
with scopes_disabled():
return self.get_response(request)
with scopes_disabled():
if request.user.userpreference.space is None and not reverse('account_logout') in request.path:
return views.no_space(request)
if request.user.groups.count() == 0 and not reverse('account_logout') in request.path:
return views.no_groups(request)
request.space = request.user.userpreference.space
# with scopes_disabled():
with scope(space=request.space):
return self.get_response(request)
else:
with scopes_disabled():
request.space = None
return self.get_response(request)

View File

@@ -1,6 +1,6 @@
import bleach
import markdown as md
from bleach_whitelist import markdown_attrs, markdown_tags
from bleach_allowlist import markdown_attrs, markdown_tags
from cookbook.helper.mdx_attributes import MarkdownFormatExtension
from cookbook.helper.mdx_urlize import UrlizeExtension
from jinja2 import Template, TemplateSyntaxError