From 1321c56ded404249a49f7048d2928cdf0ae53e33 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 30 Jul 2020 19:06:58 +0200
Subject: [PATCH] pwa: import/export pwa application-icon (#44833)

---
 combo/apps/pwa/models.py    | 15 ++++++++++++++-
 tests/test_import_export.py | 18 ++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/combo/apps/pwa/models.py b/combo/apps/pwa/models.py
index 281089a0..7549148c 100644
--- a/combo/apps/pwa/models.py
+++ b/combo/apps/pwa/models.py
@@ -76,27 +76,40 @@ class PwaSettings(models.Model):
         return cls.objects.first() or cls()
 
     @classmethod
     def export_for_json(cls):
         obj = cls.singleton()
         if not obj.id:
             return {}
         serialized_settings = json.loads(serializers.serialize('json', [obj]))
-        return serialized_settings[0].get('fields')
+        result = serialized_settings[0].get('fields')
+        result['icon:base64'] = force_text(base64.encodebytes(obj.application_icon.read()))
+        return result
 
     @classmethod
     def load_serialized_settings(cls, json_settings):
         if not json_settings:
             return
 
         obj = cls.singleton()
+        decoded_icon = None
+        if json_settings.get('icon:base64'):
+            decoded_icon = base64.decodebytes(force_bytes(json_settings['icon:base64']))
+            del json_settings['icon:base64']
         for attr in json_settings:
             setattr(obj, attr, json_settings[attr])
         obj.save()
+        if decoded_icon:
+            if not default_storage.exists(obj.application_icon.name) or obj.application_icon.read() != decoded_icon:
+                # save new file
+                path = obj.application_icon.name
+                if path.startswith('pwa/'):
+                    path = path[len('pwa/'):]
+                obj.application_icon.save(path, ContentFile(decoded_icon))
 
     @classmethod
     def get_default_application_name(cls):
         return settings.TEMPLATE_VARS.get('global_title') or 'Compte Citoyen'
 
     def get_application_name(self):
         return self.application_name or self.get_default_application_name()
 
diff --git a/tests/test_import_export.py b/tests/test_import_export.py
index e8ab90c4..2278c76e 100644
--- a/tests/test_import_export.py
+++ b/tests/test_import_export.py
@@ -255,24 +255,42 @@ def test_import_export_assets(app, some_assets):
     import_site(data={}, if_empty=True)
     assert Asset.objects.count() == 2
 
 def test_import_export_pwa_settings(app):
     output = get_output_of_command('export_site')
     pwa_settings = PwaSettings.singleton()
     pwa_settings.offline_text = 'Hello world'
     pwa_settings.offline_retry_button = False
+    pwa_settings.application_icon = File(BytesIO(b'te\30st'), 'test.png')
     pwa_settings.save()
     output = get_output_of_command('export_site')
     import_site(data={}, clean=True)
     assert PwaSettings.objects.all().count() == 0
 
     import_site(data=json.loads(output))
     assert PwaSettings.singleton().offline_retry_button is False
     assert PwaSettings.singleton().offline_text == 'Hello world'
+    # check identical file was not touched
+    assert os.path.basename(PwaSettings.objects.get().application_icon.file.name) == 'test.png'
+    assert PwaSettings.objects.get().application_icon.read() == b'te\30st'
+
+    # check with a change in icon file content
+    data = json.loads(output)
+    data['pwa']['settings']['icon:base64'] = force_text(base64.encodebytes(b'TEST'))
+    import_site(data=data)
+    assert PwaSettings.objects.get().application_icon.read() == b'TEST'
+
+    # check with a change in icon file name
+    data = json.loads(output)
+    data['pwa']['settings']['icon:base64'] = force_text(base64.encodebytes(b'TEST2'))
+    data['pwa']['settings']['application_icon'] = 'pwa/test2.png'
+    import_site(data=data)
+    assert os.path.basename(PwaSettings.objects.get().application_icon.file.name) == 'test2.png'
+    assert PwaSettings.objects.get().application_icon.read() == b'TEST2'
 
 def test_import_export_pwa_navigation(app, some_data):
     page = Page.objects.get(slug='one')
     entry1 = PwaNavigationEntry(label='a', url='/', order=0)
     entry2 = PwaNavigationEntry(link_page=page, order=1, icon=File(BytesIO(b'te\30st'), 'test.png'))
     entry1.save()
     entry2.save()
     output = get_output_of_command('export_site')
-- 
2.27.0

