From 7fe0787007c18f34b2030edc1dcbaffca79f196e Mon Sep 17 00:00:00 2001
From: vtexier <vit@free.fr>
Date: Tue, 24 Mar 2020 12:22:52 +0100
Subject: [PATCH] [enh] #798 add all sources without filtering complex
 condition

---
 src/sakia/services/sources.py       | 86 +++++++++++++++++------------
 tests/unit/services/test_sources.py | 64 +++++++++++++++++++++
 2 files changed, 115 insertions(+), 35 deletions(-)
 create mode 100644 tests/unit/services/test_sources.py

diff --git a/src/sakia/services/sources.py b/src/sakia/services/sources.py
index 9c6b47ae..7c8be058 100644
--- a/src/sakia/services/sources.py
+++ b/src/sakia/services/sources.py
@@ -1,6 +1,7 @@
 from PyQt5.QtCore import QObject
 from duniterpy.api import bma, errors
 from duniterpy.documents import Transaction as TransactionDoc
+from duniterpy.grammars import output
 from duniterpy.grammars.output import Condition
 from duniterpy.documents import BlockUID
 import logging
@@ -106,25 +107,10 @@ class SourcesServices(QObject):
             self.currency, bma.tx.sources, req_args={"pubkey": pubkey}
         )
         nb_sources = len(sources_data["sources"])
-        for i, s in enumerate(sources_data["sources"]):
-            log_stream("Parsing source ud/tx {:}/{:}".format(i, nb_sources))
+        for index, source in enumerate(sources_data["sources"]):
+            log_stream("Parsing source ud/tx {:}/{:}".format(index, nb_sources))
             progress(1 / nb_sources)
-            conditions = pypeg2.parse(s["conditions"], Condition)
-            if conditions.left.pubkey == pubkey:
-                try:
-                    if conditions.left.pubkey == pubkey:
-                        source = Source(
-                            currency=self.currency,
-                            pubkey=pubkey,
-                            identifier=s["identifier"],
-                            type=s["type"],
-                            noffset=s["noffset"],
-                            amount=s["amount"],
-                            base=s["base"],
-                        )
-                        self._sources_processor.insert(source)
-                except AttributeError as e:
-                    self._logger.error(str(e))
+            self.add_source(pubkey, source)
 
     async def check_destruction(self, pubkey, block_number, unit_base):
         amount = self._sources_processor.amount(self.currency, pubkey)
@@ -177,23 +163,8 @@ class SourcesServices(QObject):
             self.currency, bma.tx.sources, req_args={"pubkey": pubkey}
         )
         self._sources_processor.drop_all_of(self.currency, pubkey)
-        for i, s in enumerate(sources_data["sources"]):
-            conditions = pypeg2.parse(s["conditions"], Condition)
-            if conditions.left.pubkey == pubkey:
-                try:
-                    if conditions.left.pubkey == pubkey:
-                        source = Source(
-                            currency=self.currency,
-                            pubkey=pubkey,
-                            identifier=s["identifier"],
-                            type=s["type"],
-                            noffset=s["noffset"],
-                            amount=s["amount"],
-                            base=s["base"],
-                        )
-                        self._sources_processor.insert(source)
-                except AttributeError as e:
-                    self._logger.error(str(e))
+        for source in sources_data["sources"]:
+            self.add_source(pubkey, source)
 
     async def refresh_sources(self, connections):
         """
@@ -241,3 +212,48 @@ class SourcesServices(QObject):
             )
             if source.pubkey == pubkey:
                 self._sources_processor.insert(source)
+
+    def find_signature_in_condition(self, _condition, pubkey, result=False):
+        """
+        Recursive function to find a SIG(pubkey) in a Condition object
+
+        :param output.Condition _condition: Condition instance
+        :param str pubkey: Pubkey to find
+        :param bool result: True if found
+        :return:
+        """
+        if isinstance(_condition.left, output.Condition):
+            result |= self.find_signature_in_condition(_condition.left, pubkey, result)
+        if isinstance(_condition.right, output.Condition):
+            result |= self.find_signature_in_condition(_condition.right, pubkey, result)
+        if (
+            isinstance(_condition.left, output.SIG)
+            and _condition.left.pubkey == pubkey
+            or isinstance(_condition.right, output.SIG)
+            and _condition.right.pubkey == pubkey
+        ):
+            result |= True
+        return result
+
+    def add_source(self, pubkey, source):
+        """
+        Add a new source for the pubkey
+
+        :param str pubkey: Pubkey concerned
+        :param dict source: Source dict from api
+        :return:
+        """
+        try:
+            entity = Source(
+                currency=self.currency,
+                pubkey=pubkey,
+                identifier=source["identifier"],
+                type=source["type"],
+                noffset=source["noffset"],
+                amount=source["amount"],
+                base=source["base"],
+                conditions=source["conditions"],
+            )
+            self._sources_processor.insert(entity)
+        except AttributeError as e:
+            self._logger.error(str(e))
diff --git a/tests/unit/services/test_sources.py b/tests/unit/services/test_sources.py
new file mode 100644
index 00000000..3d62b9d6
--- /dev/null
+++ b/tests/unit/services/test_sources.py
@@ -0,0 +1,64 @@
+import pytest
+from duniterpy.documents.transaction import output
+
+
+def test_parse_source_condition(application_with_one_connection, alice, bob):
+    application_with_one_connection.instanciate_services()
+
+    issuer = alice.key.pubkey
+    receiver = bob.key.pubkey
+    condition = output.Condition.token(
+        output.SIG.token(receiver),
+        output.Operator.token("||"),
+        output.Condition.token(
+            output.SIG.token(issuer),
+            output.Operator.token("&&"),
+            output.CSV.token(604800),
+        ),
+    )
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, receiver
+        )
+        is True
+    )
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, issuer
+        )
+        is True
+    )
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, "badpubkey"
+        )
+        is False
+    )
+    condition = output.Condition.token(
+        output.Condition.token(
+            output.CSV.token(604800),
+            output.Operator.token("&&"),
+            output.SIG.token(issuer),
+        ),
+        output.Operator.token("||"),
+        output.SIG.token(receiver),
+    )
+
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, receiver
+        )
+        is True
+    )
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, issuer
+        )
+        is True
+    )
+    assert (
+        application_with_one_connection.sources_service.find_signature_in_condition(
+            condition, "badpubkey"
+        )
+        is False
+    )
-- 
GitLab