From 1f1f0d4ac7f862b40143773c8e6ed06deaa888b9 Mon Sep 17 00:00:00 2001 From: Emi Grady-Willis Date: Tue, 17 Aug 2021 14:18:39 -0400 Subject: [PATCH 1/7] Create and implement new serializer for workspace renaming --- multinet/api/views/serializers.py | 6 ++++++ multinet/api/views/workspace.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/multinet/api/views/serializers.py b/multinet/api/views/serializers.py index b31b1d1..f07874d 100644 --- a/multinet/api/views/serializers.py +++ b/multinet/api/views/serializers.py @@ -30,6 +30,12 @@ class Meta: ] read_only_fields = ['created'] +class WorkspaceRenameSerializer(serializers.ModelSerializer): + class Meta: + model = Workspace + fields = [ + 'name', + ] class WorkspaceSerializer(serializers.ModelSerializer): class Meta: diff --git a/multinet/api/views/workspace.py b/multinet/api/views/workspace.py index 240f5c4..bec3b32 100644 --- a/multinet/api/views/workspace.py +++ b/multinet/api/views/workspace.py @@ -11,7 +11,7 @@ from rest_framework.viewsets import ReadOnlyModelViewSet from multinet.api.models import Workspace -from multinet.api.views.serializers import WorkspaceCreateSerializer, WorkspaceSerializer +from multinet.api.views.serializers import WorkspaceCreateSerializer, WorkspaceRenameSerializer, WorkspaceSerializer from .common import MultinetPagination From 8f454ceac0b6878ad38f5e83212f104c545ce921 Mon Sep 17 00:00:00 2001 From: Emi Grady-Willis Date: Wed, 18 Aug 2021 10:44:06 -0400 Subject: [PATCH 2/7] Add new endpoint for renaming workspaces using update() function --- multinet/api/views/workspace.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/multinet/api/views/workspace.py b/multinet/api/views/workspace.py index bec3b32..3014599 100644 --- a/multinet/api/views/workspace.py +++ b/multinet/api/views/workspace.py @@ -49,6 +49,21 @@ def create(self, request): assign_perm('owner', request.user, workspace) return Response(WorkspaceSerializer(workspace).data, status=status.HTTP_200_OK) + @swagger_auto_schema( + request_body=WorkspaceRenameSerializer(), + responses={200: WorkspaceSerializer()}, + ) + @method_decorator(permission_required_or_403('owner', (Workspace, 'name', 'name'))) + def update(self, request, name): + workspace: Workspace = get_object_or_404(Workspace, name=name) + serializer = WorkspaceRenameSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + workspace.name = serializer.validated_data['name'] + workspace.save() + + return Response(WorkspaceSerializer(workspace).data, status=status.HTTP_200_OK) + @method_decorator(permission_required_or_403('owner', (Workspace, 'name', 'name'))) def destroy(self, request, name): workspace: Workspace = get_object_or_404(Workspace, name=name) From 3fbfbc382dd85522da0ce2e01e96fcc72cfe077b Mon Sep 17 00:00:00 2001 From: Emi Grady-Willis Date: Wed, 18 Aug 2021 12:32:58 -0400 Subject: [PATCH 3/7] Use new permissions model --- multinet/api/views/workspace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multinet/api/views/workspace.py b/multinet/api/views/workspace.py index ddda8dd..1b86278 100644 --- a/multinet/api/views/workspace.py +++ b/multinet/api/views/workspace.py @@ -77,7 +77,7 @@ def create(self, request): request_body=WorkspaceRenameSerializer(), responses={200: WorkspaceSerializer()}, ) - @method_decorator(permission_required_or_403('owner', (Workspace, 'name', 'name'))) + @require_workspace_permission(WorkspaceRoleChoice.MAINTAINER) def update(self, request, name): workspace: Workspace = get_object_or_404(Workspace, name=name) serializer = WorkspaceRenameSerializer(data=request.data) From 3ec36bb58f822b4ba59ee0b012ee26abe61b8c02 Mon Sep 17 00:00:00 2001 From: Emi Grady-Willis Date: Wed, 18 Aug 2021 13:41:36 -0400 Subject: [PATCH 4/7] Fix linting errors with serializers --- multinet/api/views/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/multinet/api/views/serializers.py b/multinet/api/views/serializers.py index b093b5d..6ab4411 100644 --- a/multinet/api/views/serializers.py +++ b/multinet/api/views/serializers.py @@ -38,6 +38,7 @@ class Meta: ] read_only_fields = ['created'] + class WorkspaceRenameSerializer(serializers.ModelSerializer): class Meta: model = Workspace @@ -45,6 +46,7 @@ class Meta: 'name', ] + class WorkspaceSerializer(serializers.ModelSerializer): class Meta: model = Workspace From cb44b4386d36c95f78d72b4510da1b8f39f169f3 Mon Sep 17 00:00:00 2001 From: Jacob Nesbitt Date: Thu, 19 Aug 2021 13:59:05 -0400 Subject: [PATCH 5/7] Add test function signature --- multinet/api/tests/test_workspace.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/multinet/api/tests/test_workspace.py b/multinet/api/tests/test_workspace.py index 4cc71ff..9409114 100644 --- a/multinet/api/tests/test_workspace.py +++ b/multinet/api/tests/test_workspace.py @@ -99,6 +99,29 @@ def test_workspace_rest_create(authenticated_api_client: APIClient): Workspace.objects.get(name=workspace_name) +@pytest.mark.django_db +@pytest.mark.parametrize( + 'permission,is_owner,status_code,success', + [ + (None, False, 404, False), + (WorkspaceRoleChoice.READER, False, 403, False), + (WorkspaceRoleChoice.WRITER, False, 403, False), + (WorkspaceRoleChoice.MAINTAINER, False, 200, True), + (None, True, 200, True), + ], +) +def test_workspace_rest_rename( + workspace: Workspace, + user: User, + authenticated_api_client: APIClient, + permission: WorkspaceRoleChoice, + is_owner: bool, + status_code: int, + success: bool, +): + pass + + @pytest.mark.django_db @pytest.mark.parametrize( 'permission,is_owner,status_code,success', From 25d5a2277a66b906ef76c7154ef0ac3c6771162e Mon Sep 17 00:00:00 2001 From: Emi Grady-Willis Date: Thu, 19 Aug 2021 14:43:06 -0400 Subject: [PATCH 6/7] Finish first draft of rename test --- multinet/api/tests/test_workspace.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/multinet/api/tests/test_workspace.py b/multinet/api/tests/test_workspace.py index 9409114..061db27 100644 --- a/multinet/api/tests/test_workspace.py +++ b/multinet/api/tests/test_workspace.py @@ -119,7 +119,28 @@ def test_workspace_rest_rename( status_code: int, success: bool, ): - pass + if permission is not None: + workspace.set_user_permission(user, permission) + elif is_owner: + workspace.set_owner(user) + + old_name = workspace.name + fake = Faker() + new_name = fake.pystr() + + request_data = { + 'name': new_name, + } + + r = authenticated_api_client.put( + f'/api/workspaces/{workspace.name}/', + request_data, + ) + assert r.status_code == status_code + + workspace = Workspace.objects.get(id=workspace.pk) + assert success == (workspace.name == new_name) + assert success != (workspace.name == old_name) @pytest.mark.django_db From 947c559e25569fb9534908a8a1534de1f555720e Mon Sep 17 00:00:00 2001 From: eagw <87092433+eagw@users.noreply.github.com> Date: Fri, 20 Aug 2021 10:16:03 -0400 Subject: [PATCH 7/7] Update test with style improvements Co-authored-by: Jacob Nesbitt --- multinet/api/tests/test_workspace.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/multinet/api/tests/test_workspace.py b/multinet/api/tests/test_workspace.py index 061db27..6c076be 100644 --- a/multinet/api/tests/test_workspace.py +++ b/multinet/api/tests/test_workspace.py @@ -125,22 +125,23 @@ def test_workspace_rest_rename( workspace.set_owner(user) old_name = workspace.name - fake = Faker() - new_name = fake.pystr() - - request_data = { - 'name': new_name, - } + new_name = Faker().pystr() r = authenticated_api_client.put( f'/api/workspaces/{workspace.name}/', - request_data, + { + 'name': new_name, + }, + format='json', ) assert r.status_code == status_code + # Retrieve workspace to ensure it's up to date workspace = Workspace.objects.get(id=workspace.pk) - assert success == (workspace.name == new_name) - assert success != (workspace.name == old_name) + + # Assert name is as expected + expected_name = new_name if success else old_name + assert workspace.name == expected_name @pytest.mark.django_db