From 8c940638789c314c1460e75faea6bc7b57b0f503 Mon Sep 17 00:00:00 2001
From: inso <insomniak.fr@gmaiL.com>
Date: Fri, 7 Apr 2017 00:07:37 +0200
Subject: [PATCH] Export identity and revocation files

---
 .../gui/dialogs/connection_cfg/controller.py  | 41 ++++++++++++++++++-
 src/sakia/gui/dialogs/connection_cfg/model.py |  8 ++++
 .../functional/test_connection_cfg_dialog.py  | 18 +++++++-
 tests/helpers.py                              | 11 ++++-
 4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/src/sakia/gui/dialogs/connection_cfg/controller.py b/src/sakia/gui/dialogs/connection_cfg/controller.py
index d17d6925..83e6efcf 100644
--- a/src/sakia/gui/dialogs/connection_cfg/controller.py
+++ b/src/sakia/gui/dialogs/connection_cfg/controller.py
@@ -1,10 +1,11 @@
 import asyncio
 import logging
 
-from PyQt5.QtCore import QObject
+from PyQt5.QtCore import QObject, Qt
 from aiohttp import ClientError
 from asyncio import TimeoutError
 
+from sakia.gui.widgets.dialogs import dialog_async_exec, QAsyncFileDialog, QMessageBox
 from duniterpy.api.errors import DuniterError
 from duniterpy.documents import MalformedDocumentError
 from sakia.data.connectors import BmaConnector
@@ -212,6 +213,8 @@ class ConnectionConfigController(QObject):
 
             if self.mode == ConnectionConfigController.REGISTER:
                 await self.view.show_register_message(self.model.blockchain_parameters())
+                await self.export_identity_document()
+                await self.action_save_revokation()
         except (NoPeerAvailable, DuniterError, StopIteration) as e:
             if not isinstance(e, StopIteration):
                 self.view.show_error(self.model.notification(), str(e))
@@ -268,6 +271,42 @@ class ConnectionConfigController(QObject):
         self.view.label_info.setText("")
         return True
 
+    async def action_save_revokation(self):
+        raw_document = self.model.generate_revokation()
+        # Testable way of using a QFileDialog
+        selected_files = await QAsyncFileDialog.get_save_filename(self.view, self.tr("Save a revokation document"),
+                                                                  "", self.tr("All text files (*.txt)"))
+        if selected_files:
+            path = selected_files[0]
+            if not path.endswith('.txt'):
+                path = "{0}.txt".format(path)
+            with open(path, 'w') as save_file:
+                save_file.write(raw_document)
+
+            dialog = QMessageBox(QMessageBox.Information, self.tr("Revokation file"),
+                                 self.tr("""<div>Your revokation document has been saved.</div>
+<div><b>Please keep it in a safe place.</b></div>
+The publication of this document will remove your identity from the network.</p>"""), QMessageBox.Ok)
+            dialog.setTextFormat(Qt.RichText)
+            await dialog_async_exec(dialog)
+
+    async def export_identity_document(self):
+        identity, identity_doc = self.model.generate_identity()
+        selected_files = await QAsyncFileDialog.get_save_filename(self.view, self.tr("Save an identity document"),
+                                                                  "", self.tr("All text files (*.txt)"))
+        if selected_files:
+            path = selected_files[0]
+            if not path.endswith('.txt'):
+                path = "{0}.txt".format(path)
+            with open(path, 'w') as save_file:
+                save_file.write(identity_doc.signed_raw())
+
+            dialog = QMessageBox(QMessageBox.Information, self.tr("Identity file"),
+                                 self.tr("""<div>Your identity document has been saved.</div>
+Share this document to your friends for them to certify you.</p>"""), QMessageBox.Ok)
+            dialog.setTextFormat(Qt.RichText)
+            await dialog_async_exec(dialog)
+
     @asyncify
     async def check_pubkey(self, checked=False):
         self._logger.debug("Is valid ? ")
diff --git a/src/sakia/gui/dialogs/connection_cfg/model.py b/src/sakia/gui/dialogs/connection_cfg/model.py
index 28d9b1d4..4f8567f4 100644
--- a/src/sakia/gui/dialogs/connection_cfg/model.py
+++ b/src/sakia/gui/dialogs/connection_cfg/model.py
@@ -56,6 +56,14 @@ class ConnectionConfigModel(QObject):
     def insert_or_update_identity(self, identity):
         self.identities_processor.insert_or_update_identity(identity)
 
+    def generate_revokation(self):
+        return self.app.documents_service.generate_revokation(self.connection,
+                                                              self.connection.salt,
+                                                              self.connection.password)
+
+    def generate_identity(self):
+        return self.app.documents_service.generate_identity(self.connection)
+
     async def initialize_blockchain(self, log_stream):
         """
         Download blockchain information locally
diff --git a/tests/functional/test_connection_cfg_dialog.py b/tests/functional/test_connection_cfg_dialog.py
index 792397f7..d9518097 100644
--- a/tests/functional/test_connection_cfg_dialog.py
+++ b/tests/functional/test_connection_cfg_dialog.py
@@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt
 from PyQt5.QtTest import QTest
 from sakia.data.processors import ConnectionsProcessor
 from sakia.gui.dialogs.connection_cfg import ConnectionConfigController
-from tests.helpers import click_on_top_message_box
+from tests.helpers import click_on_top_message_box, select_file_dialog
 
 
 def assert_key_parameters_behaviour(connection_config_dialog, user):
@@ -35,7 +35,10 @@ def assert_pubkey_parameters_behaviour(connection_config_dialog, user):
 
 
 @pytest.mark.asyncio
-async def test_register_empty_blockchain(application, fake_server, bob):
+async def test_register_empty_blockchain(application, fake_server, bob, tmpdir):
+    tmpdir.mkdir("test_register")
+    revocation_file = tmpdir.join("test_register").join("revocation.txt")
+    identity_file = tmpdir.join("test_register").join("identity.txt")
     connection_config_dialog = ConnectionConfigController.create_connection(None, application)
 
     def close_dialog():
@@ -56,6 +59,17 @@ async def test_register_empty_blockchain(application, fake_server, bob):
         assert connection_config_dialog.view.stacked_pages.currentWidget() == connection_config_dialog.view.page_services
         assert len(ConnectionsProcessor.instanciate(application).connections()) == 1
         click_on_top_message_box()
+        await asyncio.sleep(1)
+        select_file_dialog(str(identity_file))
+        await asyncio.sleep(1)
+        click_on_top_message_box()
+        identity_file.ensure()
+        await asyncio.sleep(1)
+        select_file_dialog(str(revocation_file))
+        await asyncio.sleep(1)
+        click_on_top_message_box()
+        await asyncio.sleep(1)
+        revocation_file.ensure()
 
     application.loop.call_later(10, close_dialog)
     asyncio.ensure_future(exec_test())
diff --git a/tests/helpers.py b/tests/helpers.py
index 74b83d37..6e340a19 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -1,4 +1,4 @@
-from PyQt5.QtWidgets import QApplication, QMessageBox, QDialog
+from PyQt5.QtWidgets import QApplication, QMessageBox, QDialog, QFileDialog
 from PyQt5.QtCore import Qt
 from PyQt5.QtTest import QTest
 
@@ -10,3 +10,12 @@ def click_on_top_message_box():
             QTest.keyClick(w, Qt.Key_Enter)
         elif isinstance(w, QDialog) and w.windowTitle() == "Registration":
             QTest.keyClick(w, Qt.Key_Enter)
+
+def select_file_dialog(filename):
+    topWidgets = QApplication.topLevelWidgets()
+    for w in topWidgets:
+        if isinstance(w, QFileDialog) and w.isVisible():
+            w.hide()
+            w.selectFile(filename)
+            w.show()
+            w.accept()
-- 
GitLab