From 2d2d30ef6e3f8df8cf1f0b46bf7743e43597a5e1 Mon Sep 17 00:00:00 2001 From: WinnyTroy Date: Wed, 9 Oct 2019 11:47:42 +0300 Subject: [PATCH] Add deleted_at Field to Attachments. Create soft_delete action that will populate deleted_at field for attachments. Fixes #1696 --- .../tests/viewsets/test_attachment_viewset.py | 49 +++++++++++++++++++ .../apps/api/viewsets/attachment_viewset.py | 4 +- onadata/apps/logger/models/attachment.py | 12 +++++ onadata/apps/logger/models/instance.py | 1 + .../libs/serializers/attachment_serializer.py | 2 +- 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/onadata/apps/api/tests/viewsets/test_attachment_viewset.py b/onadata/apps/api/tests/viewsets/test_attachment_viewset.py index 40a0f18097..243e37e9c5 100644 --- a/onadata/apps/api/tests/viewsets/test_attachment_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_attachment_viewset.py @@ -188,6 +188,55 @@ def test_list_view(self): self.assertTrue(isinstance(response.data, list)) self.assertEqual(len(response.data), 0) + def test_list_view_surfaces_current_attachment(self): + self._submit_transport_instance_w_attachment() + filename = "1335783522564.JPG" + path = os.path.join(self.main_directory, 'fixtures', 'transportation', + 'instances', self.surveys[0], filename) + media_file = django_file(path, 'video2', 'image/jpeg') + + Attachment.objects.create( + instance=self.xform.instances.first(), + mimetype='video/mp4', + extension='MP4', + name=filename, + media_file=media_file) + + Attachment.objects.create( + instance=self.xform.instances.first(), + mimetype='application/pdf', + extension='PDF', + name=filename, + media_file=media_file) + Attachment.objects.create( + instance=self.xform.instances.first(), + mimetype='text/plain', + extension='TXT', + name=filename, + media_file=media_file) + Attachment.objects.create( + instance=self.xform.instances.first(), + mimetype='audio/mp3', + extension='MP3', + name=filename, + media_file=media_file) + + request = self.factory.get('/', **self.extra) + response = self.list_view(request) + self.assertNotEqual(response.get('Cache-Control'), None) + self.assertEqual(response.status_code, 200) + self.assertTrue(isinstance(response.data, list)) + self.assertEqual(len(response.data), 5) + + # test when the attachment is soft deleted + self.attachment.soft_delete() + self.attachment.save() + + request = self.factory.get('/', **self.extra) + response = self.list_view(request) + + self.assertEqual(len(response.data), 4) + def test_data_list_with_xform_in_delete_async(self): self._submit_transport_instance_w_attachment() diff --git a/onadata/apps/api/viewsets/attachment_viewset.py b/onadata/apps/api/viewsets/attachment_viewset.py index 0d63153ca6..3cc9ac05ee 100644 --- a/onadata/apps/api/viewsets/attachment_viewset.py +++ b/onadata/apps/api/viewsets/attachment_viewset.py @@ -100,7 +100,9 @@ def list(self, request, *args, **kwargs): if not xform.shared_data: raise Http404(_("Not Found")) - self.object_list = self.filter_queryset(self.get_queryset()) + request_data = self.filter_queryset(self.get_queryset()) + self.object_list = self.object_list = [ + a for a in request_data if a.deleted_at is None] page = self.paginate_queryset(self.object_list) if page is not None: serializer = self.get_serializer(page, many=True) diff --git a/onadata/apps/logger/models/attachment.py b/onadata/apps/logger/models/attachment.py index 72f6399305..3755645ddf 100644 --- a/onadata/apps/logger/models/attachment.py +++ b/onadata/apps/logger/models/attachment.py @@ -3,6 +3,7 @@ from hashlib import md5 from django.db import models +from django.utils import timezone def get_original_filename(filename): @@ -86,3 +87,14 @@ def file_hash(self): def filename(self): if self.media_file: return os.path.basename(self.media_file.name) + + def soft_delete(self, user=None): + """ + Soft deletes an attachment by adding a deleted_at timestamp. + """ + + soft_deletion_time = timezone.now() + self.deleted_at = soft_deletion_time + if user is not None: + self.deleted_by = user + self.save() diff --git a/onadata/apps/logger/models/instance.py b/onadata/apps/logger/models/instance.py index eba834e846..988fa4ebc4 100644 --- a/onadata/apps/logger/models/instance.py +++ b/onadata/apps/logger/models/instance.py @@ -74,6 +74,7 @@ def _get_attachments_from_instance(instance): attachment['mimetype'] = a.mimetype attachment['filename'] = a.media_file.name attachment['name'] = a.name + attachment['deleted_at'] = a.deleted_at attachment['instance'] = a.instance.pk attachment['xform'] = instance.xform.id attachment['id'] = a.id diff --git a/onadata/libs/serializers/attachment_serializer.py b/onadata/libs/serializers/attachment_serializer.py index d59ecdd959..cb0c374d77 100644 --- a/onadata/libs/serializers/attachment_serializer.py +++ b/onadata/libs/serializers/attachment_serializer.py @@ -54,7 +54,7 @@ class AttachmentSerializer(serializers.HyperlinkedModelSerializer): class Meta: fields = ('url', 'filename', 'mimetype', 'field_xpath', 'id', 'xform', 'instance', 'download_url', 'small_download_url', - 'medium_download_url') + 'medium_download_url', 'deleted_at') model = Attachment @check_obj