diff --git a/src/sakia/gui/dialogs/certification/controller.py b/src/sakia/gui/dialogs/certification/controller.py index b804a2dd865ee9373f81c7067e74c1b9fb086f56..1f96b82138d65da2eda1bfd8fd6fe5689c54d10b 100644 --- a/src/sakia/gui/dialogs/certification/controller.py +++ b/src/sakia/gui/dialogs/certification/controller.py @@ -7,6 +7,7 @@ from sakia.decorators import asyncify from sakia.gui.sub.search_user.controller import SearchUserController from sakia.gui.sub.user_information.controller import UserInformationController from sakia.gui.sub.password_input import PasswordInputController +from sakia.gui.widgets import dialogs from .model import CertificationModel from .view import CertificationView import attr @@ -103,11 +104,33 @@ class CertificationController(QObject): """ Validate the dialog """ + + if not self.user_information.model.identity.member: + result = await dialogs.QAsyncMessageBox.question(self.view, "Certifying a non-member", +""" +Did you ensure that :<br> +<br/> +1°) <b>You know the person declaring owning this pubkey +well enough and to personally verify that it is the correct key you are going to certify.</b><br/> +2°) To physically meet her to ensure that it is the person you know who owns this pubkey.<br/> +3°) Or did you ensure by contacting her using multiple communications means, +like forum + mail + videoconferencing + phone (to recognize voice)<br/> +Because if one can hack 1 mail account or 1 forum account, it will be way more difficult to hack multiple +communication means and imitate the voice of the person.<br/> +<br/> +The 2°) is however preferable to the 3°)... whereas <b>1°) is mandatory in any case.</b><br/> +<br/> +<b>Reminder</b> : Certifying is not only uniquely ensuring that you met the person, its ensuring the {0} community +that you know her well enough and that you will know how to find a double account done by a person certified by you +using cross checking which will help to reveal the problem if needs to be.</br>""") + if result == dialogs.QMessageBox.No: + return + self.view.button_box.setDisabled(True) secret_key, password = self.password_input.get_salt_password() QApplication.setOverrideCursor(Qt.WaitCursor) result = await self.model.certify_identity(secret_key, password, self.user_information.model.identity) - +# if result[0]: QApplication.restoreOverrideCursor() await self.view.show_success(self.model.notification()) @@ -129,21 +152,22 @@ class CertificationController(QObject): if self.model.could_certify(): if written < stock or stock == 0: - 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) + 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) 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) - elif self.password_input.valid(): - self.view.set_button_box(CertificationView.ButtonBoxState.OK) + self.view.set_button_box(CertificationView.ButtonBoxState.OK) else: self.view.set_button_box(CertificationView.ButtonBoxState.WRONG_PASSWORD) else: - self.view.set_button_box(CertificationView.ButtonBoxState.NO_MORE_CERTIFICATION) + self.view.set_button_box(CertificationView.ButtonBoxState.NO_MORE_CERTIFICATION) else: self.view.set_button_box(CertificationView.ButtonBoxState.NOT_A_MEMBER) diff --git a/src/sakia/gui/navigation/informations/controller.py b/src/sakia/gui/navigation/informations/controller.py index a65bb4347ffb52df832508276714cb7872914bcd..402c9618127ad704b31091959c9a22b7df5945f3 100644 --- a/src/sakia/gui/navigation/informations/controller.py +++ b/src/sakia/gui/navigation/informations/controller.py @@ -10,7 +10,7 @@ from .view import InformationsView from sakia.decorators import asyncify from sakia.gui.sub.password_input import PasswordInputController from sakia.gui.widgets import toast -from sakia.gui.widgets.dialogs import QAsyncMessageBox +from sakia.gui.widgets.dialogs import QAsyncMessageBox, QMessageBox class InformationsController(QObject): @@ -107,6 +107,12 @@ class InformationsController(QObject): async def send_join_demand(self, checked=False): if not self.model.connection: return + if not self.model.get_identity_data()["membership_state"]: + result = await self.view.licence_dialog(self.model.connection.currency, + self.model.parameters()) + if result == QMessageBox.No: + return + secret_key, password = await PasswordInputController.open_dialog(self, self.model.connection) if not password or not secret_key: return diff --git a/src/sakia/gui/navigation/informations/view.py b/src/sakia/gui/navigation/informations/view.py index 3e1715606a06c59451cd47a3374c28a3da51d5ae..f5d3988b54dc5d0bd68a8d3185a5ae355d846544 100644 --- a/src/sakia/gui/navigation/informations/view.py +++ b/src/sakia/gui/navigation/informations/view.py @@ -1,8 +1,10 @@ -from PyQt5.QtWidgets import QWidget +from PyQt5.QtWidgets import QWidget, QMessageBox from PyQt5.QtCore import QEvent, QLocale, pyqtSignal from .informations_uic import Ui_InformationsWidget from enum import Enum from sakia.helpers import timestamp_to_dhms +from sakia.constants import ROOT_SERVERS +from sakia.gui.widgets.dialogs import dialog_async_exec class InformationsView(QWidget, Ui_InformationsWidget): @@ -301,35 +303,112 @@ class InformationsView(QWidget, Ui_InformationsWidget): self.label_wot.setText( self.tr(""" <table cellpadding="5"> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> - </table> - """).format( - QLocale().toString(params.sig_period / 86400, 'f', 2), - self.tr('Minimum delay between 2 certifications (in days)'), - QLocale().toString(params.sig_validity / 86400, 'f', 2), - self.tr('Maximum age of a valid signature (in days)'), - params.sig_qty, - self.tr('Minimum quantity of signatures to be part of the WoT'), - params.sig_stock, - self.tr('Maximum quantity of active certifications made by member.'), - params.sig_window, - self.tr('Maximum delay a certification can wait before being expired for non-writing.'), - params.xpercent, - self.tr('Minimum percent of sentries to reach to match the distance rule'), - params.ms_validity / 86400, - self.tr('Maximum age of a valid membership (in days)'), - params.step_max, - self.tr('Maximum distance between each WoT member and a newcomer'), +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +<tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +</table> +""").format( + QLocale().toString(params.sig_period / 86400, 'f', 2), + self.tr('Minimum delay between 2 certifications (in days)'), + QLocale().toString(params.sig_validity / 86400, 'f', 2), + self.tr('Maximum age of a valid signature (in days)'), + params.sig_qty, + self.tr('Minimum quantity of signatures to be part of the WoT'), + params.sig_stock, + self.tr('Maximum quantity of active certifications made by member.'), + params.sig_window, + self.tr('Maximum delay a certification can wait before being expired for non-writing.'), + params.xpercent, + self.tr('Minimum percent of sentries to reach to match the distance rule'), + params.ms_validity / 86400, + self.tr('Maximum age of a valid membership (in days)'), + params.step_max, + self.tr('Maximum distance between each WoT member and a newcomer'), ) ) + async def licence_dialog(self, currency, params): + dt_dhms = timestamp_to_dhms(params.dt) + if dt_dhms[0] > 0: + dt_as_str = self.tr("{:} day(s) {:} hour(s)").format(*dt_dhms) + else: + dt_as_str = self.tr("{:} hour(s)").format(dt_dhms[1]) + if dt_dhms[2] > 0 or dt_dhms[3] > 0: + dt_dhms += ", {:} minute(s) and {:} second(s)".format(*dt_dhms[1:]) + dt_reeval_dhms = timestamp_to_dhms(params.dt_reeval) + dt_reeval_as_str = self.tr("{:} day(s) {:} hour(s)").format(*dt_reeval_dhms) + + message_box = QMessageBox(self) + + message_box.setText("Do you recognize the terms of the following licence :") + message_box.setInformativeText(""" +{:} is being produced by a Universal Dividend (UD) for any human member, which is :<br/> +<br/> +<table cellpadding="5"> + <tr><td align="right"><b>{:2.0%} / {:} days</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:} {:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +</table> +<br/> +<br/> + +The parameters of the Web of Trust of {:} are :<br/> +<table cellpadding="5"> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> +</table> +<br/> +<br/> + +<b>By asking to join as member, you recognize that this is your unique account, +and that you will only certify persons that you know well enough.</b> + """.format( + ROOT_SERVERS[currency]["display"], + params.c, + QLocale().toString(params.dt / 86400, 'f', 2), + self.tr('Fundamental growth (c)'), + params.ud0, + self.tr('Initial Universal Dividend UD(0) in'), + ROOT_SERVERS[currency]["display"], + dt_as_str, + self.tr('Time period between two UD'), + dt_reeval_as_str, + self.tr('Time period between two UD reevaluation'), + ROOT_SERVERS[currency]["display"], + QLocale().toString(params.sig_period / 86400, 'f', 2), + self.tr('Minimum delay between 2 certifications (in days)'), + QLocale().toString(params.sig_validity / 86400, 'f', 2), + self.tr('Maximum age of a valid signature (in days)'), + params.sig_qty, + self.tr('Minimum quantity of signatures to be part of the WoT'), + params.sig_stock, + self.tr('Maximum quantity of active certifications made by member.'), + params.sig_window, + self.tr('Maximum delay a certification can wait before being expired for non-writing.'), + params.xpercent, + self.tr('Minimum percent of sentries to reach to match the distance rule'), + params.ms_validity / 86400, + self.tr('Maximum age of a valid membership (in days)'), + params.step_max, + self.tr('Maximum distance between each WoT member and a newcomer'), + ) + ) + message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No ) + message_box.setDefaultButton(QMessageBox.No) + return await dialog_async_exec(message_box) + def changeEvent(self, event): """ Intercepte LanguageChange event to translate UI diff --git a/src/sakia/gui/sub/user_information/user_information.ui b/src/sakia/gui/sub/user_information/user_information.ui index b7aa85477487eaa90d1ad37f283857503996d91a..8dd0958db218eb0a4d50f9ef7c8bd45ed48acbc8 100644 --- a/src/sakia/gui/sub/user_information/user_information.ui +++ b/src/sakia/gui/sub/user_information/user_information.ui @@ -33,60 +33,79 @@ QGroupBox::title { <property name="title"> <string>User</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="1"> - <widget class="QLabel" name="label_icon"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>81</width> - <height>71</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../res/icons/icons.qrc">:/icons/member_icon</pixmap> - </property> - <property name="scaledContents"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="widgetResizable"> <bool>true</bool> </property> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QLabel" name="label_properties"> - <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="label_uid"> - <property name="maximumSize"> - <size> - <width>471</width> - <height>51</height> - </size> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="3" column="1" colspan="2"> - <widget class="QLabel" name="label_path"> - <property name="text"> - <string/> - </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>362</width> + <height>212</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="5" column="0"> + <widget class="QLabel" name="label_path"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_properties"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_icon"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>81</width> + <height>71</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../../../../../res/icons/icons.qrc">:/icons/member_icon</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_uid"> + <property name="maximumSize"> + <size> + <width>471</width> + <height>51</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> </widget> </item> </layout> @@ -95,8 +114,9 @@ QGroupBox::title { </layout> </widget> <resources> - <include location="../../../../res/icons/icons.qrc"/> - <include location="../../../../res/icons/icons.qrc"/> + <include location="../../../../../res/icons/icons.qrc"/> + <include location="../../../../../res/icons/icons.qrc"/> + <include location="../../../../../res/icons/icons.qrc"/> </resources> <connections/> </ui>