Use Doctrine entity in calling LinkTokens::verifyToken

[MAILPOET-3269]
This commit is contained in:
Jan Lysý
2021-05-27 19:29:03 +02:00
committed by Veljko V
parent d34c923cef
commit 85b9d5b7e4
8 changed files with 77 additions and 55 deletions

View File

@ -4,7 +4,6 @@ namespace MailPoet\Newsletter\ViewInBrowser;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\Newsletter\Url as NewsletterUrl;
use MailPoet\Subscribers\LinkTokens;
@ -91,11 +90,7 @@ class ViewInBrowserController {
throw new \InvalidArgumentException("Missing 'subscriber_token'");
}
$subscriberModel = Subscriber::findOne($subscriber->getId());
if (!$subscriberModel) {
return null;
}
if (!$this->linkTokens->verifyToken($subscriberModel, $data['subscriber_token'])) {
if (!$this->linkTokens->verifyToken($subscriber, $data['subscriber_token'])) {
throw new \InvalidArgumentException("Invalid 'subscriber_token'");
}
return $subscriber;

View File

@ -5,7 +5,6 @@ namespace MailPoet\Router\Endpoints;
use MailPoet\Config\AccessControl;
use MailPoet\Cron\Workers\StatsNotifications\NewsletterLinkRepository;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Links\Links;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
@ -99,13 +98,12 @@ class Track {
public function _validateTrackData($data) {
if (!$data->subscriber || !$data->queue || !$data->newsletter) return false;
$subscriberModel = Subscriber::findOne($data->subscriber->getId());
$subscriberTokenMatch = $this->linkTokens->verifyToken($subscriberModel, $data->subscriber_token); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps
$subscriberTokenMatch = $this->linkTokens->verifyToken($data->subscriber, $data->subscriber_token); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps
if (!$subscriberTokenMatch) {
$this->terminate(403);
}
// return if this is a WP user previewing the newsletter
if ($subscriberModel->isWPUser() && $data->preview) {
if ($data->subscriber->isWPUser() && $data->preview) {
return $data;
}
// check if the newsletter was sent to the subscriber

View File

@ -6,6 +6,7 @@ use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\InvalidStateException;
use MailPoet\Models\CustomField;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
@ -16,6 +17,7 @@ use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Util\Url as UrlHelper;
class Manage {
@ -41,6 +43,9 @@ class Manage {
/** @var WelcomeScheduler */
private $welcomeScheduler;
/** @var SubscribersRepository */
private $subscribersRepository;
/** @var SubscriberSegmentRepository */
private $subscriberSegmentRepository;
@ -52,6 +57,7 @@ class Manage {
SettingsController $settings,
NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
WelcomeScheduler $welcomeScheduler,
SubscribersRepository $subscribersRepository,
SubscriberSegmentRepository $subscriberSegmentRepository
) {
$this->urlHelper = $urlHelper;
@ -61,6 +67,7 @@ class Manage {
$this->settings = $settings;
$this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
$this->welcomeScheduler = $welcomeScheduler;
$this->subscribersRepository = $subscribersRepository;
$this->subscriberSegmentRepository = $subscriberSegmentRepository;
}
@ -76,25 +83,29 @@ class Manage {
$result = [];
if (!empty($subscriberData['email'])) {
$subscriber = Subscriber::where('email', $subscriberData['email'])->findOne();
$subscriber = $this->subscribersRepository->findOneBy(['email' => $subscriberData['email']]);
if (
($subscriberData['status'] === SubscriberEntity::STATUS_UNSUBSCRIBED)
&& ($subscriber instanceof Subscriber)
&& ($subscriber->status === SubscriberEntity::STATUS_SUBSCRIBED)
&& ($subscriber instanceof SubscriberEntity)
&& ($subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED)
) {
$this->unsubscribesTracker->track(
(int)$subscriber->id,
(int)$subscriber->getId(),
StatisticsUnsubscribeEntity::SOURCE_MANAGE
);
}
if ($subscriber && $this->linkTokens->verifyToken($subscriber, $token)) {
$subscriberModel = Subscriber::findOne($subscriber->getId());
if (!$subscriberModel instanceof Subscriber) {
throw new InvalidStateException();
}
if ($subscriberData['email'] !== Pages::DEMO_EMAIL) {
$this->updateSubscriptions($subscriber, $subscriberData);
$this->updateSubscriptions($subscriberModel, $subscriberData);
unset($subscriberData['segments']);
$subscriber = Subscriber::createOrUpdate($this->filterOutEmptyMandatoryFields($subscriberData));
$subscriber->getErrors();
$subscriberModel = Subscriber::createOrUpdate($this->filterOutEmptyMandatoryFields($subscriberData));
$subscriberModel->getErrors();
}
}
$result = ['success' => true];

View File

@ -12,6 +12,7 @@ use MailPoet\Settings\SettingsController;
use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Util\Helpers;
use MailPoet\WP\Functions as WPFunctions;
@ -60,6 +61,9 @@ class Pages {
/** @var ManageSubscriptionFormRenderer */
private $manageSubscriptionFormRenderer;
/** @var SubscribersRepository */
private $subscribersRepository;
public function __construct(
NewSubscriberNotificationMailer $newSubscriberNotificationSender,
WPFunctions $wp,
@ -71,7 +75,8 @@ class Pages {
AssetsController $assetsController,
TemplateRenderer $templateRenderer,
Unsubscribes $unsubscribesTracker,
ManageSubscriptionFormRenderer $manageSubscriptionFormRenderer
ManageSubscriptionFormRenderer $manageSubscriptionFormRenderer,
SubscribersRepository $subscribersRepository
) {
$this->wp = $wp;
$this->newSubscriberNotificationSender = $newSubscriberNotificationSender;
@ -84,6 +89,7 @@ class Pages {
$this->templateRenderer = $templateRenderer;
$this->unsubscribesTracker = $unsubscribesTracker;
$this->manageSubscriptionFormRenderer = $manageSubscriptionFormRenderer;
$this->subscribersRepository = $subscribersRepository;
}
public function init($action = false, $data = [], $initShortcodes = false, $initPageFilters = false) {
@ -135,7 +141,8 @@ class Pages {
}
$subscriber = Subscriber::where('email', $email)->findOne();
return ($subscriber && $this->linkTokens->verifyToken($subscriber, $token)) ? $subscriber : null;
$subscriberEntity = $subscriber ? $this->subscribersRepository->findOneById($subscriber->id) : null;
return ($subscriber && $subscriberEntity && $this->linkTokens->verifyToken($subscriberEntity, $token)) ? $subscriber : null;
}
public function confirm() {

View File

@ -66,16 +66,14 @@ class ViewInBrowserControllerTest extends \MailPoetTest {
$sendingTask->setSubscribers([$subscriber->getId()]);
$sendingTask->updateProcessedSubscribers([$subscriber->getId()]);
$this->sendingTask = $sendingTask->save();
$linkTokens = new LinkTokens;
// build browser preview data
$subscriberModel = Subscriber::findOne($subscriber->getId());
$this->browserPreviewData = [
'queue_id' => $sendingTask->queue()->id,
'subscriber_id' => $subscriber->getId(),
'newsletter_id' => $newsletter->id,
'newsletter_hash' => $newsletter->hash,
'subscriber_token' => $linkTokens->getToken($subscriberModel),
'subscriber_token' => $this->linkTokens->getToken($subscriber),
'preview' => false,
];
}

View File

@ -12,7 +12,6 @@ use MailPoet\Entities\SubscriberEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterLink;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\Router\Endpoints\Track;
use MailPoet\Subscribers\LinkTokens;
@ -26,6 +25,9 @@ class TrackTest extends \MailPoetTest {
public $subscriber;
public $newsletter;
/** @var LinkTokens */
private $linkTokens;
public function _before() {
parent::_before();
$this->cleanup();
@ -60,21 +62,20 @@ class TrackTest extends \MailPoetTest {
$scheduledTaskSubscriber = new ScheduledTaskSubscriberEntity($task, $subscriber, 1);
$this->entityManager->persist($scheduledTaskSubscriber);
$this->entityManager->flush();
$subscriberModel = Subscriber::findOne($subscriber->getId());
$linkTokens = new LinkTokens;
$this->linkTokens = $this->diContainer->get(LinkTokens::class);
// build track data
$this->trackData = [
'queue_id' => $queue->getId(),
'subscriber_id' => $subscriber->getId(),
'newsletter_id' => $newsletter->getId(),
'subscriber_token' => $linkTokens->getToken($subscriberModel),
'subscriber_token' => $this->linkTokens->getToken($subscriber),
'link_hash' => $link->getHash(),
'preview' => false,
];
$queue = SendingQueue::findOne($queue->getId());
assert($queue instanceof SendingQueue);
$queue = SendingTask::createFromQueue($queue);
$queue->updateProcessedSubscribers([$subscriberModel->id]);
$queue->updateProcessedSubscribers([$subscriber->getId()]);
// instantiate class
$this->track = $this->diContainer->get(Track::class);
}
@ -106,8 +107,8 @@ class TrackTest extends \MailPoetTest {
$data->subscriber->setEmail('random@email.com');
$this->entityManager->flush();
$track = Stub::make(Track::class, [
'linkTokens' => new LinkTokens,
'sendingQueuesRepository' => $this->diContainer->get(SendingQueuesRepository::class),
'linkTokens' => $this->linkTokens,
'terminate' => function($code) {
expect($code)->equals(403);
},

View File

@ -13,6 +13,7 @@ use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Subscription\Manage;
use MailPoet\Util\Url as UrlHelper;
use MailPoetVendor\Idiorm\ORM;
@ -62,6 +63,7 @@ class ManageTest extends \MailPoetTest {
$this->settings,
$this->diContainer->get(NewSubscriberNotificationMailer::class),
$this->diContainer->get(WelcomeScheduler::class),
$this->diContainer->get(SubscribersRepository::class),
$this->diContainer->get(SubscriberSegmentRepository::class)
);
$_POST['action'] = 'mailpoet_subscription_update';

View File

@ -3,9 +3,9 @@
namespace MailPoet\Test\Subscription;
use Codeception\Stub;
use Codeception\Util\Fixtures;
use MailPoet\Config\Renderer;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Form\AssetsController;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterOption;
@ -21,6 +21,7 @@ use MailPoet\Settings\SettingsController;
use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Subscription\CaptchaRenderer;
use MailPoet\Subscription\ManageSubscriptionFormRenderer;
use MailPoet\Subscription\Pages;
@ -32,18 +33,24 @@ use MailPoetVendor\Idiorm\ORM;
class PagesTest extends \MailPoetTest {
private $testData = [];
/** @var Subscriber */
/** @var SubscriberEntity */
private $subscriber;
/** @var SubscribersRepository */
private $subscribersRepository;
public function _before() {
parent::_before();
$this->subscriber = Subscriber::create();
$this->subscriber->hydrate(Fixtures::get('subscriber_template'));
$this->subscriber->status = Subscriber::STATUS_UNCONFIRMED;
$this->subscriber->save();
$linkTokens = new LinkTokens;
expect($this->subscriber->getErrors())->false();
$this->testData['email'] = $this->subscriber->email;
$this->subscribersRepository = $this->diContainer->get(SubscribersRepository::class);
$this->subscriber = new SubscriberEntity();
$this->subscriber->setFirstName('John');
$this->subscriber->setLastName('John');
$this->subscriber->setEmail('john.doe@example.com');
$this->subscriber->setStatus(Subscriber::STATUS_UNCONFIRMED);
$this->subscribersRepository->persist($this->subscriber);
$this->subscribersRepository->flush();
$linkTokens = $this->diContainer->get(LinkTokens::class);
$this->testData['email'] = $this->subscriber->getEmail();
$this->testData['token'] = $linkTokens->getToken($this->subscriber);
}
@ -52,7 +59,7 @@ class PagesTest extends \MailPoetTest {
$pages = $this->getPages($newSubscriberNotificationSender);
$subscription = $pages->init($action = false, $this->testData, false, false);
$subscription->confirm();
$confirmedSubscriber = Subscriber::findOne($this->subscriber->id);
$confirmedSubscriber = Subscriber::findOne($this->subscriber->getId());
expect($confirmedSubscriber->status)->equals(Subscriber::STATUS_SUBSCRIBED);
expect($confirmedSubscriber->lastSubscribedAt)->greaterOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->subSecond());
expect($confirmedSubscriber->lastSubscribedAt)->lessOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->addSecond());
@ -62,21 +69,23 @@ class PagesTest extends \MailPoetTest {
$newSubscriberNotificationSender = $this->makeEmpty(NewSubscriberNotificationMailer::class, ['send' => Stub\Expected::never()]);
$pages = $this->getPages($newSubscriberNotificationSender);
$subscriber = $this->subscriber;
$subscriber->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber->firstName = 'First name';
$subscriber->unconfirmedData = '{"first_name" : "Updated first name", "email" : "' . $this->subscriber->email . '"}';
$subscriber->lastSubscribedAt = Carbon::now()->subDays(10);
$subscriber->confirmedAt = Carbon::now()->subDays(10);
$subscriber->save();
$subscriber->setStatus(Subscriber::STATUS_SUBSCRIBED);
$subscriber->setFirstName('First name');
$subscriber->setUnconfirmedData('{"first_name" : "Updated first name", "email" : "' . $this->subscriber->getEmail() . '"}');
$subscriber->setLastSubscribedAt(Carbon::now()->subDays(10));
$subscriber->setConfirmedIp(Carbon::now()->subDays(10));
$this->entityManager->flush();
$subscription = $pages->init($action = false, $this->testData, false, false);
$subscription->confirm();
$confirmedSubscriber = Subscriber::findOne($this->subscriber->id);
expect($confirmedSubscriber->status)->equals(Subscriber::STATUS_SUBSCRIBED);
expect($confirmedSubscriber->confirmedAt)->greaterOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->subSecond());
expect($confirmedSubscriber->confirmedAt)->lessOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->addSecond());
expect($confirmedSubscriber->lastSubscribedAt)->greaterOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->subSecond());
expect($confirmedSubscriber->lastSubscribedAt)->lessOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->addSecond());
expect($confirmedSubscriber->firstName)->equals('Updated first name');
$this->entityManager->clear();
$confirmedSubscriber = $this->subscribersRepository->findOneById($subscriber->getId());
assert($confirmedSubscriber instanceof SubscriberEntity);
expect($confirmedSubscriber->getStatus())->equals(Subscriber::STATUS_SUBSCRIBED);
expect($confirmedSubscriber->getConfirmedAt())->greaterOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->subSecond());
expect($confirmedSubscriber->getConfirmedAt())->lessOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->addSecond());
expect($confirmedSubscriber->getLastSubscribedAt())->greaterOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->subSecond());
expect($confirmedSubscriber->getLastSubscribedAt())->lessOrEquals(Carbon::createFromTimestamp((int)current_time('timestamp'))->addSecond());
expect($confirmedSubscriber->getFirstName())->equals('Updated first name');
}
public function testItSendsWelcomeNotificationUponConfirmingSubscription() {
@ -92,7 +101,7 @@ class PagesTest extends \MailPoetTest {
$subscriberSegment = SubscriberSegment::create();
$subscriberSegment->hydrate(
[
'subscriber_id' => $this->subscriber->id,
'subscriber_id' => $this->subscriber->getId(),
'segment_id' => $segment->id,
]
);
@ -143,7 +152,7 @@ class PagesTest extends \MailPoetTest {
public function testItUnsubscribes() {
$pages = $this->getPages()->init($action = 'unsubscribe', $this->testData);
$pages->unsubscribe();
$updatedSubscriber = Subscriber::findOne($this->subscriber->id);
$updatedSubscriber = Subscriber::findOne($this->subscriber->getId());
expect($updatedSubscriber->status)->equals(Subscriber::STATUS_UNSUBSCRIBED);
}
@ -167,7 +176,7 @@ class PagesTest extends \MailPoetTest {
$this->testData['preview'] = 1;
$pages = $this->getPages()->init($action = 'unsubscribe', $this->testData);
$pages->unsubscribe();
$updatedSubscriber = Subscriber::findOne($this->subscriber->id);
$updatedSubscriber = Subscriber::findOne($this->subscriber->getId());
expect($updatedSubscriber->status)->notEquals(Subscriber::STATUS_UNSUBSCRIBED);
}
@ -199,7 +208,8 @@ class PagesTest extends \MailPoetTest {
$container->get(AssetsController::class),
$container->get(Renderer::class),
$unsubscribesMock ?? $container->get(Unsubscribes::class),
$container->get(ManageSubscriptionFormRenderer::class)
$container->get(ManageSubscriptionFormRenderer::class),
$this->subscribersRepository
);
}
}