From 969df37e28fc8059a006ad3255f4172245dad3b4 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 7 Feb 2022 15:43:06 +0100 Subject: [PATCH] fixed sharing and added additional tests --- cookbook/serializer.py | 16 +++++++++------- cookbook/tests/api/test_api_recipe.py | 17 ++++++++++++++++- cookbook/views/api.py | 6 ++++-- vue/src/apps/RecipeView/RecipeView.vue | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 9f86906f2..9ffbbabfb 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -91,7 +91,10 @@ class CustomOnHandField(serializers.Field): if request := self.context.get('request', None): shared_users = getattr(request, '_shared_users', None) if shared_users is None: - shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [self.context['request'].user.id] + try: + shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [self.context['request'].user.id] + except AttributeError: # Anonymous users (using share links) don't have shared users + shared_users = [] return obj.onhand_users.filter(id__in=shared_users).exists() def to_internal_value(self, data): @@ -686,11 +689,11 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer): value = Decimal(value) value = value.quantize(Decimal(1)) if value == value.to_integral() else value.normalize() # strips trailing zero return ( - obj.name - or getattr(obj.mealplan, 'title', None) - or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)]) - or obj.recipe.name - ) + f' ({value:.2g})' + obj.name + or getattr(obj.mealplan, 'title', None) + or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)]) + or obj.recipe.name + ) + f' ({value:.2g})' def update(self, instance, validated_data): # TODO remove once old shopping list @@ -863,7 +866,6 @@ class ExportLogSerializer(serializers.ModelSerializer): read_only_fields = ('created_by',) - class AutomationSerializer(serializers.ModelSerializer): def create(self, validated_data): diff --git a/cookbook/tests/api/test_api_recipe.py b/cookbook/tests/api/test_api_recipe.py index 21c621c32..2ff97669e 100644 --- a/cookbook/tests/api/test_api_recipe.py +++ b/cookbook/tests/api/test_api_recipe.py @@ -4,7 +4,7 @@ import pytest from django.urls import reverse from django_scopes import scopes_disabled -from cookbook.models import Recipe +from cookbook.models import Recipe, ShareLink from cookbook.tests.conftest import get_random_json_recipe, validate_recipe LIST_URL = 'api:recipe-list' @@ -38,6 +38,21 @@ def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2): assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1 +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])).status_code == 200 + assert u1_s2.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 404 + + with scopes_disabled(): + r = u1_s1.get(reverse('new_share_link', kwargs={'pk': recipe_1_s1.pk})) + assert r.status_code == 302 + r = u1_s2.get(reverse('new_share_link', kwargs={'pk': recipe_1_s1.pk})) + assert r.status_code == 404 + share = ShareLink.objects.filter(recipe=recipe_1_s1).first() + 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 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 + + @pytest.mark.parametrize("arg", [ ['a_u', 403], ['g1_s1', 200], diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 7f13bca48..fc0eb9f9a 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -648,11 +648,13 @@ class RecipeViewSet(viewsets.ModelViewSet): schema = QueryParamAutoSchema() def get_queryset(self): + share = self.request.query_params.get('share', None) + if self.detail: - self.queryset = self.queryset.filter(space=self.request.space) + if not share: + self.queryset = self.queryset.filter(space=self.request.space) return super().get_queryset() - share = self.request.query_params.get('share', None) if not (share and self.detail): self.queryset = self.queryset.filter(space=self.request.space) diff --git a/vue/src/apps/RecipeView/RecipeView.vue b/vue/src/apps/RecipeView/RecipeView.vue index 6b09657f9..e36294fae 100644 --- a/vue/src/apps/RecipeView/RecipeView.vue +++ b/vue/src/apps/RecipeView/RecipeView.vue @@ -221,7 +221,7 @@ export default { this.$i18n.locale = window.CUSTOM_LOCALE this.requestWakeLock() }, - beforeDestroy() { + beforeUnmount() { this.destroyWakeLock() }, methods: {