From f0342d45689b2dfd9196ed462d6052745efb02ae Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Wed, 17 Sep 2025 18:04:02 +0200 Subject: [PATCH] fixed some tests --- cookbook/serializer.py | 15 +++-- cookbook/tests/api/test_api_ai_provider.py | 6 ++ cookbook/tests/api/test_api_space.py | 64 ++++++++++++++++++++-- cookbook/tests/api/test_api_userspace.py | 20 ++++++- cookbook/views/api.py | 4 +- 5 files changed, 95 insertions(+), 14 deletions(-) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 9b153a0ca..dfdf035a2 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -404,7 +404,6 @@ class SpaceSerializer(WritableNestedModelSerializer): return 0 def create(self, validated_data): - if Space.objects.filter(created_by=self.context['request'].user).count() >= self.context['request'].user.userpreference.max_owned_spaces: raise serializers.ValidationError( _('You have the reached the maximum amount of spaces that can be owned by you.') + f' ({self.context['request'].user.userpreference.max_owned_spaces})') @@ -416,6 +415,15 @@ class SpaceSerializer(WritableNestedModelSerializer): return user_space.space def update(self, instance, validated_data): + validated_data = self.filter_superuser_parameters(validated_data) + + if 'name' in validated_data: + if Space.objects.filter(Q(name=validated_data['name']), ~Q(pk=instance.pk)).exists(): + raise ValidationError(_('Space Name must be unique.')) + + return super().update(instance, validated_data) + + def filter_superuser_parameters(self, validated_data): if 'ai_enabled' in validated_data and not self.context['request'].user.is_superuser: del validated_data['ai_enabled'] @@ -425,10 +433,7 @@ class SpaceSerializer(WritableNestedModelSerializer): if 'ai_credits_balance' in validated_data and not self.context['request'].user.is_superuser: del validated_data['ai_credits_balance'] - if Space.objects.filter(Q(name=validated_data['name']), ~Q(pk=instance.pk)).exists(): - raise ValidationError(_('Space Name must be unique.')) - - return super().update(instance, validated_data) + return validated_data class Meta: model = Space diff --git a/cookbook/tests/api/test_api_ai_provider.py b/cookbook/tests/api/test_api_ai_provider.py index 320624d18..14f32d0f2 100644 --- a/cookbook/tests/api/test_api_ai_provider.py +++ b/cookbook/tests/api/test_api_ai_provider.py @@ -41,6 +41,12 @@ def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2): assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 2 + obj_1.space = None + obj_1.save() + + assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 + assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 2 + @pytest.mark.parametrize("arg", [ ['a_u', 403], diff --git a/cookbook/tests/api/test_api_space.py b/cookbook/tests/api/test_api_space.py index 4b260c59d..e30821f76 100644 --- a/cookbook/tests/api/test_api_space.py +++ b/cookbook/tests/api/test_api_space.py @@ -7,6 +7,7 @@ from django.urls import reverse from django_scopes import scopes_disabled from cookbook.models import UserSpace +from recipes import settings LIST_URL = 'api:space-list' DETAIL_URL = 'api:space-detail' @@ -45,7 +46,6 @@ def test_list_multiple(u1_s1, space_1, space_2): assert u1_response['id'] == space_1.id - @pytest.mark.parametrize("arg", [ ['a_u', 403], ['g1_s1', 403], @@ -70,9 +70,9 @@ def test_update(arg, request, space_1, a1_s1): @pytest.mark.parametrize("arg", [ ['a_u', 403], - ['g1_s1', 403], - ['u1_s1', 403], - ['a1_s1', 405], + ['g1_s1', 201], + ['u1_s1', 201], + ['a1_s1', 201], ]) def test_add(arg, request, u1_s2): c = request.getfixturevalue(arg[0]) @@ -90,3 +90,59 @@ def test_delete(u1_s1, u1_s2, a1_s1, space_1): # event the space owner cannot delete his space over the api (this might change later but for now it's only available in the UI) r = a1_s1.delete(reverse(DETAIL_URL, args={space_1.id})) assert r.status_code == 405 + + +def test_superuser_parameters(space_1, a1_s1, s1_s1): + # ------- test as normal user ------- + response = a1_s1.post(reverse(LIST_URL), {'name': 'test', 'ai_enabled': not settings.SPACE_AI_ENABLED, 'ai_credits_monthly': settings.SPACE_AI_CREDITS_MONTHLY + 100, 'ai_credits_balance': 100}, + content_type='application/json') + + assert response.status_code == 201 + response = json.loads(response.content) + assert response['ai_enabled'] == settings.SPACE_AI_ENABLED + assert response['ai_credits_monthly'] == settings.SPACE_AI_CREDITS_MONTHLY + assert response['ai_credits_balance'] == 0 + + space_1.created_by = auth.get_user(a1_s1) + space_1.ai_enabled = False + space_1.ai_credits_monthly = 0 + space_1.ai_credits_balance = 0 + space_1.save() + + response = a1_s1.patch(reverse(DETAIL_URL, args={space_1.id}), {'ai_enabled': True, 'ai_credits_monthly': 100, 'ai_credits_balance': 100}, + content_type='application/json') + + assert response.status_code == 200 + + space_1.refresh_from_db() + assert space_1.ai_enabled == False + assert space_1.ai_credits_monthly == 0 + assert space_1.ai_credits_balance == 0 + + # ------- test as superuser ------- + + response = s1_s1.post(reverse(LIST_URL), + {'name': 'test', 'ai_enabled': not settings.SPACE_AI_ENABLED, 'ai_credits_monthly': settings.SPACE_AI_CREDITS_MONTHLY + 100, 'ai_credits_balance': 100}, + content_type='application/json') + + assert response.status_code == 201 + response = json.loads(response.content) + assert response['ai_enabled'] == settings.SPACE_AI_ENABLED + assert response['ai_credits_monthly'] == settings.SPACE_AI_CREDITS_MONTHLY + assert response['ai_credits_balance'] == 0 + + space_1.created_by = auth.get_user(s1_s1) + space_1.ai_enabled = False + space_1.ai_credits_monthly = 0 + space_1.ai_credits_balance = 0 + space_1.save() + + response = s1_s1.patch(reverse(DETAIL_URL, args={space_1.id}), {'ai_enabled': True, 'ai_credits_monthly': 100, 'ai_credits_balance': 100}, + content_type='application/json') + + assert response.status_code == 200 + + space_1.refresh_from_db() + assert space_1.ai_enabled == True + assert space_1.ai_credits_monthly == 100 + assert space_1.ai_credits_balance == 100 diff --git a/cookbook/tests/api/test_api_userspace.py b/cookbook/tests/api/test_api_userspace.py index cb1750e35..c31d5a960 100644 --- a/cookbook/tests/api/test_api_userspace.py +++ b/cookbook/tests/api/test_api_userspace.py @@ -5,6 +5,8 @@ from django.contrib import auth from django.urls import reverse from django_scopes import scopes_disabled +from cookbook.models import UserSpace + LIST_URL = 'api:userspace-list' DETAIL_URL = 'api:userspace-detail' @@ -13,10 +15,10 @@ DETAIL_URL = 'api:userspace-detail' ['a_u', 403, 0], ['g1_s1', 200, 1], # sees only own user space ['u1_s1', 200, 1], - ['a1_s1', 200, 3], # sees user space of all users in space - ['a2_s1', 200, 1], + ['a1_s1', 200, 4], # admins can see all other members + ['a2_s1', 200, 4], ]) -def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1): +def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1, a2_s1): space_1.created_by = auth.get_user(a1_s1) space_1.save() @@ -27,6 +29,18 @@ def test_list_permission(arg, request, space_1, g1_s1, u1_s1, a1_s1): assert len(json.loads(result.content)['results']) == arg[2] +def test_list_all_personal(space_2, u1_s1): + result = u1_s1.get(reverse('api:userspace-all-personal')) + assert result.status_code == 200 + assert len(json.loads(result.content)) == 1 + + UserSpace.objects.create(user=auth.get_user(u1_s1), space=space_2) + + result = u1_s1.get(reverse('api:userspace-all-personal')) + assert result.status_code == 200 + assert len(json.loads(result.content)) == 2 + + @pytest.mark.parametrize("arg", [ ['a_u', 403], ['g1_s1', 403], diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 856f79074..bcd39727e 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -579,8 +579,8 @@ class UserSpaceViewSet(LoggingMixin, viewsets.ModelViewSet): if internal_note is not None: self.queryset = self.queryset.filter(internal_note=internal_note) - # starting with users you can SEE all other users in a space, guests only see themselves - if has_group_permission(self.request.user, ['user']): + # >= admins can see all users, guest/user can only see themselves + if has_group_permission(self.request.user, ['admin']): return self.queryset.filter(space=self.request.space) else: return self.queryset.filter(space=self.request.space, user=self.request.user)