diff --git a/src/_cutecoin_test/models/account/test_wallets.py b/src/_cutecoin_test/models/account/test_wallets.py index 89df2a85d541a9fad5aaab6afbec85c84e605abc..af74ff052cb2f4e25465979143b7887b2006c6cd 100644 --- a/src/_cutecoin_test/models/account/test_wallets.py +++ b/src/_cutecoin_test/models/account/test_wallets.py @@ -49,8 +49,8 @@ class Test_Wallets: mock_wallet2 = Mock(spec=Wallet, community=mock2) mock_wallet3 = Mock(spec=Wallet, community=mock3) wallets = Wallets() - wallets.wallets_list.append(mock_wallet1) - wallets.wallets_list.append(mock_wallet2) + wallets._wallets_list.append(mock_wallet1) + wallets._wallets_list.append(mock_wallet2) assert wallets.get_wallet(mock_wallet1) is not None assert wallets.get_wallet(mock_wallet2) is not None @@ -62,8 +62,8 @@ class Test_Wallets: mock_wallet1 = Mock(spec=Wallet, community=mock1) mock_wallet2 = Mock(spec=Wallet, community=mock2) wallets = Wallets() - wallets.wallets_list.append(mock_wallet1) - wallets.wallets_list.append(mock_wallet2) + wallets._wallets_list.append(mock_wallet1) + wallets._wallets_list.append(mock_wallet2) wallets.remove_all_wallets_of(mock1) assert wallets.get_wallet(mock_wallet1) is None diff --git a/src/cutecoin/gui/communityTabWidget.py b/src/cutecoin/gui/communityTabWidget.py index f9365ccbc5e8a836e1cb4ac7169b4cfe776a7cc7..35e81dcf3476b1a685c96485671cfc7ce4be2c38 100644 --- a/src/cutecoin/gui/communityTabWidget.py +++ b/src/cutecoin/gui/communityTabWidget.py @@ -24,4 +24,5 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): self.setupUi(self) self.community = community self.account = account - self.list_community_members.setModel(MembersListModel(community)) + wallets = account.wallets.community_wallets(community.currency) + self.list_community_members.setModel(MembersListModel(community, wallets)) diff --git a/src/cutecoin/gui/mainWindow.py b/src/cutecoin/gui/mainWindow.py index f6adbe6feebc82276706bfbf2274602bf7bbf174..f97d676c72f155a29a7a2ab682a618dc8f0103ae 100644 --- a/src/cutecoin/gui/mainWindow.py +++ b/src/cutecoin/gui/mainWindow.py @@ -108,8 +108,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): def refresh_wallet_content(self, index): if index.isValid(): - current_wallet = self.core.current_account.wallets.wallets_list[ - index.row()] + current_wallet = self.core.current_account.wallets[index.row()] self.list_wallet_content.setModel(WalletListModel(current_wallet)) else: self.list_wallet_content.setModel(WalletListModel([])) diff --git a/src/cutecoin/gui/processConfigureAccount.py b/src/cutecoin/gui/processConfigureAccount.py index 3a8fd2e8c76149cd6e83ac5f101d49ac016b05f6..e8c7bc0bffd7a4ada35d5ffff7fade697c49822f 100644 --- a/src/cutecoin/gui/processConfigureAccount.py +++ b/src/cutecoin/gui/processConfigureAccount.py @@ -8,7 +8,8 @@ from cutecoin.gui.processConfigureCommunity import ProcessConfigureCommunity from cutecoin.models.account.communities.listModel import CommunitiesListModel from cutecoin.tools.exceptions import KeyAlreadyUsed from cutecoin.models.account import Account -from cutecoin.models.account import Communities +from cutecoin.models.account.communities import Communities +from cutecoin.models.account.wallets import Wallets from cutecoin.models.node import Node from PyQt5.QtWidgets import QDialog, QErrorMessage, QInputDialog @@ -104,7 +105,8 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): self.account = Account.create( available_keys[0]['keyid'], "", - Communities()) + Communities(), + Wallets()) self.combo_keys_list.currentIndexChanged[ int].connect(self.key_changed) @@ -157,7 +159,7 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): self.stacked_pages.setCurrentIndex(next_index) self.step.display_page() else: - self.accepted.emit() + self.accept() def previous(self): if self.step.previous_step is not None: @@ -173,4 +175,5 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): self.core.add_account(self.account) except KeyAlreadyUsed as e: QErrorMessage(self).showMessage(e.message) + self.accepted.emit() self.close() diff --git a/src/cutecoin/gui/processConfigureCommunity.py b/src/cutecoin/gui/processConfigureCommunity.py index 89df0821bf9f2af6c185c99315f39e1113f7e2c1..0778af06d28203cd8b924dd7093f87cbb2d53bf5 100644 --- a/src/cutecoin/gui/processConfigureCommunity.py +++ b/src/cutecoin/gui/processConfigureCommunity.py @@ -6,8 +6,8 @@ Created on 8 mars 2014 import ucoin from cutecoin.gen_resources.communityConfigurationDialog_uic import Ui_CommunityConfigurationDialog from PyQt5.QtWidgets import QDialog, QMenu, QMessageBox -from cutecoin.models.community.treeModel import CommunityTreeModel -from cutecoin.models.community.trustsTreeModel import CommunityTrustsTreeModel +from cutecoin.models.node.treeModel import NodesTreeModel +from cutecoin.models.wallet.trustsTreeModel import TrustsTreeModel from cutecoin.models.node import Node from cutecoin.gui.walletTabWidget import WalletTabWidget @@ -45,11 +45,8 @@ class StepPageInit(Step): port = self.config_dialog.spinbox_port.value() default_node = Node(server, port, trust=True, hoster=True) account = self.config_dialog.account - self.config_dialog.community = account.communities.add_community( - default_node) - #TODO: Get existing Wallet from ucoin node - account.wallets.add_wallet(account.fingerprint, - self.config_dialog.community) + self.config_dialog.community = account.add_community(default_node) + self.config_dialog.nodes.append(default_node) def display_page(self): self.config_dialog.button_previous.setEnabled(False) @@ -70,7 +67,8 @@ class StepPageAddNodes(Step): pass def display_page(self): - tree_model = CommunityTreeModel(self.config_dialog.community) + tree_model = NodesTreeModel(self.config_dialog.nodes, + self.config_dialog.community.name()) self.config_dialog.tree_nodes.setModel(tree_model) self.config_dialog.button_previous.setEnabled(False) self.config_dialog.button_next.setText("Next") @@ -89,14 +87,14 @@ class StepPageSetWallets(Step): def display_page(self): self.config_dialog.tabs_wallets.clear() - for wallet in self.config_dialog.account.wallets.wallets_list: + for wallet in self.config_dialog.account.wallets: wallet_tab = WalletTabWidget(self.config_dialog.account, self.config_dialog.community) self.config_dialog.tabs_wallets.addTab(wallet_tab, wallet.name) + tree_model = TrustsTreeModel(wallet, + self.config_dialog.community.name()) + wallet_tab.trusts_tree_view.setModel(tree_model) - tree_model = CommunityTrustsTreeModel(self.config_dialog.community) - current_tab = self.config_dialog.tabs_wallets.currentWidget() - current_tab.trusts_tree_view.setModel(tree_model) self.config_dialog.button_previous.setEnabled(True) self.config_dialog.button_next.setText("Ok") @@ -105,7 +103,6 @@ class StepPageSetWallets(Step): class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): - ''' Dialog to configure or add a community ''' @@ -119,6 +116,7 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): self.community = community self.account = account self.step = None + self.nodes = [] step_init = StepPageInit(self) step_add_nodes = StepPageAddNodes(self) @@ -160,16 +158,18 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): ''' Add node slot ''' - server = self.edit_server.text() - port = self.box_port.value() + server = self.lineedit_server.text() + port = self.spinbox_port.value() if self.community is not None: - self.community.nodes.append(Node(server, port, trust=True)) - self.tree_nodes.setModel(CommunityTreeModel(self.community)) + self.nodes.append(Node(server, port, trust=True)) + self.tree_nodes.setModel(NodesTreeModel(self.community, + self.nodes)) def showContextMenu(self, point): - menu = QMenu() - action = menu.addAction("Delete", self.removeNode) - if self.community is not None: - if len(self.community.nodes) == 1: - action.setEnabled(False) - menu.exec_(self.tree_nodes.mapToGlobal(point)) + if self.stacked_pages.currentIndex() == 1: + menu = QMenu() + action = menu.addAction("Delete", self.removeNode) + if self.community is not None: + if len(self.nodes) == 1: + action.setEnabled(False) + menu.exec_(self.mapToGlobal(point)) diff --git a/src/cutecoin/gui/transferMoneyDialog.py b/src/cutecoin/gui/transferMoneyDialog.py index f7cf0542e421374c43d5e345aa46453fc20cb218..444da4d6f743ecca654a7eeb8206eff282422062 100644 --- a/src/cutecoin/gui/transferMoneyDialog.py +++ b/src/cutecoin/gui/transferMoneyDialog.py @@ -30,13 +30,13 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): super(TransferMoneyDialog, self).__init__() self.setupUi(self) self.sender = sender - for wallet in sender.wallets.wallets_list: + for wallet in sender.wallets: self.combo_wallets.addItem(wallet.getText()) for contact in sender.contacts: self.combo_contact.addItem(contact.name) - self.refresh_transaction(sender.wallets.wallets_list[0]) + self.refresh_transaction(sender.wallets[0]) def remove_coins_from_transfer(self): selection = self.list_coins_sent.selectedIndexes() @@ -93,7 +93,7 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): QErrorMessage(self).showMessage("Cannot transfer coins.") def change_displayed_wallet(self, index): - wallet = self.sender.wallets.wallets_list[index] + wallet = self.sender.wallets[index] self.refresh_transaction(wallet) def refresh_transaction(self, wallet): diff --git a/src/cutecoin/models/account/__init__.py b/src/cutecoin/models/account/__init__.py index 60ccc0dbf19ead1542c3185770ee76bd291e79ce..079fa39f49d6198e1d8023eb4e0eda7de0f3ffef 100644 --- a/src/cutecoin/models/account/__init__.py +++ b/src/cutecoin/models/account/__init__.py @@ -35,15 +35,11 @@ class Account(object): self.contacts = contacts @classmethod - def create(cls, keyid, name, communities): + def create(cls, keyid, name, communities, wallets): ''' Constructor ''' - wallets = Wallets() account = cls(keyid, name, communities, wallets, []) - for community in account.communities.communities_list: - wallet = account.wallets.add_wallet(community) - wallet.refresh_coins(account.fingerprint()) return account @classmethod @@ -76,6 +72,17 @@ class Account(object): def add_contact(self, person): self.contacts.append(person) + def add_community(self, default_node): + promoted = ucoin.hdc.amendments.Promoted() + default_node.use(promoted) + amendment_data = promoted.get() + currency = amendment_data['currency'] + community = self.communities.add_community(currency) + self.wallets.add_wallet(self.fingerprint(), + currency, + default_node) + return community + def fingerprint(self): gpg = gnupg.GPG() available_keys = gpg.list_keys() @@ -86,37 +93,6 @@ class Account(object): return k['fingerprint'] return "" - def transactions_received(self): - received = [] - for community in self.communities.communities_list: - transactions_data = community.network.request( - ucoin.hdc.transactions.Recipient( - self.fingerprint())) - for trx_data in transactions_data: - received.append( - Transaction.create( - trx_data['value']['transaction']['sender'], - trx_data['value']['transaction']['number'], - community)) - return received - - def transactions_sent(self): - sent = [] - for community in self.communities.communities_list: - transactions_data = community.network.request( - ucoin.hdc.transactions.sender.Last( - self.fingerprint(), - 20)) - for trx_data in transactions_data: - # Small bug in ucoinpy library - if not isinstance(trx_data, str): - sent.append( - Transaction.create( - trx_data['value']['transaction']['sender'], - trx_data['value']['transaction']['number'], - community)) - return sent - def transfer_coins(self, node, recipient, coins, message): transfer = ucoin.wrappers.transactions.RawTransfer( self.fingerprint(), @@ -128,9 +104,24 @@ class Account(object): port=node.port) return transfer() + def transactions_received(self): + received = [] + for w in self.wallets: + for r in w.transactions_received(): + received.append(r) + return received + + def transactions_sent(self): + sent = [] + for w in self.wallets: + for t in w.transactions_sent(): + sent.append(t) + return sent + def quality(self, community): if community in self.communities.communities_list: - return community.person_quality(self.fingerprint()) + wallets = self.wallets.community_wallets(community.currency) + return community.person_quality(wallets, self.fingerprint()) else: raise CommunityNotFoundError(self.keyid, community.amendment_id()) diff --git a/src/cutecoin/models/account/communities/__init__.py b/src/cutecoin/models/account/communities/__init__.py index 829ea4df1547629f0c978d1db1b4e7219bbbf5da..13995afeb75888a4ebcca1eca2b7e270eb8d19ab 100644 --- a/src/cutecoin/models/account/communities/__init__.py +++ b/src/cutecoin/models/account/communities/__init__.py @@ -20,11 +20,11 @@ class Communities(object): ''' self.communities_list = [] - def add_community(self, main_node): + def add_community(self, wallets): ''' Add a community with a mainNode ''' - community = Community.create(main_node) + community = Community.create(wallets) if community not in self.communities_list: self.communities_list.append(community) return community diff --git a/src/cutecoin/models/account/wallets/__init__.py b/src/cutecoin/models/account/wallets/__init__.py index 2b4164006c360fd83065423b5f3c1ffcac06a7e9..bb6eb10910913eb104197e3b90ec3205c96834b2 100644 --- a/src/cutecoin/models/account/wallets/__init__.py +++ b/src/cutecoin/models/account/wallets/__init__.py @@ -4,6 +4,7 @@ Created on 7 févr. 2014 @author: inso ''' +import logging from cutecoin.models.wallet import Wallet @@ -13,46 +14,66 @@ class Wallets(object): The list of the wallets owned by an account. ''' - def __init__(self): + def __init__(self, _wallets_list=[]): ''' Constructor ''' - self.wallets_list = [] + self._wallets_list = _wallets_list - def add_wallet(self, fingerprint, community, name="Main Wallet"): + def __iter__(self): + return self._wallets_list.__iter__() + + def __contains__(self, wallet): + return wallet in self._wallets_list + + def __reverse__(self): + return self._wallets_list.__reverse__() + + def __len__(self): + return len(self._wallets_list) + + def __getitem__(self, key): + return self._wallets_list[key] + + def add_wallet(self, fingerprint, community, node, name="Main Wallet"): ''' Create a new wallet of a specific currency. This wallet must not already be present in the account, it means the wallet must have a different name or a different currency. ''' - wallet = Wallet.create(fingerprint, community, name) - if wallet not in self.wallets_list: - self.wallets_list.append(wallet) + wallet = Wallet.create(fingerprint, community, node, name) + if wallet not in self._wallets_list: + self._wallets_list.append(wallet) return wallet else: - return self.wallets_list.get(wallet) + return self._wallets_list.get(wallet) - def get_wallet(self, wallet): - ''' - Look for a wallet in the wallets list. - ''' - for w in self.wallets_list: - if w == wallet: - return w - return None - - def remove_all_wallets_of(self, community): - for wallet in self.wallets_list: - if wallet.community == community: - self.wallets_list.remove(wallet) + def community_wallets(self, currency): + return Wallets([w for w in self._wallets_list if w.currency == currency]) def jsonify(self, community): ''' Return the list of wallets in a key:value form. ''' community_wallets = [ - w for w in self.wallets_list if w.community == community] + w for w in self._wallets_list if w.community == community] data = [] for wallet in community_wallets: data.append(wallet.jsonify()) return data + + def request(self, request, get_args={}): + for wallet in self._wallets_list: + try: + response = wallet.request(request, get_args) + except: + pass + return response + + def post(self, request, get_args={}): + for wallet in self._wallets_list: + try: + response = wallet.post(request, get_args) + except: + pass + return response diff --git a/src/cutecoin/models/account/wallets/listModel.py b/src/cutecoin/models/account/wallets/listModel.py index e7e779ae7ba5b28449f0cdb4a5286353a24b4c79..8bae73860245f5c5a927dfa48895f0f7d2924da9 100644 --- a/src/cutecoin/models/account/wallets/listModel.py +++ b/src/cutecoin/models/account/wallets/listModel.py @@ -21,12 +21,12 @@ class WalletsListModel(QAbstractListModel): self.wallets = account.wallets def rowCount(self, parent): - return len(self.wallets.wallets_list) + return len(self.wallets) def data(self, index, role): if role == Qt.DisplayRole: row = index.row() - value = self.wallets.wallets_list[row].getText() + value = self.wallets[row].get_text() return value def flags(self, index): diff --git a/src/cutecoin/models/community/__init__.py b/src/cutecoin/models/community/__init__.py index 83a2d88b6b59413bc99accdbde53618ef41721ce..eea03aa10e26450f4c66eb28a934128bcf27f1f8 100644 --- a/src/cutecoin/models/community/__init__.py +++ b/src/cutecoin/models/community/__init__.py @@ -9,78 +9,58 @@ import hashlib import json import logging from cutecoin.models.node import Node -from cutecoin.models.wallet import Wallet -from cutecoin.models.community.network import CommunityNetwork +from cutecoin.models.account.wallets import Wallets class Community(object): - ''' classdocs ''' - - def __init__(self, network): + def __init__(self, currency): ''' A community is a group of nodes using the same currency. They are all using the same amendment and are syncing their datas. An account is a member of a community if he is a member of the current amendment. ''' - self.network = network - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) - self.currency = current_amendment['currency'] + self.currency = currency @classmethod - def create(cls, main_node): - nodes = [] - nodes.append(main_node) - return cls(CommunityNetwork(nodes)) + def create(cls, currency): + return cls(currency) @classmethod - def load(cls, json_data, account): - known_nodes = [] - for node_data in json_data['nodes']: - known_nodes.append( - Node( - node_data['server'], - node_data['port'], - node_data['trust'], - node_data['hoster'])) - - community = cls(CommunityNetwork(known_nodes)) - - for wallets_data in json_data['wallets']: - wallet = Wallet.load(wallets_data, community) - wallet.refreshCoins(account.fingerprint()) - account.wallets.wallets_list.append(wallet) + def load(cls, json_data): + currency = json_data['currency'] + community = cls(currency) return community def name(self): return self.currency def __eq__(self, other): - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) - current_amendment_hash = hashlib.sha1( - current_amendment['raw'].encode('utf-8')).hexdigest().upper() + #current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) + #current_amendment_hash = hashlib.sha1( + # current_amendment['raw'].encode('utf-8')).hexdigest().upper() - other_amendment = other.network.request(ucoin.hdc.amendments.Promoted()) - other_amendment_hash = hashlib.sha1( - other_amendment['raw'].encode('utf-8')).hexdigest().upper() + #other_amendment = other.network.request(ucoin.hdc.amendments.Promoted()) + #other_amendment_hash = hashlib.sha1( + # other_amendment['raw'].encode('utf-8')).hexdigest().upper() - return (other_amendment_hash == current_amendment_hash) + return (other.currency == self.currency) - def dividend(self): - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) + def dividend(self, wallets): + current_amendment = wallets.request(ucoin.hdc.amendments.Promoted()) return int(current_amendment['dividend']) - def coin_minimal_power(self): - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) + def coin_minimal_power(self, wallets): + current_amendment = wallets.request(ucoin.hdc.amendments.Promoted()) if 'coinMinimalPower' in current_amendment.keys(): return int(current_amendment['coinMinimalPower']) else: return 0 - def amendment_id(self): - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) + def amendment_id(self, wallets): + current_amendment = wallets.request(ucoin.hdc.amendments.Promoted()) current_amendment_hash = hashlib.sha1( current_amendment['raw'].encode('utf-8')).hexdigest().upper() amendment_id = str( @@ -88,50 +68,41 @@ class Community(object): logging.debug("Amendment : " + amendment_id) return amendment_id - def amendment_number(self): - current_amendment = self.network.request(ucoin.hdc.amendments.Promoted()) + def amendment_number(self, wallets): + current_amendment = wallets.request(ucoin.hdc.amendments.Promoted()) return int(current_amendment['number']) - def person_quality(self, fingerprint): - if (fingerprint in self.voters_fingerprints()): + def person_quality(self, wallets, fingerprint): + if (fingerprint in self.voters_fingerprints(wallets)): return "voter" - elif (fingerprint in self.members_fingerprints()): + elif (fingerprint in self.members_fingerprints(wallets)): return "member" else: return "nothing" - def members_fingerprints(self): + def members_fingerprints(self, wallets): ''' Listing members of a community ''' - fingerprints = self.network.request( - ucoin.registry.community.Members( - amendment_id=self.amendment_id())) + memberships = wallets.request( + ucoin.registry.community.Members()) members = [] - for f in fingerprints: - members.append(f['value']) + print(memberships) + for m in memberships: + members.append(m['membership']['issuer']) return members - def voters_fingerprints(self): + def voters_fingerprints(self, wallets): ''' Listing members of a community ''' - fingerprints = self.network.request( - ucoin.registry.community.Voters( - amendment_id=self.amendment_id())) + votings = wallets.request( + ucoin.registry.community.Voters()) voters = [] - for f in fingerprints: - voters.append(f['value']) + for v in votings: + voters.append(v['voting']['issuer']) return voters - def jsonify_nodes_list(self): - data = [] - for node in self.network.nodes: - data.append(node.jsonify()) - return data - - def jsonify(self, wallets): - data = {'nodes': self.jsonify_nodes_list(), - 'currency': self.currency, - 'wallets': wallets.jsonify(self)} + def jsonify(self): + data = {'currency': self.currency} return data diff --git a/src/cutecoin/models/community/membersListModel.py b/src/cutecoin/models/community/membersListModel.py index 71b8766121f25b844b9ffae69a5863ccd5ec189b..723f44fde9fcbff3d09dbc55402032fd1ddb054a 100644 --- a/src/cutecoin/models/community/membersListModel.py +++ b/src/cutecoin/models/community/membersListModel.py @@ -14,12 +14,12 @@ class MembersListModel(QAbstractListModel): A Qt abstract item model to display communities in a tree ''' - def __init__(self, community, parent=None): + def __init__(self, community, wallets, parent=None): ''' Constructor ''' super(MembersListModel, self).__init__(parent) - fingerprints = community.members_fingerprints() + fingerprints = community.members_fingerprints(wallets) self.members = [] for f in fingerprints: self.members.append(Person.lookup(f, community)) diff --git a/src/cutecoin/models/community/network.py b/src/cutecoin/models/community/network.py deleted file mode 100644 index a2e87e22e669c016ad6f8b2c613370c599f3c859..0000000000000000000000000000000000000000 --- a/src/cutecoin/models/community/network.py +++ /dev/null @@ -1,98 +0,0 @@ -''' -Created on 27 mars 2014 - -@author: inso -''' -from cutecoin.models.node import Node -import ucoin -import logging - -class CommunityNetwork(object): - ''' - classdocs - ''' - - #TODO: Factory to load json - def __init__(self, nodes): - ''' - Constructor - ''' - self.nodes = nodes - - def request(self, request, get_args={}): - for node in self.trusts(): - logging.debug("Trying to connect to : " + node.get_text()) - node.use(request) - return request.get(**get_args) - raise RuntimeError("Cannot connect to any node") - - def post(self, request, get_args={}): - for node in self.hosters(): - logging.debug("Trying to connect to : " + node.get_text()) - node.use(request) - return request.post(**get_args) - raise RuntimeError("Cannot connect to any node") - - # TODO: Check if its working - def _search_node_by_fingerprint(self, node_fg, next_node, traversed_nodes=[]): - next_fg = next_node.peering()['fingerprint'] - if next_fg not in traversed_nodes: - traversed_nodes.append(next_fg) - if node_fg == next_fg: - return next_node - else: - for peer in next_node.peers(): - # Look for next node informations - found = self._searchTrustAddresses( - node_fg, Node( - peer['ipv4'], int( - peer['port'])), traversed_nodes) - if found is not None: - return found - return None - - def get_nodes_in_peering(self, fingerprints): - nodes = [] - for node_fg in fingerprints: - nodes.append( - self._search_node_by_fingerprint( - node_fg, - self.trusts()[0])) - return nodes - - def trusts(self): - return [node for node in self.nodes if node.trust] - - def hosters(self): - return [node for node in self.nodes if node.hoster] - -#TODO: Manager in Wallets -""" - def pull_tht(self, fingerprint): - tht = self.network.request(ucoin.ucg.THT(fingerprint)) - nodes = [] - nodes.append(self.trusts()[0]) - # We add trusts to the node list - for node_fg in tht['trusts']: - nodes.append( - self._search_node_by_fingerprint( - node_fg, - self.trusts()[0])) - # We look in hosters lists - for node_fg in tht['hosters']: - # If the node was already added as a trust - if node_fg in tht['trusts']: - found_nodes = [ - node for node in nodes if node.peering()['fingerprint'] == node_fg] - if len(found_nodes) == 1: - found_nodes[0].hoster = True - else: - # not supposed to happen - pass - # Else we add it - else: - nodes.append( - self._search_node_by_fingerprint( - node_fg, - self.trusts()[0])) -""" diff --git a/src/cutecoin/models/node/itemModel.py b/src/cutecoin/models/node/itemModel.py index b55f309cba8ae340e98ad7577add4fd2a0990390..5ace48c70883185f2ae35ef9ab3c9be8cc6c2e24 100644 --- a/src/cutecoin/models/node/itemModel.py +++ b/src/cutecoin/models/node/itemModel.py @@ -4,12 +4,45 @@ Created on 5 févr. 2014 @author: inso ''' +import logging + + +class RootItem(object): + + def __init__(self, name): + self.name = name + self.main_node_items = [] + + def appendChild(self, item): + self.main_node_items.append(item) + + def child(self, row): + return self.main_node_items[row] + + def childCount(self): + return len(self.main_node_items) + + def columnCount(self): + return 1 + + def data(self, column): + try: + return self.name + except IndexError: + return None + + def parent(self): + return None + + def row(self): + return 0 + class NodeItem(object): - def __init__(self, main_node, community_item=None): - self.community_item = community_item + def __init__(self, main_node, root_item): self.main_node_text = main_node.get_text() + self.root_item = root_item self.trust = main_node.trust self.hoster = main_node.hoster self.node_items = [] @@ -33,10 +66,9 @@ class NodeItem(object): return None def parent(self): - return self.community_item + return self.root_item def row(self): - if self.community_item: - return self.community_item.main_node_items.index(self) - + if self.root_item: + return self.root_item.main_node_items.index(self) return 0 diff --git a/src/cutecoin/models/community/treeModel.py b/src/cutecoin/models/node/treeModel.py similarity index 87% rename from src/cutecoin/models/community/treeModel.py rename to src/cutecoin/models/node/treeModel.py index 81c5ec791c8c61c5b4f6a5b2b259be13dbc880c9..c157b1af4508aa31e65f757238b717e7b35fa341 100644 --- a/src/cutecoin/models/community/treeModel.py +++ b/src/cutecoin/models/node/treeModel.py @@ -5,24 +5,23 @@ Created on 5 févr. 2014 ''' from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt -from cutecoin.models.node.itemModel import NodeItem -from cutecoin.models.community.itemModel import CommunityItemModel +from cutecoin.models.node.itemModel import NodeItem, RootItem import logging -class CommunityTreeModel(QAbstractItemModel): +class NodesTreeModel(QAbstractItemModel): ''' A Qt abstract item model to display nodes of a community ''' - def __init__(self, community): + def __init__(self, nodes, community_name): ''' Constructor ''' - super(CommunityTreeModel, self).__init__(None) - self.community = community - self.root_item = CommunityItemModel(self.community) + super(NodesTreeModel, self).__init__(None) + self.nodes = nodes + self.root_item = RootItem(community_name) self.refresh_tree_nodes() def columnCount(self, parent): @@ -95,7 +94,7 @@ class CommunityTreeModel(QAbstractItemModel): def refresh_tree_nodes(self): logging.debug("root : " + self.root_item.data(0)) - for node in self.community.network.nodes: + for node in self.nodes: node_item = NodeItem(node, self.root_item) logging.debug( "mainNode : " + diff --git a/src/cutecoin/models/person/__init__.py b/src/cutecoin/models/person/__init__.py index 720e6b553b4ed9d7cc0e431e8941aefe81000fd7..a9c65aaec3cb897d1298570ed19ae0d56e389899 100644 --- a/src/cutecoin/models/person/__init__.py +++ b/src/cutecoin/models/person/__init__.py @@ -24,11 +24,11 @@ class Person(object): self.email = email @classmethod - def lookup(cls, fingerprint, community): + def lookup(cls, fingerprint, wallet): ''' Create a person from the fngerprint found in a community ''' - keys = community.network.request( + keys = wallet.request( ucoin.pks.Lookup(), get_args={ 'search': "0x" + @@ -41,7 +41,7 @@ class Person(object): email = json['email'] return cls(name, fingerprint, email) else: - raise PersonNotFoundError(fingerprint, "fingerprint", community) + raise PersonNotFoundError(fingerprint, "fingerprint", wallet) return None @classmethod diff --git a/src/cutecoin/models/transaction/__init__.py b/src/cutecoin/models/transaction/__init__.py index 60b369f8d4cdb6e9b55576ca5885d0394750a1db..16f5dc7e597cfe4b6c3e5d8e2d79e1c7f42a92fa 100644 --- a/src/cutecoin/models/transaction/__init__.py +++ b/src/cutecoin/models/transaction/__init__.py @@ -16,28 +16,28 @@ class Transaction(object): At the moment the difference is not made ''' - def __init__(self, sender, tx_number, community, recipient): + def __init__(self, sender, tx_number, wallet, recipient): self.tx_number = tx_number - self.community = community + self.wallet = wallet self.sender = sender self.recipient = recipient @classmethod - def create(cls, pgp_fingerprint, tx_number, community): - transaction_view = community.network.request( + def create(cls, pgp_fingerprint, tx_number, wallet): + transaction_view = wallet.request( ucoin.hdc.transactions.sender.View(pgp_fingerprint, tx_number)) transaction_data = transaction_view['transaction'] - sender = Person.lookup(pgp_fingerprint, community) + sender = Person.lookup(pgp_fingerprint, wallet) recipient = Person.lookup( transaction_data['recipient'], - community) + wallet) - return cls(Transaction(sender, tx_number, community, recipient)) + return cls(Transaction(sender, tx_number, wallet, recipient)) def value(self): value = 0 - trx_data = self.community.network.request( + trx_data = self.wallet.request( ucoin.hdc.transactions.sender.View(self.sender.fingerprint, self.tx_number)) for coin in trx_data['transaction']['coins']: @@ -45,7 +45,7 @@ class Transaction(object): return value def currency(self): - trx_data = self.community.network.request( + trx_data = self.wallet.request( ucoin.hdc.transactions.sender.View(self.sender.fingerprint, self.tx_number)) currency = trx_data['transaction']['currency'] diff --git a/src/cutecoin/models/transaction/receivedListModel.py b/src/cutecoin/models/transaction/receivedListModel.py index a40d3acdfe9f9715a99d6298b616ca5b87a66623..9bbe63445e4726e57d58a4d8e3fab81fd307d0ef 100644 --- a/src/cutecoin/models/transaction/receivedListModel.py +++ b/src/cutecoin/models/transaction/receivedListModel.py @@ -29,7 +29,7 @@ class ReceivedListModel(QAbstractListModel): if role == Qt.DisplayRole: row = index.row() - value = self.transactions[row].getText() + value = self.transactions[row].get_text() return value def flags(self, index): diff --git a/src/cutecoin/models/wallet/__init__.py b/src/cutecoin/models/wallet/__init__.py index 2d918c765e3af2468ec4e833527c419e083f3dc8..fb979ca1435563a58054dcf4f2dd0a3b46f5a4b8 100644 --- a/src/cutecoin/models/wallet/__init__.py +++ b/src/cutecoin/models/wallet/__init__.py @@ -9,6 +9,8 @@ import logging import gnupg import json from cutecoin.models.coin import Coin +from cutecoin.models.node import Node +from cutecoin.models.transaction import Transaction from cutecoin.tools.exceptions import CommunityNotFoundError @@ -19,25 +21,31 @@ class Wallet(object): It's only used to sort coins. ''' - def __init__(self, fingerprint, coins, community, name): + def __init__(self, fingerprint, coins, currency, nodes, name): ''' Constructor ''' self.coins = coins self.fingerprint = fingerprint - self.community = community + self.currency = currency self.name = name + self.nodes = nodes @classmethod - def create(cls, fingerprint, community, name): - return cls(fingerprint, [], community, name) + def create(cls, fingerprint, currency, node, name): + node.trust = True + node.hoster = True + return cls(fingerprint, [], currency, [node], name) @classmethod - def load(cls, json_data, community): + def load(cls, json_data): coins = [] for coinData in json_data['coins']: coins.append(Coin.from_id(coinData['coin'])) - return cls(coins, community) + fingerprint = json_data['fingerprint'] + name = json_data['name'] + currency = json_data['currency'] + return cls(fingerprint, coins, currency, name) def __eq__(self, other): return (self.community == other.community) @@ -48,71 +56,123 @@ class Wallet(object): value += coin.value() return value - # TODO: Refresh coins when changing current account - def refresh_coins(self): - data_list = self.community.network.request( - ucoin.hdc.coins.List({'pgp_fingerprint': self.fingerprint})) - for issuances in data_list['coins']: - issuer = issuances['issuer'] - for coins_ids in issuances['ids']: - shortened_id = coins_ids - coin = Coin.from_id(issuer + "-" + shortened_id) - self.coins.append(coin) - - - #TODO: Adapt to new WHT - def tht(self, community): - if community in self.communities.communities_list: - #tht = community.ucoinRequest(ucoin.wallets.tht(self.fingerprint())) - #return tht['entries'] + def transactions_received(self): + received = [] + transactions_data = self.request( + ucoin.hdc.transactions.Recipient(self.fingerprint)) + for trx_data in transactions_data: + received.append( + Transaction.create( + trx_data['value']['transaction']['sender'], + trx_data['value']['transaction']['number'], + self)) + return received + + def transactions_sent(self): + sent = [] + transactions_data = self.request( + ucoin.hdc.transactions.sender.Last( + self.fingerprint, 20)) + for trx_data in transactions_data: + # Small bug in ucoinpy library + if not isinstance(trx_data, str): + sent.append( + Transaction.create( + trx_data['value']['transaction']['sender'], + trx_data['value']['transaction']['number'], + self)) + return sent + + def pull_wht(self): + try: + wht = self.request(ucoin.network.Wallet(self.fingerprint())) + return wht['entries'] + except ValueError: return None + + def push_wht(self, community): + hosters_fg = [] + trusts_fg = [] + for trust in self.trusts(): + peering = trust.peering() + logging.debug(peering) + trusts_fg.append(peering['fingerprint']) + for hoster in self.hosters(): + logging.debug(peering) + peering = hoster.peering() + hosters_fg.append(peering['fingerprint']) + entry = { + 'version': '1', + 'currency': self.currency, + 'issuer': self.fingerprint(), + 'requiredTrusts': self.required_trusts, + 'hosters': hosters_fg, + 'trusts': trusts_fg + } + logging.debug(entry) + json_entry = json.JSONEncoder(indent=2).encode(entry) + gpg = gnupg.GPG() + signature = gpg.sign(json_entry, keyid=self.keyid, clearsign=True) + + dataPost = { + 'entry': entry, + 'signature': str(signature) + } + + self.post(ucoin.network.Wallet( + pgp_fingerprint=self.fingerprint()), + dataPost) + + # TODO: Check if its working + def _search_node_by_fingerprint(self, node_fg, next_node, traversed_nodes=[]): + next_fg = next_node.peering()['fingerprint'] + if next_fg not in traversed_nodes: + traversed_nodes.append(next_fg) + if node_fg == next_fg: + return next_node + else: + for peer in next_node.peers(): + # Look for next node informations + found = self._search_node_by_fingerprint( + node_fg, Node( + peer['ipv4'], int( + peer['port'])), traversed_nodes) + if found is not None: + return found return None - def push_tht(self, community): - if community in self.communities.communities_list: - hosters_fg = [] - trusts_fg = [] - for trust in community.network.trusts(): - peering = trust.peering() - logging.debug(peering) - trusts_fg.append(peering['fingerprint']) - for hoster in community.network.hosters(): - logging.debug(peering) - peering = hoster.peering() - hosters_fg.append(peering['fingerprint']) - entry = { - 'version': '1', - 'currency': community.currency, - 'fingerprint': self.fingerprint(), - 'hosters': hosters_fg, - 'trusts': trusts_fg - } - logging.debug(entry) - json_entry = json.JSONEncoder(indent=2).encode(entry) - gpg = gnupg.GPG() - signature = gpg.sign(json_entry, keyid=self.keyid, clearsign=True) - - dataPost = { - 'entry': entry, - 'signature': str(signature) - } - - #community.network.post( - # ucoin.ucg.THT( - # pgp_fingerprint=self.fingerprint()), - # dataPost) - else: - raise CommunityNotFoundError(self.keyid, community.amendment_id()) - - def pull_tht(self, community): - if community in self.communities.communities_list: - community.pull_tht(self.fingerprint()) - else: - raise CommunityNotFoundError(self.keyid, community.amendment_id()) + def get_nodes_in_peering(self, fingerprints): + nodes = [] + for node_fg in fingerprints: + nodes.append( + self._search_node_by_fingerprint( + node_fg, + self.trusts()[0])) + return nodes + + def request(self, request, get_args={}): + for node in self.trusts(): + logging.debug("Trying to connect to : " + node.get_text()) + node.use(request) + return request.get(**get_args) + raise RuntimeError("Cannot connect to any node") + + def post(self, request, get_args={}): + for node in self.hosters(): + logging.debug("Trying to connect to : " + node.get_text()) + node.use(request) + return request.post(**get_args) + raise RuntimeError("Cannot connect to any node") + + def trusts(self): + return [node for node in self.nodes if node.trust] + + def hosters(self): + return [node for node in self.nodes if node.hoster] def get_text(self): return self.name + " : " + \ - str(self.value()) + " " + self.community.currency + str(self.value()) + " " + self.currency def jsonify_coins_list(self): data = [] @@ -121,5 +181,8 @@ class Wallet(object): return data def jsonify(self): + #TODO: Jsonify nodes return {'coins': self.jsonify_coins_list(), - 'name': self.name} + 'fingerprint': self.fingerprint, + 'name': self.name, + 'currency': self.currency} diff --git a/src/cutecoin/models/community/trustsTreeModel.py b/src/cutecoin/models/wallet/trustsTreeModel.py similarity index 90% rename from src/cutecoin/models/community/trustsTreeModel.py rename to src/cutecoin/models/wallet/trustsTreeModel.py index 314a9d09c49c1117c16585c322effbb3394c9041..a47571ac9c6d02d06900a67639e9fbe409f32603 100644 --- a/src/cutecoin/models/community/trustsTreeModel.py +++ b/src/cutecoin/models/wallet/trustsTreeModel.py @@ -5,24 +5,23 @@ Created on 5 févr. 2014 ''' from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt -from cutecoin.models.node.itemModel import NodeItem -from cutecoin.models.community.itemModel import CommunityItemModel +from cutecoin.models.node.itemModel import NodeItem, RootItem import logging -class CommunityTrustsTreeModel(QAbstractItemModel): +class TrustsTreeModel(QAbstractItemModel): ''' A Qt abstract item model to display nodes of a community ''' - def __init__(self, community): + def __init__(self, wallet, community_name): ''' Constructor ''' - super(CommunityTrustsTreeModel, self).__init__(None) - self.community = community - self.root_item = CommunityItemModel(self.community) + super(TrustsTreeModel, self).__init__(None) + self.wallet = wallet + self.root_item = RootItem(community_name) self.refresh_tree_nodes() def columnCount(self, parent): @@ -116,7 +115,7 @@ class CommunityTrustsTreeModel(QAbstractItemModel): def refresh_tree_nodes(self): logging.debug("root : " + self.root_item.data(0)) - for node in self.community.network.nodes: + for node in self.wallet.nodes: node_item = NodeItem(node, self.root_item) logging.debug( "mainNode : " + diff --git a/src/cutecoin/tools/exceptions.py b/src/cutecoin/tools/exceptions.py index 5de93dba1b5e59613f95e0b17fea217eb2a41d8f..eaca9d739c2232e442f6a50d39f33faeb08d77a9 100644 --- a/src/cutecoin/tools/exceptions.py +++ b/src/cutecoin/tools/exceptions.py @@ -46,8 +46,7 @@ class PersonNotFoundError(Error): class_type + " in " + type + - " not present in community " + - community.name) + " not found ") class CommunityNotFoundError(Error): @@ -68,7 +67,8 @@ class CommunityNotFoundError(Error): class KeyAlreadyUsed(Error): ''' - Exception raised trying to add an account using a key already used for another account. + Exception raised trying to add an account using + a key already used for another account. ''' def __init__(self, new_account, keyid, found_account):