Skip to content
Snippets Groups Projects
Commit fb0d3b3a authored by inso's avatar inso
Browse files

Community config component

parent 3aa8e5b5
No related branches found
No related tags found
No related merge requests found
...@@ -370,7 +370,7 @@ class Account(QObject): ...@@ -370,7 +370,7 @@ class Account(QObject):
uids = result['uids'] uids = result['uids']
for uid_data in uids: for uid_data in uids:
if BlockUID.from_str(uid_data["meta"]["timestamp"]) >= timestamp: if BlockUID.from_str(uid_data["meta"]["timestamp"]) >= timestamp:
timestamp = uid_data["meta"]["timestamp"] timestamp = BlockUID.from_str(uid_data["meta"]["timestamp"])
found_uid = uid_data["uid"] found_uid = uid_data["uid"]
if found_uid == self.name: if found_uid == self.name:
found_result = result['pubkey'], found_uid found_result = result['pubkey'], found_uid
......
...@@ -2,8 +2,12 @@ from PyQt5.QtWidgets import QDialog ...@@ -2,8 +2,12 @@ from PyQt5.QtWidgets import QDialog
from sakia.gui.password_asker import PasswordAskerDialog, detect_non_printable from sakia.gui.password_asker import PasswordAskerDialog, detect_non_printable
from sakia.gui.component.controller import ComponentController from sakia.gui.component.controller import ComponentController
from ..community_cfg.controller import CommunityConfigController
from .view import AccountConfigView from .view import AccountConfigView
from .model import AccountConfigModel from .model import AccountConfigModel
from sakia.tools.decorators import asyncify
import logging
class AccountConfigController(ComponentController): class AccountConfigController(ComponentController):
...@@ -15,8 +19,8 @@ class AccountConfigController(ComponentController): ...@@ -15,8 +19,8 @@ class AccountConfigController(ComponentController):
""" """
Constructor of the AccountConfigController component Constructor of the AccountConfigController component
:param sakia.gui.AccountConfigController.view.AccountConfigControllerView: the view :param sakia.gui.account_cfg.view.AccountConfigCView: the view
:param sakia.gui.AccountConfigController.model.AccountConfigControllerModel model: the model :param sakia.gui.account_cfg.model.AccountConfigModel model: the model
""" """
super().__init__(parent, view, model) super().__init__(parent, view, model)
...@@ -53,7 +57,7 @@ class AccountConfigController(ComponentController): ...@@ -53,7 +57,7 @@ class AccountConfigController(ComponentController):
:param sakia.gui.component.controller.ComponentController parent: :param sakia.gui.component.controller.ComponentController parent:
:param sakia.core.Application app: :param sakia.core.Application app:
:return: a new AccountConfigController controller :return: a new AccountConfigController controller
:rtype: AccountConfigControllerController :rtype: AccountConfigController
""" """
view = AccountConfigView(parent.view) view = AccountConfigView(parent.view)
model = AccountConfigModel(None, app, None) model = AccountConfigModel(None, app, None)
...@@ -157,6 +161,7 @@ class AccountConfigController(ComponentController): ...@@ -157,6 +161,7 @@ class AccountConfigController(ComponentController):
return True return True
def init_communities(self): def init_communities(self):
self.view.button_add_community.clicked.connect(self.open_process_add_community)
self.view.button_previous.setEnabled(False) self.view.button_previous.setEnabled(False)
self.view.button_next.setText("Ok") self.view.button_next.setText("Ok")
list_model = self.model.communities_list_model() list_model = self.model.communities_list_model()
...@@ -170,6 +175,16 @@ class AccountConfigController(ComponentController): ...@@ -170,6 +175,16 @@ class AccountConfigController(ComponentController):
self._steps[self._current_step]['init']() self._steps[self._current_step]['init']()
self.view.stacked_pages.setCurrentWidget(self._steps[self._current_step]['page']) self.view.stacked_pages.setCurrentWidget(self._steps[self._current_step]['page'])
@asyncify
async def open_process_add_community(self, checked=False):
logging.debug("Opening configure community dialog")
logging.debug(self.password_asker)
await CommunityConfigController.create_community(self,
self.model.app,
account=self.model.account,
password_asker=self.password_asker)
def accept(self): def accept(self):
if self.password_asker.result() == QDialog.Rejected: if self.password_asker.result() == QDialog.Rejected:
return return
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CommunityConfigurationDialog</class>
<widget class="QDialog" name="CommunityConfigurationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>329</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="windowTitle">
<string>Add a community</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QStackedWidget" name="stacked_pages">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_node">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Please enter the address of a node :</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="rightMargin">
<number>5</number>
</property>
<item>
<widget class="QLineEdit" name="lineedit_server"/>
</item>
<item>
<widget class="QLabel" name="label_double_dot">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinbox_port">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8001</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="topMargin">
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="button_register">
<property name="text">
<string>Register your account</string>
</property>
<property name="icon">
<iconset resource="../../../../../res/icons/icons.qrc">
<normaloff>:/icons/new_membership</normaloff>:/icons/new_membership</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_connect">
<property name="text">
<string>Connect using your account</string>
</property>
<property name="icon">
<iconset resource="../../../../../res/icons/icons.qrc">
<normaloff>:/icons/connect_icon</normaloff>:/icons/connect_icon</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_guest">
<property name="text">
<string>Connect as a guest</string>
</property>
<property name="icon">
<iconset resource="../../../../../res/icons/icons.qrc">
<normaloff>:/icons/guest_icon</normaloff>:/icons/guest_icon</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_error">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_add_nodes">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Communities nodes</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTreeView" name="tree_peers">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineedit_add_address">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Server</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinbox_add_port">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>8081</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="layout_previous_next">
<item>
<widget class="QPushButton" name="button_previous">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Previous</string>
</property>
</widget>
</item>
<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="QPushButton" name="button_next">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Next</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../../../res/icons/icons.qrc"/>
</resources>
<connections/>
<slots>
<slot>add_node()</slot>
<slot>showContextMenu(QPoint)</slot>
<slot>check()</slot>
<slot>next()</slot>
<slot>previous()</slot>
<slot>current_wallet_changed(int)</slot>
<slot>remove_node()</slot>
</slots>
</ui>
from PyQt5.QtWidgets import QDialog, QApplication, QMenu
from PyQt5.QtGui import QCursor
from sakia.gui.component.controller import ComponentController
from .view import CommunityConfigView
from .model import CommunityConfigModel
from sakia.tools.decorators import asyncify
from aiohttp.errors import DisconnectedError, ClientError, TimeoutError
from duniterpy.documents import MalformedDocumentError
from sakia.tools.exceptions import NoPeerAvailable
import logging
class CommunityConfigController(ComponentController):
"""
The CommunityConfigController view
"""
def __init__(self, parent, view, model):
"""
Constructor of the CommunityConfigController component
:param sakia.gui.community_cfg.view.CommunityConfigView: the view
:param sakia.gui.community_cfg.model.CommunityConfigModel model: the model
"""
super().__init__(parent, view, model)
self._current_step = 0
self.view.button_next.clicked.connect(lambda checked: self.handle_next_step(False))
self._steps = (
{
'page': self.view.page_node,
'init': self.init_connect_page,
'next': lambda: True
},
{
'page': self.view.page_add_nodes,
'init': self.init_nodes_page,
'next': self.accept
}
)
self.handle_next_step(init=True)
self.password_asker = None
self.view.button_connect.clicked.connect(self.check_connect)
self.view.button_register.clicked.connect(self.check_register)
self.view.button_guest.clicked.connect(self.check_guest)
@classmethod
def create(cls, parent, app, **kwargs):
"""
Instanciate a CommunityConfigController component
:param sakia.gui.component.controller.ComponentController parent:
:param sakia.core.Application app:
:return: a new CommunityConfigController controller
:rtype: CommunityConfigController
"""
account = kwargs['account']
community = kwargs['community']
password_asker = kwargs['password_asker']
view = CommunityConfigView(parent.view)
model = CommunityConfigModel(None, app, account, community)
community_cfg = cls(parent, view, model)
model.setParent(community_cfg)
community_cfg.password_asker = password_asker
return community_cfg
@classmethod
@asyncify
def create_community(cls, parent, app, account, password_asker):
"""
Open a dialog to create a new Community
:param parent:
:param app:
:param account:
:return:
"""
community_cfg = cls.create(parent, app, account=account, community=None, password_asker=password_asker)
community_cfg.view.set_creation_layout()
return community_cfg.view.async_exec()
@classmethod
@asyncify
def modify_community(cls, parent, app, account, community, password_asker):
"""
Open a dialog to modify an existing Community
:param parent:
:param app:
:param account:
:param community:
:return:
"""
community_cfg = cls.create(parent, app, account=account,
community=community, password_asker=password_asker)
community_cfg.view.set_modification_layout(community.name)
community_cfg._current_step = 1
return community_cfg.view.async_exec()
def handle_next_step(self, init=False):
if self._current_step < len(self._steps) - 1:
if not init:
self._steps[self._current_step]['next']()
self._current_step += 1
self._steps[self._current_step]['init']()
self.view.stacked_pages.setCurrentWidget(self._steps[self._current_step]['page'])
def init_connect_page(self):
pass
def init_nodes_page(self):
self.view.set_steps_buttons_visible(True)
model = self.model.init_nodes_model()
self.view.tree_peers.customContextMenuRequested(self.show_context_menu)
self.view.set_nodes_model(model)
self.view.button_previous.setEnabled(False)
self.view.button_next.setText(self.config_dialog.tr("Ok"))
@asyncify
async def check_guest(self, checked=False):
server, port = self.view.node_parameters()
logging.debug("Is valid ? ")
self.view.display_info(self.tr("connecting..."))
try:
await self.model.create_community(server, port)
self.view.button_connect.setEnabled(False)
self.view.button_register.setEnabled(False)
self._steps[self._current_step]['next']()
except (DisconnectedError, ClientError, MalformedDocumentError, ValueError) as e:
self.view.display_info(str(e))
except TimeoutError:
self.view.display_info(self.tr("Could not connect. Check hostname, ip address or port"))
@asyncify
async def check_connect(self, checked=False):
server, port = self.view.node_parameters()
logging.debug("Is valid ? ")
self.view.display_info.setText(self.tr("connecting..."))
try:
await self.model.create_community(server, port)
self.view.button_connect.setEnabled(False)
self.view.button_register.setEnabled(False)
registered = await self.model.check_registered()
self.view.button_connect.setEnabled(True)
self.view.button_register.setEnabled(True)
if registered[0] is False and registered[2] is None:
self.view.display_info(self.tr("Could not find your identity on the network."))
elif registered[0] is False and registered[2]:
self.view.display_info(self.tr("""Your pubkey or UID is different on the network.
Yours : {0}, the network : {1}""".format(registered[1], registered[2])))
else:
self._steps[self._current_step]['next']()
except (DisconnectedError, ClientError, MalformedDocumentError, ValueError) as e:
self.view.display_info(str(e))
except TimeoutError:
self.view.display_info(self.tr("Could not connect. Check hostname, ip address or port"))
except NoPeerAvailable:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check node peering entry"))
@asyncify
async def check_register(self, checked=False):
server, port = self.view.node_parameters()
logging.debug("Is valid ? ")
self.view.display_info(self.tr("connecting..."))
try:
await self.model.create_community(server, port)
self.view.button_connect.setEnabled(False)
self.view.button_register.setEnabled(False)
registered = await self.model.check_registered()
self.view.button_connect.setEnabled(True)
self.view.button_register.setEnabled(True)
if registered[0] is False and registered[2] is None:
password = await self.password_asker.async_exec()
if self.password_asker.result() == QDialog.Rejected:
return
self.view.display_info(self.tr("Broadcasting identity..."))
result = await self.model.publish_selfcert(password)
if result[0]:
self.view.show_success()
QApplication.restoreOverrideCursor()
self._steps[self._current_step]['next']()
else:
self.view.show_error(self.model.notification(), result[1])
QApplication.restoreOverrideCursor()
elif registered[0] is False and registered[2]:
self.view.display_info(self.tr("""Your pubkey or UID was already found on the network.
Yours : {0}, the network : {1}""".format(registered[1], registered[2])))
else:
self.display_info("Your account already exists on the network")
except (DisconnectedError, ClientError, MalformedDocumentError, ValueError) as e:
self.view.display_info(str(e))
except NoPeerAvailable:
self.view.display_info(self.tr("Could not connect. Check node peering entry"))
except TimeoutError:
self.view.display_info(self.tr("Could not connect. Check hostname, ip address or port"))
def show_context_menu(self, point):
if self.view.stacked_pages.currentWidget() == self.steps[1]['widget']:
menu = QMenu()
index = self.model.nodes_tree_model.indexAt(point)
action = menu.addAction(self.tr("Delete"), self.remove_node)
action.setData(index.row())
if len(self.nodes) == 1:
action.setEnabled(False)
menu.exec_(QCursor.pos())
@asyncify
async def add_node(self, checked=False):
"""
Add node slot
"""
server, port = self.view.add_node_parameters()
try:
await self.model.add_node(server, port)
except Exception as e:
self.view.show_error(self.model.notification(), str(e))
def remove_node(self):
"""
Remove node slot
"""
logging.debug("Remove node")
index = self.sender().data()
self.model.remove_node(index)
def accept(self):
if self.community not in self.account.communities:
self.account.add_community(self.community)
self.view.accept()
@property
def view(self) -> CommunityConfigView:
return self._view
@property
def model(self) -> CommunityConfigModel:
return self._model
\ No newline at end of file
from sakia.gui.component.model import ComponentModel
from sakia.core.net import Node
from sakia.core import Community
import aiohttp
from sakia.models.peering import PeeringTreeModel
class CommunityConfigModel(ComponentModel):
"""
The model of CommunityConfig component
"""
def __init__(self, parent, app, account, community):
"""
:param sakia.gui.dialogs.Community_cfg.controller.CommunityConfigController parent:
:param sakia.core.Application app:
:param sakia.core.Account account:
:param sakia.core.Community community:
"""
super().__init__(parent)
self.app = app
self.account = account
self.community = community
self.nodes = []
self.nodes_tree_model = None
async def create_community(self, server, port):
node = await Node.from_address(None, server, port, session=aiohttp.ClientSession())
self.community = Community.create(node)
async def add_node(self, server, port):
node = await Node.from_address(self.community.currency, server, port, session=self.community.network.session)
self.community.add_node(node)
self.nodes_tree_model.refresh_tree()
def remove_node(self, index):
self.community.remove_node(index)
self.nodes_tree_model.refresh_tree()
async def check_registered(self):
return await self.account.check_registered(self.community)
async def publish_selfcert(self, password):
return await self.account.send_selfcert(password, self.community)
def init_nodes_model(self):
# We add already known peers to the displayed list
self.nodes = self.community.network.root_nodes
self.nodes_tree_model = PeeringTreeModel(self.community)
def notification(self):
self.app.preferences['notifications']
"""
Created on 8 mars 2014
@author: inso
"""
import logging
import asyncio
import aiohttp
from duniterpy.api import errors
from duniterpy.documents import MalformedDocumentError
from PyQt5.QtWidgets import QDialog, QMenu, QApplication
from PyQt5.QtGui import QCursor
from PyQt5.QtCore import pyqtSignal, QObject
from ..presentation.community_cfg_uic import Ui_CommunityConfigurationDialog
from ..models.peering import PeeringTreeModel
from ..core import Community
from ..core.net import Node
from .widgets import toast
from .widgets.dialogs import QAsyncMessageBox
from ..tools.decorators import asyncify
from ..tools.exceptions import NoPeerAvailable
class Step(QObject):
def __init__(self, config_dialog, previous_step=None, next_step=None):
super().__init__()
self.previous_step = previous_step
self.next_step = next_step
self.config_dialog = config_dialog
class StepPageInit(Step):
"""
First step when adding a community
"""
def __init__(self, config_dialog):
super().__init__(config_dialog)
self.node = None
logging.debug("Init")
self.config_dialog.button_connect.clicked.connect(self.check_connect)
self.config_dialog.button_register.clicked.connect(self.check_register)
self.config_dialog.button_guest.clicked.connect(self.check_guest)
@property
def app(self):
return self.config_dialog.app
@property
def account(self):
return self.config_dialog.account
@property
def community(self):
return self.config_dialog.community
@property
def password_asker(self):
return self.config_dialog.password_asker
@asyncify
async def check_guest(self, checked=False):
server = self.config_dialog.lineedit_server.text()
port = self.config_dialog.spinbox_port.value()
logging.debug("Is valid ? ")
self.config_dialog.label_error.setText(self.tr("connecting..."))
try:
self.node = await Node.from_address(None, server, port, session=aiohttp.ClientSession())
community = Community.create(self.node)
self.config_dialog.button_connect.setEnabled(False)
self.config_dialog.button_register.setEnabled(False)
self.config_dialog.community = community
self.config_dialog.next()
except aiohttp.errors.DisconnectedError as e:
self.config_dialog.label_error.setText(str(e))
except aiohttp.errors.ClientError as e:
self.config_dialog.label_error.setText(str(e))
except (MalformedDocumentError, ValueError) as e:
self.config_dialog.label_error.setText(str(e))
except aiohttp.errors.TimeoutError:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check hostname, ip address or port"))
@asyncify
async def check_connect(self, checked=False):
server = self.config_dialog.lineedit_server.text()
port = self.config_dialog.spinbox_port.value()
logging.debug("Is valid ? ")
self.config_dialog.label_error.setText(self.tr("connecting..."))
try:
self.node = await Node.from_address(None, server, port, session=aiohttp.ClientSession())
community = Community.create(self.node)
self.config_dialog.button_connect.setEnabled(False)
self.config_dialog.button_register.setEnabled(False)
registered = await self.account.check_registered(community)
self.config_dialog.button_connect.setEnabled(True)
self.config_dialog.button_register.setEnabled(True)
if registered[0] is False and registered[2] is None:
self.config_dialog.label_error.setText(self.tr("Could not find your identity on the network."))
elif registered[0] is False and registered[2]:
self.config_dialog.label_error.setText(self.tr("""Your pubkey or UID is different on the network.
Yours : {0}, the network : {1}""".format(registered[1], registered[2])))
else:
self.config_dialog.community = community
self.config_dialog.next()
except aiohttp.errors.DisconnectedError as e:
self.config_dialog.label_error.setText(str(e))
except aiohttp.errors.ClientError as e:
self.config_dialog.label_error.setText(str(e))
except (MalformedDocumentError, ValueError) as e:
self.config_dialog.label_error.setText(str(e))
except NoPeerAvailable:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check node peering entry"))
except aiohttp.errors.TimeoutError:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check hostname, ip address or port"))
@asyncify
async def check_register(self, checked=False):
server = self.config_dialog.lineedit_server.text()
port = self.config_dialog.spinbox_port.value()
logging.debug("Is valid ? ")
self.config_dialog.label_error.setText(self.tr("connecting..."))
try:
session = aiohttp.ClientSession()
self.node = await Node.from_address(None, server, port, session=session)
community = Community.create(self.node)
self.config_dialog.button_connect.setEnabled(False)
self.config_dialog.button_register.setEnabled(False)
registered = await self.account.check_registered(community)
self.config_dialog.button_connect.setEnabled(True)
self.config_dialog.button_register.setEnabled(True)
if registered[0] is False and registered[2] is None:
password = await self.password_asker.async_exec()
if self.password_asker.result() == QDialog.Rejected:
return
self.config_dialog.label_error.setText(self.tr("Broadcasting identity..."))
result = await self.account.send_selfcert(password, community)
if result[0]:
if self.app.preferences['notifications']:
toast.display(self.tr("UID broadcast"), self.tr("Identity broadcasted to the network"))
QApplication.restoreOverrideCursor()
self.config_dialog.next()
else:
self.config_dialog.label_error.setText(self.tr("Error") + " " + \
self.tr("{0}".format(result[1])))
if self.app.preferences['notifications']:
toast.display(self.tr("Error"), self.tr("{0}".format(result[1])))
QApplication.restoreOverrideCursor()
self.config_dialog.community = community
elif registered[0] is False and registered[2]:
self.config_dialog.label_error.setText(self.tr("""Your pubkey or UID was already found on the network.
Yours : {0}, the network : {1}""".format(registered[1], registered[2])))
else:
self.config_dialog.label_error.setText(self.tr("Your account already exists on the network"))
except (MalformedDocumentError, ValueError, errors.DuniterError,
aiohttp.errors.ClientError, aiohttp.errors.DisconnectedError) as e:
session.close()
self.config_dialog.label_error.setText(str(e))
except NoPeerAvailable:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check node peering entry"))
except aiohttp.errors.TimeoutError:
self.config_dialog.label_error.setText(self.tr("Could not connect. Check hostname, ip address or port"))
def is_valid(self):
return self.node is not None
def process_next(self):
"""
We create the community
"""
account = self.config_dialog.account
logging.debug("Account : {0}".format(account))
self.config_dialog.community = Community.create(self.node)
def display_page(self):
self.config_dialog.button_next.hide()
self.config_dialog.button_previous.hide()
class StepPageAddpeers(Step):
"""
The step where the user add peers
"""
def __init__(self, config_dialog):
super().__init__(config_dialog)
def is_valid(self):
return True
def process_next(self):
pass
def display_page(self):
self.config_dialog.button_next.show()
self.config_dialog.button_previous.show()
# We add already known peers to the displayed list
self.config_dialog.nodes = self.config_dialog.community.network.root_nodes
tree_model = PeeringTreeModel(self.config_dialog.community)
self.config_dialog.tree_peers.setModel(tree_model)
self.config_dialog.button_previous.setEnabled(False)
self.config_dialog.button_next.setText(self.config_dialog.tr("Ok"))
class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog):
"""
Dialog to configure or add a community
"""
community_added = pyqtSignal()
def __init__(self, app, account, community, password_asker):
"""
Constructor
:param sakia.core.Application app: The application
:param sakia.core.Account account: The configured account
:param sakia.core.Community community: The configured community
:param sakia.gui.password_asker.Password_Asker password_asker: The password asker
"""
super().__init__()
self.setupUi(self)
self.app = app
self.community = community
self.account = account
self.password_asker = password_asker
self.step = None
self.nodes = []
self.community_added.connect(self.add_community_and_close)
self._step_init = StepPageInit(self)
step_add_peers = StepPageAddpeers(self)
self._step_init.next_step = step_add_peers
if self.community is not None:
self.stacked_pages.removeWidget(self.page_node)
self.step = step_add_peers
self.setWindowTitle(self.tr("Configure community {0}").format(self.community.currency))
else:
self.step = self._step_init
self.setWindowTitle(self.tr("Add a community"))
self.step.display_page()
def next(self):
if self.step.next_step is not None:
if self.step.is_valid():
self.step.process_next()
self.step = self.step.next_step
next_index = self.stacked_pages.currentIndex() + 1
self.stacked_pages.setCurrentIndex(next_index)
self.step.display_page()
else:
self.add_community_and_close()
def previous(self):
if self.step.previous_step is not None:
self.step = self.step.previous_step
previous_index = self.stacked_pages.currentIndex() - 1
self.stacked_pages.setCurrentIndex(previous_index)
self.step.display_page()
async def start_add_node(self):
"""
Add node slot
"""
server = self.lineedit_add_address.text()
port = self.spinbox_add_port.value()
try:
node = await Node.from_address(self.community.currency, server, port, session=self.community.network.session)
self.community.add_node(node)
except Exception as e:
await QAsyncMessageBox.critical(self, self.tr("Error"),
str(e))
self.tree_peers.setModel(PeeringTreeModel(self.community))
def add_node(self):
asyncio.ensure_future(self.start_add_node())
def remove_node(self):
"""
Remove node slot
"""
logging.debug("Remove node")
index = self.sender().data()
self.community.remove_node(index)
self.tree_peers.setModel(PeeringTreeModel(self.community))
@property
def nb_steps(self):
s = self.step
nb_steps = 1
while s.next_step != None:
s = s.next_step
nb_steps = nb_steps + 1
return nb_steps
def showContextMenu(self, point):
if self.stacked_pages.currentIndex() == self.nb_steps - 1:
menu = QMenu()
index = self.tree_peers.indexAt(point)
action = menu.addAction(self.tr("Delete"), self.remove_node)
action.setData(index.row())
if self.community is not None:
if len(self.nodes) == 1:
action.setEnabled(False)
menu.exec_(QCursor.pos())
def async_exec(self):
future = asyncio.Future()
self.finished.connect(lambda r: future.set_result(r))
self.open()
return future
def add_community_and_close(self):
if self.community not in self.account.communities:
self.account.add_community(self.community)
self.accept()
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import pyqtSignal
from .community_cfg_uic import Ui_CommunityConfigurationDialog
from sakia.gui.widgets import toast
from sakia.gui.widgets.dialogs import QAsyncMessageBox
import asyncio
class CommunityConfigView(QDialog, Ui_CommunityConfigurationDialog):
"""
community config view
"""
def __init__(self, parent):
"""
Constructor
"""
super().__init__(parent)
self.setupUi(self)
self.set_steps_buttons_visible(False)
def set_creation_layout(self):
self.setWindowTitle(self.tr("Add a community"))
def set_edition_layout(self, name):
self.stacked_pages.removeWidget(self.page_node)
self.setWindowTitle(self.tr("Configure community {0}").format(name))
def display_info(self, info):
self.label_error.setText(info)
def node_parameters(self):
server = self.lineedit_server.text()
port = self.spinbox_port.value()
return server, port
def add_node_parameters(self):
server = self.lineedit_add_address.text()
port = self.spinbox_add_port.value()
return server, port
async def show_success(self, notification):
if notification:
toast.display(self.tr("UID broadcast"), self.tr("Identity broadcasted to the network"))
else:
await QAsyncMessageBox.information(self, self.tr("UID broadcast"),
self.tr("Identity broadcasted to the network"))
def show_error(self, notification, error_txt):
if notification:
toast.display(self.tr("UID broadcast"), error_txt)
self.label_error.setText(self.tr("Error") + " " + error_txt)
def set_steps_buttons_visible(self, visible):
self.button_next.setVisible(visible)
self.button_previous.setVisible(visible)
def set_nodes_model(self, model):
self.tree_peers.setModel(model)
def async_exec(self):
future = asyncio.Future()
self.finished.connect(lambda r: future.set_result(r))
self.open()
return future
...@@ -167,7 +167,10 @@ class PeeringTreeModel(QAbstractItemModel): ...@@ -167,7 +167,10 @@ class PeeringTreeModel(QAbstractItemModel):
return True return True
def refresh_tree(self): def refresh_tree(self):
self.beginResetModel()
logging.debug("root : " + self.root_item.data(0)) logging.debug("root : " + self.root_item.data(0))
self.root_item.node_items = []
for node in self.nodes: for node in self.nodes:
node_item = NodeItem(node, self.root_item) node_item = NodeItem(node, self.root_item)
self.root_item.appendChild(node_item) self.root_item.appendChild(node_item)
self.endResetModel()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment