general: add basic export/import of named assets (#24933)

This commit is contained in:
Frédéric Péters 2018-07-18 10:32:21 +02:00
parent 35d9a1bbba
commit a745d98e7a
3 changed files with 76 additions and 1 deletions

View File

@ -14,8 +14,42 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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()

View File

@ -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 [])

View File

@ -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