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