diff --git a/CHANGES.md b/CHANGES.md index 0d68f86..e861687 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ CHANGELOG 1.0.23+dev (XXXX-XX-XX) --------------------------- +* Add deletion signal delete properties pictures and thumbnails 1.0.23 (2022-02-11) --------------------------- diff --git a/terra_geocrud/properties/files.py b/terra_geocrud/properties/files.py index 78f2a77..2373b0e 100644 --- a/terra_geocrud/properties/files.py +++ b/terra_geocrud/properties/files.py @@ -54,13 +54,25 @@ def delete_old_picture_property(file_prop, old_properties): delete(old_storage_file_path) -def store_feature_files(feature, old_properties=None): - """ Handle base64 encoded files to django storage. Use fake base64 to compatibility with react-json-schema """ - fake_content = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=' +def get_files_properties(feature): files_properties = [ key for key, value in feature.layer.schema['properties'].items() if feature.layer.schema['properties'][key].get('format') == 'data-url' ] + return files_properties + + +def delete_feature_files(feature): + files_properties = get_files_properties(feature) + if files_properties: + for file_prop in files_properties: + delete_old_picture_property(file_prop, feature.properties) + + +def store_feature_files(feature, old_properties=None): + """ Handle base64 encoded files to django storage. Use fake base64 to compatibility with react-json-schema """ + fake_content = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=' + files_properties = get_files_properties(feature) if files_properties: storage = get_storage() for file_prop in files_properties: diff --git a/terra_geocrud/signals.py b/terra_geocrud/signals.py index 13eb7d6..1e365ef 100644 --- a/terra_geocrud/signals.py +++ b/terra_geocrud/signals.py @@ -6,6 +6,7 @@ from geostore.helpers import execute_async_func from geostore.models import Feature, LayerRelation from geostore.signals import save_feature, save_layer_relation +from terra_geocrud.properties.files import delete_feature_files from terra_geocrud.tasks import (feature_update_relations_and_properties, layer_relations_set_destinations, feature_update_relations_origins, feature_update_destination_properties) @@ -42,8 +43,14 @@ def save_layer_relation(sender, instance, **kwargs): execute_async_func(layer_relations_set_destinations, (instance.pk, )) +@receiver(post_delete, sender=Feature, dispatch_uid='delete_files_feature') +def delete_files_feature(sender, instance, **kwargs): + delete_feature_files(instance) + + @receiver(post_delete, sender=Feature, dispatch_uid='delete_feature') def delete_feature(sender, instance, **kwargs): + # save base64 file content to storage if app_settings.GEOSTORE_RELATION_CELERY_ASYNC: kwargs['relation_id'] = None kwargs.pop('signal') diff --git a/terra_geocrud/tests/test_signals.py b/terra_geocrud/tests/test_signals.py index f5465c5..a99a35b 100644 --- a/terra_geocrud/tests/test_signals.py +++ b/terra_geocrud/tests/test_signals.py @@ -13,6 +13,7 @@ from django.contrib.gis.geos import LineString, Polygon from terra_geocrud.models import CrudViewProperty +from terra_geocrud.properties.files import get_storage, store_feature_files from terra_geocrud.tasks import ( ConcurrentPropertyModificationError, feature_update_relations_and_properties, @@ -20,9 +21,13 @@ feature_update_destination_properties, sync_properties_relations_destination, ) +from terra_geocrud.thumbnail_backends import ThumbnailDataFileBackend + from terra_geocrud.tests.factories import CrudViewFactory from ..signals import save_feature +thumbnail_backend = ThumbnailDataFileBackend() + class AsyncSideEffect(object): def add_side_effect_async(self, mocked): @@ -31,6 +36,46 @@ def side_effect_async(async_func, args=()): mocked.side_effect = side_effect_async +@patch('terra_geocrud.tasks.feature_update_relations_and_properties.delay') +@patch('terra_geocrud.signals.execute_async_func') +class DeletionFeatureDeletePictureTest(TestCase): + def setUp(self): + + layer = LayerFactory.create(geom_type=GeometryTypes.LineString, + schema={"type": "object", + "required": ["name", ], + "properties": {"name": {"type": "string", "title": "Name"}} + }) + self.crud_view = CrudViewFactory(layer=layer) + self.prop_name = CrudViewProperty.objects.create( + view=self.crud_view, key="picture", + editable=True, + json_schema={'type': "string", + 'title': "Picture", + 'format': "data-url"} + ) + sync_layer_schema(self.crud_view) + self.feature = Feature.objects.create( + layer=self.crud_view.layer, + properties={'name': 'foo', + 'picture': "data:image/png;name=titre_laromieu-fondblanc.jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAA" + "EAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="}, + geom=LineString((0, 0), (1, 0)) + ) + store_feature_files(self.feature, {}) + self.storage = get_storage() + self.property_value = self.feature.properties.get('picture') + self.storage_file_path = self.property_value.split(';name=')[-1].split(';')[0] + self.thumbnail = thumbnail_backend.get_thumbnail(self.storage_file_path, "500x500", crop='noop', upscale=False) + self.assertTrue(self.storage.exists(self.thumbnail.name)) + self.assertTrue(self.storage.exists(self.storage_file_path)) + + def test_signal_feature_delete_pictures(self, async_mocked, mock_delay): + self.feature.delete() + self.assertFalse(self.storage.exists(self.thumbnail.name)) + self.assertFalse(self.storage.exists(self.storage_file_path)) + + @patch('terra_geocrud.tasks.feature_update_relations_and_properties.delay') @patch('terra_geocrud.signals.execute_async_func') @patch('geostore.settings.GEOSTORE_RELATION_CELERY_ASYNC', new_callable=PropertyMock) @@ -70,7 +115,7 @@ def setUp(self): geom=LineString((0, 0), (10, 10)) ) - def test_signal(self, property_mocked, async_mocked, mock_delay): + def test_signal_property_update(self, property_mocked, async_mocked, mock_delay): property_mocked.return_value = True self.add_side_effect_async(async_mocked) self.feature.refresh_from_db() diff --git a/terra_geocrud/tests/test_views.py b/terra_geocrud/tests/test_views.py index f83d28f..5687dff 100644 --- a/terra_geocrud/tests/test_views.py +++ b/terra_geocrud/tests/test_views.py @@ -376,7 +376,8 @@ def test_list_endpoint(self): response_list = self.client.get(reverse('feature-list', args=(self.crud_view.layer_id,)), format="json") data = response_list.json() - self.assertEqual(len(data), self.crud_view.layer.features.count()) + features = self.crud_view.layer.features.all() + self.assertEqual(len(data), len(features)) def test_property_detail_display_with_groups(self): response_detail = self.client.get(reverse('feature-detail',