Save user agent on open

[MAILPOET-3735]
This commit is contained in:
Pavel Dohnal
2021-08-17 12:53:06 +02:00
committed by Veljko V
parent 4f37cde9f9
commit a84471b65c
6 changed files with 84 additions and 12 deletions

View File

@ -443,6 +443,7 @@ class Migrator {
'newsletter_id int(11) unsigned NOT NULL,',
'subscriber_id int(11) unsigned NOT NULL,',
'queue_id int(11) unsigned NOT NULL,',
'user_agent_id int(11) unsigned NULL,',
'created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,',
'PRIMARY KEY (id),',
'KEY newsletter_id_subscriber_id (newsletter_id, subscriber_id),',

View File

@ -37,6 +37,12 @@ class StatisticsOpenEntity {
*/
private $subscriber;
/**
* @ORM\ManyToOne(targetEntity="MailPoet\Entities\UserAgentEntity")
* @var UserAgentEntity|null
*/
private $userAgent;
public function __construct(
NewsletterEntity $newsletter,
SendingQueueEntity $queue,
@ -83,4 +89,12 @@ class StatisticsOpenEntity {
public function setSubscriber($subscriber) {
$this->subscriber = $subscriber;
}
public function getUserAgent(): ?UserAgentEntity {
return $this->userAgent;
}
public function setUserAgent(?UserAgentEntity $userAgent): void {
$this->userAgent = $userAgent;
}
}

View File

@ -98,6 +98,7 @@ class Track {
'queue' => $data->queue_id, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
]);
}
$data->userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
return $this->_validateTrackData($data);
}

View File

@ -7,13 +7,21 @@ use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\StatisticsOpenEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Statistics\StatisticsOpensRepository;
use MailPoet\Statistics\UserAgentsRepository;
class Opens {
/** @var StatisticsOpensRepository */
private $statisticsOpensRepository;
public function __construct(StatisticsOpensRepository $statisticsOpensRepository) {
/** @var UserAgentsRepository */
private $userAgentsRepository;
public function __construct(
StatisticsOpensRepository $statisticsOpensRepository,
UserAgentsRepository $userAgentsRepository
) {
$this->statisticsOpensRepository = $statisticsOpensRepository;
$this->userAgentsRepository = $userAgentsRepository;
}
public function track($data, $displayImage = true) {
@ -40,6 +48,9 @@ class Opens {
return $this->returnResponse($displayImage);
}
$statistics = new StatisticsOpenEntity($newsletter, $queue, $subscriber);
if (!empty($data->userAgent)) {
$statistics->setUserAgent($this->userAgentsRepository->findOrCreate($data->userAgent));
}
$this->statisticsOpensRepository->persist($statistics);
$this->statisticsOpensRepository->flush();
$this->statisticsOpensRepository->recalculateSubscriberScore($subscriber);

View File

@ -0,0 +1,24 @@
<?php
namespace MailPoet\Statistics;
use MailPoet\Doctrine\Repository;
use MailPoet\Entities\UserAgentEntity;
/**
* @extends Repository<UserAgentEntity>
*/
class UserAgentsRepository extends Repository {
protected function getEntityClassName() {
return UserAgentEntity::class;
}
public function findOrCreate(string $userAgent): UserAgentEntity {
$hash = (string)crc32($userAgent);
$userAgentEntity = $this->findOneBy(['hash' => $hash]);
if ($userAgentEntity) return $userAgentEntity;
$userAgentEntity = new UserAgentEntity($userAgent);
$this->persist($userAgentEntity);
return $userAgentEntity;
}
}

View File

@ -7,17 +7,13 @@ use Codeception\Stub\Expected;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\StatisticsOpenEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Models\ScheduledTask;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\StatisticsOpens;
use MailPoet\Models\Subscriber;
use MailPoet\Statistics\StatisticsOpensRepository;
use MailPoet\Statistics\Track\Opens;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Tasks\Sending as SendingTask;
use MailPoetVendor\Idiorm\ORM;
class OpensTest extends \MailPoetTest {
public $opens;
@ -26,6 +22,9 @@ class OpensTest extends \MailPoetTest {
public $subscriber;
public $newsletter;
/** @var StatisticsOpensRepository */
private $statisticsOpensRepository;
public function _before() {
parent::_before();
$this->cleanup();
@ -68,7 +67,8 @@ class OpensTest extends \MailPoetTest {
'preview' => false,
];
// instantiate class
$this->opens = new Opens($this->diContainer->get(StatisticsOpensRepository::class));
$this->statisticsOpensRepository = $this->diContainer->get(StatisticsOpensRepository::class);
$this->opens = new Opens($this->statisticsOpensRepository);
}
public function testItReturnsImageWhenTrackDataIsEmpty() {
@ -119,15 +119,36 @@ class OpensTest extends \MailPoetTest {
$opens->track($this->trackData);
}
public function testItSavesNewUserAgent() {
$this->trackData->userAgent = 'User agent';
$opens = Stub::construct($this->opens, [$this->diContainer->get(StatisticsOpensRepository::class)], [
'returnResponse' => null,
], $this);
$opens->track($this->trackData);
$opens = $this->statisticsOpensRepository->findAll();
expect($opens)->count(1);
$open = $opens[0];
$userAgent = $open->getUserAgent();
expect($userAgent)->notNull();
}
public function testItSavesOpenWithExistingUserAgent() {
}
public function testItOverridesOldUserAgent() {
}
public function _after() {
$this->cleanup();
}
public function cleanup() {
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
ORM::raw_execute('TRUNCATE ' . ScheduledTask::$_table);
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
ORM::raw_execute('TRUNCATE ' . StatisticsOpens::$_table);
$this->truncateEntity(NewsletterEntity::class);
$this->truncateEntity(SubscriberEntity::class);
$this->truncateEntity(ScheduledTaskEntity::class);
$this->truncateEntity(SendingQueueEntity::class);
$this->truncateEntity(StatisticsOpenEntity::class);
}
}