From a745d98e7aa78b5dc5e7898392a459fb50863874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Wed, 18 Jul 2018 10:32:21 +0200 Subject: [PATCH] general: add basic export/import of named assets (#24933) --- combo/apps/assets/models.py | 34 ++++++++++++++++++++++++++++++++++ combo/data/utils.py | 8 +++++++- tests/test_import_export.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/combo/apps/assets/models.py b/combo/apps/assets/models.py index 7915b13..815678e 100644 --- a/combo/apps/assets/models.py +++ b/combo/apps/assets/models.py @@ -14,8 +14,42 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import json + +from django.core import serializers from django.db import models +class AssetManager(models.Manager): + def get_by_natural_key(self, key): + return self.get(key=key) + + class Asset(models.Model): + objects = AssetManager() + key = models.CharField(max_length=128, unique=True) asset = models.FileField(upload_to='assets') + + @classmethod + def export_all_for_json(cls): + return [x.get_as_serialized_object() for x in Asset.objects.all()] + + def get_as_serialized_object(self): + serialized_asset = json.loads(serializers.serialize('json', [self], + use_natural_foreign_keys=True, use_natural_primary_keys=True))[0] + del serialized_asset['model'] + del serialized_asset['pk'] + return serialized_asset + + @classmethod + def load_serialized_objects(cls, json_site): + for json_asset in json_site: + cls.load_serialized_object(json_asset) + + @classmethod + def load_serialized_object(cls, json_asset): + json_asset['model'] = 'assets.asset' + asset, created = Asset.objects.get_or_create(key=json_asset['fields']['key']) + json_asset['pk'] = asset.id + asset = [x for x in serializers.deserialize('json', json.dumps([json_asset]))][0] + asset.save() diff --git a/combo/data/utils.py b/combo/data/utils.py index 62014f2..369902d 100644 --- a/combo/data/utils.py +++ b/combo/data/utils.py @@ -18,6 +18,7 @@ from django.contrib.auth.models import Group from django.db import transaction from django.utils.translation import ugettext_lazy as _ +from combo.apps.assets.models import Asset from combo.apps.maps.models import MapLayer from .models import Page @@ -33,7 +34,8 @@ class MissingGroups(Exception): def export_site(): '''Dump site objects to JSON-dumpable dictionnary''' return {'pages': Page.export_all_for_json(), - 'map-layers': MapLayer.export_all_for_json()} + 'map-layers': MapLayer.export_all_for_json(), + 'assets': Asset.export_all_for_json(),} def import_site(data, if_empty=False, clean=False): @@ -61,10 +63,14 @@ def import_site(data, if_empty=False, clean=False): if clean: MapLayer.objects.all().delete() + Asset.objects.all().delete() Page.objects.all().delete() with transaction.atomic(): MapLayer.load_serialized_objects(data.get('map-layers') or []) + with transaction.atomic(): + Asset.load_serialized_objects(data.get('assets') or []) + with transaction.atomic(): Page.load_serialized_pages(data.get('pages') or []) diff --git a/tests/test_import_export.py b/tests/test_import_export.py index 6c48756..c6e7a18 100644 --- a/tests/test_import_export.py +++ b/tests/test_import_export.py @@ -8,8 +8,10 @@ import tempfile import pytest from django.contrib.auth.models import Group +from django.core.files import File from django.core.management import call_command +from combo.apps.assets.models import Asset from combo.apps.maps.models import MapLayer, Map from combo.data.models import Page, TextCell from combo.data.utils import export_site, import_site, MissingGroups @@ -33,6 +35,11 @@ def some_map_layers(): MapLayer(label='Foo', slug='foo', geojson_url='http://example.net/foo/').save() MapLayer(label='Bar', slug='bar', geojson_url='http://example.net/bar/').save() +@pytest.fixture +def some_assets(): + Asset(key='banner', asset=File(StringIO('test'), 'test.png')).save() + Asset(key='favicon', asset=File(StringIO('test2'), 'test2.png')).save() + def get_output_of_command(command, *args, **kwargs): old_stdout = sys.stdout output = sys.stdout = StringIO() @@ -162,3 +169,31 @@ def test_group_restrictions_import_export(app, some_data): cell = TextCell.objects.get(order=0) assert [x.name for x in cell.groups.all()] == ['A Group'] + +def test_import_export_assets(app, some_assets): + output = get_output_of_command('export_site') + assert len(json.loads(output)['assets']) == 2 + import_site(data={}, clean=True) + assert Asset.objects.all().count() == 0 + empty_output = get_output_of_command('export_site') + assert len(json.loads(empty_output)['assets']) == 0 + + Asset(key='footer', asset=File(StringIO('test3'), 'test3.png')).save() + old_stdin = sys.stdin + sys.stdin = StringIO(json.dumps({})) + assert Asset.objects.count() == 1 + try: + call_command('import_site', '-', clean=True) + finally: + sys.stdin = old_stdin + assert Asset.objects.count() == 0 + + with tempfile.NamedTemporaryFile() as f: + f.write(output) + f.flush() + call_command('import_site', f.name) + + assert Asset.objects.count() == 2 + + import_site(data={}, if_empty=True) + assert Asset.objects.count() == 2 -- 2.18.0