From c36d0a40050426178bb38436aacee2d815af816b Mon Sep 17 00:00:00 2001 From: Hironsan Date: Tue, 21 Jul 2020 21:10:49 +0900 Subject: [PATCH] Allow annotator to update/delete other's annotations --- app/api/tests/test_api.py | 27 ++++++++++++++++++++++----- app/api/views.py | 9 ++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/app/api/tests/test_api.py b/app/api/tests/test_api.py index a1387a15..7c8b1b8a 100644 --- a/app/api/tests/test_api.py +++ b/app/api/tests/test_api.py @@ -880,9 +880,11 @@ class TestAnnotationDetailAPI(APITestCase): another_entity = mommy.make('SequenceAnnotation', document=main_project_doc, user=another_project_member) - sub_project = mommy.make('SequenceLabelingProject', users=[non_project_member]) - sub_project_doc = mommy.make('Document', project=sub_project) - mommy.make('SequenceAnnotation', document=sub_project_doc) + shared_project = mommy.make('SequenceLabelingProject', + collaborative_annotation=True, + users=[project_member, another_project_member]) + shared_project_doc = mommy.make('Document', project=shared_project) + shared_entity = mommy.make('SequenceAnnotation', document=shared_project_doc, user=another_project_member) cls.url = reverse(viewname='annotation_detail', args=[main_project.id, main_project_doc.id, @@ -890,9 +892,12 @@ class TestAnnotationDetailAPI(APITestCase): cls.another_url = reverse(viewname='annotation_detail', args=[main_project.id, main_project_doc.id, another_entity.id]) + cls.shared_url = reverse(viewname='annotation_detail', args=[shared_project.id, + shared_project_doc.id, + shared_entity.id]) cls.post_data = {'start_offset': 0, 'end_offset': 10} - assign_user_to_role(project_member=project_member, project=main_project, - role_name=settings.ROLE_ANNOTATOR) + assign_user_to_role(project_member=project_member, project=main_project, role_name=settings.ROLE_ANNOTATOR) + assign_user_to_role(project_member=project_member, project=shared_project, role_name=settings.ROLE_ANNOTATOR) def test_returns_annotation_to_project_member(self): self.client.login(username=self.project_member_name, @@ -954,6 +959,18 @@ class TestAnnotationDetailAPI(APITestCase): response = self.client.delete(self.another_url, format='json', data=self.post_data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + def test_allow_member_to_update_others_annotation_in_shared_project(self): + self.client.login(username=self.project_member_name, + password=self.project_member_pass) + response = self.client.patch(self.shared_url, format='json', data=self.post_data) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_allow_member_to_delete_others_annotation_in_shared_project(self): + self.client.login(username=self.project_member_name, + password=self.project_member_pass) + response = self.client.delete(self.shared_url, format='json') + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + @classmethod def doCleanups(cls): remove_all_role_mappings() diff --git a/app/api/views.py b/app/api/views.py index 5635c984..01fac0b0 100644 --- a/app/api/views.py +++ b/app/api/views.py @@ -235,9 +235,16 @@ class AnnotationList(generics.ListCreateAPIView): class AnnotationDetail(generics.RetrieveUpdateDestroyAPIView): lookup_url_kwarg = 'annotation_id' - permission_classes = [IsAuthenticated & (((IsAnnotator & IsOwnAnnotation) | IsAnnotationApprover) | IsProjectAdmin)] swagger_schema = None + def get_permissions(self): + project = get_object_or_404(Project, pk=self.kwargs['project_id']) + if project.collaborative_annotation: + self.permission_classes = [IsAuthenticated & IsInProjectOrAdmin] + else: + self.permission_classes = [IsAuthenticated & IsInProjectOrAdmin & IsOwnAnnotation] + return super().get_permissions() + def get_serializer_class(self): project = get_object_or_404(Project, pk=self.kwargs['project_id']) self.serializer_class = project.get_annotation_serializer()