From cda8bb61e6e594815a0473cdb0e8c8f977dd9190 Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Mon, 14 Oct 2024 14:41:14 +0300 Subject: [PATCH 1/7] Customized deleted_by serializer field Update lookup field --- onadata/libs/serializers/dataview_serializer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/onadata/libs/serializers/dataview_serializer.py b/onadata/libs/serializers/dataview_serializer.py index 90f7e94262..9d428e7980 100644 --- a/onadata/libs/serializers/dataview_serializer.py +++ b/onadata/libs/serializers/dataview_serializer.py @@ -109,6 +109,11 @@ class DataViewSerializer(serializers.HyperlinkedModelSerializer): project = serializers.HyperlinkedRelatedField( view_name="project-detail", lookup_field="pk", queryset=Project.objects.all() ) + deleted_by = serializers.HyperlinkedRelatedField( + view_name="user-detail", + lookup_field="username", + read_only=True, + ) columns = JsonField() query = JsonField(required=False) count = serializers.SerializerMethodField() From 121d8366205591fac9b1713c7d6ab4935ca55094 Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Fri, 18 Oct 2024 17:09:26 +0300 Subject: [PATCH 2/7] Add test case to ensure that error is not thrown by dataview endpoint --- .../serializers/test_dataview_serializer.py | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/onadata/libs/tests/serializers/test_dataview_serializer.py b/onadata/libs/tests/serializers/test_dataview_serializer.py index 4f582ef6c0..64dce2d773 100644 --- a/onadata/libs/tests/serializers/test_dataview_serializer.py +++ b/onadata/libs/tests/serializers/test_dataview_serializer.py @@ -46,9 +46,44 @@ def get_has_hxl_support_value(data_view_name): return data.get('has_hxl_support') - self.assertFalse(get_has_hxl_support_value('name_only')) - self.assertTrue(get_has_hxl_support_value('age_only')) - self.assertTrue(get_has_hxl_support_value('age_and_name')) + self.assertFalse(get_has_hxl_support_value("name_only")) + self.assertTrue(get_has_hxl_support_value("age_only")) + self.assertTrue(get_has_hxl_support_value("age_and_name")) + + def test_no_error_thrown_for_a_dataview_with_deleted_by_set(self): + """ + When `deleted_by` is set, don't throw error when serializing a DataView + """ + self._publish_form_with_hxl_support() + request = self.factory.get("/", **self.extra) + request.user = self.user + + dataview_name = "My deleted DataView" + payload = { + "name": dataview_name, + "xform": "http://testserver/api/v1/forms/%s" % self.xform.pk, + "project": "http://testserver/api/v1/projects/%s" % self.project.pk, + "columns": '["name", "age"]', + "query": "[]", + } + serializer = DataViewSerializer(data=payload, context={"request": request}) + is_valid = serializer.is_valid() + self.assertTrue(is_valid) + + serializer.save() + self.assertEqual(DataView.objects.count(), 1) + + # delete dataview and check dataviews endpoint + dataview = DataView.objects.get(name=dataview_name) + dataview.soft_delete(self.user) + serialized_dataview = DataViewSerializer( + dataview, context={"request": request} + ).data + self.assertEqual( + serialized_dataview["deleted_by"], + f"http://testserver/api/v1/users/{self.user.username}", + ) + self.assertTrue("deleted_at" in serialized_dataview) def test_name_and_xform_are_unique(self): """ From 4dc84d425ee32ae7aefd7963a72b22f851eb9e57 Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Sat, 19 Oct 2024 16:41:17 +0300 Subject: [PATCH 3/7] Remove deleted-by and deleted-at from the dataview serializer --- onadata/libs/serializers/dataview_serializer.py | 3 +-- onadata/libs/tests/serializers/test_dataview_serializer.py | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/onadata/libs/serializers/dataview_serializer.py b/onadata/libs/serializers/dataview_serializer.py index 9d428e7980..3179a351f8 100644 --- a/onadata/libs/serializers/dataview_serializer.py +++ b/onadata/libs/serializers/dataview_serializer.py @@ -124,6 +124,7 @@ class DataViewSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = DataView + exclude = ["deleted_by", "deleted_at"] fields = ( "dataviewid", "name", @@ -138,8 +139,6 @@ class Meta: "has_hxl_support", "url", "date_created", - "deleted_at", - "deleted_by", ) validators = [ serializers.UniqueTogetherValidator( diff --git a/onadata/libs/tests/serializers/test_dataview_serializer.py b/onadata/libs/tests/serializers/test_dataview_serializer.py index 64dce2d773..002fabca94 100644 --- a/onadata/libs/tests/serializers/test_dataview_serializer.py +++ b/onadata/libs/tests/serializers/test_dataview_serializer.py @@ -79,11 +79,8 @@ def test_no_error_thrown_for_a_dataview_with_deleted_by_set(self): serialized_dataview = DataViewSerializer( dataview, context={"request": request} ).data - self.assertEqual( - serialized_dataview["deleted_by"], - f"http://testserver/api/v1/users/{self.user.username}", - ) - self.assertTrue("deleted_at" in serialized_dataview) + self.assertEqual(serialized_dataview["deleted_by"], None) + self.assertFalse("deleted_at" in serialized_dataview) def test_name_and_xform_are_unique(self): """ From a64f93c806bedf6cba4f3aea50c9014a78452206 Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Sat, 19 Oct 2024 16:55:27 +0300 Subject: [PATCH 4/7] Add query filter for dataview viewset --- .../apps/api/tests/viewsets/test_dataview_viewset.py | 10 ++++++++++ onadata/apps/api/viewsets/dataview_viewset.py | 8 ++++++++ onadata/libs/serializers/dataview_serializer.py | 6 ------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/onadata/apps/api/tests/viewsets/test_dataview_viewset.py b/onadata/apps/api/tests/viewsets/test_dataview_viewset.py index 9bb5835186..b015aecfd6 100644 --- a/onadata/apps/api/tests/viewsets/test_dataview_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_dataview_viewset.py @@ -454,6 +454,16 @@ def test_list_dataview(self): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 2) + # delete DataView and check that we don't get it in response + dataview = DataView.objects.get(name="My DataView2") + deleted_dataview_id = dataview.id + dataview.soft_delete(user=self.user) + response = view(request) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), 1) + self.assertNotEqual(response.data[0]["dataviewid"], deleted_dataview_id) + anon_request = request = self.factory.get("/") anon_response = view(anon_request) self.assertEqual(anon_response.status_code, 401) diff --git a/onadata/apps/api/viewsets/dataview_viewset.py b/onadata/apps/api/viewsets/dataview_viewset.py index 1ee101c2e3..4aeff0843d 100644 --- a/onadata/apps/api/viewsets/dataview_viewset.py +++ b/onadata/apps/api/viewsets/dataview_viewset.py @@ -155,6 +155,14 @@ def get_serializer_class(self): return serializer_class + def filter_queryset(self, queryset): + """ + Remove deleted DataViews + """ + return super().filter_queryset( + queryset.filter(deleted_at=None, deleted_by=None) + ) + def list(self, request, *args, **kwargs): """ List endpoint for Filtered datasets diff --git a/onadata/libs/serializers/dataview_serializer.py b/onadata/libs/serializers/dataview_serializer.py index 3179a351f8..bdf4c51219 100644 --- a/onadata/libs/serializers/dataview_serializer.py +++ b/onadata/libs/serializers/dataview_serializer.py @@ -109,11 +109,6 @@ class DataViewSerializer(serializers.HyperlinkedModelSerializer): project = serializers.HyperlinkedRelatedField( view_name="project-detail", lookup_field="pk", queryset=Project.objects.all() ) - deleted_by = serializers.HyperlinkedRelatedField( - view_name="user-detail", - lookup_field="username", - read_only=True, - ) columns = JsonField() query = JsonField(required=False) count = serializers.SerializerMethodField() @@ -124,7 +119,6 @@ class DataViewSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = DataView - exclude = ["deleted_by", "deleted_at"] fields = ( "dataviewid", "name", From d2ef27ef170600a0eb12152994e2b83ab6cef6d1 Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Sat, 19 Oct 2024 17:12:19 +0300 Subject: [PATCH 5/7] Add a test case for making a GET request for a deleted dataview --- .../tests/viewsets/test_dataview_viewset.py | 30 +++++++++++++++++++ .../serializers/test_dataview_serializer.py | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/onadata/apps/api/tests/viewsets/test_dataview_viewset.py b/onadata/apps/api/tests/viewsets/test_dataview_viewset.py index b015aecfd6..fa74b14e26 100644 --- a/onadata/apps/api/tests/viewsets/test_dataview_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_dataview_viewset.py @@ -487,6 +487,36 @@ def test_get_dataview_no_perms(self): self.assertEqual(response.status_code, 200) + def test_can_not_get_deleted_dataview(self): + data = { + "name": "Agriculture Dataview", + "xform": f"http://testserver/api/v1/forms/{self.xform.pk}", + "project": f"http://testserver/api/v1/projects/{self.project.pk}", + "columns": '["name", "age", "gender"]', + "query": '[{"column":"age","filter":">","value":"20"},' + '{"column":"age","filter":"<","value":"50"}]', + } + + self._create_dataview(data=data) + + view = DataViewViewSet.as_view( + { + "get": "retrieve", + } + ) + + request = self.factory.get("/", **self.extra) + response = view(request, pk=self.data_view.pk) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data["dataviewid"], self.data_view.pk) + + dataview = DataView.objects.get(id=response.data["dataviewid"]) + dataview.soft_delete(user=self.user) + + request = self.factory.get("/", **self.extra) + response = view(request, pk=self.data_view.pk) + self.assertEqual(response.status_code, 404) + # pylint: disable=invalid-name def test_dataview_data_filter_integer(self): data = { diff --git a/onadata/libs/tests/serializers/test_dataview_serializer.py b/onadata/libs/tests/serializers/test_dataview_serializer.py index 002fabca94..48582601ca 100644 --- a/onadata/libs/tests/serializers/test_dataview_serializer.py +++ b/onadata/libs/tests/serializers/test_dataview_serializer.py @@ -79,7 +79,7 @@ def test_no_error_thrown_for_a_dataview_with_deleted_by_set(self): serialized_dataview = DataViewSerializer( dataview, context={"request": request} ).data - self.assertEqual(serialized_dataview["deleted_by"], None) + self.assertFalse("deleted_by" in serialized_dataview) self.assertFalse("deleted_at" in serialized_dataview) def test_name_and_xform_are_unique(self): From 8f1cea40650ee3646049e1bbe8d620d510d5bfad Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Tue, 22 Oct 2024 11:14:45 +0300 Subject: [PATCH 6/7] Filter dataviews queryset with only 'deleted_at' Remove redundant test case --- onadata/apps/api/viewsets/dataview_viewset.py | 4 +-- .../serializers/test_dataview_serializer.py | 32 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/onadata/apps/api/viewsets/dataview_viewset.py b/onadata/apps/api/viewsets/dataview_viewset.py index 4aeff0843d..e8670d6dce 100644 --- a/onadata/apps/api/viewsets/dataview_viewset.py +++ b/onadata/apps/api/viewsets/dataview_viewset.py @@ -159,9 +159,7 @@ def filter_queryset(self, queryset): """ Remove deleted DataViews """ - return super().filter_queryset( - queryset.filter(deleted_at=None, deleted_by=None) - ) + return super().filter_queryset(queryset.filter(deleted_at=None)) def list(self, request, *args, **kwargs): """ diff --git a/onadata/libs/tests/serializers/test_dataview_serializer.py b/onadata/libs/tests/serializers/test_dataview_serializer.py index 48582601ca..0c94a2cf81 100644 --- a/onadata/libs/tests/serializers/test_dataview_serializer.py +++ b/onadata/libs/tests/serializers/test_dataview_serializer.py @@ -50,38 +50,6 @@ def get_has_hxl_support_value(data_view_name): self.assertTrue(get_has_hxl_support_value("age_only")) self.assertTrue(get_has_hxl_support_value("age_and_name")) - def test_no_error_thrown_for_a_dataview_with_deleted_by_set(self): - """ - When `deleted_by` is set, don't throw error when serializing a DataView - """ - self._publish_form_with_hxl_support() - request = self.factory.get("/", **self.extra) - request.user = self.user - - dataview_name = "My deleted DataView" - payload = { - "name": dataview_name, - "xform": "http://testserver/api/v1/forms/%s" % self.xform.pk, - "project": "http://testserver/api/v1/projects/%s" % self.project.pk, - "columns": '["name", "age"]', - "query": "[]", - } - serializer = DataViewSerializer(data=payload, context={"request": request}) - is_valid = serializer.is_valid() - self.assertTrue(is_valid) - - serializer.save() - self.assertEqual(DataView.objects.count(), 1) - - # delete dataview and check dataviews endpoint - dataview = DataView.objects.get(name=dataview_name) - dataview.soft_delete(self.user) - serialized_dataview = DataViewSerializer( - dataview, context={"request": request} - ).data - self.assertFalse("deleted_by" in serialized_dataview) - self.assertFalse("deleted_at" in serialized_dataview) - def test_name_and_xform_are_unique(self): """ Test that we are preventing the creation of exactly the same dataview From 46767864f0e06ca5d9ee53ec7b87c6dbe04d131e Mon Sep 17 00:00:00 2001 From: FrankApiyo Date: Wed, 23 Oct 2024 10:31:25 +0300 Subject: [PATCH 7/7] Attachment Viewset | Apply filtering in queryset attribute Remove filter_queryset method --- onadata/apps/api/viewsets/dataview_viewset.py | 8 +------- .../libs/tests/serializers/test_dataview_serializer.py | 6 +++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/onadata/apps/api/viewsets/dataview_viewset.py b/onadata/apps/api/viewsets/dataview_viewset.py index e8670d6dce..742c2c78d4 100644 --- a/onadata/apps/api/viewsets/dataview_viewset.py +++ b/onadata/apps/api/viewsets/dataview_viewset.py @@ -126,7 +126,7 @@ class DataViewViewSet( A simple ViewSet for viewing and editing DataViews. """ - queryset = DataView.objects.select_related() + queryset = DataView.objects.filter(deleted_at__isnull=True).select_related() serializer_class = DataViewSerializer permission_classes = [DataViewViewsetPermissions] lookup_field = "pk" @@ -155,12 +155,6 @@ def get_serializer_class(self): return serializer_class - def filter_queryset(self, queryset): - """ - Remove deleted DataViews - """ - return super().filter_queryset(queryset.filter(deleted_at=None)) - def list(self, request, *args, **kwargs): """ List endpoint for Filtered datasets diff --git a/onadata/libs/tests/serializers/test_dataview_serializer.py b/onadata/libs/tests/serializers/test_dataview_serializer.py index 0c94a2cf81..4f582ef6c0 100644 --- a/onadata/libs/tests/serializers/test_dataview_serializer.py +++ b/onadata/libs/tests/serializers/test_dataview_serializer.py @@ -46,9 +46,9 @@ def get_has_hxl_support_value(data_view_name): return data.get('has_hxl_support') - self.assertFalse(get_has_hxl_support_value("name_only")) - self.assertTrue(get_has_hxl_support_value("age_only")) - self.assertTrue(get_has_hxl_support_value("age_and_name")) + self.assertFalse(get_has_hxl_support_value('name_only')) + self.assertTrue(get_has_hxl_support_value('age_only')) + self.assertTrue(get_has_hxl_support_value('age_and_name')) def test_name_and_xform_are_unique(self): """