]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Add new Helper to process Ignore Origin rules and RulerZ operator
authorKevin Decherf <kevin@kdecherf.com>
Sun, 11 Aug 2019 21:51:55 +0000 (23:51 +0200)
committerKevin Decherf <kevin@kdecherf.com>
Sat, 25 Apr 2020 13:59:23 +0000 (15:59 +0200)
This commits adds a new helper like RuleBasedTagger for processing
ignore origin rules. It also adds a new custom RulerZ operator for the
'~' pattern matching rule.

Renames 'pattern' with '_all' in IgnoreOriginRule entity.

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
src/Wallabag/CoreBundle/Entity/IgnoreOriginInstanceRule.php
src/Wallabag/CoreBundle/Entity/IgnoreOriginUserRule.php
src/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessor.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Operator/PHP/PatternMatches.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/config/services.yml
tests/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessorTest.php [new file with mode: 0644]

index 34aed50c69dec09531fc2747f790ba97f074f77c..ce3b6e7d752e5806d6a2a58fc6bf6822633a5f85 100644 (file)
@@ -11,7 +11,6 @@ use Symfony\Component\Validator\Constraints as Assert;
  *
  * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\IgnoreOriginInstanceRuleRepository")
  * @ORM\Table(name="`ignore_origin_instance_rule`")
- * @ORM\Entity
  */
 class IgnoreOriginInstanceRule implements IgnoreOriginRuleInterface, RuleInterface
 {
@@ -30,7 +29,7 @@ class IgnoreOriginInstanceRule implements IgnoreOriginRuleInterface, RuleInterfa
      * @Assert\NotBlank()
      * @Assert\Length(max=255)
      * @RulerZAssert\ValidRule(
-     *  allowed_variables={"host","pattern"},
+     *  allowed_variables={"host","_all"},
      *  allowed_operators={"=","~"}
      * )
      * @ORM\Column(name="rule", type="string", nullable=false)
index befd609055199efad3ffb21b4c91e5bf2b8e864a..0b6f318dc920230e942f1a1a3e5cf9804869227b 100644 (file)
@@ -11,7 +11,6 @@ use Symfony\Component\Validator\Constraints as Assert;
  *
  * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\IgnoreOriginUserRuleRepository")
  * @ORM\Table(name="`ignore_origin_user_rule`")
- * @ORM\Entity
  */
 class IgnoreOriginUserRule implements IgnoreOriginRuleInterface, RuleInterface
 {
@@ -30,7 +29,7 @@ class IgnoreOriginUserRule implements IgnoreOriginRuleInterface, RuleInterface
      * @Assert\NotBlank()
      * @Assert\Length(max=255)
      * @RulerZAssert\ValidRule(
-     *  allowed_variables={"host","pattern"},
+     *  allowed_variables={"host","_all"},
      *  allowed_operators={"=","~"}
      * )
      * @ORM\Column(name="rule", type="string", nullable=false)
diff --git a/src/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessor.php b/src/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessor.php
new file mode 100644 (file)
index 0000000..333e5b0
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+namespace Wallabag\CoreBundle\Helper;
+
+use Psr\Log\LoggerInterface;
+use RulerZ\RulerZ;
+use Wallabag\CoreBundle\Entity\Entry;
+use Wallabag\CoreBundle\Repository\IgnoreOriginInstanceRuleRepository;
+
+class RuleBasedIgnoreOriginProcessor
+{
+    protected $rulerz;
+    protected $logger;
+    protected $ignoreOriginInstanceRuleRepository;
+
+    public function __construct(RulerZ $rulerz, LoggerInterface $logger, IgnoreOriginInstanceRuleRepository $ignoreOriginInstanceRuleRepository)
+    {
+        $this->rulerz = $rulerz;
+        $this->logger = $logger;
+        $this->ignoreOriginInstanceRuleRepository = $ignoreOriginInstanceRuleRepository;
+    }
+
+    /**
+     * @param Entry $entry Entry to process
+     *
+     * @return bool
+     */
+    public function process(Entry $entry)
+    {
+        $url = $entry->getUrl();
+        $userRules = $entry->getUser()->getConfig()->getIgnoreOriginRules()->toArray();
+        $rules = array_merge($this->ignoreOriginInstanceRuleRepository->findAll(), $userRules);
+
+        $parsed_url = parse_url($url);
+        // We add the former url as a new key _all for pattern matching
+        $parsed_url['_all'] = $url;
+
+        foreach ($rules as $rule) {
+            if ($this->rulerz->satisfies($parsed_url, $rule->getRule())) {
+                $this->logger->info('Origin url matching ignore rule.', [
+                    'rule' => $rule->getRule(),
+                ]);
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Operator/PHP/PatternMatches.php b/src/Wallabag/CoreBundle/Operator/PHP/PatternMatches.php
new file mode 100644 (file)
index 0000000..532e2bb
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+namespace Wallabag\CoreBundle\Operator\PHP;
+
+/**
+ * Provides a "~" operator used for ignore origin rules.
+ *
+ * It asserts that a subject matches a given regexp pattern, in a
+ * case-insensitive way.
+ *
+ * This operator will be used to compile ignore origin rules in PHP, usable
+ * directly on Entry objects for instance.
+ * It's registered in RulerZ using a service (wallabag.operator.array.pattern_matches);
+ */
+class PatternMatches
+{
+    public function __invoke($subject, $pattern)
+    {
+        $count = preg_match("`$pattern`i", $subject);
+
+        return \is_int($count) && $count > 0;
+    }
+}
index 4ece046a8e262879c8d89fd7daf15e1f68ee2ea8..8417ac35c959ffb506bcd44767a6820155ffcb79 100644 (file)
@@ -92,6 +92,7 @@ services:
         arguments:
             - "@wallabag_core.graby"
             - "@wallabag_core.rule_based_tagger"
+            - "@wallabag_core.rule_based_ignore_origin_processor"
             - "@validator"
             - "@logger"
             - '%wallabag_core.fetching_error_message%'
@@ -110,6 +111,13 @@ services:
             - "@wallabag_core.entry_repository"
             - "@logger"
 
+    wallabag_core.rule_based_ignore_origin_processor:
+        class: Wallabag\CoreBundle\Helper\RuleBasedIgnoreOriginProcessor
+        arguments:
+            - "@rulerz"
+            - "@logger"
+            - "@wallabag_core.ignore_origin_instance_rule_repository"
+
     # repository as a service
     wallabag_core.entry_repository:
         class: Wallabag\CoreBundle\Repository\EntryRepository
@@ -164,6 +172,11 @@ services:
         tags:
             - { name: rulerz.operator, target: doctrine, operator: notmatches, inline: true }
 
+    wallabag.operator.array.pattern_matches:
+        class: Wallabag\CoreBundle\Operator\PHP\PatternMatches
+        tags:
+            - { name: rulerz.operator, target: native, operator: "~" }
+
     wallabag_core.helper.redirect:
         class: Wallabag\CoreBundle\Helper\Redirect
         arguments:
diff --git a/tests/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessorTest.php b/tests/Wallabag/CoreBundle/Helper/RuleBasedIgnoreOriginProcessorTest.php
new file mode 100644 (file)
index 0000000..9e39bc8
--- /dev/null
@@ -0,0 +1,212 @@
+<?php
+
+namespace Tests\Wallabag\CoreBundle\Helper;
+
+use Monolog\Handler\TestHandler;
+use Monolog\Logger;
+use PHPUnit\Framework\TestCase;
+use Wallabag\CoreBundle\Entity\Config;
+use Wallabag\CoreBundle\Entity\Entry;
+use Wallabag\CoreBundle\Entity\IgnoreOriginInstanceRule;
+use Wallabag\CoreBundle\Entity\IgnoreOriginUserRule;
+use Wallabag\CoreBundle\Helper\RuleBasedIgnoreOriginProcessor;
+use Wallabag\UserBundle\Entity\User;
+
+class RuleBasedIgnoreOriginProcessorTest extends TestCase
+{
+    private $rulerz;
+    private $processor;
+    private $ignoreOriginInstanceRuleRepository;
+    private $logger;
+    private $handler;
+
+    public function setUp()
+    {
+        $this->rulerz = $this->getRulerZMock();
+        $this->logger = $this->getLogger();
+        $this->ignoreOriginInstanceRuleRepository = $this->getIgnoreOriginInstanceRuleRepositoryMock();
+        $this->handler = new TestHandler();
+        $this->logger->pushHandler($this->handler);
+
+        $this->processor = new RuleBasedIgnoreOriginProcessor($this->rulerz, $this->logger, $this->ignoreOriginInstanceRuleRepository);
+    }
+
+    public function testProcessWithNoRule()
+    {
+        $user = $this->getUser();
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([]);
+
+        $this->rulerz
+            ->expects($this->never())
+            ->method('satisfies');
+
+        $result = $this->processor->process($entry);
+
+        $this->assertFalse($result);
+    }
+
+    public function testProcessWithNoMatchingRule()
+    {
+        $userRule = $this->getIgnoreOriginUserRule('rule as string');
+        $user = $this->getUser([$userRule]);
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([]);
+
+        $this->rulerz
+            ->expects($this->once())
+            ->method('satisfies')
+            ->willReturn(false);
+
+        $result = $this->processor->process($entry);
+
+        $this->assertFalse($result);
+    }
+
+    public function testProcessWithAMatchingRule()
+    {
+        $userRule = $this->getIgnoreOriginUserRule('rule as string');
+        $user = $this->getUser([$userRule]);
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([]);
+
+        $this->rulerz
+            ->expects($this->once())
+            ->method('satisfies')
+            ->willReturn(true);
+
+        $result = $this->processor->process($entry);
+
+        $this->assertTrue($result);
+    }
+
+    public function testProcessWithAMixOfMatchingRules()
+    {
+        $userRule = $this->getIgnoreOriginUserRule('rule as string');
+        $anotherUserRule = $this->getIgnoreOriginUserRule('another rule as string');
+        $user = $this->getUser([$userRule, $anotherUserRule]);
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([]);
+
+        $this->rulerz
+            ->method('satisfies')
+            ->will($this->onConsecutiveCalls(false, true));
+
+        $result = $this->processor->process($entry);
+
+        $this->assertTrue($result);
+    }
+
+    public function testProcessWithInstanceRules()
+    {
+        $user = $this->getUser();
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $instanceRule = $this->getIgnoreOriginInstanceRule('rule as string');
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([$instanceRule]);
+
+        $this->rulerz
+            ->expects($this->once())
+            ->method('satisfies')
+            ->willReturn(true);
+
+        $result = $this->processor->process($entry);
+
+        $this->assertTrue($result);
+    }
+
+    public function testProcessWithMixedRules()
+    {
+        $userRule = $this->getIgnoreOriginUserRule('rule as string');
+        $user = $this->getUser([$userRule]);
+        $entry = new Entry($user);
+        $entry->setUrl('http://example.com/hello-world');
+
+        $instanceRule = $this->getIgnoreOriginInstanceRule('rule as string');
+        $this->ignoreOriginInstanceRuleRepository
+            ->expects($this->once())
+            ->method('findAll')
+            ->willReturn([$instanceRule]);
+
+        $this->rulerz
+            ->method('satisfies')
+            ->will($this->onConsecutiveCalls(false, true));
+
+        $result = $this->processor->process($entry);
+
+        $this->assertTrue($result);
+    }
+
+    private function getUser(array $ignoreOriginRules = [])
+    {
+        $user = new User();
+        $config = new Config($user);
+
+        $user->setConfig($config);
+
+        foreach ($ignoreOriginRules as $rule) {
+            $config->addIgnoreOriginRule($rule);
+        }
+
+        return $user;
+    }
+
+    private function getIgnoreOriginUserRule($rule)
+    {
+        $ignoreOriginUserRule = new IgnoreOriginUserRule();
+        $ignoreOriginUserRule->setRule($rule);
+
+        return $ignoreOriginUserRule;
+    }
+
+    private function getIgnoreOriginInstanceRule($rule)
+    {
+        $ignoreOriginInstanceRule = new IgnoreOriginInstanceRule();
+        $ignoreOriginInstanceRule->setRule($rule);
+
+        return $ignoreOriginInstanceRule;
+    }
+
+    private function getRulerZMock()
+    {
+        return $this->getMockBuilder('RulerZ\RulerZ')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getIgnoreOriginInstanceRuleRepositoryMock()
+    {
+        return $this->getMockBuilder('Wallabag\CoreBundle\Repository\IgnoreOriginInstanceRuleRepository')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getLogger()
+    {
+        return new Logger('foo');
+    }
+}