diff --git a/src/sakia/gui/dialogs/account_cfg/account_cfg.ui b/src/sakia/gui/dialogs/account_cfg/account_cfg.ui index b1d3c8f38bffa067eda407511974e93089a1bead..a080207367f94a6255743708f3d9d9554e1dc2a6 100644 --- a/src/sakia/gui/dialogs/account_cfg/account_cfg.ui +++ b/src/sakia/gui/dialogs/account_cfg/account_cfg.ui @@ -20,7 +20,7 @@ <item> <widget class="QStackedWidget" name="stacked_pages"> <property name="currentIndex"> - <number>1</number> + <number>0</number> </property> <widget class="QWidget" name="page_init"> <layout class="QVBoxLayout" name="verticalLayout_4"> @@ -207,7 +207,7 @@ </item> </layout> </widget> - <widget class="QWidget" name="page__communities"> + <widget class="QWidget" name="page_communities"> <layout class="QVBoxLayout" name="verticalLayout_5"> <item> <widget class="QGroupBox" name="groupBox_2"> @@ -287,184 +287,7 @@ </layout> </widget> <resources/> - <connections> - <connection> - <sender>button_add_community</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>open_process_add_community()</slot> - <hints> - <hint type="sourcelabel"> - <x>109</x> - <y>237</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>149</y> - </hint> - </hints> - </connection> - <connection> - <sender>button_remove_community</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_remove_community()</slot> - <hints> - <hint type="sourcelabel"> - <x>290</x> - <y>237</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>149</y> - </hint> - </hints> - </connection> - <connection> - <sender>list_communities</sender> - <signal>doubleClicked(QModelIndex)</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>open_process_edit_community(QModelIndex)</slot> - <hints> - <hint type="sourcelabel"> - <x>199</x> - <y>180</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>149</y> - </hint> - </hints> - </connection> - <connection> - <sender>button_next</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>next()</slot> - <hints> - <hint type="sourcelabel"> - <x>349</x> - <y>278</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>149</y> - </hint> - </hints> - </connection> - <connection> - <sender>button_previous</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>previous()</slot> - <hints> - <hint type="sourcelabel"> - <x>49</x> - <y>278</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>149</y> - </hint> - </hints> - </connection> - <connection> - <sender>edit_salt</sender> - <signal>textChanged(QString)</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_edit_account_key()</slot> - <hints> - <hint type="sourcelabel"> - <x>199</x> - <y>69</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - <connection> - <sender>edit_password</sender> - <signal>textChanged(QString)</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_edit_account_key()</slot> - <hints> - <hint type="sourcelabel"> - <x>199</x> - <y>98</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - <connection> - <sender>edit_password_repeat</sender> - <signal>textChanged(QString)</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_edit_account_key()</slot> - <hints> - <hint type="sourcelabel"> - <x>199</x> - <y>127</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - <connection> - <sender>edit_account_name</sender> - <signal>textChanged(QString)</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_edit_account_parameters()</slot> - <hints> - <hint type="sourcelabel"> - <x>240</x> - <y>110</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - <connection> - <sender>button_generate</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_show_pubkey()</slot> - <hints> - <hint type="sourcelabel"> - <x>290</x> - <y>161</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - <connection> - <sender>button_delete</sender> - <signal>clicked()</signal> - <receiver>AccountConfigurationDialog</receiver> - <slot>action_delete_account()</slot> - <hints> - <hint type="sourcelabel"> - <x>325</x> - <y>146</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>118</y> - </hint> - </hints> - </connection> - </connections> + <connections/> <slots> <slot>open_process_add_community()</slot> <slot>key_changed(int)</slot> diff --git a/src/sakia/gui/dialogs/account_cfg/controller.py b/src/sakia/gui/dialogs/account_cfg/controller.py index a586137837dd2250c38fa5ffb5b614808e45be12..e70b13e70607188077064d9795f79a25c8025777 100644 --- a/src/sakia/gui/dialogs/account_cfg/controller.py +++ b/src/sakia/gui/dialogs/account_cfg/controller.py @@ -1,3 +1,6 @@ +from PyQt5.QtWidgets import QDialog + +from sakia.gui.password_asker import PasswordAskerDialog, detect_non_printable from sakia.gui.component.controller import ComponentController from .view import AccountConfigView from .model import AccountConfigModel @@ -17,26 +20,31 @@ class AccountConfigController(ComponentController): """ super().__init__(parent, view, model) - self.handle_next_step(init=True) + self._current_step = 0 self.view.button_next.clicked.connect(lambda checked: self.handle_next_step(False)) self._steps = ( { 'page': self.view.page_init, 'init': self.init_name_page, + 'check': self.check_name, 'next': self.account_name_selected }, { 'page': self.view.page_brainwallet, 'init': self.init_key_page, + 'check': self.check_key, 'next': self.account_key_selected }, { - 'page': self.view.page__communities, - 'init': self.inir_communities, + 'page': self.view.page_communities, + 'init': self.init_communities, + 'check': lambda: True, 'next': self.accept } ) - self._current_step = 0 + self.handle_next_step(init=True) + self.password_asker = None + self.view.values_changed.connect(self.check_values) @classmethod def create(cls, parent, app, **kwargs): @@ -48,7 +56,7 @@ class AccountConfigController(ComponentController): :rtype: AccountConfigControllerController """ view = AccountConfigView(parent.view) - model = AccountConfigModel(None, app) + model = AccountConfigModel(None, app, None) account_cfg = cls(parent, view, model) model.setParent(account_cfg) return account_cfg @@ -64,6 +72,7 @@ class AccountConfigController(ComponentController): """ account_cfg = cls.create(parent, app, account=None) account_cfg.view.set_creation_layout() + account_cfg.view.exec() @classmethod def modify_account(cls, parent, app, account): @@ -78,6 +87,13 @@ class AccountConfigController(ComponentController): account_cfg.view.set_modification_layout(account.name) account_cfg._current_step = 1 + def check_values(self): + """ + Check the values in the page and enable or disable previous/next buttons + """ + valid = self._steps[self._current_step]['check']() + self.view.button_next.setEnabled(valid) + def init_name_page(self): """ Initialize an account name page @@ -95,14 +111,70 @@ class AccountConfigController(ComponentController): else: self.model.rename_account(name) + def check_name(self): + return len(self.view.edit_account_name.text()) > 2 + + def init_key_page(self): + """ + Initialize key page + """ + self.view.button_previous.setEnabled(False) + self.view.button_next.setEnabled(False) + + def account_key_selected(self): + salt = self.view.edit_salt.text() + password = self.view.edit_password.text() + self.model.account.set_scrypt_infos(salt, password) + self.password_asker = PasswordAskerDialog(self.model.account) + + def check_key(self): + if self.model.app.preferences['expert_mode']: + return True + + if len(self.view.edit_salt.text()) < 6: + self.view.label_info.setText(self.tr("Forbidden : salt is too short")) + return False + + if len(self.view.edit_password.text()) < 6: + self.view.label_info.setText(self.tr("Forbidden : password is too short")) + return False + + if detect_non_printable(self.view.edit_salt.text()): + self.view.label_info.setText(self.tr("Forbidden : Invalid characters in salt field")) + return False + + if detect_non_printable(self.view.edit_password.text()): + self.view.label_info.setText( + self.tr("Forbidden : Invalid characters in password field")) + return False + + if self.view.edit_password.text() != \ + self.view.edit_password_repeat.text(): + self.view.label_info.setText(self.tr("Error : passwords are different")) + return False + + self.view.label_info.setText("") + return True + + def init_communities(self): + self.view.button_previous.setEnabled(False) + self.view.button_next.setText("Ok") + list_model = self.model.communities_list_model() + self.view.set_communities_list_model(list_model) + def handle_next_step(self, init=False): if self._current_step < len(self._steps) - 1: if not init: - self.view.button_next.clicked.disconnect(self._steps[self._current_step]['next']) + self._steps[self._current_step]['next']() self._current_step += 1 self._steps[self._current_step]['init']() - self.view.stackedWidget.setCurrentWidget(self._steps[self._current_step]['page']) - self.view.button_next.clicked.connect(self._steps[self._current_step]['next']) + self.view.stacked_pages.setCurrentWidget(self._steps[self._current_step]['page']) + + def accept(self): + if self.password_asker.result() == QDialog.Rejected: + return + self.model.add_account_to_app() + self.view.accept() @property def view(self) -> AccountConfigView: diff --git a/src/sakia/gui/dialogs/account_cfg/model.py b/src/sakia/gui/dialogs/account_cfg/model.py index e569382da96d55f2dd9fad3b9493254c01dd1fd5..acd44c996b10d597ddb4eabd51753464365d46cc 100644 --- a/src/sakia/gui/dialogs/account_cfg/model.py +++ b/src/sakia/gui/dialogs/account_cfg/model.py @@ -1,5 +1,5 @@ from sakia.gui.component.model import ComponentModel - +from sakia.models.communities import CommunitiesListModel class AccountConfigModel(ComponentModel): """ @@ -29,4 +29,14 @@ class AccountConfigModel(ComponentModel): Renames current account :param str name: the new name """ - self.account.name = name \ No newline at end of file + self.account.name = name + + def communities_list_model(self): + return CommunitiesListModel(self.account) + + def add_account_to_app(self): + self.app.add_account(self.account) + if len(self.app.accounts) == 1: + self.app.preferences['account'] = self.account.name + self.app.save(self.account) + self.app.change_current_account(self.account) \ No newline at end of file diff --git a/src/sakia/gui/dialogs/account_cfg/view.py b/src/sakia/gui/dialogs/account_cfg/view.py index df8b152610be6b5b5173f013b648b7b0273b363e..0aa8d07785b08ffceaac5fbeb3a371c141b814b0 100644 --- a/src/sakia/gui/dialogs/account_cfg/view.py +++ b/src/sakia/gui/dialogs/account_cfg/view.py @@ -1,11 +1,14 @@ -from PyQt5.QtWidgets import QWidget +from PyQt5.QtWidgets import QDialog +from PyQt5.QtCore import pyqtSignal from .account_cfg_uic import Ui_AccountConfigurationDialog +from duniterpy.key import SigningKey -class AccountConfigView(QWidget, Ui_AccountConfigurationDialog): +class AccountConfigView(QDialog, Ui_AccountConfigurationDialog): """ Home screen view """ + values_changed = pyqtSignal() def __init__(self, parent): """ @@ -13,6 +16,11 @@ class AccountConfigView(QWidget, Ui_AccountConfigurationDialog): """ super().__init__(parent) self.setupUi(self) + self.edit_account_name.textChanged.connect(self.values_changed) + self.edit_password.textChanged.connect(self.values_changed) + self.edit_password_repeat.textChanged.connect(self.values_changed) + self.edit_salt.textChanged.connect(self.values_changed) + self.button_generate.clicked.connect(self.action_show_pubkey) def set_creation_layout(self): """ @@ -32,5 +40,18 @@ class AccountConfigView(QWidget, Ui_AccountConfigurationDialog): self.button_next.setEnabled(True) self.setWindowTitle(self.tr("Configure {0}".format(account_name))) + def action_show_pubkey(self): + salt = self.edit_salt.text() + password = self.edit_password.text() + pubkey = SigningKey(salt, password).pubkey + self.label_info.setText(pubkey) + def account_name(self): return self.edit_account_name.text() + + def set_communities_list_model(self, model): + """ + Set communities list model + :param sakia.models.communities.CommunitiesListModel model: + """ + self.list_communities.setModel(model) diff --git a/src/sakia/gui/main_window/toolbar/controller.py b/src/sakia/gui/main_window/toolbar/controller.py index ee5729b97a2549ce30bbe601d29e2cf2534ef764..81a0f6490305abe196016ea6ece2cc698112aae1 100644 --- a/src/sakia/gui/main_window/toolbar/controller.py +++ b/src/sakia/gui/main_window/toolbar/controller.py @@ -8,6 +8,7 @@ from sakia.gui.widgets.dialogs import QAsyncMessageBox, QAsyncFileDialog, dialog from sakia.gui.widgets import toast from sakia.gui.dialogs.certification.controller import CertificationController from sakia.gui.dialogs.transfer.controller import TransferController +from sakia.gui.dialogs.account_cfg.controller import AccountConfigController import logging @@ -30,6 +31,7 @@ class ToolbarController(ComponentController): self.view.action_gen_revokation.triggered.connect(self.action_save_revokation) self.view.action_publish_uid.triggered.connect(self.publish_uid) self.view.button_membership.clicked.connect(self.send_membership_demand) + self.view.action_create_account.triggered.connect(self.open_create_account_dialog) @classmethod def create(cls, parent, app, account, community, password_asker): @@ -200,10 +202,13 @@ The process to join back the community later will have to be done again.""") self.account) def open_transfer_money_dialog(self): - dialog = TransferController.open_dialog(self, self.model.app, - account=self.model.account, - password_asker=self.password_asker, - community=self.model.community) + TransferController.open_dialog(self, self.model.app, + account=self.model.account, + password_asker=self.password_asker, + community=self.model.community) + + def open_create_account_dialog(self): + AccountConfigController.create_account(self, self.model.app) def retranslateUi(self, widget): """ diff --git a/src/sakia/gui/main_window/toolbar/view.py b/src/sakia/gui/main_window/toolbar/view.py index e9f3be10e3f76f1cf1b509dc5d9a45dadf1ea7ed..150d0e071fb06cc199498dd15c5f5cf71ef92353 100644 --- a/src/sakia/gui/main_window/toolbar/view.py +++ b/src/sakia/gui/main_window/toolbar/view.py @@ -20,12 +20,18 @@ class ToolbarView(QFrame, Ui_SakiaToolbar): self.action_publish_uid = QAction(self.tr(ToolbarView._action_publish_uid_text), self) self.action_revoke_uid = QAction(self.tr(ToolbarView._action_revoke_uid_text), self) + tool_menu.addAction(self.action_publish_uid) + tool_menu.addAction(self.action_revoke_uid) menu_advanced = QMenu(self.tr("Advanced"), self.toolbutton_menu) self.action_gen_revokation = QAction(self.tr("Save revokation document"), menu_advanced) menu_advanced.addAction(self.action_gen_revokation) tool_menu.addMenu(menu_advanced) - tool_menu.addAction(self.action_publish_uid) + + menu_options = QMenu(self.tr("Options"), self.toolbutton_menu) + self.action_create_account = QAction(self.tr("Create a new account"), menu_options) + menu_options.addAction(self.action_create_account) + tool_menu.addMenu(menu_options) + self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum) self.setMaximumHeight(60) -