diff --git a/src/sakia/core/net/api/bma/access.py b/src/sakia/core/net/api/bma/access.py index e76f48d40b312b1e10e0911d3e8049f96834b405..ce82c2831ec4353f7367f62e5d38bcb2eac6753e 100644 --- a/src/sakia/core/net/api/bma/access.py +++ b/src/sakia/core/net/api/bma/access.py @@ -199,7 +199,7 @@ class BmaAccess(QObject): def compare_versions(node, version): if node.version and node.version != '': try: - return parse_version(node.version) > parse_version(version) + return parse_version(node.version) >= parse_version(version) except TypeError: return False else: diff --git a/src/sakia/gui/widgets/context_menu.py b/src/sakia/gui/widgets/context_menu.py index e328bf39b15036e646bfb87fe28024e705bb148e..c0d00cd0519ff8dad0ea73c477d1344d498baa0b 100644 --- a/src/sakia/gui/widgets/context_menu.py +++ b/src/sakia/gui/widgets/context_menu.py @@ -1,6 +1,8 @@ from PyQt5.QtWidgets import QMenu, QAction, QApplication, QMessageBox from PyQt5.QtCore import QObject, pyqtSignal from ucoinpy.documents import Block, Membership +import logging + from ..member import MemberDialog from ..contact import ConfigureContactDialog from ..transfer import TransferMoneyDialog @@ -8,6 +10,7 @@ from ..certification import CertificationDialog from ...tools.decorators import asyncify from ...core.transfer import Transfer, TransferState from ...core.registry import Identity +from ...tools.exceptions import MembershipNotFoundError class ContextMenu(QObject): @@ -63,8 +66,7 @@ class ContextMenu(QObject): if menu._app.preferences['expert_mode']: copy_membership = QAction(menu.qmenu.tr("Copy membership document to clipboard"), menu.qmenu.parent()) copy_membership.triggered.connect(lambda checked, i=identity: menu.copy_membership_to_clipboard(i)) - # TODO: Copy membership when written field is available - #menu.qmenu.addAction(copy_membership) + menu.qmenu.addAction(copy_membership) copy_selfcert = QAction(menu.qmenu.tr("Copy self-certification document to clipboard"), menu.qmenu.parent()) copy_selfcert.triggered.connect(lambda checked, i=identity: menu.copy_selfcert_to_clipboard(i)) @@ -192,14 +194,17 @@ QMessageBox.Ok | QMessageBox.Cancel) :return: """ clipboard = QApplication.clipboard() - membership = await identity.membership(self._community) - if membership: - block_number = membership['blockNumber'] - block = await self._community.get_block(block_number) - block_doc = Block.from_signed_raw("{0}{1}\n".format(block['raw'], block['signature'])) - for ms_doc in block_doc.joiners: - if ms_doc.issuer == identity.pubkey: - clipboard.setText(ms_doc.signed_raw()) + try: + membership = await identity.membership(self._community) + if membership: + block_number = membership['written'] + block = await self._community.get_block(block_number) + block_doc = Block.from_signed_raw("{0}{1}\n".format(block['raw'], block['signature'])) + for ms_doc in block_doc.joiners: + if ms_doc.issuer == identity.pubkey: + clipboard.setText(ms_doc.signed_raw()) + except MembershipNotFoundError: + logging.debug("Could not find membership") @asyncify async def copy_selfcert_to_clipboard(self, identity): diff --git a/src/sakia/tests/unit/gui/test_context_menu.py b/src/sakia/tests/unit/gui/test_context_menu.py index 299918431949ab12364406a421775b5fde4de434..d12a2aa223d1467acbb77dfdb872359d44563401 100644 --- a/src/sakia/tests/unit/gui/test_context_menu.py +++ b/src/sakia/tests/unit/gui/test_context_menu.py @@ -5,6 +5,8 @@ from PyQt5.QtCore import QLocale from sakia.tests import QuamashTest from sakia.tests.mocks.bma import nice_blockchain from sakia.gui.widgets.context_menu import ContextMenu +from ucoinpy.documents import Membership, BlockId +from sakia.tools.exceptions import MembershipNotFoundError class TestContextMenu(unittest.TestCase, QuamashTest): @@ -44,17 +46,20 @@ class TestContextMenu(unittest.TestCase, QuamashTest): @patch('PyQt5.QtWidgets.QMenu', create=True) def test_copy_pubkey_to_clipboard(self, qmenu): app = Mock('sakia.core.Application') + async def exec_test(): context_menu = ContextMenu(qmenu, self.app, self.account, self.community, self.password_asker) context_menu.copy_pubkey_to_clipboard(self.identity) + self.lp.run_until_complete(exec_test()) self.assertEqual(self.qapplication.clipboard().text(), "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk") @patch('PyQt5.QtWidgets.QMenu', create=True) def test_copy_block_to_clipboard(self, qmenu): self.community.get_block = CoroutineMock(side_effect=lambda n: nice_blockchain.bma_blockchain_current if n == 15 \ - else nice_blockchain.bma_blockchain_0) + else nice_blockchain.bma_blockchain_0) self.qapplication.clipboard().clear() + async def exec_test(): context_menu = ContextMenu(qmenu, self.app, self.account, self.community, self.password_asker) context_menu.community = self.community @@ -64,3 +69,72 @@ class TestContextMenu(unittest.TestCase, QuamashTest): raw_block = "{0}{1}\n".format(nice_blockchain.bma_blockchain_current["raw"], nice_blockchain.bma_blockchain_current["signature"]) self.assertEqual(self.qapplication.clipboard().text(), raw_block) + + @patch('PyQt5.QtWidgets.QMenu', create=True) + def test_copy_membership_to_clipboard(self, qmenu): + ms_data = { + "version": 1, + "currency": "meta_brouzouf", + "membership": "IN", + "blockNumber": 49116, + "blockHash": "000004CA4F77E36CE52C23A9F2A8F2A259773CE9", + "written": 49119 + } + ms_document = Membership(ms_data["version"], ms_data["currency"], self.identity.pubkey, + BlockId(ms_data["blockNumber"], ms_data["blockHash"]), + ms_data["membership"], self.identity.uid, 1421787800, + "znWiWP7Sy9gg9pZq4YWKNpel8MM16VBM1lgBg2gWjSonnc+KVRCtQng5JB4JD0PgJJ0F8jdITuggFrRwqRfzAA==") + self.identity.membership = CoroutineMock(return_value=ms_data) + self.community.get_block = CoroutineMock(return_value={ + "version": 1, + "nonce": 127424, + "number": 49119, + "powMin": 5, + "time": 1453921638, + "medianTime": 1453912797, + "membersCount": 18, + "monetaryMass": 14028534972234185000, + "currency": "meta_brouzouf", + "issuer": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", + "signature": "ZmjhoRubftJ/T2WYQ3gaDeTGGUJ3beUshtlWn1k/r5opk0vt48KG3w+9JU0T9YFR5uezllaek9efoNwAHRBLDw==", + "hash": "0000075129361571E74380B686DE6E1E29FF8400", + "parameters": "", + "previousHash": "000005C27A1636FE07AB01766FBA060565142D79", + "previousIssuer": "HBSSmqZjT4UQKsCntTSmZbu7iRP14HYtifLE6mW1PsBD", + "dividend": None, + "identities": [], + "joiners": [ + "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:znWiWP7Sy9gg9pZq4YWKNpel8MM16VBM1lgBg2gWjSonnc+KVRCtQng5JB4JD0PgJJ0F8jdITuggFrRwqRfzAA==:49116:000004CA4F77E36CE52C23A9F2A8F2A259773CE9:1421787800:inso" + ], + "actives": [], + "leavers": [], + "excluded": [], + "certifications": [], + "transactions": [], + "raw": "Version: 1\nType: Block\nCurrency: meta_brouzouf\nNonce: 127424\nNumber: 49119\nPoWMin: 5\nTime: 1453921638\nMedianTime: 1453912797\nIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk\nPreviousHash: 000005C27A1636FE07AB01766FBA060565142D79\nPreviousIssuer: HBSSmqZjT4UQKsCntTSmZbu7iRP14HYtifLE6mW1PsBD\nMembersCount: 18\nIdentities:\nJoiners:\nHnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:znWiWP7Sy9gg9pZq4YWKNpel8MM16VBM1lgBg2gWjSonnc+KVRCtQng5JB4JD0PgJJ0F8jdITuggFrRwqRfzAA==:49116:000004CA4F77E36CE52C23A9F2A8F2A259773CE9:1421787800:A\nActives:\nLeavers:\nExcluded:\nCertifications:\nTransactions:\n" +}) + self.qapplication.clipboard().clear() + + async def exec_test(): + context_menu = ContextMenu(qmenu, self.app, self.account, self.community, self.password_asker) + context_menu.community = self.community + context_menu.copy_membership_to_clipboard(self.identity) + + self.lp.run_until_complete(exec_test()) + self.assertEqual(self.qapplication.clipboard().text(), ms_document.signed_raw()) + + @patch('PyQt5.QtWidgets.QMenu', create=True) + def test_copy_membership_to_clipboard_not_found(self, qmenu): + def raiser(): + raise MembershipNotFoundError("inso", "meta_brouzouf") + self.identity.membership = CoroutineMock(side_effect=lambda c: raiser()) + + self.qapplication.clipboard().clear() + + async def exec_test(): + context_menu = ContextMenu(qmenu, self.app, self.account, self.community, self.password_asker) + context_menu.community = self.community + context_menu.copy_membership_to_clipboard(self.identity) + + self.lp.run_until_complete(exec_test()) + self.assertEqual(self.qapplication.clipboard().text(), "")