From ba75e300ac0de014c1fdbc5bcf2caad4754bb998 Mon Sep 17 00:00:00 2001 From: Rich Lott / Artful Robot Date: Wed, 9 Dec 2020 10:12:36 +0000 Subject: [PATCH] Enable tracking of urls with tokens in Flexmailer --- .../src/ClickTracker/BaseClickTracker.php | 82 +++++++++++ .../src/ClickTracker/HtmlClickTracker.php | 19 ++- .../src/ClickTracker/TextClickTracker.php | 15 +- .../Civi/FlexMailer/ClickTrackerTest.php | 139 ++++++++++++++++++ .../Civi/FlexMailer/FlexMailerSystemTest.php | 13 ++ 5 files changed, 258 insertions(+), 10 deletions(-) create mode 100644 ext/flexmailer/src/ClickTracker/BaseClickTracker.php create mode 100644 ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTrackerTest.php diff --git a/ext/flexmailer/src/ClickTracker/BaseClickTracker.php b/ext/flexmailer/src/ClickTracker/BaseClickTracker.php new file mode 100644 index 0000000000..970b52fbd0 --- /dev/null +++ b/ext/flexmailer/src/ClickTracker/BaseClickTracker.php @@ -0,0 +1,82 @@ +installMe(__DIR__) + ->apply(); + } + + public function setUp() { + // Mock the getTrackerURL call; we don't need to test creating a row in a table. + BaseClickTracker::$getTrackerURL = function($a, $b, $c) { + return 'http://example.com/extern?u=1&qid=1'; + }; + + parent::setUp(); + } + + public function tearDown() { + // Reset the class. + BaseClickTracker::$getTrackerURL = ['CRM_Mailing_BAO_TrackableURL', 'getTrackerURL']; + parent::tearDown(); + } + + /** + * Example: Test that a link without any tokens works. + */ + public function testLinkWithoutTokens() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?a=b&c=d#frag'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1', $result); + } + + /** + * Example: Test that a link with tokens in the query works. + */ + public function testLinkWithTokensInQueryWithStaticParams() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?a=b&cid={contact.id}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1&cid={contact.id}', $result); + } + + /** + * Example: Test that a link with tokens in the query works. + */ + public function testLinkWithTokensInQueryWithMultipleStaticParams() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?cs={contact.checksum}&a=b&cid={contact.id}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1&cs={contact.checksum}&cid={contact.id}', $result); + } + + /** + * Example: Test that a link with tokens in the query works. + */ + public function testLinkWithTokensInQueryWithMultipleStaticParamsHtml() { + $filter = new HtmlClickTracker(); + $msg = 'See this'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this', $result); + } + + /** + * Example: Test that a link with tokens in the query works. + */ + public function testLinkWithTokensInQueryWithoutStaticParams() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?cid={contact.id}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1&cid={contact.id}', $result); + } + + /** + * Example: Test that a link with tokens in the fragment works. + * + * Seems browsers maintain the fragment when they receive a redirect, so a + * token here might still work. + */ + public function testLinkWithTokensInFragment() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?a=b#cid={contact.id}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1#cid={contact.id}', $result); + } + + /** + * Example: Test that a link with tokens in the fragment works. + * + * Seems browsers maintain the fragment when they receive a redirect, so a + * token here might still work. + */ + public function testLinkWithTokensInQueryAndFragment() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/foo/bar?a=b&cid={contact.id}#cid={contact.id}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: http://example.com/extern?u=1&qid=1&cid={contact.id}#cid={contact.id}', $result); + } + + /** + * We can't handle tokens in the domain so it should not be tracked. + */ + public function testLinkWithTokensInDomainFails() { + $filter = new TextClickTracker(); + $msg = 'See this: https://{some.domain}.com/foo/bar'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: https://{some.domain}.com/foo/bar', $result); + } + + /** + * We can't handle tokens in the path so it should not be tracked. + */ + public function testLinkWithTokensInPathFails() { + $filter = new TextClickTracker(); + $msg = 'See this: https://example.com/{some.path}'; + $result = $filter->filterContent($msg, 1, 1); + $this->assertEquals('See this: https://example.com/{some.path}', $result); + } + +} diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php index d592787e8d..5e4504ca70 100644 --- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php +++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php @@ -110,6 +110,19 @@ class FlexMailerSystemTest extends \CRM_Mailing_BaseMailingSystemTest { parent::testUrlTracking($inputHtml, $htmlUrlRegex, $textUrlRegex, $params); } + /** + * + * This takes CiviMail's own ones, but removes one that tested for a + * non-feature (i.e. that tokenised links are not handled). + * + * @return array + */ + public function urlTrackingExamples() { + $cases = parent::urlTrackingExamples(); + unset($cases[6]); + return $cases; + } + public function testBasicHeaders() { parent::testBasicHeaders(); } -- 2.25.1