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

Certification component

parent 48d04795
No related branches found
No related tags found
No related merge requests found
Showing
with 524 additions and 294 deletions
"""
Created on 24 dec. 2014
@author: inso
"""
import asyncio
import logging
from duniterpy.api import errors
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QApplication, QMessageBox
from PyQt5.QtCore import Qt, QObject, QLocale, QDateTime
from .widgets import toast
from .widgets.dialogs import QAsyncMessageBox
from .member import MemberDialog
from ..tools.decorators import asyncify, once_at_a_time
from ..tools.exceptions import NoPeerAvailable
from ..presentation.certification_uic import Ui_CertificationDialog
class CertificationDialog(QObject):
"""
A dialog to certify individuals
"""
def __init__(self, app, account, password_asker, widget, ui):
"""
Constructor if a certification dialog
:param sakia.core.Application app:
:param sakia.core.Account account:
:param sakia.gui.password_asker.PasswordAsker password_asker:
:param PyQt5.QtWidgets widget: the widget of the dialog
:param sakia.gen_resources.certification_uic.Ui_CertificationDialog view: the view of the certification dialog
:return:
"""
super().__init__()
self.widget = widget
self.ui = ui
self.ui.setupUi(self.widget)
self.app = app
self.account = account
self.password_asker = password_asker
self.community = self.account.communities[0]
self.ui.radio_contact.toggled.connect(lambda c, radio="contact": self.recipient_mode_changed(radio))
self.ui.radio_pubkey.toggled.connect(lambda c, radio="pubkey": self.recipient_mode_changed(radio))
self.ui.radio_search.toggled.connect(lambda c, radio="search": self.recipient_mode_changed(radio))
self.ui.button_box.accepted.connect(self.accept)
self.ui.button_box.rejected.connect(self.widget.reject)
for community in self.account.communities:
self.ui.combo_community.addItem(community.currency)
for contact_name in sorted([c['name'] for c in account.contacts], key=str.lower):
self.ui.combo_contact.addItem(contact_name)
if len(account.contacts) == 0:
self.ui.radio_pubkey.setChecked(True)
self.ui.radio_contact.setEnabled(False)
self.ui.member_widget = MemberDialog.as_widget(self.ui.groupBox, self.app, self.account, self.community, None)
self.ui.horizontalLayout_5.addWidget(self.ui.member_widget.widget)
self.ui.search_user.button_reset.hide()
self.ui.search_user.init(self.app)
self.ui.search_user.change_account(self.account)
self.ui.search_user.change_community(self.community)
self.ui.combo_contact.currentIndexChanged.connect(self.refresh_member)
self.ui.edit_pubkey.textChanged.connect(self.refresh_member)
self.ui.search_user.identity_selected.connect(self.refresh_member)
self.ui.radio_contact.toggled.connect(self.refresh_member)
self.ui.radio_search.toggled.connect(self.refresh_member)
self.ui.radio_pubkey.toggled.connect(self.refresh_member)
self.ui.combo_community.currentIndexChanged.connect(self.change_current_community)
@classmethod
def open_dialog(cls, app, account, community, password_asker):
"""
Certify and identity
:param sakia.core.Application app: the application
:param sakia.core.Account account: the account certifying the identity
:param sakia.core.Community community: the community
:param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
:return:
"""
dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog())
if community:
dialog.ui.combo_community.setCurrentText(community.name)
dialog.refresh()
return dialog.exec()
@classmethod
async def certify_identity(cls, app, account, password_asker, community, identity):
"""
Certify and identity
:param sakia.core.Application app: the application
:param sakia.core.Account account: the account certifying the identity
:param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
:param sakia.core.Community community: the community
:param sakia.core.registry.Identity identity: the identity certified
:return:
"""
dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog())
dialog.ui.combo_community.setCurrentText(community.name)
dialog.ui.edit_pubkey.setText(identity.pubkey)
dialog.ui.radio_pubkey.setChecked(True)
dialog.refresh()
return await dialog.async_exec()
@asyncify
async def accept(self):
"""
Validate the dialog
"""
pubkey = self.selected_pubkey()
if pubkey:
password = await self.password_asker.async_exec()
if password == "":
self.ui.button_box.setEnabled(True)
return
QApplication.setOverrideCursor(Qt.WaitCursor)
result = await self.account.certify(password, self.community, pubkey)
if result[0]:
if self.app.preferences['notifications']:
toast.display(self.tr("Certification"),
self.tr("Success sending certification"))
else:
await QAsyncMessageBox.information(self.widget, self.tr("Certification"),
self.tr("Success sending certification"))
QApplication.restoreOverrideCursor()
self.widget.accept()
else:
if self.app.preferences['notifications']:
toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}"
.format(result[1])))
else:
await QAsyncMessageBox.critical(self.widget, self.tr("Certification"),
self.tr("Could not broadcast certification : {0}"
.format(result[1])))
QApplication.restoreOverrideCursor()
self.ui.button_box.setEnabled(True)
def change_current_community(self, index):
self.community = self.account.communities[index]
self.ui.search_user.change_community(self.community)
self.ui.member_widget.change_community(self.community)
if self.widget.isVisible():
self.refresh()
def selected_pubkey(self):
"""
Get selected pubkey in the widgets of the window
:return: the current pubkey
:rtype: str
"""
pubkey = None
if self.ui.radio_contact.isChecked():
for contact in self.account.contacts:
if contact['name'] == self.ui.combo_contact.currentText():
pubkey = contact['pubkey']
break
elif self.ui.radio_search.isChecked():
if self.ui.search_user.current_identity():
pubkey = self.ui.search_user.current_identity().pubkey
else:
pubkey = self.ui.edit_pubkey.text()
return pubkey
@asyncify
async def refresh_member(self, checked=False):
"""
Refresh the member widget
"""
current_pubkey = self.selected_pubkey()
if current_pubkey:
identity = await self.app.identities_registry.future_find(current_pubkey, self.community)
else:
identity = None
self.ui.member_widget.identity = identity
self.ui.member_widget.refresh()
@once_at_a_time
@asyncify
async def refresh(self):
account_identity = await self.account.identity(self.community)
is_member = await account_identity.is_member(self.community)
try:
block_0 = await self.community.get_block(0)
except errors.DuniterError as e:
if e.ucode == errors.BLOCK_NOT_FOUND:
block_0 = None
except NoPeerAvailable as e:
logging.debug(str(e))
block_0 = None
params = await self.community.parameters()
certifications = await account_identity.unique_valid_certified_by(self.app.identities_registry, self.community)
nb_certifications = len([c for c in certifications if c['block_number']])
nb_cert_pending = len([c for c in certifications if not c['block_number']])
remaining_time = await account_identity.cert_issuance_delay(self.app.identities_registry, self.community)
cert_text = self.tr("Certifications sent : {nb_certifications}/{stock}").format(
nb_certifications=nb_certifications,
stock=params['sigStock'])
if nb_cert_pending > 0:
cert_text += " (+{nb_cert_pending} certifications pending)".format(nb_cert_pending=nb_cert_pending)
if remaining_time > 0:
cert_text += "\n"
days, remainder = divmod(remaining_time, 3600*24)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
if days > 0:
remaining_localized = self.tr("{days} days").format(days=days)
else:
remaining_localized = self.tr("{hours} hours and {min} min.").format(hours=hours,
min=minutes)
cert_text += self.tr("Remaining time before next certification validation : {0}".format(remaining_localized))
self.ui.label_cert_stock.setText(cert_text)
if is_member or not block_0:
if nb_certifications < params['sigStock'] or params['sigStock'] == 0:
self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
if remaining_time > 0:
self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok") +
self.tr(" (Not validated before ")
+ remaining_localized + ")")
else:
self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok"))
else:
self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("No more certifications"))
else:
self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("Not a member"))
def showEvent(self, event):
super().showEvent(event)
self.first_certification_check()
def first_certification_check(self):
if self.account.notifications['warning_certifying_first_time']:
self.account.notifications['warning_certifying_first_time'] = False
QMessageBox.warning(self, "Certifying individuals", """Please follow the following guidelines :
1.) Don't certify an account if you believe the issuers identity might be faked.
2.) Don't certify an account if you believe the issuer already has another certified account.
3.) Don't certify an account if you believe the issuer purposely or carelessly violates rule 1 or 2 (the issuer certifies faked or double accounts
""")
def recipient_mode_changed(self, radio):
"""
:param str radio:
"""
self.ui.edit_pubkey.setEnabled(radio == "pubkey")
self.ui.combo_contact.setEnabled(radio == "contact")
self.ui.search_user.setEnabled(radio == "search")
def async_exec(self):
future = asyncio.Future()
self.widget.finished.connect(lambda r: future.set_result(r))
self.widget.open()
self.refresh()
return future
def exec(self):
self.widget.exec()
...@@ -55,16 +55,16 @@ ...@@ -55,16 +55,16 @@
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="layout_target_choice">
<property name="topMargin"> <property name="topMargin">
<number>6</number> <number>6</number>
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="layout_mode_contact">
<item> <item>
<widget class="QRadioButton" name="radio_contact"> <widget class="QRadioButton" name="radio_contact">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="layout_mode_pubkey">
<item> <item>
<widget class="QRadioButton" name="radio_pubkey"> <widget class="QRadioButton" name="radio_pubkey">
<property name="text"> <property name="text">
...@@ -161,14 +161,14 @@ ...@@ -161,14 +161,14 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="layout_mode_search">
<property name="topMargin"> <property name="topMargin">
<number>6</number> <number>6</number>
</property> </property>
<item> <item>
<widget class="QRadioButton" name="radio_search"> <widget class="QRadioButton" name="radio_search">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
......
from ..component.controller import ComponentController
from .view import CertificationView
from .model import CertificationModel
from ..search_user.controller import SearchUserController
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt
from ...tools.decorators import asyncify, once_at_a_time
import asyncio
class CertificationController(ComponentController):
"""
The Certification view
"""
def __init__(self, parent, view, model, search_user):
"""
Constructor of the Certification component
:param sakia.gui.Certification.view.CertificationView: the view
:param sakia.gui.Certification.model.CertificationModel model: the model
:param sakia.gui.SearchUser.controller.SearchUserController search_user: the search user component
"""
super().__init__(parent, view, model)
self.view.button_box.accepted.connect(self.accept)
self.view.button_box.rejected.connect(self.reject)
self.view.combo_community.currentIndexChanged.connect(self.change_current_community)
self.search_user = search_user
@classmethod
def create(cls, parent, app, **kwargs):
"""
Instanciate a Certification component
:param sakia.gui.component.controller.ComponentController parent:
:return: a new Certification controller
:rtype: CertificationController
"""
account = kwargs['account']
community = kwargs['community']
communities_names = [c.name for c in account.communities]
contacts_names = [c['name'] for c in account.contacts]
view = CertificationView(parent.view, None, communities_names, contacts_names)
model = CertificationModel(None, app, account, community)
certification = cls(parent, view, model, None)
search_user = SearchUserController.create(certification, app, account=model.account, community=model.community)
view.set_search_user(search_user.view)
model.setParent(certification)
return certification
@classmethod
def open_dialog(cls, parent, app, account, community, password_asker):
"""
Certify and identity
:param sakia.gui.component.controller.ComponentController parent: the parent
:param sakia.core.Application app: the application
:param sakia.core.Account account: the account certifying the identity
:param sakia.core.Community community: the community
:param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
:return:
"""
dialog = cls.create(parent, app, account=account, community=community, password_asker=password_asker)
if community:
dialog.ui.combo_community.setCurrentText(community.name)
dialog.refresh()
return dialog.exec()
@classmethod
async def certify_identity(cls, parent, app, account, password_asker, community, identity):
"""
Certify and identity
:param sakia.gui.component.controller.ComponentController parent: the parent
:param sakia.core.Application app: the application
:param sakia.core.Account account: the account certifying the identity
:param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
:param sakia.core.Community community: the community
:param sakia.core.registry.Identity identity: the identity certified
:return:
"""
dialog = cls.create(parent, app, account=account, community=community, password_asker=password_asker)
dialog.view.combo_community.setCurrentText(community.name)
dialog.view.edit_pubkey.setText(identity.pubkey)
dialog.view.radio_pubkey.setChecked(True)
dialog.refresh()
return await dialog.async_exec()
@property
def view(self) -> CertificationView:
return self._view
@property
def model(self) -> CertificationModel:
return self._model
@asyncify
async def accept(self):
"""
Validate the dialog
"""
pubkey = self.selected_pubkey()
if pubkey:
password = await self.password_asker.async_exec()
if password == "":
self.view.enable_button_box()
return
QApplication.setOverrideCursor(Qt.WaitCursor)
result = await self.account.certify(password, self.community, pubkey)
if result[0]:
QApplication.restoreOverrideCursor()
await self.view.show_success()
self.view.accept()
else:
await self.view.show_error(result[1])
QApplication.restoreOverrideCursor()
self.view.enable_button_box()
def reject(self):
self.view.reject()
def selected_pubkey(self):
"""
Get selected pubkey in the widgets of the window
:return: the current pubkey
:rtype: str
"""
pubkey = None
if self.view.recipient_mode() == CertificationView.RecipientMode.CONTACT:
contact_name = self.view.selected_contact()
pubkey = self.model.contact_name_pubkey(contact_name)
elif self.view.recipient_mode() == CertificationView.RecipientMode.SEARCH:
if self.search_user.current_identity():
pubkey = self.search_user.current_identity().pubkey
else:
pubkey = self.view.pubkey_value()
return pubkey
@once_at_a_time
@asyncify
async def refresh(self):
stock = await self.model.get_cert_stock()
written, pending = await self.model.nb_certifications()
days, hours, minutes, seconds = await self.model.remaining_time()
self.view.display_cert_stock(written, pending, stock, days, hours, minutes)
if await self.model.could_certify():
if written < stock or stock == 0:
if 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:
self.view.set_button_box(CertificationView.ButtonBoxState.OK)
else:
self.view.set_button_box(CertificationView.ButtonBoxState.NO_MORE_CERTIFICATION)
else:
self.view.set_button_box(CertificationView.ButtonBoxState.NOT_A_MEMBER)
def change_current_community(self, index):
self.model.change_community(index)
self.search_user.set_community(self.community)
#self.member_widget.change_community(self.community)
self.refresh()
def async_exec(self):
future = asyncio.Future()
self.view.finished.connect(lambda r: future.set_result(r))
self.view.open()
self.refresh()
return future
def exec(self):
self.refresh()
self.view.exec()
from ..component.model import ComponentModel
from duniterpy.api import errors
from sakia.tools.exceptions import NoPeerAvailable
import logging
class CertificationModel(ComponentModel):
"""
The model of Certification component
"""
def __init__(self, parent, app, account, community):
super().__init__(parent)
self.app = app
self.account = account
self.community = community
if self.community is None:
self.community = self.account.communities[0]
def contact_name_pubkey(self, name):
"""
Get the pubkey of a contact from its name
:param str name:
:return:
:rtype: str
"""
for contact in self.account.contacts:
if contact['name'] == name:
return contact['pubkey']
def change_community(self, index):
"""
Change current community
:param int index: index of the community in the account list
"""
self.community = self.account.communities[index]
async def get_cert_stock(self):
"""
:return: the certifications stock
:rtype: int
"""
params = await self.community.parameters()
return params['sigStock']
async def remaining_time(self):
"""
Get remaining time as a tuple to display
:return: a tuple containing (days, hours, minutes, seconds)
:rtype: tuple[int]
"""
account_identity = await self.account.identity(self.community)
remaining_time = await account_identity.cert_issuance_delay(self.app.identities_registry, self.community)
days, remainder = divmod(remaining_time, 3600 * 24)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return days, hours, minutes, seconds
async def nb_certifications(self):
"""
Get
:return: a tuple containing (written valid certifications, pending certifications)
:rtype: tuple[int]
"""
account_identity = await self.account.identity(self.community)
certifications = await account_identity.unique_valid_certified_by(self.app.identities_registry, self.community)
nb_certifications = len([c for c in certifications if c['block_number']])
nb_cert_pending = len([c for c in certifications if not c['block_number']])
return nb_certifications, nb_cert_pending
async def could_certify(self):
"""
Check if the user could theorically certify
:return: true if the user can certifiy
:rtype: bool
"""
account_identity = await self.account.identity(self.community)
is_member = await account_identity.is_member(self.community)
try:
block_0 = await self.community.get_block(0)
except errors.DuniterError as e:
if e.ucode == errors.BLOCK_NOT_FOUND:
block_0 = None
except NoPeerAvailable as e:
logging.debug(str(e))
block_0 = None
return is_member or not block_0
\ No newline at end of file
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
from PyQt5.QtCore import QT_TRANSLATE_NOOP
from .certification_uic import Ui_CertificationDialog
from ..widgets import toast
from ..widgets.dialogs import QAsyncMessageBox
from enum import Enum
class CertificationView(QDialog, Ui_CertificationDialog):
"""
The view of the certification component
"""
class ButtonBoxState(Enum):
NO_MORE_CERTIFICATION = 0
NOT_A_MEMBER = 1
REMAINING_TIME_BEFORE_VALIDATION = 2
OK = 3
class RecipientMode(Enum):
CONTACT = 0
PUBKEY = 1
SEARCH = 2
_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.REMAINING_TIME_BEFORE_VALIDATION: (True,
QT_TRANSLATE_NOOP("CertificationView",
"&Ok (Not validated before {remaining})")),
ButtonBoxState.OK: (True, QT_TRANSLATE_NOOP("CertificationView", "&Ok"))
}
def __init__(self, parent, search_user_view, communities_names, contacts_names):
"""
Constructor
"""
super().__init__(parent)
self.setupUi(self)
self.radio_contact.toggled.connect(lambda c, radio=CertificationView.RecipientMode.CONTACT: self.recipient_mode_changed(radio))
self.radio_pubkey.toggled.connect(lambda c, radio=CertificationView.RecipientMode.PUBKEY: self.recipient_mode_changed(radio))
self.radio_search.toggled.connect(lambda c, radio=CertificationView.RecipientMode.SEARCH: self.recipient_mode_changed(radio))
for name in communities_names:
self.combo_community.addItem(name)
for name in sorted(contacts_names):
self.combo_contact.addItem(name)
if len(contacts_names) == 0:
self.radio_pubkey.setChecked(True)
self.radio_contact.setEnabled(False)
self.search_user = search_user_view
#self.combo_contact.currentIndexChanged.connect(self.refresh_member)
#self.edit_pubkey.textChanged.connect(self.refresh_member)
#self.search_user.identity_selected.connect(self.refresh_member)
#self.radio_contact.toggled.connect(self.refresh_member)
#self.radio_search.toggled.connect(self.refresh_member)
#self.radio_pubkey.toggled.connect(self.refresh_member)
def set_search_user(self, search_user_view):
"""
:param sakia.gui.search_user.view.SearchUserView search_user_view:
:return:
"""
self.search_user = search_user_view
self.layout_mode_search.addWidget(search_user_view)
self.search_user.button_reset.hide()
def set_member_widget(self, member_widget):
self.horizontalLayout_5.addWidget(member_widget)
def recipient_mode(self):
if self.radio_contact.isChecked():
return CertificationView.RecipientMode.CONTACT
elif self.radio_search.isChecked():
return CertificationView.RecipientMode.SEARCH
else:
return CertificationView.RecipientMode.PUBKEY
def selected_contact(self):
return self.combo_contact.currentText()
def pubkey_value(self):
return self.edit_pubkey.text()
async def show_success(self):
if self.app.preferences['notifications']:
toast.display(self.tr("Certification"),
self.tr("Success sending certification"))
else:
await QAsyncMessageBox.information(self.widget, self.tr("Certification"),
self.tr("Success sending certification"))
async def show_error(self, error_txt):
if self.app.preferences['notifications']:
toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}"
.format(error_txt)))
else:
await QAsyncMessageBox.critical(self.widget, self.tr("Certification"),
self.tr("Could not broadcast certification : {0}"
.format(error_txt)))
def display_cert_stock(self, written, pending, stock,
remaining_days, remaining_hours, remaining_minutes):
"""
Display values in informations label
:param int written: number of written certifications
:param int pending: number of pending certifications
:param int stock: maximum certifications
:param int remaining_days:
:param int remaining_hours:
:param int remaining_minutes:
"""
cert_text = self.tr("Certifications sent : {nb_certifications}/{stock}").format(
nb_certifications=written,
stock=stock)
if pending > 0:
cert_text += " (+{nb_cert_pending} certifications pending)".format(nb_cert_pending=pending)
if remaining_days > 0:
remaining_localized = self.tr("{days} days").format(days=remaining_days)
else:
remaining_localized = self.tr("{hours} hours and {min} min.").format(hours=remaining_hours,
min=remaining_minutes)
cert_text += self.tr("Remaining time before next certification validation : {0}".format(remaining_localized))
self.label_cert_stock.setText(cert_text)
def set_button_box(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_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 recipient_mode_changed(self, radio):
"""
:param str radio:
"""
self.edit_pubkey.setEnabled(radio == CertificationView.RecipientMode.PUBKEY)
self.combo_contact.setEnabled(radio == CertificationView.RecipientMode.CONTACT)
self.search_user.setEnabled(radio == CertificationView.RecipientMode.SEARCH)
...@@ -21,9 +21,10 @@ class HomeScreenController(ComponentController): ...@@ -21,9 +21,10 @@ class HomeScreenController(ComponentController):
def create(cls, parent, app, **kwargs): def create(cls, parent, app, **kwargs):
""" """
Instanciate a homescreen component Instanciate a homescreen component
:param sakia.gui.agent.controller.AgentController parent: :param sakia.gui.component.controller.ComponentController parent:
:param sakia.core.Application app:
:return: a new Homescreen controller :return: a new Homescreen controller
:rtype: NavigationController :rtype: HomeScreenController
""" """
view = HomeScreenView(parent.view) view = HomeScreenView(parent.view)
model = HomeScreenModel(None, app) model = HomeScreenModel(None, app)
......
...@@ -3,7 +3,7 @@ from sakia.gui.component.model import ComponentModel ...@@ -3,7 +3,7 @@ from sakia.gui.component.model import ComponentModel
class HomeScreenModel(ComponentModel): class HomeScreenModel(ComponentModel):
""" """
The model of Navigation component The model of HomeScreen component
""" """
def __init__(self, parent, app): def __init__(self, parent, app):
......
...@@ -7,10 +7,9 @@ class HomeScreenView(QWidget, Ui_HomescreenWidget): ...@@ -7,10 +7,9 @@ class HomeScreenView(QWidget, Ui_HomescreenWidget):
classdocs classdocs
""" """
def __init__(self, app): def __init__(self, parent):
""" """
Constructor Constructor
""" """
super().__init__() super().__init__(parent)
self.setupUi(self) self.setupUi(self)
self.app = app
...@@ -12,8 +12,8 @@ class IdentitiesView(QWidget, Ui_IdentitiesWidget): ...@@ -12,8 +12,8 @@ class IdentitiesView(QWidget, Ui_IdentitiesWidget):
search_by_text_requested = pyqtSignal(str) search_by_text_requested = pyqtSignal(str)
search_directly_connected_requested = pyqtSignal() search_directly_connected_requested = pyqtSignal()
_direct_connections_text = QT_TRANSLATE_NOOP("IdentitiesTabWidget", "Search direct certifications") _direct_connections_text = QT_TRANSLATE_NOOP("IdentitiesView", "Search direct certifications")
_search_placeholder = QT_TRANSLATE_NOOP("IdentitiesTabWidget", "Research a pubkey, an uid...") _search_placeholder = QT_TRANSLATE_NOOP("IdentitiesView", "Research a pubkey, an uid...")
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
......
...@@ -61,11 +61,15 @@ class MainWindowController(ComponentController): ...@@ -61,11 +61,15 @@ class MainWindowController(ComponentController):
main_window.status_bar = main_window.attach(StatusBarController.create(main_window, app)) main_window.status_bar = main_window.attach(StatusBarController.create(main_window, app))
view.setStatusBar(main_window.status_bar._view) view.setStatusBar(main_window.status_bar._view)
main_window.toolbar = main_window.attach(ToolbarController.create(main_window, password_asker))
view.top_layout.addWidget(main_window.toolbar._view)
main_window.navigation = main_window.attach(NavigationController.create(main_window, app)) main_window.navigation = main_window.attach(NavigationController.create(main_window, app))
view.bottom_layout.insertWidget(0, main_window.navigation._view) view.bottom_layout.insertWidget(0, main_window.navigation._view)
main_window.navigation.community_changed.connect(main_window.handle_community_change)
main_window.navigation.account_changed.connect(main_window.handle_community_change)
main_window.toolbar = main_window.attach(ToolbarController.create(main_window, app,
app.current_account, None,
password_asker))
view.top_layout.addWidget(main_window.toolbar._view)
#app.version_requested.connect(main_window.latest_version_requested) #app.version_requested.connect(main_window.latest_version_requested)
#app.account_imported.connect(main_window.import_account_accepted) #app.account_imported.connect(main_window.import_account_accepted)
...@@ -107,6 +111,20 @@ class MainWindowController(ComponentController): ...@@ -107,6 +111,20 @@ class MainWindowController(ComponentController):
version_info=version_info, version_info=version_info,
version_url=version_url)) version_url=version_url))
def handle_account_change(self, account):
"""
Set current account
:param sakia.core.Account account:
"""
self.toolbar.set_account(account)
def handle_community_change(self, community):
"""
Set current community
:param sakia.core.Community community:
"""
self.toolbar.set_community(community)
def refresh(self): def refresh(self):
""" """
Refresh main window Refresh main window
......
...@@ -8,12 +8,16 @@ from ..identities.controller import IdentitiesController ...@@ -8,12 +8,16 @@ from ..identities.controller import IdentitiesController
from ..informations.controller import InformationsController from ..informations.controller import InformationsController
from ..graphs.wot.controller import WotController from ..graphs.wot.controller import WotController
from ..graphs.explorer.controller import ExplorerController from ..graphs.explorer.controller import ExplorerController
from sakia.core import Account, Community
from PyQt5.QtCore import pyqtSignal
class NavigationController(ComponentController): class NavigationController(ComponentController):
""" """
The navigation panel The navigation panel
""" """
community_changed = pyqtSignal(Community)
account_changed = pyqtSignal(Account)
def __init__(self, parent, view, model): def __init__(self, parent, view, model):
""" """
...@@ -32,6 +36,7 @@ class NavigationController(ComponentController): ...@@ -32,6 +36,7 @@ class NavigationController(ComponentController):
'Wot': WotController, 'Wot': WotController,
'Explorer': ExplorerController 'Explorer': ExplorerController
} }
self.view.current_view_changed.connect(self.handle_view_change)
@classmethod @classmethod
def create(cls, parent, app): def create(cls, parent, app):
...@@ -74,3 +79,16 @@ class NavigationController(ComponentController): ...@@ -74,3 +79,16 @@ class NavigationController(ComponentController):
self.view.set_model(self.model) self.view.set_model(self.model)
def handle_view_change(self, raw_data):
"""
Handle view change
:param dict raw_data:
:return:
"""
account = raw_data.get('account', None)
community = raw_data.get('community', None)
if account != self.model.current_data('account'):
self.account_changed.emit(account)
if community != self.model.current_data('community'):
self.community_changed.emit(community)
self.model.set_current_data(raw_data)
...@@ -18,17 +18,20 @@ class NavigationModel(ComponentModel): ...@@ -18,17 +18,20 @@ class NavigationModel(ComponentModel):
super().__init__(parent) super().__init__(parent)
self.app = app self.app = app
self.navigation = {} self.navigation = {}
self._current_data = None
def init_navigation_data(self): def init_navigation_data(self):
self.navigation = [ self.navigation = [
{ {
'node': { 'node': {
'title': self.app.current_account.name, 'title': self.app.current_account.name,
'component': "HomeScreen" 'component': "HomeScreen",
'account': self.app.current_account
}, },
'children': [] 'children': []
} }
] ]
self._current_data = self.navigation[0]
for c in self.app.current_account.communities: for c in self.app.current_account.communities:
self.navigation[0]['children'].append({ self.navigation[0]['children'].append({
'node': { 'node': {
...@@ -89,3 +92,9 @@ class NavigationModel(ComponentModel): ...@@ -89,3 +92,9 @@ class NavigationModel(ComponentModel):
def generic_tree(self): def generic_tree(self):
return GenericTreeModel.create("Navigation", self.navigation) return GenericTreeModel.create("Navigation", self.navigation)
def set_current_data(self, raw_data):
self._current_data = raw_data
def current_data(self, key):
return self._current_data.get(key, None)
\ No newline at end of file
from PyQt5.QtWidgets import QFrame, QSizePolicy from PyQt5.QtWidgets import QFrame, QSizePolicy
from PyQt5.QtCore import QModelIndex from PyQt5.QtCore import pyqtSignal
from .navigation_uic import Ui_Navigation from .navigation_uic import Ui_Navigation
from ...models.generic_tree import GenericTreeModel from ...models.generic_tree import GenericTreeModel
...@@ -8,6 +8,7 @@ class NavigationView(QFrame, Ui_Navigation): ...@@ -8,6 +8,7 @@ class NavigationView(QFrame, Ui_Navigation):
""" """
The view of navigation panel The view of navigation panel
""" """
current_view_changed = pyqtSignal(dict)
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
...@@ -40,4 +41,5 @@ class NavigationView(QFrame, Ui_Navigation): ...@@ -40,4 +41,5 @@ class NavigationView(QFrame, Ui_Navigation):
if 'widget' in raw_data: if 'widget' in raw_data:
widget = raw_data['widget'] widget = raw_data['widget']
if self.stacked_widget.indexOf(widget): if self.stacked_widget.indexOf(widget):
self.stacked_widget.setCurrentWidget(widget) self.stacked_widget.setCurrentWidget(widget)
\ No newline at end of file self.current_view_changed.emit(raw_data)
...@@ -60,4 +60,12 @@ class SearchUserController(ComponentController): ...@@ -60,4 +60,12 @@ class SearchUserController(ComponentController):
Select node in graph when item is selected in combobox Select node in graph when item is selected in combobox
""" """
self.model.select_identity(index) self.model.select_identity(index)
self.identity_selected.emit(self.model.identity()) self.identity_selected.emit(self.model.identity())
\ No newline at end of file
def set_community(self, community):
"""
Set community
:param sakia.core.Community community:
:return:
"""
self.model.community = community
...@@ -6,6 +6,7 @@ from .view import ToolbarView ...@@ -6,6 +6,7 @@ from .view import ToolbarView
from ...tools.decorators import asyncify, once_at_a_time, cancel_once_task from ...tools.decorators import asyncify, once_at_a_time, cancel_once_task
from ..widgets.dialogs import QAsyncMessageBox, QAsyncFileDialog, dialog_async_exec from ..widgets.dialogs import QAsyncMessageBox, QAsyncFileDialog, dialog_async_exec
from ..widgets import toast from ..widgets import toast
from ..certification.controller import CertificationController
import logging import logging
...@@ -16,7 +17,7 @@ class ToolbarController(ComponentController): ...@@ -16,7 +17,7 @@ class ToolbarController(ComponentController):
def __init__(self, parent, view, model, password_asker): def __init__(self, parent, view, model, password_asker):
""" """
:param sakia.gui.agent.controller.AgentController parent: the parent :param sakia.gui.component.controller.ComponentController parent: the parent
:param sakia.gui.toolbar.view.ToolbarView view: :param sakia.gui.toolbar.view.ToolbarView view:
:param sakia.gui.toolbar.model.ToolbarModel model: :param sakia.gui.toolbar.model.ToolbarModel model:
""" """
...@@ -30,7 +31,7 @@ class ToolbarController(ComponentController): ...@@ -30,7 +31,7 @@ class ToolbarController(ComponentController):
self.view.button_membership.clicked.connect(self.send_membership_demand) self.view.button_membership.clicked.connect(self.send_membership_demand)
@classmethod @classmethod
def create(cls, parent, password_asker): def create(cls, parent, app, account, community, password_asker):
""" """
Instanciate a navigation component Instanciate a navigation component
:param sakia.gui.agent.controller.AgentController parent: :param sakia.gui.agent.controller.AgentController parent:
...@@ -38,7 +39,7 @@ class ToolbarController(ComponentController): ...@@ -38,7 +39,7 @@ class ToolbarController(ComponentController):
:rtype: ToolbarController :rtype: ToolbarController
""" """
view = ToolbarView(parent.view) view = ToolbarView(parent.view)
model = ToolbarModel(None) model = ToolbarModel(None, app, account, community)
toolbar = cls(parent, view, model, password_asker) toolbar = cls(parent, view, model, password_asker)
model.setParent(toolbar) model.setParent(toolbar)
return toolbar return toolbar
...@@ -173,10 +174,24 @@ The process to join back the community later will have to be done again.""") ...@@ -173,10 +174,24 @@ The process to join back the community later will have to be done again.""")
self.button_certification.setEnabled(False) self.button_certification.setEnabled(False)
self.action_publish_uid.setEnabled(False) self.action_publish_uid.setEnabled(False)
def set_account(self, account):
"""
Set current account
:param sakia.core.Account account:
"""
self.model.account = account
def set_community(self, community):
"""
Set current community
:param sakia.core.Community community:
"""
self.model.community = community
def open_certification_dialog(self): def open_certification_dialog(self):
CertificationDialog.open_dialog(self.app, CertificationController.open_dialog(self, self.model.app,
self.account, self.model.account,
self.community_view.community, self.model.community,
self.password_asker) self.password_asker)
def open_revocation_dialog(self): def open_revocation_dialog(self):
......
...@@ -6,5 +6,8 @@ class ToolbarModel(ComponentModel): ...@@ -6,5 +6,8 @@ class ToolbarModel(ComponentModel):
The model of Navigation component The model of Navigation component
""" """
def __init__(self, parent): def __init__(self, parent, app, account, community):
super().__init__(parent) super().__init__(parent)
self.app = app
self.account = account
self.community = community
...@@ -6,7 +6,7 @@ import logging ...@@ -6,7 +6,7 @@ import logging
from ..member import MemberDialog from ..member import MemberDialog
from ..contact import ConfigureContactDialog from ..contact import ConfigureContactDialog
from ..transfer import TransferMoneyDialog from ..transfer import TransferMoneyDialog
from ..certification import CertificationDialog from ..certification.controller import CertificationController
from ...tools.decorators import asyncify from ...tools.decorators import asyncify
from ...core.transfer import Transfer, TransferState from ...core.transfer import Transfer, TransferState
from ...core.registry import Identity from ...core.registry import Identity
...@@ -152,7 +152,7 @@ class ContextMenu(QObject): ...@@ -152,7 +152,7 @@ class ContextMenu(QObject):
@asyncify @asyncify
async def certify_identity(self, identity): async def certify_identity(self, identity):
await CertificationDialog.certify_identity(self._app, self._account, self._password_asker, await CertificationController.certify_identity(None, self._app, self._account, self._password_asker,
self._community, identity) self._community, identity)
@asyncify @asyncify
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment