From aac84aeab34fb139ff135336987e7535adf9d977 Mon Sep 17 00:00:00 2001
From: inso <insomniak.fr@gmaiL.com>
Date: Mon, 5 Dec 2016 12:51:56 +0100
Subject: [PATCH] Working on certificaton dialog

---
 src/sakia/data/processors/certifications.py   | 15 ++++
 src/sakia/data/processors/sources.py          |  1 -
 src/sakia/data/repositories/certifications.py | 17 +++++
 .../dialogs/certification/certification.ui    | 53 +-------------
 .../gui/dialogs/certification/controller.py   | 31 ++++----
 src/sakia/gui/dialogs/certification/model.py  | 70 ++++++-------------
 6 files changed, 69 insertions(+), 118 deletions(-)

diff --git a/src/sakia/data/processors/certifications.py b/src/sakia/data/processors/certifications.py
index 9065ef17..07e96dba 100644
--- a/src/sakia/data/processors/certifications.py
+++ b/src/sakia/data/processors/certifications.py
@@ -44,6 +44,21 @@ class CertificationsProcessor:
         """
         return self._certifications_repo.get_all(currency=currency, certified=pubkey)
 
+    def cert_issuance_delay(self, currency, pubkey, parameters, blockchain_time):
+        """
+        Get the remaining time before being able to issue new certification.
+        :param str currency: the currency of the certifications
+        :param str pubkey: the pubkey of the certifications
+        :param sakia.data.entities.BlockchainParameters parameters: the parameters of the blockchain
+        :param int blockchain_time: the current time of the blockchain
+        :return: the remaining time
+        :rtype: int
+        """
+        certified = self._certifications_repo.get_latest_sent(currency=currency, certifier=pubkey)
+        if certified and blockchain_time - certified.timestamp < parameters.sig_period:
+            return parameters.sig_period - (blockchain_time - certified.timestamp)
+        return 0
+
     def create_certification(self, currency, cert, blockstamp):
         """
         Creates a certification and insert it in the db
diff --git a/src/sakia/data/processors/sources.py b/src/sakia/data/processors/sources.py
index 4ebef26a..0d43d4af 100644
--- a/src/sakia/data/processors/sources.py
+++ b/src/sakia/data/processors/sources.py
@@ -4,7 +4,6 @@ from ..entities import Source
 from .nodes import NodesProcessor
 from ..connectors import BmaConnector
 from duniterpy.api import bma, errors
-from duniterpy.documents import Block, BMAEndpoint
 import asyncio
 
 
diff --git a/src/sakia/data/repositories/certifications.py b/src/sakia/data/repositories/certifications.py
index 87a5f7de..10624202 100644
--- a/src/sakia/data/repositories/certifications.py
+++ b/src/sakia/data/repositories/certifications.py
@@ -78,6 +78,23 @@ class CertificationsRepo:
             return [Certification(*data) for data in datas]
         return []
 
+    def get_latest_sent(self, currency, pubkey):
+        """
+        Get latest sent certification
+        :param str currency:
+        :param str pubkey:
+        :return:
+        :rtype: sakia.data.entities.Certification
+        """
+        request = """SELECT * FROM certifications
+                  WHERE currency=? AND certifier=?
+                  ORDER BY timestamp DESC
+                  LIMIT 1"""
+        c = self._conn.execute(request, (currency, pubkey))
+        data = c.fetchone()
+        if data:
+            return Certification(*data)
+
     def drop(self, certification):
         """
         Drop an existing certification from the database
diff --git a/src/sakia/gui/dialogs/certification/certification.ui b/src/sakia/gui/dialogs/certification/certification.ui
index b45c0930..7f45c2f7 100644
--- a/src/sakia/gui/dialogs/certification/certification.ui
+++ b/src/sakia/gui/dialogs/certification/certification.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>715</width>
-    <height>477</height>
+    <width>517</width>
+    <height>316</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -59,55 +59,6 @@
         <property name="topMargin">
          <number>6</number>
         </property>
-        <item>
-         <layout class="QHBoxLayout" name="layout_mode_contact">
-          <item>
-           <widget class="QRadioButton" name="radio_contact">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Con&amp;tact</string>
-            </property>
-            <property name="checked">
-             <bool>true</bool>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <spacer name="horizontalSpacer">
-            <property name="orientation">
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeType">
-             <enum>QSizePolicy::Maximum</enum>
-            </property>
-            <property name="sizeHint" stdset="0">
-             <size>
-              <width>20</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item>
-           <widget class="QComboBox" name="combo_contact">
-            <property name="enabled">
-             <bool>true</bool>
-            </property>
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </item>
         <item>
          <layout class="QHBoxLayout" name="layout_mode_pubkey">
           <item>
diff --git a/src/sakia/gui/dialogs/certification/controller.py b/src/sakia/gui/dialogs/certification/controller.py
index 7a19764b..d5a64f47 100644
--- a/src/sakia/gui/dialogs/certification/controller.py
+++ b/src/sakia/gui/dialogs/certification/controller.py
@@ -42,13 +42,11 @@ class CertificationController(ComponentController):
         :rtype: CertificationController
         """
 
-        view = CertificationView(parent.view, None, None, communities_names, contacts_names)
-        model = CertificationModel(None, app, account, community)
+        view = CertificationView(parent.view, None, None)
+        model = CertificationModel(None, app)
         certification = cls(parent, view, model, None, None)
 
-        search_user = SearchUserController.create(certification, app,
-                                                  account=model.account,
-                                                  community=model.community)
+        search_user = SearchUserController.create(certification, app)
         certification.set_search_user(search_user)
 
         user_information = UserInformationController.create(certification, app,
@@ -156,25 +154,20 @@ class CertificationController(ComponentController):
         """
         pubkey = None
 
-        if self.view.recipient_mode() == CertificationView.RecipientMode.CONTACT:
-            contact_name = self.view.selected_contact()
-            pubkey = self.model.contact_name_pubkey(contact_name)
-        elif self.view.recipient_mode() == CertificationView.RecipientMode.SEARCH:
+        if self.view.recipient_mode() == CertificationView.RecipientMode.SEARCH:
             if self.search_user.current_identity():
                 pubkey = self.search_user.current_identity().pubkey
         else:
             pubkey = self.view.pubkey_value()
         return pubkey
 
-    @once_at_a_time
-    @asyncify
-    async def refresh(self):
+    def refresh(self):
         stock = self.model.get_cert_stock()
-        written, pending = await self.model.nb_certifications()
-        days, hours, minutes, seconds = await self.model.remaining_time()
+        written, pending = self.model.nb_certifications()
+        days, hours, minutes, seconds = self.model.remaining_time()
         self.view.display_cert_stock(written, pending, stock, days, hours, minutes)
 
-        if await self.model.could_certify():
+        if self.model.could_certify():
             if written < stock or stock == 0:
                 if days+hours+minutes > 0:
                     if days > 0:
@@ -197,10 +190,10 @@ class CertificationController(ComponentController):
         pubkey = self.selected_pubkey()
         self.user_information.search_identity(pubkey)
 
-    def change_current_community(self, index):
-        self.model.change_community(index)
-        self.search_user.set_community(self.community)
-        self.user_information.change_community(self.community)
+    def change_current_connection(self, index):
+        self.model.change_connection(index)
+        self.search_user.set_connection(self.model.connection)
+        self.user_information.change_connection(self.model.connection)
         self.refresh()
 
     def async_exec(self):
diff --git a/src/sakia/gui/dialogs/certification/model.py b/src/sakia/gui/dialogs/certification/model.py
index 5bb46468..dbadf913 100644
--- a/src/sakia/gui/dialogs/certification/model.py
+++ b/src/sakia/gui/dialogs/certification/model.py
@@ -1,8 +1,5 @@
 from sakia.gui.component.model import ComponentModel
-from duniterpy.api import errors
-from sakia.errors import NoPeerAvailable
-
-import logging
+from sakia.data.processors import IdentitiesProcessor, CertificationsProcessor, BlockchainProcessor
 
 
 class CertificationModel(ComponentModel):
@@ -10,42 +7,26 @@ class CertificationModel(ComponentModel):
     The model of Certification component
     """
 
-    def __init__(self, parent, app, identity, currency,
-                 connections_repo, identities_processor, blockchain_processor):
+    def __init__(self, parent, app, connection):
         """
         The data model of the certification dialog
         :param parent:
         :param sakia.app.Application app:
-        :param sakia.data.entities.Identity identity: the identity of the certifier
-        :param str currency:
-        :param sakia.data.repositories.ConnectionsRepository connections_repo:
-        :param sakia.data.processors.IdentitiesProcessor identities_processor:
-        :param sakia.data.processors.BlockchainProcessor blockchain_processor:
+        :param sakia.data.entities.Connection connection: the connection used to certify
         """
         super().__init__(parent)
         self.app = app
-        self.currency = currency
-        self.connections_repo = connections_repo
-        self.identities_processor = identities_processor
-        self.blockchain_processor = blockchain_processor
+        self.connection = connection
+        self._certifications_processor = CertificationsProcessor.instanciate(app)
+        self._identities_processor = IdentitiesProcessor.instanciate(app)
+        self._blockchain_processor = BlockchainProcessor.instanciate(app)
 
-    def contact_name_pubkey(self, name):
-        """
-        Get the pubkey of a contact from its name
-        :param str name:
-        :return:
-        :rtype: str
-        """
-        for contact in self.account.contacts:
-            if contact['name'] == name:
-                return contact['pubkey']
-
-    def change_currency(self, index):
+    def change_connection(self, index):
         """
         Change current currency
         :param int index: index of the community in the account list
         """
-        self.currency = self.connections_repo.get_currencies()[index]
+        self.connection = self.connections_repo.get_currencies()[index]
 
     def get_cert_stock(self):
         """
@@ -55,45 +36,40 @@ class CertificationModel(ComponentModel):
         """
         return self.blockchain_processor.parameters(self.currency).sig_stock
 
-    async def remaining_time(self):
+    def remaining_time(self):
         """
         Get remaining time as a tuple to display
         :return: a tuple containing (days, hours, minutes, seconds)
         :rtype: tuple[int]
         """
-        remaining_time = await account_identity.cert_issuance_delay(self.app.identities_registry, self.currency)
+        remaining_time = self._certifications_processor.cert_issuance_delay(self.connection.currency,
+                                                                            self.connection.pubkey)
 
         days, remainder = divmod(remaining_time, 3600 * 24)
         hours, remainder = divmod(remainder, 3600)
         minutes, seconds = divmod(remainder, 60)
         return days, hours, minutes, seconds
 
-    async def nb_certifications(self):
+    def nb_certifications(self):
         """
         Get
         :return: a tuple containing (written valid certifications, pending certifications)
         :rtype: tuple[int]
         """
-        account_identity = await self.account.identity(self.currency)
-        certifications = await account_identity.unique_valid_certified_by(self.app.identities_registry, self.currency)
-        nb_certifications = len([c for c in certifications if c['block_number']])
-        nb_cert_pending = len([c for c in certifications if not c['block_number']])
+        certifications = self._certifications_processor.certifications_sent(self.connection.currency,
+                                                                            self.connection.pubkey)
+        nb_certifications = len([c for c in certifications if c.written_on])
+        nb_cert_pending = len([c for c in certifications if not c.written_on])
         return nb_certifications, nb_cert_pending
 
-    async def could_certify(self):
+    def could_certify(self):
         """
         Check if the user could theorically certify
         :return: true if the user can certifiy
         :rtype: bool
         """
-        account_identity = await self.account.identity(self.community)
-        is_member = await account_identity.is_member(self.community)
-        try:
-            block_0 = await self.community.get_block(0)
-        except errors.DuniterError as e:
-            if e.ucode == errors.BLOCK_NOT_FOUND:
-                block_0 = None
-        except NoPeerAvailable as e:
-            logging.debug(str(e))
-            block_0 = None
-        return is_member or not block_0
\ No newline at end of file
+        is_member = self._identities_processor.get_identity(self.connection.currency,
+                                                            self.connection.pubkey,
+                                                            self.connection.pubkey)
+
+        return is_member and self._blockchain_processor.current_buid(self.connection.currency)
-- 
GitLab