From d02974be0de0cbed73e3c4bb996d92dc1c1abacb Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 9 Feb 2021 11:54:43 +0100
Subject: [PATCH] assets: add export/import commands (#50399)

---
 combo/apps/assets/management/__init__.py      |  0
 .../assets/management/commands/__init__.py    |  0
 .../management/commands/export_assets.py      | 35 ++++++++++++++++
 .../management/commands/import_assets.py      | 40 +++++++++++++++++++
 tests/test_assets.py                          | 25 ++++++++++++
 5 files changed, 100 insertions(+)
 create mode 100644 combo/apps/assets/management/__init__.py
 create mode 100644 combo/apps/assets/management/commands/__init__.py
 create mode 100644 combo/apps/assets/management/commands/export_assets.py
 create mode 100644 combo/apps/assets/management/commands/import_assets.py

diff --git a/combo/apps/assets/management/__init__.py b/combo/apps/assets/management/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/combo/apps/assets/management/commands/__init__.py b/combo/apps/assets/management/commands/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/combo/apps/assets/management/commands/export_assets.py b/combo/apps/assets/management/commands/export_assets.py
new file mode 100644
index 00000000..7b1ec085
--- /dev/null
+++ b/combo/apps/assets/management/commands/export_assets.py
@@ -0,0 +1,35 @@
+# combo - content management system
+# Copyright (C) 2021  Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# 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/>.
+
+from django.core.management.base import BaseCommand, CommandError
+
+from combo.apps.assets.utils import export_assets
+
+
+class Command(BaseCommand):
+    help = 'Export assets'
+    def add_arguments(self, parser):
+        parser.add_argument(
+                '--output', metavar='FILE', default='assets_export.tar',
+                help='name of a file to write output to')
+
+    def handle(self, *args, **options):
+        try:
+            output = open(options['output'], 'wb')
+        except IOError as e:
+            raise CommandError(e)
+        export_assets(output)
+        output.close()
diff --git a/combo/apps/assets/management/commands/import_assets.py b/combo/apps/assets/management/commands/import_assets.py
new file mode 100644
index 00000000..af3813d9
--- /dev/null
+++ b/combo/apps/assets/management/commands/import_assets.py
@@ -0,0 +1,40 @@
+# combo - content management system
+# Copyright (C) 2016  Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# 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
+import sys
+import tarfile
+
+from django.core.management.base import BaseCommand, CommandError
+
+from combo.apps.assets.utils import import_assets
+
+class Command(BaseCommand):
+    help = 'Import an exported site'
+
+    def add_arguments(self, parser):
+        parser.add_argument('filename', metavar='FILENAME', type=str,
+                help='name of file to import')
+        parser.add_argument(
+                '--overwrite', action='store_true', default=False,
+                help='Overwrite asset files')
+
+    def handle(self, filename, *args, **options):
+        fd = open(filename, 'rb')
+        try:
+            import_assets(fd, overwrite=options['overwrite'])
+        except ImportSiteError as e:
+            raise CommandError(e)
diff --git a/tests/test_assets.py b/tests/test_assets.py
index 41ad5659..02f25e2a 100644
--- a/tests/test_assets.py
+++ b/tests/test_assets.py
@@ -2,16 +2,17 @@
 
 import base64
 import os
 import tarfile
 
 from django.urls import reverse
 from django.core.files.storage import default_storage
 from django.core.files import File
+from django.core.management import call_command
 from django.utils.six import BytesIO
 
 import pytest
 
 from combo.apps.assets.models import Asset
 from combo.apps.assets.utils import add_tar_content
 from combo.apps.assets.utils import clean_assets_files
 from combo.apps.assets.utils import export_assets
@@ -138,8 +139,32 @@ def test_import_export_assets(some_assets, tmpdir):
     clean_assets_files()
     assert count_asset_files() == 0
     clean_assets_files()
 
 
 def test_assets_export_size_view(app, some_assets):
     resp = app.get(reverse('combo-manager-assets-export-size'))
     assert resp.text.split() == ['(9', 'bytes)']
+    clean_assets_files()
+
+
+def test_cmd_import_export_assets(tmpdir, some_assets):
+    assert Asset.objects.count() == 2
+    assert count_asset_files() == 2
+
+    filename = os.path.join(str(tmpdir), 'file.tar')
+    call_command('export_assets', '--output', filename)
+    Asset.objects.all().delete()
+    assert Asset.objects.count() == 0
+    clean_assets_files()
+
+    Asset(key='banner', asset=File(BytesIO(b'modified'), 'test.png')).save()
+    call_command('import_assets', filename)  # default behaviour
+    assert Asset.objects.count() == 2
+    assert count_asset_files() == 2
+    assert open('%s/assets/test.png' % default_storage.path('')).read() == 'modified'
+
+    call_command('import_assets', filename, '--overwrite')
+    assert Asset.objects.count() == 2
+    assert count_asset_files() == 2
+    assert open('%s/assets/test.png' % default_storage.path('')).read() == 'test'
+    clean_assets_files()
-- 
2.29.2

