From 3b9e642b41ecf005c5b037bf333f9b7f0ad2a05a Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Sat, 20 Jun 2015 10:00:48 +0200 Subject: [PATCH] Fix all bugs with identities refreshing - Beware of python closure parameters in for loops ! - Use the bma_access.get directly in classes that needs to be refreshed when getting the result, instead --- src/cutecoin/core/account.py | 5 +- src/cutecoin/core/community.py | 6 -- src/cutecoin/core/graph.py | 118 +++++++++++------------ src/cutecoin/core/net/api/bma/access.py | 5 +- src/cutecoin/core/registry/identities.py | 15 +-- src/cutecoin/core/registry/identity.py | 28 +++++- src/cutecoin/gui/community_tab.py | 16 ++- src/cutecoin/gui/wallets_tab.py | 38 +++++--- src/cutecoin/gui/wot_tab.py | 117 +++++++++++----------- src/cutecoin/models/identities.py | 48 ++++++--- 10 files changed, 231 insertions(+), 165 deletions(-) diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 786e31c8..256eb7fc 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -264,7 +264,10 @@ class Account(QObject): :return: The account identity in the community :rtype: cutecoin.core.registry.Identity """ - return self._identities_registry.lookup(self.pubkey, community) + identity = self._identities_registry.lookup(self.pubkey, community) + if identity.status == Identity.NOT_FOUND: + identity.uid = self.name + return identity @property def units_to_ref(self): diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 1835ce42..84e6cd63 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -89,12 +89,6 @@ class Community(QObject): """ return self.currency - def __eq__(self, other): - """ - :return: True if this community has the same currency name as the other one. - """ - return (other.currency == self.currency) - @property def short_currency(self): """ diff --git a/src/cutecoin/core/graph.py b/src/cutecoin/core/graph.py index a4066087..64d9955f 100644 --- a/src/cutecoin/core/graph.py +++ b/src/cutecoin/core/graph.py @@ -36,29 +36,29 @@ class Graph(object): """ return self._graph - def get_shortest_path_between_members(self, from_person, to_person): + def get_shortest_path_between_members(self, from_identity, to_identity): """ - Return path list of nodes from from_person to to_person - :param Person from_person: - :param Person to_person: + Return path list of nodes from from_identity to to_identity + :param identity from_identity: + :param identity to_identity: :return: """ path = list() - logging.debug("path between %s to %s..." % (from_person.uid, to_person.uid)) - if from_person.pubkey not in self._graph.keys(): - self.add_person(from_person) - certifier_list = from_person.certifiers_of(self.community) - self.add_certifier_list(certifier_list, from_person, to_person) - certified_list = from_person.certified_by(self.community) - self.add_certified_list(certified_list, from_person, to_person) + logging.debug("path between %s to %s..." % (from_identity.uid, to_identity.uid)) + if from_identity.pubkey not in self._graph.keys(): + self.add_identity(from_identity) + certifier_list = from_identity.certifiers_of(self.community) + self.add_certifier_list(certifier_list, from_identity, to_identity) + certified_list = from_identity.certified_by(self.community) + self.add_certified_list(certified_list, from_identity, to_identity) - if to_person.pubkey not in self._graph.keys(): + if to_identity.pubkey not in self._graph.keys(): # recursively feed graph searching for account node... - self.explore_to_find_member(to_person, self._graph[from_person.pubkey]['connected'], list()) - if len(self._graph[from_person.pubkey]['connected']) > 0: - # calculate path of nodes between person and to_person - path = self.find_shortest_path(self._graph[from_person.pubkey], self._graph[to_person.pubkey]) + self.explore_to_find_member(to_identity, self._graph[from_identity.pubkey]['connected'], list()) + if len(self._graph[from_identity.pubkey]['connected']) > 0: + # calculate path of nodes between identity and to_identity + path = self.find_shortest_path(self._graph[from_identity.pubkey], self._graph[to_identity.pubkey]) if path: logging.debug([node['text'] for node in path]) @@ -67,10 +67,10 @@ class Graph(object): return path - def explore_to_find_member(self, person, connected=None, done=None): + def explore_to_find_member(self, identity, connected=None, done=None): """ - Scan graph recursively to find person - :param Person person: Person instance to find + Scan graph recursively to find identity + :param identity identity: identity instance to find :param list connected: Optional, default=None, Pubkey list of the connected nodes around the current scanned node :param list done: Optional, default=None, List of node already scanned @@ -79,7 +79,7 @@ class Graph(object): # functions keywords args are persistent... Need to reset it with None trick connected = connected or (list() and (connected is None)) done = done or (list() and (done is None)) - logging.debug("search %s in " % person.uid) + logging.debug("search %s in " % identity.uid) logging.debug([self._graph[pubkey]['text'] for pubkey in connected]) # for each pubkey connected... for pubkey in tuple(connected): @@ -87,20 +87,20 @@ class Graph(object): node = self._graph[pubkey] if node['id'] in tuple(done): continue - person_selected = Person.from_metadata(node) - certifier_list = person_selected.certifiers_of(self.community) - self.add_certifier_list(certifier_list, person_selected, person) - if person.pubkey in tuple(self._graph.keys()): + identity_selected = identity.from_metadata(node) + certifier_list = identity_selected.certifiers_of(self.community) + self.add_certifier_list(certifier_list, identity_selected, identity) + if identity.pubkey in tuple(self._graph.keys()): return False - certified_list = person_selected.certified_by(self.community) - self.add_certified_list(certified_list, person_selected, person) - if person.pubkey in tuple(self._graph.keys()): + certified_list = identity_selected.certified_by(self.community) + self.add_certified_list(certified_list, identity_selected, identity) + if identity.pubkey in tuple(self._graph.keys()): return False if node['id'] not in tuple(done): done.append(node['id']) if len(done) >= len(self._graph): return True - result = self.explore_to_find_member(person, self._graph[person_selected.pubkey]['connected'], done) + result = self.explore_to_find_member(identity, self._graph[identity_selected.pubkey]['connected'], done) if not result: return False @@ -130,12 +130,12 @@ class Graph(object): shortest = newpath return shortest - def add_certifier_list(self, certifier_list, person, person_account): + def add_certifier_list(self, certifier_list, identity, identity_account): """ Add list of certifiers to graph :param list certifier_list: List of certifiers from api - :param Person person: Person instance which is certified - :param Person person_account: Account person instance + :param identity identity: identity instance which is certified + :param identity identity_account: Account identity instance :return: """ #  add certifiers of uid @@ -146,7 +146,7 @@ class Graph(object): # new node if certifier['pubkey'] not in self._graph.keys(): node_status = 0 - if certifier['pubkey'] == person_account.pubkey: + if certifier['pubkey'] == identity_account.pubkey: node_status += NODE_STATUS_HIGHLIGHTED if certifier['isMember'] is False: node_status += NODE_STATUS_OUT @@ -156,7 +156,7 @@ class Graph(object): 'text': certifier['uid'], 'tooltip': certifier['pubkey'], 'status': node_status, - 'connected': [person.pubkey] + 'connected': [identity.pubkey] } # keep only the latest certification @@ -169,7 +169,7 @@ class Graph(object): else: arc_status = ARC_STATUS_STRONG arc = { - 'id': person.pubkey, + 'id': identity.pubkey, 'status': arc_status, 'tooltip': QLocale.toString( QLocale(), @@ -180,17 +180,17 @@ class Graph(object): } #  add arc to certifier self._graph[certifier['pubkey']]['arcs'].append(arc) - # if certifier node not in person nodes - if certifier['pubkey'] not in tuple(self._graph[person.pubkey]['connected']): - # add certifier node to person node - self._graph[person.pubkey]['connected'].append(certifier['pubkey']) + # if certifier node not in identity nodes + if certifier['pubkey'] not in tuple(self._graph[identity.pubkey]['connected']): + # add certifier node to identity node + self._graph[identity.pubkey]['connected'].append(certifier['pubkey']) - def add_certified_list(self, certified_list, person, person_account): + def add_certified_list(self, certified_list, identity, identity_account): """ Add list of certified from api to graph :param list certified_list: List of certified from api - :param Person person: Person instance which is certifier - :param Person person_account: Account person instance + :param identity identity: identity instance which is certifier + :param identity identity_account: Account identity instance :return: """ # add certified by uid @@ -200,7 +200,7 @@ class Graph(object): continue if certified['pubkey'] not in self._graph.keys(): node_status = 0 - if certified['pubkey'] == person_account.pubkey: + if certified['pubkey'] == identity_account.pubkey: node_status += NODE_STATUS_HIGHLIGHTED if certified['isMember'] is False: node_status += NODE_STATUS_OUT @@ -210,7 +210,7 @@ class Graph(object): 'text': certified['uid'], 'tooltip': certified['pubkey'], 'status': node_status, - 'connected': [person.pubkey] + 'connected': [identity.pubkey] } # display validity status if (time.time() - certified['cert_time']['medianTime']) > self.ARC_STATUS_STRONG_time: @@ -231,42 +231,42 @@ class Graph(object): # replace old arc if this one is more recent new_arc = True index = 0 - for a in self._graph[person.pubkey]['arcs']: + for a in self._graph[identity.pubkey]['arcs']: # if same arc already exists... if a['id'] == arc['id']: # if arc more recent, dont keep old one... if arc['cert_time'] >= a['cert_time']: - self._graph[person.pubkey]['arcs'][index] = arc + self._graph[identity.pubkey]['arcs'][index] = arc new_arc = False index += 1 #  if arc not in graph... if new_arc: # add arc in graph - self._graph[person.pubkey]['arcs'].append(arc) - # if certified node not in person nodes - if certified['pubkey'] not in tuple(self._graph[person.pubkey]['connected']): - # add certified node to person node - self._graph[person.pubkey]['connected'].append(certified['pubkey']) + self._graph[identity.pubkey]['arcs'].append(arc) + # if certified node not in identity nodes + if certified['pubkey'] not in tuple(self._graph[identity.pubkey]['connected']): + # add certified node to identity node + self._graph[identity.pubkey]['connected'].append(certified['pubkey']) - def add_person(self, person, status=None, arcs=None, connected=None): + def add_identity(self, identity, status=None, arcs=None, connected=None): """ - Add person as a new node in graph - :param Person person: Person instance + Add identity as a new node in graph + :param identity identity: identity instance :param int status: Optional, default=None, Node status (see cutecoin.gui.views.wot) - :param list arcs: Optional, default=None, List of arcs (certified by person) - :param list connected: Optional, default=None, Public key list of the connected nodes around the person + :param list arcs: Optional, default=None, List of arcs (certified by identity) + :param list connected: Optional, default=None, Public key list of the connected nodes around the identity :return: """ # functions keywords args are persistent... Need to reset it with None trick status = status or (0 and (status is None)) arcs = arcs or (list() and (arcs is None)) connected = connected or (list() and (connected is None)) - self._graph[person.pubkey] = { - 'id': person.pubkey, + self._graph[identity.pubkey] = { + 'id': identity.pubkey, 'arcs': arcs, - 'text': person.uid, - 'tooltip': person.pubkey, + 'text': identity.uid, + 'tooltip': identity.pubkey, 'status': status, 'connected': connected } diff --git a/src/cutecoin/core/net/api/bma/access.py b/src/cutecoin/core/net/api/bma/access.py index 251b0f6e..aefdb481 100644 --- a/src/cutecoin/core/net/api/bma/access.py +++ b/src/cutecoin/core/net/api/bma/access.py @@ -93,11 +93,14 @@ class BmaAccess(QObject): if need_reload: #Move to network nstead of community #after removing qthreads - reply = self.request(request, req_args, get_args) if cache_key in self._pending_requests: if caller not in self._pending_requests[cache_key]: + logging.debug("New caller".format(caller)) self._pending_requests[cache_key].append(caller) + logging.debug("Callers".format(self._pending_requests[cache_key])) else: + reply = self.request(request, req_args, get_args) + logging.debug("New pending request {0}, caller {1}".format(cache_key, caller)) self._pending_requests[cache_key] = [caller] reply.finished.connect(lambda: self.handle_reply(request, req_args, get_args, tries)) diff --git a/src/cutecoin/core/registry/identities.py b/src/cutecoin/core/registry/identities.py index e17fb2ad..79aa6ac6 100644 --- a/src/cutecoin/core/registry/identities.py +++ b/src/cutecoin/core/registry/identities.py @@ -4,6 +4,7 @@ from cutecoin.core.net.api import bma as qtbma from .identity import Identity import json +import logging class IdentitiesRegistry: @@ -55,11 +56,12 @@ class IdentitiesRegistry: """ if pubkey in self._instances: identity = self._instances[pubkey] + self._instances[pubkey] = identity else: identity = Identity.empty(pubkey) self._instances[pubkey] = identity - reply = community.bma_access.request(qtbma.wot.Lookup, req_args={'search': pubkey}) - reply.finished.connect(lambda: self.handle_lookup(reply, identity)) + reply = community.bma_access.request(qtbma.wot.Lookup, req_args={'search': pubkey}) + reply.finished.connect(lambda: self.handle_lookup(reply, identity)) return identity def handle_lookup(self, reply, identity): @@ -79,10 +81,11 @@ class IdentitiesRegistry: if uid_data["meta"]["timestamp"] > timestamp: timestamp = uid_data["meta"]["timestamp"] identity_uid = uid_data["uid"] - identity.uid = identity_uid - identity.status = Identity.FOUND - identity.inner_data_changed.emit(str(qtbma.wot.Lookup)) - return + identity.uid = identity_uid + identity.status = Identity.FOUND + logging.debug("Lookup : found {0}".format(identity)) + identity.inner_data_changed.emit(str(qtbma.wot.Lookup)) + return def from_metadata(self, metadata): """ diff --git a/src/cutecoin/core/registry/identity.py b/src/cutecoin/core/registry/identity.py index 0517c1be..eb9cb649 100644 --- a/src/cutecoin/core/registry/identity.py +++ b/src/cutecoin/core/registry/identity.py @@ -8,7 +8,7 @@ import logging import time from ucoinpy.documents.certification import SelfCertification -from cutecoin.tools.exceptions import Error, LookupFailureError,\ +from cutecoin.tools.exceptions import Error, NoPeerAvailable,\ MembershipNotFoundError from cutecoin.core.net.api import bma as qtbma from cutecoin.core.net.api.bma import PROTOCOL_VERSION @@ -101,12 +101,34 @@ class Identity(QObject): if search != qtbma.blockchain.Membership.null_value: if len(search['memberships']) > 0: membership_data = search['memberships'][0] - return community.get_block(membership_data['blockNumber']).mediantime + return community.get_block(membership_data['blockNumber'])['medianTime'] else: return None else: raise MembershipNotFoundError(self.pubkey, community.name) + def get_expiration_date(self, community): + try: + join_block_number = self.membership(community)['blockNumber'] + try: + join_block = community.bma_access.get(self, qtbma.blockchain.Block, + req_args={'number': join_block_number}) + + parameters = community.bma_access.get(self, qtbma.blockchain.Parameters) + if join_block != qtbma.blockchain.Block.null_value \ + and parameters != qtbma.blockchain.Parameters.null_value: + join_date = join_block['medianTime'] + expiration_date = join_date + parameters['sigValidity'] + else: + return None + except NoPeerAvailable: + expiration_date = None + except MembershipNotFoundError: + expiration_date = None + return expiration_date + + + #TODO: Manage 'OUT' memberships ? Maybe ? def membership(self, community): """ @@ -192,7 +214,7 @@ class Identity(QObject): certifier['isMember'] = certifier_data['isMember'] certifier['cert_time'] = dict() certifier['cert_time']['medianTime'] = community.get_block( - certifier_data['meta']['block_number']).mediantime + certifier_data['meta']['block_number'])['medianTime'] certifiers.append(certifier) return certifiers diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index ab53db02..8ead8516 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -39,13 +39,16 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): :return: """ super().__init__() - self.setupUi(self) self.parent = parent self.app = app self.community = community self.account = account self.password_asker = password_asker - identities_model = IdentitiesTableModel(community) + self.setup_ui() + + def setup_ui(self): + self.setupUi(self) + identities_model = IdentitiesTableModel(self.community) proxy = IdentitiesFilterProxyModel() proxy.setSourceModel(identities_model) self.table_identities.setModel(proxy) @@ -54,7 +57,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): self.table_identities.sortByColumn(0, Qt.AscendingOrder) self.table_identities.resizeColumnsToContents() - self.wot_tab = WotTabWidget(app, account, community, password_asker, self) + self.wot_tab = WotTabWidget(self.app, self.account, self.community, self.password_asker, self) self.tabs_information.addTab(self.wot_tab, QIcon(':/icons/wot_icon'), self.tr("Web of Trust")) members_action = QAction(self.tr("Members"), self) members_action.triggered.connect(self.search_members) @@ -62,7 +65,10 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): direct_connections = QAction(self.tr("Direct connections"), self) direct_connections.triggered.connect(self.search_direct_connections) self.button_search.addAction(direct_connections) + + self.account.identity(self.community).inner_data_changed.connect(self.handle_account_identity_change) self.search_direct_connections() + self.refresh_quality_buttons() def identity_context_menu(self, point): @@ -327,11 +333,11 @@ Revoking your UID can only success if it is not already validated by the network """ self_identity = self.account.identity(self.community) try: - self_identity.inner_data_changed.connect(self.handle_account_identity_change) self.community.inner_data_changed.disconnect(self.handle_community_change) + self_identity.inner_data_changed.connect(self.handle_account_identity_change) except TypeError as e: if "disconnect() failed" in str(e): - pass + logging.debug("Could not disconnect community") else: raise diff --git a/src/cutecoin/gui/wallets_tab.py b/src/cutecoin/gui/wallets_tab.py index e07581ff..cb39c8f9 100644 --- a/src/cutecoin/gui/wallets_tab.py +++ b/src/cutecoin/gui/wallets_tab.py @@ -8,7 +8,7 @@ import logging from PyQt5.QtWidgets import QWidget, QMenu, QAction, QApplication, QDialog from PyQt5.QtCore import QDateTime, QModelIndex, Qt, QLocale from PyQt5.QtGui import QCursor -from ..core.registry import IdentitiesRegistry +from ..core.registry import Identity from ..core.wallet import Wallet from ..gui.password_asker import PasswordAskerDialog from ..models.wallets import WalletsTableModel, WalletsFilterProxyModel @@ -36,16 +36,29 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): self.account = account self.community = community self.password_asker = password_asker + self.setup_connections() - self.refresh() + def setup_connections(self): + self.account.inner_data_changed.connect(self.refresh_informations_frame) + self.community.inner_data_changed.connect(self.refresh_informations_frame) def refresh(self): + self.refresh_informations_frame() + self.refresh_wallets() + + def refresh_wallets(self): + wallets_model = WalletsTableModel(self.account, self.community) + proxy_model = WalletsFilterProxyModel() + proxy_model.setSourceModel(wallets_model) + wallets_model.dataChanged.connect(self.wallet_changed) + self.table_wallets.setModel(proxy_model) + self.table_wallets.resizeColumnsToContents() + + def refresh_informations_frame(self): parameters = self.community.parameters - last_renewal = "" - expiration = "" try: - person = self.app.identities_registry.lookup(self.account.pubkey, self.community) - membership = person.membership(self.community) + identity = self.account.identity(self.community) + membership = identity.membership(self.community) renew_block = membership['blockNumber'] last_renewal = self.community.get_block(renew_block)['medianTime'] expiration = last_renewal + parameters['sigValidity'] @@ -53,8 +66,8 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): last_renewal = None expiration = None - certified = person.unique_valid_certified_by(self.community) - certifiers = person.unique_valid_certifiers_of(self.community) + certified = identity.unique_valid_certified_by(self.community) + certifiers = identity.unique_valid_certifiers_of(self.community) if last_renewal and expiration: date_renewal = QLocale.toString( QLocale(), @@ -135,13 +148,6 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): ) ) - wallets_model = WalletsTableModel(self.account, self.community) - proxy_model = WalletsFilterProxyModel() - proxy_model.setSourceModel(wallets_model) - wallets_model.dataChanged.connect(self.wallet_changed) - self.table_wallets.setModel(proxy_model) - self.table_wallets.resizeColumnsToContents() - def get_referential_value(self, value): return self.account.units_to_ref(value, self.community) @@ -231,7 +237,7 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): clipboard = QApplication.clipboard() if data.__class__ is Wallet: clipboard.setText(data.pubkey) - elif data.__class__ is Person: + elif data.__class__ is Identity: clipboard.setText(data.pubkey) elif data.__class__ is str: clipboard.setText(data) diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index be83d962..e17630b8 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -47,71 +47,80 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): self.nodes = list() # create node metadata from account - self._current_metadata = {'text': self.account.name, 'id': self.account.pubkey} - self.refresh() + self._current_identity = None + self.draw_graph(self.account.identity(self.community)) - def draw_graph(self, metadata): + def draw_graph(self, identity): """ Draw community graph centered on the identity - :param dict metadata: Graph node metadata of the identity + :param cutecoin.core.registry.Identity identity: Graph node identity """ - logging.debug("Draw graph - " + metadata['text']) - self._current_metadata = metadata - - # create Person from node metadata - person = self.app.identities_registry.from_metadata(metadata) - person_account = self.app.identities_registry.from_metadata({'text': self.account.name, - 'id': self.account.pubkey}) - certifier_list = person.certifiers_of(self.community) - certified_list = person.certified_by(self.community) - - # create empty graph instance - graph = Graph(self.community) - - # add wallet node - node_status = 0 - if person.pubkey == person_account.pubkey: - node_status += NODE_STATUS_HIGHLIGHTED - if person.is_member(self.community) is False: - node_status += NODE_STATUS_OUT - node_status += NODE_STATUS_SELECTED - graph.add_person(person, node_status) - - # populate graph with certifiers-of - graph.add_certifier_list(certifier_list, person, person_account) - # populate graph with certified-by - graph.add_certified_list(certified_list, person, person_account) - - # draw graph in qt scene - self.graphicsView.scene().update_wot(graph.get()) - - # if selected member is not the account member... - if person.pubkey != person_account.pubkey: - # add path from selected member to account member - path = graph.get_shortest_path_between_members(person, person_account) - if path: - self.graphicsView.scene().update_path(path) + logging.debug("Draw graph - " + identity.uid) + + identity_account = self.account.identity(self.community) + + #Disconnect old identity + if self._current_identity != identity: + try: + if self._current_identity: + self._current_identity.inner_data_changed.disconnect(self.handle_identity_change) + except TypeError as e: + if "disconnect()" in str(e): + logging.debug("Disconnect of old identity failed.") + #Connect new identity + identity.inner_data_changed.connect(self.handle_identity_change) + + self._current_identity = identity + + # create Identity from node metadata + certifier_list = identity.certifiers_of(self.community) + certified_list = identity.certified_by(self.community) + + # create empty graph instance + graph = Graph(self.community) + + # add wallet node + node_status = 0 + if identity == identity_account: + node_status += NODE_STATUS_HIGHLIGHTED + if identity.is_member(self.community) is False: + node_status += NODE_STATUS_OUT + node_status += NODE_STATUS_SELECTED + graph.add_identity(identity, node_status) + + # populate graph with certifiers-of + graph.add_certifier_list(certifier_list, identity, identity_account) + # populate graph with certified-by + graph.add_certified_list(certified_list, identity, identity_account) + + # draw graph in qt scene + self.graphicsView.scene().update_wot(graph.get()) + + # if selected member is not the account member... + if identity.pubkey != identity_account.pubkey: + # add path from selected member to account member + path = graph.get_shortest_path_between_members(identity, identity_account) + if path: + self.graphicsView.scene().update_path(path) def reset(self): """ Reset graph scene to wallet identity """ - metadata = {'text': self.account.name, 'id': self.account.pubkey} self.draw_graph( - metadata + self.account.identity(self.community) ) def refresh(self): """ Refresh graph scene to current metadata """ - self.draw_graph(self._current_metadata) + self.draw_graph(self._current_identity) - @pyqtSlot(str) - def handle_person_change(self, pubkey): - if pubkey == self._current_metadata['id']: - self.refresh() + @pyqtSlot() + def handle_identity_change(self): + self.refresh() def search(self): """ @@ -149,20 +158,20 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): node = self.nodes[index] metadata = {'id': node['pubkey'], 'text': node['uid']} self.draw_graph( - metadata + self.app.identities_registry.from_metadata(metadata) ) def identity_informations(self, metadata): - person = self.app.identities_registry.from_metadata(metadata) - self.parent.identity_informations(person) + identity = self.app.identities_registry.from_metadata(metadata) + self.parent.identity_informations(identity) def sign_node(self, metadata): - person = self.app.identities_registry.from_metadata(metadata) - self.parent.certify_identity(person) + identity = self.app.identities_registry.from_metadata(metadata) + self.parent.certify_identity(identity) def send_money_to_node(self, metadata): - person = self.app.identities_registry.from_metadata(metadata) - self.parent.send_money_to_identity(person) + identity = self.app.identities_registry.from_metadata(metadata) + self.parent.send_money_to_identity(identity) def add_node_as_contact(self, metadata): # check if contact already exists... diff --git a/src/cutecoin/models/identities.py b/src/cutecoin/models/identities.py index 21c4642b..e30af70d 100644 --- a/src/cutecoin/models/identities.py +++ b/src/cutecoin/models/identities.py @@ -4,7 +4,7 @@ Created on 5 févr. 2014 @author: inso ''' -from ..core.registry import IdentitiesRegistry +from ..core.net.api import bma as qtbma from ..tools.exceptions import NoPeerAvailable, MembershipNotFoundError from PyQt5.QtCore import QAbstractTableModel, QSortFilterProxyModel, Qt, \ QDateTime, QModelIndex, QLocale @@ -86,6 +86,8 @@ class IdentitiesTableModel(QAbstractTableModel): 'expiration': self.tr('Expiration')} self.columns_ids = ('uid', 'pubkey', 'renewed', 'expiration') self.identities_data = [] + self._identities = [] + self._refresh_slots = [] @property def pubkeys(self): @@ -95,15 +97,9 @@ class IdentitiesTableModel(QAbstractTableModel): return [i[1] for i in self.identities_data] def identity_data(self, identity): - parameters = self.community.parameters try: - join_block = identity.membership(self.community)['blockNumber'] - try: - join_date = self.community.get_block(join_block)['medianTime'] - expiration_date = join_date + parameters['sigValidity'] - except NoPeerAvailable: - join_date = None - expiration_date = None + join_date = identity.get_join_date(self.community) + expiration_date = identity.get_expiration_date(self.community) except MembershipNotFoundError: join_date = None expiration_date = None @@ -117,24 +113,48 @@ class IdentitiesTableModel(QAbstractTableModel): :param cutecoin.core.registry.IdentitiesRegistry identities: The new identities to display """ logging.debug("Refresh {0} identities".format(len(identities))) + + # We disconnect identities from their local slots + for (index, identity) in enumerate(self._identities): + identity.inner_data_changed.disconnect(self._refresh_slots[index]) + self.identities_data = [] + self._identities = [] + self._refresh_slots = [] self.beginResetModel() for identity in identities: - identity.inner_data_changed.connect(lambda: self.refresh_identity(identity)) + logging.debug(identity) + + # Connection + refresh_slot = lambda req, identity=identity: self.refresh_identity(req, identity) + identity.inner_data_changed.connect(refresh_slot) + + self._identities.append(identity) + self._refresh_slots.append(refresh_slot) self.identities_data.append(self.identity_data(identity)) self.endResetModel() - def refresh_identity(self, identity): + def refresh_identity(self, request, identity): """ Refresh an identity when its inner_data changed :param cutecoin.core.registry.Identity identity: The refreshed identity """ + logging.debug("Refresh {0} because of {1}".format(identity, request)) try: - index = self.identities_data.index(identity) + index = self._identities.index(identity) self.identities_data[index] = self.identity_data(identity) - self.dataChanged.emit(index, index) + if request == str(qtbma.wot.Lookup): + model_index_0 = self.createIndex(index, self.columns_ids.index('uid')) + model_index_max = self.createIndex(index, self.columns_ids.index('pubkey')) + self.dataChanged.emit(model_index_0, model_index_max) + elif request in (str(qtbma.blockchain.Membership), + str(qtbma.blockchain.Block), + str(qtbma.blockchain.Parameters)): + model_index_0 = self.createIndex(index, self.columns_ids.index('renewed')) + model_index_max = self.createIndex(index, self.columns_ids.index('expiration')) + self.dataChanged.emit(model_index_0, model_index_max) except ValueError: - logging.debug("Identity {0} is not in list".format(identity)) + logging.debug("Identity {0} is not in list : {1}".format(identity, self.identities_data)) def rowCount(self, parent): return len(self.identities_data) -- GitLab