Add updating last engagement within clicks tracking
[MAILPOET-3762]
This commit is contained in:
committed by
Veljko V
parent
ed8de3eb17
commit
9c3fc95a6d
@@ -13,6 +13,7 @@ use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
|||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
use MailPoet\Statistics\StatisticsClicksRepository;
|
use MailPoet\Statistics\StatisticsClicksRepository;
|
||||||
use MailPoet\Statistics\UserAgentsRepository;
|
use MailPoet\Statistics\UserAgentsRepository;
|
||||||
|
use MailPoet\Subscribers\SubscribersRepository;
|
||||||
use MailPoet\Util\Cookies;
|
use MailPoet\Util\Cookies;
|
||||||
use MailPoet\WP\Functions as WPFunctions;
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
@@ -45,6 +46,9 @@ class Clicks {
|
|||||||
/** @var UserAgentsRepository */
|
/** @var UserAgentsRepository */
|
||||||
private $userAgentsRepository;
|
private $userAgentsRepository;
|
||||||
|
|
||||||
|
/** @var SubscribersRepository */
|
||||||
|
private $subscribersRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
SettingsController $settingsController,
|
SettingsController $settingsController,
|
||||||
Cookies $cookies,
|
Cookies $cookies,
|
||||||
@@ -52,7 +56,8 @@ class Clicks {
|
|||||||
Opens $opens,
|
Opens $opens,
|
||||||
StatisticsClicksRepository $statisticsClicksRepository,
|
StatisticsClicksRepository $statisticsClicksRepository,
|
||||||
UserAgentsRepository $userAgentsRepository,
|
UserAgentsRepository $userAgentsRepository,
|
||||||
LinkShortcodeCategory $linkShortcodeCategory
|
LinkShortcodeCategory $linkShortcodeCategory,
|
||||||
|
SubscribersRepository $subscribersRepository
|
||||||
) {
|
) {
|
||||||
$this->settingsController = $settingsController;
|
$this->settingsController = $settingsController;
|
||||||
$this->cookies = $cookies;
|
$this->cookies = $cookies;
|
||||||
@@ -61,6 +66,7 @@ class Clicks {
|
|||||||
$this->opens = $opens;
|
$this->opens = $opens;
|
||||||
$this->statisticsClicksRepository = $statisticsClicksRepository;
|
$this->statisticsClicksRepository = $statisticsClicksRepository;
|
||||||
$this->userAgentsRepository = $userAgentsRepository;
|
$this->userAgentsRepository = $userAgentsRepository;
|
||||||
|
$this->subscribersRepository = $subscribersRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,6 +108,8 @@ class Clicks {
|
|||||||
$this->sendAbandonedCartCookie($subscriber);
|
$this->sendAbandonedCartCookie($subscriber);
|
||||||
// track open event
|
// track open event
|
||||||
$this->opens->track($data, $displayImage = false);
|
$this->opens->track($data, $displayImage = false);
|
||||||
|
// Update engagement date
|
||||||
|
$this->subscribersRepository->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
|
||||||
}
|
}
|
||||||
$url = $this->processUrl($link->getUrl(), $newsletter, $subscriber, $queue, $wpUserPreview);
|
$url = $this->processUrl($link->getUrl(), $newsletter, $subscriber, $queue, $wpUserPreview);
|
||||||
$this->redirectToUrl($url);
|
$this->redirectToUrl($url);
|
||||||
|
@@ -10,7 +10,6 @@ use MailPoet\Entities\UserAgentEntity;
|
|||||||
use MailPoet\Statistics\StatisticsOpensRepository;
|
use MailPoet\Statistics\StatisticsOpensRepository;
|
||||||
use MailPoet\Statistics\UserAgentsRepository;
|
use MailPoet\Statistics\UserAgentsRepository;
|
||||||
use MailPoet\Subscribers\SubscribersRepository;
|
use MailPoet\Subscribers\SubscribersRepository;
|
||||||
use MailPoetVendor\Carbon\Carbon;
|
|
||||||
|
|
||||||
class Opens {
|
class Opens {
|
||||||
/** @var StatisticsOpensRepository */
|
/** @var StatisticsOpensRepository */
|
||||||
@@ -63,7 +62,7 @@ class Opens {
|
|||||||
$this->statisticsOpensRepository->flush();
|
$this->statisticsOpensRepository->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
|
$this->subscribersRepository->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
|
||||||
return $this->returnResponse($displayImage);
|
return $this->returnResponse($displayImage);
|
||||||
}
|
}
|
||||||
$statistics = new StatisticsOpenEntity($newsletter, $queue, $subscriber);
|
$statistics = new StatisticsOpenEntity($newsletter, $queue, $subscriber);
|
||||||
@@ -74,21 +73,12 @@ class Opens {
|
|||||||
}
|
}
|
||||||
$this->statisticsOpensRepository->persist($statistics);
|
$this->statisticsOpensRepository->persist($statistics);
|
||||||
$this->statisticsOpensRepository->flush();
|
$this->statisticsOpensRepository->flush();
|
||||||
$this->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
|
$this->subscribersRepository->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
|
||||||
$this->statisticsOpensRepository->recalculateSubscriberScore($subscriber);
|
$this->statisticsOpensRepository->recalculateSubscriberScore($subscriber);
|
||||||
}
|
}
|
||||||
return $this->returnResponse($displayImage);
|
return $this->returnResponse($displayImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function maybeUpdateLastEngagement(SubscriberEntity $subscriberEntity, ?UserAgentEntity $userAgent): void {
|
|
||||||
if ($userAgent instanceof UserAgentEntity && $userAgent->getUserAgentType() === UserAgentEntity::USER_AGENT_TYPE_MACHINE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Update last engagement for human (and also unknown) user agent
|
|
||||||
$subscriberEntity->setLastEngagementAt(Carbon::now());
|
|
||||||
$this->subscribersRepository->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function returnResponse($displayImage) {
|
public function returnResponse($displayImage) {
|
||||||
if (!$displayImage) return;
|
if (!$displayImage) return;
|
||||||
// return 1x1 pixel transparent gif image
|
// return 1x1 pixel transparent gif image
|
||||||
|
@@ -7,6 +7,7 @@ use MailPoet\Entities\SegmentEntity;
|
|||||||
use MailPoet\Entities\SubscriberCustomFieldEntity;
|
use MailPoet\Entities\SubscriberCustomFieldEntity;
|
||||||
use MailPoet\Entities\SubscriberEntity;
|
use MailPoet\Entities\SubscriberEntity;
|
||||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||||
|
use MailPoet\Entities\UserAgentEntity;
|
||||||
use MailPoet\WP\Functions as WPFunctions;
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
use MailPoetVendor\Carbon\Carbon;
|
use MailPoetVendor\Carbon\Carbon;
|
||||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||||
@@ -306,4 +307,13 @@ class SubscribersRepository extends Repository {
|
|||||||
->setMaxResults($limit)
|
->setMaxResults($limit)
|
||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function maybeUpdateLastEngagement(SubscriberEntity $subscriberEntity, ?UserAgentEntity $userAgent): void {
|
||||||
|
if ($userAgent instanceof UserAgentEntity && $userAgent->getUserAgentType() === UserAgentEntity::USER_AGENT_TYPE_MACHINE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Update last engagement for human (and also unknown) user agent
|
||||||
|
$subscriberEntity->setLastEngagementAt(Carbon::now());
|
||||||
|
$this->flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,19 +23,31 @@ use MailPoet\Statistics\Track\Clicks;
|
|||||||
use MailPoet\Statistics\Track\Opens;
|
use MailPoet\Statistics\Track\Opens;
|
||||||
use MailPoet\Statistics\UserAgentsRepository;
|
use MailPoet\Statistics\UserAgentsRepository;
|
||||||
use MailPoet\Subscribers\LinkTokens;
|
use MailPoet\Subscribers\LinkTokens;
|
||||||
|
use MailPoet\Subscribers\SubscribersRepository;
|
||||||
use MailPoet\Tasks\Sending as SendingTask;
|
use MailPoet\Tasks\Sending as SendingTask;
|
||||||
use MailPoet\Util\Cookies;
|
use MailPoet\Util\Cookies;
|
||||||
|
use MailPoetVendor\Carbon\Carbon;
|
||||||
|
|
||||||
class ClicksTest extends \MailPoetTest {
|
class ClicksTest extends \MailPoetTest {
|
||||||
|
/** @var \stdClass */
|
||||||
public $trackData;
|
public $trackData;
|
||||||
|
|
||||||
|
/** @var NewsletterLinkEntity */
|
||||||
public $link;
|
public $link;
|
||||||
|
|
||||||
|
/** @var SendingQueueEntity */
|
||||||
public $queue;
|
public $queue;
|
||||||
|
|
||||||
|
/** @var SubscriberEntity */
|
||||||
public $subscriber;
|
public $subscriber;
|
||||||
|
|
||||||
|
/** @var NewsletterEntity */
|
||||||
public $newsletter;
|
public $newsletter;
|
||||||
|
|
||||||
/** @var Clicks */
|
/** @var Clicks */
|
||||||
private $clicks;
|
private $clicks;
|
||||||
|
|
||||||
|
/** @var SettingsController */
|
||||||
private $settingsController;
|
private $settingsController;
|
||||||
|
|
||||||
public function _before() {
|
public function _before() {
|
||||||
@@ -94,7 +106,8 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(Opens::class),
|
$this->diContainer->get(Opens::class),
|
||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class)
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +121,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'abort' => Expected::exactly(2),
|
'abort' => Expected::exactly(2),
|
||||||
], $this);
|
], $this);
|
||||||
@@ -132,6 +146,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -150,6 +165,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -170,6 +186,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -192,6 +209,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -218,6 +236,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -258,6 +277,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -298,6 +318,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -331,6 +352,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$clicksRepository,
|
$clicksRepository,
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -366,6 +388,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => Expected::exactly(1),
|
'redirectToUrl' => Expected::exactly(1),
|
||||||
], $this);
|
], $this);
|
||||||
@@ -381,6 +404,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'redirectToUrl' => null,
|
'redirectToUrl' => null,
|
||||||
], $this);
|
], $this);
|
||||||
@@ -410,6 +434,7 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
$this->diContainer->get(StatisticsClicksRepository::class),
|
$this->diContainer->get(StatisticsClicksRepository::class),
|
||||||
$this->diContainer->get(UserAgentsRepository::class),
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
$this->diContainer->get(LinkShortcodeCategory::class),
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
], [
|
], [
|
||||||
'abort' => Expected::exactly(1),
|
'abort' => Expected::exactly(1),
|
||||||
], $this);
|
], $this);
|
||||||
@@ -456,6 +481,70 @@ class ClicksTest extends \MailPoetTest {
|
|||||||
expect($link)->equals('http://example.com/?email=test@example.com&newsletter_subject=Subject');
|
expect($link)->equals('http://example.com/?email=test@example.com&newsletter_subject=Subject');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItUpdatesSubscriberEngagementForHumanAgent() {
|
||||||
|
Carbon::setTestNow($now = Carbon::now());
|
||||||
|
$clicksRepository = $this->diContainer->get(StatisticsClicksRepository::class);
|
||||||
|
$data = $this->trackData;
|
||||||
|
$data->userAgent = 'User Agent';
|
||||||
|
$clicks = Stub::construct($this->clicks, [
|
||||||
|
$this->settingsController,
|
||||||
|
new Cookies(),
|
||||||
|
$this->diContainer->get(Shortcodes::class),
|
||||||
|
$this->diContainer->get(Opens::class),
|
||||||
|
$clicksRepository,
|
||||||
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
|
], [
|
||||||
|
'redirectToUrl' => null,
|
||||||
|
], $this);
|
||||||
|
$clicks->track($data);
|
||||||
|
expect($this->subscriber->getLastEngagementAt())->equals($now);
|
||||||
|
Carbon::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItUpdatesSubscriberEngagementForUnknownAgent() {
|
||||||
|
Carbon::setTestNow($now = Carbon::now());
|
||||||
|
$clicksRepository = $this->diContainer->get(StatisticsClicksRepository::class);
|
||||||
|
$data = $this->trackData;
|
||||||
|
$data->userAgent = null;
|
||||||
|
$clicks = Stub::construct($this->clicks, [
|
||||||
|
$this->settingsController,
|
||||||
|
new Cookies(),
|
||||||
|
$this->diContainer->get(Shortcodes::class),
|
||||||
|
$this->diContainer->get(Opens::class),
|
||||||
|
$clicksRepository,
|
||||||
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
|
], [
|
||||||
|
'redirectToUrl' => null,
|
||||||
|
], $this);
|
||||||
|
$clicks->track($data);
|
||||||
|
expect($this->subscriber->getLastEngagementAt())->equals($now);
|
||||||
|
Carbon::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItWontUpdateSubscriberEngagementForMachineAgent() {
|
||||||
|
$clicksRepository = $this->diContainer->get(StatisticsClicksRepository::class);
|
||||||
|
$data = $this->trackData;
|
||||||
|
$data->userAgent = UserAgentEntity::MACHINE_USER_AGENTS[0];
|
||||||
|
$clicks = Stub::construct($this->clicks, [
|
||||||
|
$this->settingsController,
|
||||||
|
new Cookies(),
|
||||||
|
$this->diContainer->get(Shortcodes::class),
|
||||||
|
$this->diContainer->get(Opens::class),
|
||||||
|
$clicksRepository,
|
||||||
|
$this->diContainer->get(UserAgentsRepository::class),
|
||||||
|
$this->diContainer->get(LinkShortcodeCategory::class),
|
||||||
|
$this->diContainer->get(SubscribersRepository::class),
|
||||||
|
], [
|
||||||
|
'redirectToUrl' => null,
|
||||||
|
], $this);
|
||||||
|
$clicks->track($data);
|
||||||
|
expect($this->subscriber->getLastEngagementAt())->null();
|
||||||
|
}
|
||||||
|
|
||||||
public function cleanup() {
|
public function cleanup() {
|
||||||
$this->truncateEntity(NewsletterEntity::class);
|
$this->truncateEntity(NewsletterEntity::class);
|
||||||
$this->truncateEntity(SubscriberEntity::class);
|
$this->truncateEntity(SubscriberEntity::class);
|
||||||
|
Reference in New Issue
Block a user