From d11d5994562a6c4516bdfb0fa5f931dfd5d32a4e Mon Sep 17 00:00:00 2001 From: inso <insomniak.fr@gmaiL.com> Date: Thu, 13 Apr 2017 08:55:56 +0200 Subject: [PATCH] New certification process --- sakia.spec | 4 +- src/sakia/constants.py | 3 + src/sakia/g1_licence.html | 105 +++++++ src/sakia/gui/dialogs/connection_cfg/view.py | 110 +------- src/sakia/gui/navigation/identity/view.py | 18 -- .../gui/sub/certification/certification.ui | 260 +++++++++++------- src/sakia/gui/sub/certification/controller.py | 35 ++- src/sakia/gui/sub/certification/view.py | 51 +++- src/sakia/gui/sub/search_user/controller.py | 3 + src/sakia/gui/sub/search_user/model.py | 6 +- src/sakia/gui/sub/search_user/view.py | 4 + .../gui/sub/user_information/controller.py | 4 + src/sakia/gui/sub/user_information/model.py | 6 +- src/sakia/gui/sub/user_information/view.py | 4 + src/sakia/root_servers.yml | 7 +- 15 files changed, 360 insertions(+), 260 deletions(-) create mode 100644 src/sakia/g1_licence.html diff --git a/sakia.spec b/sakia.spec index c036561a..1af9d334 100644 --- a/sakia.spec +++ b/sakia.spec @@ -40,10 +40,12 @@ if is_linux: a.binaries = a.binaries + TOC([('libsodium.so', libsodium_path, 'BINARY')]) a.datas = a.datas + [('sakia/root_servers.yml', 'src/sakia/root_servers.yml', 'DATA')] + a.datas = a.datas + [('sakia/g1_licence.html', 'src/sakia/g1_licence.html', 'DATA')] if is_win: a.binaries = a.binaries + TOC([('libsodium.dll', ctypes.util.find_library('libsodium.dll'), 'BINARY')]) - a.datas = a.datas + [('sakia\\root_servers.yml', 'src\\/sakia\\root_servers.yml', 'DATA')] + a.datas = a.datas + [('sakia\\root_servers.yml', 'src\\sakia\\root_servers.yml', 'DATA')] + a.datas = a.datas + [('sakia\\g1_licence.html', 'src\\sakia\\g1_licence.html', 'DATA')] for file in os.listdir(os.path.join("src", "sakia", "data", "repositories")): if file.endswith(".sql"): diff --git a/src/sakia/constants.py b/src/sakia/constants.py index 6daa2dd6..c1ad2bef 100644 --- a/src/sakia/constants.py +++ b/src/sakia/constants.py @@ -5,3 +5,6 @@ MAX_CONFIRMATIONS = 6 with open(os.path.join(os.path.dirname(__file__), "root_servers.yml"), 'r') as stream: ROOT_SERVERS = yaml.load(stream) + +with open(os.path.join(os.path.dirname(__file__), "g1_licence.html"), 'r') as stream: + G1_LICENCE = stream.read() diff --git a/src/sakia/g1_licence.html b/src/sakia/g1_licence.html new file mode 100644 index 00000000..4cedfcbf --- /dev/null +++ b/src/sakia/g1_licence.html @@ -0,0 +1,105 @@ +<H1> License Ğ1 - v0.2 </H1> +<H2> Money licensing and liability commitment. </H2> + +<P>Any certification operation of a new member of Ğ1 +must first be accompanied by the transmission of this + license of the currency Ğ1 whose certifier must ensure + that it has been studied, understood and accepted by the + person who will be certified. +</P> +<H4> Production of Units Ğ1 </h4> +<P> Ğ1 occurs via a Universal Dividend (DU) for any human member, which is of the form: </ p> +<Ul> +<Li> 1 DU per person per day </ li> +</Ul> +<div> +<P> The amount of DU is identical each day until the next equinox, +where the DU will then be reevaluated according to the formula: </p> +</div> +<div> +<ul> +<li> DU <sub> day </sub> (the following equinox) = DU <day> (equinox) + c² (M / N) (equinox) / (15778800 seconds) +</Ul> +</div> +<div> +<P> With as parameters: </p> +</div> +<div> +<Ul> +<Li> c = 4.88% / equinox </li> +<Li> UD (0) = 10.00 Ğ1 </li> +</Ul> +</div> +<div> +<P> And as variables: </p> +</div> +<div> +<Ul> +<Li> <em> M </em> the total monetary mass at the equinox </li> +<Li> <em> N </em> the number of members at the equinox </li> +</Ul> +<div> +<H4>Web of Trust</H4> +</div> +<div> +<P> <strong> Warning: </strong> Certifying is not just about making sure you've met the person, +it's ensuring that the community Ğ1 knows the certified person well enough and Duplicate account +made by a person certified by you, or other types of problems (disappearance ...), +by cross-checking that will reveal the problem if necessary. </P> +</div> +<div> +<P> When you are a member of Ğ1 and you are about to certify a new account: </p> +</div> +<div> +<P> <strong> You are assured: </strong> </p> +</div> +<div> +<P> 1 °) The person who declares to manage this public key (new account) and to +have personally checked with him that this is the public key is sufficiently well known + (not only to know this person visually) that you are about to certify. + </P> +<P> 2a °) To meet her physically to make sure that it is this person you know who manages this public key. </P> +<P> 2b °) Remotely verify the public person / key link by contacting the person via several different means of communication, +such as social network + forum + mail + video conference + phone (acknowledge voice). </P> +<P> Because if you can hack an email account or a forum account, it will be much harder to imagine hacking four distinct + means of communication, and mimic the appearance (video) as well as the voice of the person . </P> +<P> However, the 2 °) is preferable to 3 °, whereas the 1 °) is always indispensable in all cases. </P> +<p> 3 °) To have verified with the person concerned that he has indeed generated his Duniter account revocation document, +which will enable him, if necessary, to cancel his account (in case of account theft, +ID, an incorrectly created account, etc.).</p> +</div> +<h4>Abbreviated Web of Trust rules</h4> +<div><p> +Each member has a stock of 100 possible certifications, +which can only be issued at the rate of 1 certification / 5 days.</p> + +<p>Valid for 2 months, certification for a new member is definitively adopted only if the certified has + at least 4 other certifications after these 2 months, otherwise the entry process will have to be relaunched. +</p> + +<p>To become a new member of TOC Ğ1 therefore 5 certifications +must be obtained at a distance> 5 of 80% of the TOC sentinels.</p> + +<p>A member of the TdC Ğ1 is sentinel when he has received and issued at least Y [N] certifications +where N is the number of members of the TdC and Y [N] = ceiling N ^ (1/5). Examples:</p> + +<ul> +<li>For 1024 < N ≤ 3125 we have Y [N] = 5</li> +<li>For 7776 < N ≤ 16807 we have Y [N] = 7</li> +<li>For 59049 < N ≤ 100 000 we have Y [N] = 10</li> +</ul> + +<p>Once the new member is part of the TOC Ğ1 his certifications remain valid for 2 years.</p> + +<p>To remain a member, you must renew your agreement regularly with your private key (every 12 months) +and make sure you have at least 5 certifications valid after 2 years.</p> + +<h4>Software Ğ1 and license Ğ1</h4> + +<p>The software Ğ1 allowing users to manage their use of Ğ1 must transmit this license with the software +and all the technical parameters of the currency Ğ1 and TdC Ğ1 which are entered in block 0 of Ğ1.</p> + +<p>For more details in the technical details it is possible to consult directly the code of Duniter +which is a free software and also the data of the blockchain Ğ1 by retrieving it via a Duniter instance or node Ğ1.</p> + +More information on the Duniter Team website <a href="https://www.duniter.org">https://www.duniter.org</a> \ No newline at end of file diff --git a/src/sakia/gui/dialogs/connection_cfg/view.py b/src/sakia/gui/dialogs/connection_cfg/view.py index 9f9ba0f5..3961ea3a 100644 --- a/src/sakia/gui/dialogs/connection_cfg/view.py +++ b/src/sakia/gui/dialogs/connection_cfg/view.py @@ -7,7 +7,7 @@ from math import ceil, log from sakia.gui.widgets import toast from sakia.helpers import timestamp_to_dhms from sakia.gui.widgets.dialogs import dialog_async_exec, QAsyncMessageBox -from sakia.constants import ROOT_SERVERS +from sakia.constants import ROOT_SERVERS, G1_LICENCE class ConnectionConfigView(QDialog, Ui_ConnectionConfigurationDialog): @@ -60,113 +60,7 @@ class ConnectionConfigView(QDialog, Ui_ConnectionConfigurationDialog): self.spin_p.blockSignals(False) def set_license(self, currency): - license_text = self.tr(""" -<H1> License Ğ1 - v0.2 </H1> -<H2> Money licensing and liability commitment. </H2> - -<P>Any certification operation of a new member of Ğ1 -must first be accompanied by the transmission of this - license of the currency Ğ1 whose certifier must ensure - that it has been studied, understood and accepted by the - person who will be certified. -</P> -<H4> Production of Units Ğ1 </h4> -<P> Ğ1 occurs via a Universal Dividend (DU) for any human member, which is of the form: </ p> -<Ul> -<Li> 1 DU per person per day </ li> -</Ul> -<div> -<P> The amount of DU is identical each day until the next equinox, -where the DU will then be reevaluated according to the formula: </p> -</div> -<div> -<ul> -<li> DU <sub> day </sub> (the following equinox) = DU <day> (equinox) + c² (M / N) (equinox) / (15778800 seconds) -</Ul> -</div> -<div> -<P> With as parameters: </p> -</div> -<div> -<Ul> -<Li> c = 4.88% / equinox </li> -<Li> UD (0) = 10.00 Ğ1 </li> -</Ul> -</div> -<div> -<P> And as variables: </p> -</div> -<div> -<Ul> -<Li> <em> M </em> the total monetary mass at the equinox </li> -<Li> <em> N </em> the number of members at the equinox </li> -</Ul> -<div> -<H4>Web of Trust</H4> -</div> -<div> -<P> <strong> Warning: </strong> Certifying is not just about making sure you've met the person, -it's ensuring that the community Ğ1 knows the certified person well enough and Duplicate account -made by a person certified by you, or other types of problems (disappearance ...), -by cross-checking that will reveal the problem if necessary. </P> -</div> -<div> -<P> When you are a member of Ğ1 and you are about to certify a new account: </p> -</div> -<div> -<P> <strong> You are assured: </strong> </p> -</div> -<div> -<P> 1 °) The person who declares to manage this public key (new account) and to -have personally checked with him that this is the public key is sufficiently well known - (not only to know this person visually) that you are about to certify. - </P> -<P> 2a °) To meet her physically to make sure that it is this person you know who manages this public key. </P> -<P> 2b °) Remotely verify the public person / key link by contacting the person via several different means of communication, -such as social network + forum + mail + video conference + phone (acknowledge voice). </P> -<P> Because if you can hack an email account or a forum account, it will be much harder to imagine hacking four distinct - means of communication, and mimic the appearance (video) as well as the voice of the person . </P> -<P> However, the 2 °) is preferable to 3 °, whereas the 1 °) is always indispensable in all cases. </P> -<p> 3 °) To have verified with the person concerned that he has indeed generated his Duniter account revocation document, -which will enable him, if necessary, to cancel his account (in case of account theft, -ID, an incorrectly created account, etc.).</p> -</div> -<h4>Abbreviated Web of Trust rules</h4> -<div><p> -Each member has a stock of 100 possible certifications, -which can only be issued at the rate of 1 certification / 5 days.</p> - -<p>Valid for 2 months, certification for a new member is definitively adopted only if the certified has - at least 4 other certifications after these 2 months, otherwise the entry process will have to be relaunched. -</p> - -<p>To become a new member of TOC Ğ1 therefore 5 certifications -must be obtained at a distance> 5 of 80% of the TOC sentinels.</p> - -<p>A member of the TdC Ğ1 is sentinel when he has received and issued at least Y [N] certifications -where N is the number of members of the TdC and Y [N] = ceiling N ^ (1/5). Examples:</p> - -<ul> -<li>For 1024 < N ≤ 3125 we have Y [N] = 5</li> -<li>For 7776 < N ≤ 16807 we have Y [N] = 7</li> -<li>For 59049 < N ≤ 100 000 we have Y [N] = 10</li> -</ul> - -<p>Once the new member is part of the TOC Ğ1 his certifications remain valid for 2 years.</p> - -<p>To remain a member, you must renew your agreement regularly with your private key (every 12 months) -and make sure you have at least 5 certifications valid after 2 years.</p> - -<h4>Software Ğ1 and license Ğ1</h4> - -<p>The software Ğ1 allowing users to manage their use of Ğ1 must transmit this license with the software -and all the technical parameters of the currency Ğ1 and TdC Ğ1 which are entered in block 0 of Ğ1.</p> - -<p>For more details in the technical details it is possible to consult directly the code of Duniter -which is a free software and also the data of the blockchain Ğ1 by retrieving it via a Duniter instance or node Ğ1.</p> - -More information on the Duniter Team website <a href="https://www.duniter.org">https://www.duniter.org</a> -""") + license_text = self.tr(G1_LICENCE) self.text_license.setText(license_text) def handle_n_change(self, value): diff --git a/src/sakia/gui/navigation/identity/view.py b/src/sakia/gui/navigation/identity/view.py index a9585d05..055b635b 100644 --- a/src/sakia/gui/navigation/identity/view.py +++ b/src/sakia/gui/navigation/identity/view.py @@ -72,22 +72,6 @@ class IdentityView(QWidget, Ui_IdentityWidget): mstime_remaining_text = self.tr("Expired or never published") status_color = '#00AA00' if data['membership_state'] else self.tr('#FF0000') - description_currency = """<html> -<body> - <p> - <span style=" font-size:16pt; font-weight:600;">{currency}</span> - </p> - <p>{nb_members} {members_label}</p> - <p><span style="font-weight:600;">{monetary_mass_label}</span> : {monetary_mass}</p> - <p><span style="font-weight:600;">{balance_label}</span> : {balance}</p> -</body> -</html>""".format(currency=data['currency'], - nb_members=data['members_count'], - members_label=self.tr("members"), - monetary_mass_label=self.tr("Monetary mass"), - monetary_mass=data['mass'], - balance_label=self.tr("Balance"), - balance=data['amount']) description_membership = """<html> <body> @@ -110,8 +94,6 @@ class IdentityView(QWidget, Ui_IdentityWidget): mstime_remaining_label=self.tr("Membership"), mstime_remaining=mstime_remaining_text) - self.label_currency.setText(description_currency) - if data['is_identity']: self.label_membership.setText(description_membership) self.label_identity.setText(description_identity) diff --git a/src/sakia/gui/sub/certification/certification.ui b/src/sakia/gui/sub/certification/certification.ui index 626e4130..46a5719f 100644 --- a/src/sakia/gui/sub/certification/certification.ui +++ b/src/sakia/gui/sub/certification/certification.ui @@ -15,108 +15,178 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="groupbox_identity"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="currentIndex"> + <number>0</number> </property> - <property name="title"> - <string>Select your identity</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QComboBox" name="combo_connections"/> - </item> - <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>Certifications stock</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> + <widget class="QWidget" name="page"> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QGroupBox" name="groupbox_identity"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Select your identity</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QComboBox" name="combo_connections"/> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Certifications stock</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QLabel" name="label_cert_stock"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupbox_certified"> + <property name="title"> + <string>Certify user</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="identity_select_layout"> + <item> + <widget class="QPushButton" name="button_import_identity"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Import identity document</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> <item> - <widget class="QLabel" name="label_cert_stock"> + <widget class="QPushButton" name="button_process"> <property name="text"> - <string/> + <string>Process certification</string> </property> </widget> </item> </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupbox_certified"> - <property name="title"> - <string>Certify user</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="button_import_identity"> - <property name="text"> - <string>Import identity document</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QLabel" name="label_confirm"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>label_confirm</string> - </property> - </widget> - </item> - <item> - <widget class="QGroupBox" name="group_box_password"> - <property name="title"> - <string>Secret Key / Password</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <item> - <layout class="QVBoxLayout" name="layout_password_input"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="button_box"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_2"> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Licence</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QTextEdit" name="text_licence"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_confirm"> + <property name="text"> + <string>By going throught the process of creating a wallet, you accept the license above.</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="button_accept"> + <property name="text"> + <string>I accept the above licence</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_3"> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QGroupBox" name="group_box_password"> + <property name="title"> + <string>Secret Key / Password</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <layout class="QVBoxLayout" name="layout_password_input"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="button_box"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> </widget> </item> </layout> diff --git a/src/sakia/gui/sub/certification/controller.py b/src/sakia/gui/sub/certification/controller.py index c658a9a0..3c08a575 100644 --- a/src/sakia/gui/sub/certification/controller.py +++ b/src/sakia/gui/sub/certification/controller.py @@ -159,6 +159,9 @@ using cross checking which will help to reveal the problem if needs to be.</br>" if result[0]: QApplication.restoreOverrideCursor() await self.view.show_success(self.model.notification()) + self.search_user.clear() + self.user_information.clear() + self.view.clear() self.accepted.emit() else: await self.view.show_error(self.model.notification(), result[1]) @@ -166,6 +169,9 @@ using cross checking which will help to reveal the problem if needs to be.</br>" self.view.button_box.setEnabled(True) def reject(self): + self.search_user.clear() + self.user_information.clear() + self.view.clear() self.rejected.emit() def refresh(self): @@ -176,24 +182,25 @@ using cross checking which will help to reveal the problem if needs to be.</br>" if self.model.could_certify(): if written < stock or stock == 0: - if self.password_input.valid(): - if not self.user_information.model.identity: - self.view.set_button_box(CertificationView.ButtonBoxState.SELECT_IDENTITY) - elif days+hours+minutes > 0: - if days > 0: - remaining_localized = self.tr("{days} days").format(days=days) - else: - remaining_localized = self.tr("{hours}h {min}min").format(hours=hours, min=minutes) - self.view.set_button_box(CertificationView.ButtonBoxState.REMAINING_TIME_BEFORE_VALIDATION, - remaining=remaining_localized) + if not self.user_information.model.identity: + self.view.set_button_process(CertificationView.ButtonsState.SELECT_IDENTITY) + elif days+hours+minutes > 0: + if days > 0: + remaining_localized = self.tr("{days} days").format(days=days) else: - self.view.set_button_box(CertificationView.ButtonBoxState.OK) + remaining_localized = self.tr("{hours}h {min}min").format(hours=hours, min=minutes) + self.view.set_button_process(CertificationView.ButtonsState.REMAINING_TIME_BEFORE_VALIDATION, + remaining=remaining_localized) else: - self.view.set_button_box(CertificationView.ButtonBoxState.WRONG_PASSWORD) + self.view.set_button_process(CertificationView.ButtonsState.OK) + if self.password_input.valid(): + self.view.set_button_box(CertificationView.ButtonsState.OK) + else: + self.view.set_button_box(CertificationView.ButtonsState.WRONG_PASSWORD) else: - self.view.set_button_box(CertificationView.ButtonBoxState.NO_MORE_CERTIFICATION) + self.view.set_button_process(CertificationView.ButtonsState.NO_MORE_CERTIFICATION) else: - self.view.set_button_box(CertificationView.ButtonBoxState.NOT_A_MEMBER) + self.view.set_button_process(CertificationView.ButtonsState.NOT_A_MEMBER) def load_identity_document(self, identity_doc): """ diff --git a/src/sakia/gui/sub/certification/view.py b/src/sakia/gui/sub/certification/view.py index 0c6ceaa9..cdcf7b79 100644 --- a/src/sakia/gui/sub/certification/view.py +++ b/src/sakia/gui/sub/certification/view.py @@ -3,7 +3,7 @@ from PyQt5.QtCore import QT_TRANSLATE_NOOP, Qt, pyqtSignal from .certification_uic import Ui_CertificationWidget from sakia.gui.widgets import toast from sakia.gui.widgets.dialogs import QAsyncMessageBox -from sakia.constants import ROOT_SERVERS +from sakia.constants import ROOT_SERVERS, G1_LICENCE from duniterpy.documents import Identity, MalformedDocumentError from enum import Enum @@ -13,7 +13,7 @@ class CertificationView(QWidget, Ui_CertificationWidget): The view of the certification component """ - class ButtonBoxState(Enum): + class ButtonsState(Enum): NO_MORE_CERTIFICATION = 0 NOT_A_MEMBER = 1 REMAINING_TIME_BEFORE_VALIDATION = 2 @@ -21,16 +21,20 @@ class CertificationView(QWidget, Ui_CertificationWidget): SELECT_IDENTITY = 4 WRONG_PASSWORD = 5 - _button_box_values = { - ButtonBoxState.NO_MORE_CERTIFICATION: (False, - QT_TRANSLATE_NOOP("CertificationView", "No more certifications")), - ButtonBoxState.NOT_A_MEMBER: (False, QT_TRANSLATE_NOOP("CertificationView", "Not a member")), - ButtonBoxState.SELECT_IDENTITY: (False, QT_TRANSLATE_NOOP("CertificationView", "Please select an identity")), - ButtonBoxState.REMAINING_TIME_BEFORE_VALIDATION: (True, - QT_TRANSLATE_NOOP("CertificationView", + _button_process_values = { + ButtonsState.NO_MORE_CERTIFICATION: (False, + QT_TRANSLATE_NOOP("CertificationView", "No more certifications")), + ButtonsState.NOT_A_MEMBER: (False, QT_TRANSLATE_NOOP("CertificationView", "Not a member")), + ButtonsState.SELECT_IDENTITY: (False, QT_TRANSLATE_NOOP("CertificationView", "Please select an identity")), + ButtonsState.REMAINING_TIME_BEFORE_VALIDATION: (True, + QT_TRANSLATE_NOOP("CertificationView", "&Ok (Not validated before {remaining})")), - ButtonBoxState.OK: (True, QT_TRANSLATE_NOOP("CertificationView", "&Ok")), - ButtonBoxState.WRONG_PASSWORD: (False, QT_TRANSLATE_NOOP("CertificationView", "Please enter correct password")) + ButtonsState.OK: (True, QT_TRANSLATE_NOOP("CertificationView", "&Process Certification")), + } + + _button_box_values = { + ButtonsState.OK: (True, QT_TRANSLATE_NOOP("CertificationView", "&Ok")), + ButtonsState.WRONG_PASSWORD: (False, QT_TRANSLATE_NOOP("CertificationView", "Please enter correct password")) } identity_document_imported = pyqtSignal(Identity) @@ -49,11 +53,20 @@ class CertificationView(QWidget, Ui_CertificationWidget): self.search_user_view = search_user_view self.user_information_view = user_information_view self.password_input_view = password_input_view - self.groupbox_certified.layout().addWidget(search_user_view) + self.identity_select_layout.insertWidget(0, search_user_view) self.search_user_view.button_reset.hide() self.layout_password_input.addWidget(password_input_view) self.groupbox_certified.layout().addWidget(user_information_view) self.button_import_identity.clicked.connect(self.import_identity_document) + self.button_process.clicked.connect(lambda c: self.stackedWidget.setCurrentIndex(1)) + self.button_accept.clicked.connect(lambda c: self.stackedWidget.setCurrentIndex(2)) + + licence_text = self.tr(G1_LICENCE) + self.text_licence.setText(licence_text) + + def clear(self): + self.stackedWidget.setCurrentIndex(0) + self.set_button_process(CertificationView.ButtonsState.SELECT_IDENTITY) def set_keys(self, connections): self.combo_connections.clear() @@ -87,8 +100,7 @@ class CertificationView(QWidget, Ui_CertificationWidget): def set_label_confirm(self, currency): self.label_confirm.setTextFormat(Qt.RichText) self.label_confirm.setText("""<b>Vous confirmez engager votre responsabilité envers la communauté Duniter {:} - et acceptez de certifier le compte Duniter {:} ci-dessus.<br/><br/> -Pour confirmer votre certification veuillez confirmer votre signature :</b>""".format(ROOT_SERVERS[currency]["display"], + et acceptez de certifier le compte Duniter {:} sélectionné.<br/><br/>""".format(ROOT_SERVERS[currency]["display"], ROOT_SERVERS[currency]["display"])) async def show_success(self, notification): @@ -145,3 +157,14 @@ Pour confirmer votre certification veuillez confirmer votre signature :</b>""".f button_box_state = CertificationView._button_box_values[state] self.button_box.button(QDialogButtonBox.Ok).setEnabled(button_box_state[0]) self.button_box.button(QDialogButtonBox.Ok).setText(button_box_state[1].format(**kwargs)) + + def set_button_process(self, state, **kwargs): + """ + Set button box state + :param sakia.gui.certification.view.CertificationView.ButtonBoxState state: the state of te button box + :param dict kwargs: the values to replace from the text in the state + :return: + """ + button_process_state = CertificationView._button_process_values[state] + self.button_process.setEnabled(button_process_state[0]) + self.button_process.setText(button_process_state[1].format(**kwargs)) diff --git a/src/sakia/gui/sub/search_user/controller.py b/src/sakia/gui/sub/search_user/controller.py index 67649e7e..7973c676 100644 --- a/src/sakia/gui/sub/search_user/controller.py +++ b/src/sakia/gui/sub/search_user/controller.py @@ -59,3 +59,6 @@ class SearchUserController(QObject): if self.model.select_identity(index): self.identity_selected.emit(self.model.identity()) + def clear(self): + self.model.clear() + self.view.clear() \ No newline at end of file diff --git a/src/sakia/gui/sub/search_user/model.py b/src/sakia/gui/sub/search_user/model.py index 8839788c..2afcabe9 100644 --- a/src/sakia/gui/sub/search_user/model.py +++ b/src/sakia/gui/sub/search_user/model.py @@ -69,4 +69,8 @@ class SearchUserModel(QObject): self._current_identity = None return False self._current_identity = self._nodes[index] - return True \ No newline at end of file + return True + + def clear(self): + self._current_identity = None + self._nodes = list() \ No newline at end of file diff --git a/src/sakia/gui/sub/search_user/view.py b/src/sakia/gui/sub/search_user/view.py index 8f8c4205..58636e22 100644 --- a/src/sakia/gui/sub/search_user/view.py +++ b/src/sakia/gui/sub/search_user/view.py @@ -29,6 +29,10 @@ class SearchUserView(QWidget, Ui_SearchUserWidget): self.combobox_search.setInsertPolicy(QComboBox.NoInsert) self.combobox_search.activated.connect(self.node_selected) + def clear(self): + self.combobox_search.clear() + self.combobox_search.lineEdit().setPlaceholderText(self.tr(SearchUserView._search_placeholder)) + def search(self, text=""): """ Search nodes when return is pressed in combobox lineEdit diff --git a/src/sakia/gui/sub/user_information/controller.py b/src/sakia/gui/sub/user_information/controller.py index 1e6f3264..a54de72e 100644 --- a/src/sakia/gui/sub/user_information/controller.py +++ b/src/sakia/gui/sub/user_information/controller.py @@ -89,6 +89,10 @@ class UserInformationController(QObject): self.refresh() self.view.hide_busy() + def clear(self): + self.model.clear() + self.view.clear() + def change_identity(self, identity): """ Set identity diff --git a/src/sakia/gui/sub/user_information/model.py b/src/sakia/gui/sub/user_information/model.py index a8ee2aea..982903ef 100644 --- a/src/sakia/gui/sub/user_information/model.py +++ b/src/sakia/gui/sub/user_information/model.py @@ -21,9 +21,9 @@ class UserInformationModel(QObject): self.app = app self.identity = identity self.identities_service = self.app.identities_service - if identity: - self.certs_sent = self._certifications_processor.certifications_sent(identity.currency, identity.pubkey) - self.certs_received = self._certifications_processor.certifications_received(identity.currency, identity.pubkey) + + def clear(self): + self.identity = None async def load_identity(self, identity): """ diff --git a/src/sakia/gui/sub/user_information/view.py b/src/sakia/gui/sub/user_information/view.py index 8a0ccbc2..c6d1acdc 100644 --- a/src/sakia/gui/sub/user_information/view.py +++ b/src/sakia/gui/sub/user_information/view.py @@ -102,6 +102,10 @@ class UserInformationView(QWidget, Ui_UserInformationWidget): def hide_busy(self): self.busy.hide() + def clear(self): + self.label_properties.setText("") + self.label_uid.setText("") + def resizeEvent(self, event): self.busy.resize(event.size()) super().resizeEvent(event) \ No newline at end of file diff --git a/src/sakia/root_servers.yml b/src/sakia/root_servers.yml index 7f7d8b02..91cab01d 100644 --- a/src/sakia/root_servers.yml +++ b/src/sakia/root_servers.yml @@ -1,8 +1,3 @@ -fakenet: - display: fakenet - nodes: - HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk: - - "BASIC_MERKLED_API fakenet.cgeek.fr 10900" gtest: display: ğtest nodes: @@ -13,4 +8,4 @@ g1: nodes: 4aCqwikTaTPBRQLGiLHohuoJLPmLephy9eDtgCWLMwBk: - "BMAS g1.duniter.org 443" - - "BMA_ENDPOINT_API g1.duniter.org 80" + - "BMA_ENDPOINT_API g1.duniter.org 10901" -- GitLab