Pass SubscriberEntity to sendConfirmationEmail() and sendConfirmationEmailOnce()

This commit changes the methods sendConfirmationEmail() and
sendConfirmationEmailOnce() to accept as the first parameter an instance
of SubscriberEntity instead of the old model Subscriber. It also updates
all the places where those two methods are called.

[MAILPOET-3815]
This commit is contained in:
Rodrigo Primo
2021-12-01 20:25:36 -03:00
committed by Veljko V
parent 8cd3205ade
commit 6c05b3eaf0
9 changed files with 153 additions and 106 deletions

View File

@ -197,8 +197,8 @@ class Subscribers extends APIEndpoint {
public function sendConfirmationEmail($data = []) {
$id = (isset($data['id']) ? (int)$data['id'] : false);
$subscriber = Subscriber::findOne($id);
if ($subscriber instanceof Subscriber) {
$subscriber = $this->subscribersRepository->findOneById($id);
if ($subscriber instanceof SubscriberEntity) {
if ($this->confirmationEmailMailer->sendConfirmationEmail($subscriber)) {
return $this->successResponse();
}

View File

@ -2,6 +2,7 @@
namespace MailPoet\API\MP\v1;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
@ -11,6 +12,7 @@ use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\Source;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending;
use MailPoet\Util\Helpers;
use MailPoet\WP\Functions as WPFunctions;
@ -35,13 +37,17 @@ class API {
/** @var CustomFields */
private $customFields;
/** @var SubscribersRepository */
private $subscribersRepository;
public function __construct(
NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
ConfirmationEmailMailer $confirmationEmailMailer,
RequiredCustomFieldValidator $requiredCustomFieldValidator,
WelcomeScheduler $welcomeScheduler,
CustomFields $customFields,
SettingsController $settings
SettingsController $settings,
SubscribersRepository $subscribersRepository
) {
$this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
$this->confirmationEmailMailer = $confirmationEmailMailer;
@ -49,6 +55,7 @@ class API {
$this->welcomeScheduler = $welcomeScheduler;
$this->settings = $settings;
$this->customFields = $customFields;
$this->subscribersRepository = $subscribersRepository;
}
public function getSubscriberFields() {
@ -324,7 +331,10 @@ class API {
}
protected function _sendConfirmationEmail(Subscriber $subscriber) {
return $this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriber);
$subscriberEntity = $this->subscribersRepository->findOneById($subscriber->id);
if ($subscriberEntity instanceof SubscriberEntity) {
return $this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriberEntity);
}
}
protected function _scheduleWelcomeNotification(Subscriber $subscriber, array $segments) {

View File

@ -13,6 +13,7 @@ use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\Source;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\WooCommerce\Helper as WooCommerceHelper;
use MailPoet\WooCommerce\Subscription as WooCommerceSubscription;
use MailPoet\WP\Functions as WPFunctions;
@ -30,14 +31,19 @@ class WP {
/** @var WooCommerceHelper */
private $wooHelper;
/** @var SubscribersRepository */
private $subscribersRepository;
public function __construct(
WPFunctions $wp,
WelcomeScheduler $welcomeScheduler,
WooCommerceHelper $wooHelper
WooCommerceHelper $wooHelper,
SubscribersRepository $subscribersRepository
) {
$this->wp = $wp;
$this->welcomeScheduler = $welcomeScheduler;
$this->wooHelper = $wooHelper;
$this->subscribersRepository = $subscribersRepository;
}
public function synchronizeUser($wpUserId, $oldWpUserData = false) {
@ -143,7 +149,10 @@ class WP {
if ($sendConfirmationEmail && ($subscriber->status === Subscriber::STATUS_UNCONFIRMED)) {
/** @var ConfirmationEmailMailer $confirmationEmailMailer */
$confirmationEmailMailer = ContainerWrapper::getInstance()->get(ConfirmationEmailMailer::class);
$confirmationEmailMailer->sendConfirmationEmailOnce($subscriber);
$subscriberEntity = $this->subscribersRepository->findOneById($subscriber->id);
if ($subscriberEntity instanceof SubscriberEntity) {
$confirmationEmailMailer->sendConfirmationEmailOnce($subscriberEntity);
}
}
// welcome email

View File

@ -3,6 +3,8 @@
namespace MailPoet\Subscribers;
use Html2Text\Html2Text;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MetaInfo;
use MailPoet\Models\Subscriber;
@ -58,19 +60,19 @@ class ConfirmationEmailMailer {
* is not sent multiple times within a single request
* e.g. if sending confirmation emails from hooks
*/
public function sendConfirmationEmailOnce(Subscriber $subscriber): bool {
if (isset($this->sentEmails[$subscriber->id])) {
public function sendConfirmationEmailOnce(SubscriberEntity $subscriber): bool {
if (isset($this->sentEmails[$subscriber->getId()])) {
return true;
}
return $this->sendConfirmationEmail($subscriber);
}
public function sendConfirmationEmail(Subscriber $subscriber) {
public function sendConfirmationEmail(SubscriberEntity $subscriber) {
$signupConfirmation = $this->settings->get('signup_confirmation');
if ((bool)$signupConfirmation['enabled'] === false) {
return false;
}
if (!$this->wp->isUserLoggedIn() && $subscriber->countConfirmations >= self::MAX_CONFIRMATION_EMAILS) {
if (!$this->wp->isUserLoggedIn() && $subscriber->getConfirmationsCount() >= self::MAX_CONFIRMATION_EMAILS) {
return false;
}
@ -80,9 +82,9 @@ class ConfirmationEmailMailer {
return false;
}
$segments = $subscriber->segments()->findMany();
$segmentNames = array_map(function($segment) {
return $segment->name;
$segments = $subscriber->getSegments()->toArray();
$segmentNames = array_map(function(SegmentEntity $segment) {
return $segment->getName();
}, $segments);
$body = nl2br($signupConfirmation['body']);
@ -95,10 +97,9 @@ class ConfirmationEmailMailer {
);
// replace activation link
$subscriberEntity = $this->subscribersRepository->findOneById($subscriber->id);
$body = Helpers::replaceLinkTags(
$body,
$this->subscriptionUrlFactory->getConfirmationUrl($subscriberEntity),
$this->subscriptionUrlFactory->getConfirmationUrl($subscriber),
['target' => '_blank'],
'activation_link'
);
@ -118,25 +119,28 @@ class ConfirmationEmailMailer {
],
];
$subscriberModel = Subscriber::findOne($subscriber->getId());
// send email
try {
$extraParams = [
'meta' => $this->mailerMetaInfo->getConfirmationMetaInfo($subscriberEntity),
'meta' => $this->mailerMetaInfo->getConfirmationMetaInfo($subscriber),
];
$result = $this->mailer->send($email, $subscriber, $extraParams);
if ($result['response'] === false) {
$subscriber->setError(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
$subscriberModel->setError(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
return false;
};
if (!$this->wp->isUserLoggedIn()) {
$subscriber->countConfirmations++;
$subscriber->save();
$subscriber->setConfirmationsCount($subscriber->getConfirmationsCount() + 1);
$this->subscribersRepository->persist($subscriber);
$this->subscribersRepository->flush();
}
$this->sentEmails[$subscriber->id] = true;
$this->sentEmails[$subscriber->getId()] = true;
return true;
} catch (\Exception $e) {
$subscriber->setError(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
$subscriberModel->setError(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
return false;
}
}

View File

@ -103,11 +103,9 @@ class SubscriberActions {
// link subscriber to segments
$segments = $this->segmentsRepository->findBy(['id' => $segmentIds]);
$this->subscriberSegmentRepository->subscribeToSegments($subscriber, $segments);
$this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriber);
$subscriberModel = Subscriber::findOne($subscriber->getId());
if ($subscriberModel) {
$this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriberModel);
}
// We want to send the notification on subscribe only when signupConfirmation is disabled
if ($signupConfirmationEnabled === false && $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED && $subscriberModel) {

View File

@ -215,10 +215,18 @@ class Subscription {
}
private function requireSubscriptionConfirmation(Subscriber $subscriber) {
$subscriber->status = Subscriber::STATUS_UNCONFIRMED;
// we need to save the subscriber here since handleSubscriberOptin() sets the source but doesn't save the model.
// when we migrate this class to use Doctrine we can probably remove this call to save() as the call to persist() below should be enough.
$subscriber->save();
$subscriberEntity = $this->subscribersRepository->findOneById($subscriber->id);
$this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriber);
if ($subscriberEntity instanceof SubscriberEntity) {
$subscriberEntity->setStatus(Subscriber::STATUS_UNCONFIRMED);
$this->subscribersRepository->persist($subscriberEntity);
$this->subscribersRepository->flush();
$this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriberEntity);
}
}
private function updateSubscriberStatus(Subscriber $subscriber) {

View File

@ -17,6 +17,7 @@ use MailPoet\Settings\SettingsController;
use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending;
use MailPoetVendor\Idiorm\ORM;
@ -40,7 +41,8 @@ class APITest extends \MailPoetTest {
$this->diContainer->get(RequiredCustomFieldValidator::class),
Stub::makeEmpty(WelcomeScheduler::class),
$this->diContainer->get(CustomFields::class),
SettingsController::getInstance()
SettingsController::getInstance(),
$this->diContainer->get(SubscribersRepository::class)
);
}
@ -228,7 +230,8 @@ class APITest extends \MailPoetTest {
$this->makeEmpty(RequiredCustomFieldValidator::class),
Stub::makeEmpty(WelcomeScheduler::class),
$this->diContainer->get(CustomFields::class),
SettingsController::getInstance()
SettingsController::getInstance(),
$this->diContainer->get(SubscribersRepository::class)
);
$API->subscribeToLists($subscriber->email, $segments, ['send_confirmation_email' => false, 'skip_subscriber_notification' => true]);
@ -241,7 +244,8 @@ class APITest extends \MailPoetTest {
$this->makeEmpty(RequiredCustomFieldValidator::class),
Stub::makeEmpty(WelcomeScheduler::class),
$this->diContainer->get(CustomFields::class),
SettingsController::getInstance()
SettingsController::getInstance(),
$this->diContainer->get(SubscribersRepository::class)
);
$API->subscribeToLists($subscriber->email, $segments, ['send_confirmation_email' => false, 'skip_subscriber_notification' => false]);
}
@ -468,6 +472,7 @@ class APITest extends \MailPoetTest {
'confirmationEmailMailer' => Stub::makeEmpty(ConfirmationEmailMailer::class),
'_scheduleWelcomeNotification' => Expected::once(),
'settings' => $settings,
'subscribersRepository' => Stub::makeEmpty(SubscribersRepository::class),
],
$this
);
@ -500,7 +505,8 @@ class APITest extends \MailPoetTest {
$this->diContainer->get(RequiredCustomFieldValidator::class),
$welcomeScheduler,
$this->diContainer->get(CustomFields::class),
Stub::makeEmpty(SettingsController::class)
Stub::makeEmpty(SettingsController::class),
$this->diContainer->get(SubscribersRepository::class)
);
$subscriber = [
'email' => 'test@example.com',

View File

@ -12,6 +12,7 @@ use MailPoet\Models\SubscriberSegment;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\WP;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Subscription\Registration;
use MailPoet\WooCommerce\Helper;
use MailPoet\WooCommerce\Subscription;
@ -420,7 +421,12 @@ class WPTest extends \MailPoetTest {
],
$this
);
$wpSegment = new WP($wp, $this->diContainer->get(WelcomeScheduler::class), $this->diContainer->get(Helper::class));
$wpSegment = new WP(
$wp,
$this->diContainer->get(WelcomeScheduler::class),
$this->diContainer->get(Helper::class),
$this->diContainer->get(SubscribersRepository::class)
);
$wpSegment->synchronizeUser($id);
$subscriber = Subscriber::where("wp_user_id", $id)->findOne();
$deletedAt = Carbon::createFromFormat('Y-m-d H:i:s', $subscriber->deletedAt);
@ -438,7 +444,12 @@ class WPTest extends \MailPoetTest {
],
$this
);
$wpSegment = new WP($wp, $this->diContainer->get(WelcomeScheduler::class), $this->diContainer->get(Helper::class));
$wpSegment = new WP(
$wp,
$this->diContainer->get(WelcomeScheduler::class),
$this->diContainer->get(Helper::class),
$this->diContainer->get(SubscribersRepository::class)
);
$_POST[Subscription::CHECKOUT_OPTIN_PRESENCE_CHECK_INPUT_NAME] = 1;
$wpSegment->synchronizeUser($id);
$subscriber = Subscriber::where("wp_user_id", $id)->findOne();
@ -463,7 +474,12 @@ class WPTest extends \MailPoetTest {
],
$this
);
$wpSegment = new WP($wp, $this->diContainer->get(WelcomeScheduler::class), $this->diContainer->get(Helper::class));
$wpSegment = new WP(
$wp,
$this->diContainer->get(WelcomeScheduler::class),
$this->diContainer->get(Helper::class),
$this->diContainer->get(SubscribersRepository::class)
);
$wpSegment->synchronizeUser($id);
$wpSubscriber = Segment::getWPSegment()->subscribers()->where('wp_user_id', $id)->findOne();
expect($wpSubscriber->countConfirmations)->equals(0);
@ -491,7 +507,12 @@ class WPTest extends \MailPoetTest {
],
$this
);
$wpSegment = new WP($wp, $this->diContainer->get(WelcomeScheduler::class), $this->diContainer->get(Helper::class));
$wpSegment = new WP(
$wp,
$this->diContainer->get(WelcomeScheduler::class),
$this->diContainer->get(Helper::class),
$this->diContainer->get(SubscribersRepository::class)
);
$wpSegment->synchronizeUser($id);
$subscriber1 = Subscriber::where("wp_user_id", $id)->findOne();
expect($subscriber1->status)->equals(SubscriberEntity::STATUS_SUBSCRIBED);
@ -521,7 +542,12 @@ class WPTest extends \MailPoetTest {
],
$this
);
$wpSegment = new WP($wp, $this->diContainer->get(WelcomeScheduler::class), $wooHelper);
$wpSegment = new WP(
$wp,
$this->diContainer->get(WelcomeScheduler::class),
$wooHelper,
$this->diContainer->get(SubscribersRepository::class)
);
$wpSegment->synchronizeUser($id);
$subscriber1 = Subscriber::where("wp_user_id", $id)->findOne();
expect($subscriber1->status)->equals(SubscriberEntity::STATUS_UNCONFIRMED);

View File

@ -3,17 +3,49 @@
namespace MailPoet\Subscribers;
use Codeception\Stub;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Mailer\Mailer;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Services\AuthorizedEmailsController;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscription\SubscriptionUrlFactory;
use MailPoet\Test\DataFactories\Segment as SegmentFactory;
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Idiorm\ORM;
class ConfirmationEmailMailerTest extends \MailPoetTest {
/** @var SegmentFactory */
private $segmentFactory;
/** @var SubscriberEntity */
private $subscriber;
/** @var SubscriberFactory */
private $subscriberFactory;
/** @var SubscribersRepository */
private $subscribersRepository;
/** @var SubscriberSegmentRepository */
private $subscriberSegmentRepository;
public function _before() {
parent::_before();
$this->segmentFactory = new SegmentFactory();
$this->subscriberFactory = new SubscriberFactory();
$this->subscribersRepository = $this->diContainer->get(SubscribersRepository::class);
$this->subscriberSegmentRepository = $this->diContainer->get(SubscriberSegmentRepository::class);
$this->subscriber = $this->subscriberFactory
->withFirstName('John')
->withLastName('Mailer')
->withEmail('john@mailpoet.com')
->create();
}
public function testItSendsConfirmationEmail() {
$subcriptionUrlFactoryMock = $this->createMock(SubscriptionUrlFactory::class);
$subcriptionUrlFactoryMock->method('getConfirmationUrl')->willReturn('http://example.com');
@ -24,15 +56,10 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
$settings->get('signup_confirmation.body') . "\nLists: [lists_to_confirm]"
);
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com',
'status' => 'unconfirmed',
'source' => 'api',
]);
$subscriber->save();
$this->subscriber->setStatus('unconfirmed');
$this->subscriber->setSource('api');
$this->subscribersRepository->persist($this->subscriber);
$this->subscribersRepository->flush();
$mailer = Stub::makeEmpty(Mailer::class, [
'send' =>
@ -56,36 +83,19 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
$subcriptionUrlFactoryMock
);
$segment = $this->segmentFactory->withName('Test segment')->create();
$this->subscriberSegmentRepository->subscribeToSegments($this->subscriber, [$segment]);
$segment = Segment::createOrUpdate(
[
'name' => 'Test segment',
]
);
SubscriberSegment::subscribeToSegments(
$subscriber,
[$segment->id]
);
$result = $sender->sendConfirmationEmail($subscriber);
$result = $sender->sendConfirmationEmail($this->subscriber);
expect($result)->true();
expect($subscriber->countConfirmations)->equals(1);
expect($this->subscriber->getConfirmationsCount())->equals(1);
$sender->sendConfirmationEmailOnce($subscriber);
$subscriberFromDb = Subscriber::findOne($subscriber->id);
expect($subscriberFromDb->countConfirmations)->equals(1);
expect($subscriber->countConfirmations)->equals(1);
$sender->sendConfirmationEmailOnce($this->subscriber);
$this->subscribersRepository->refresh($this->subscriber);
expect($this->subscriber->getConfirmationsCount())->equals(1);
}
public function testItSetsErrorsWhenConfirmationEmailCannotBeSent() {
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com',
]);
$subscriber->save();
public function testItReturnsFalseWhenConfirmationEmailCannotBeSent() {
$mailer = Stub::makeEmpty(Mailer::class, [
'send' =>
Stub\Expected::once(function () {
@ -101,20 +111,10 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
$this->diContainer->get(SubscriptionUrlFactory::class)
);
$sender->sendConfirmationEmail($subscriber);
// error is set on the subscriber model object
expect($subscriber->getErrors()[0])->equals('Something went wrong with your subscription. Please contact the website owner.');
$this->assertFalse($sender->sendConfirmationEmail($this->subscriber));
}
public function testItDoesntSendWhenMSSIsActiveAndConfirmationEmailIsNotAuthorized() {
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com',
]);
$subscriber->save();
$mailer = $this->makeEmpty(Mailer::class, [
'send' => Stub\Expected::never(),
]);
@ -130,7 +130,7 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
$this->diContainer->get(SubscriptionUrlFactory::class)
);
$result = $sender->sendConfirmationEmail($subscriber);
$result = $sender->sendConfirmationEmail($this->subscriber);
expect($result)->equals(false);
$settings->set(AuthorizedEmailsController::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING, null);
}
@ -138,13 +138,6 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
public function testItLimitsNumberOfConfirmationEmailsForNotLoggedInUser() {
wp_set_current_user(0);
expect((new WPFunctions)->isUserLoggedIn())->false();
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com',
]);
$subscriber->save();
$mailer = Stub::makeEmpty(Mailer::class, [
'send' => function() {
@ -160,21 +153,14 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
);
for ($i = 0; $i < $sender::MAX_CONFIRMATION_EMAILS; $i++) {
expect($sender->sendConfirmationEmail($subscriber))->equals(true);
expect($sender->sendConfirmationEmail($this->subscriber))->equals(true);
}
expect($sender->sendConfirmationEmail($subscriber))->equals(false);
expect($sender->sendConfirmationEmail($this->subscriber))->equals(false);
}
public function testItDoesNotLimitNumberOfConfirmationEmailsForLoggedInUser() {
wp_set_current_user(1);
expect((new WPFunctions)->isUserLoggedIn())->true();
$subscriber = Subscriber::create();
$subscriber->hydrate([
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com',
]);
$subscriber->save();
$mailer = Stub::makeEmpty(Mailer::class, [
'send' => function() {
@ -190,14 +176,14 @@ class ConfirmationEmailMailerTest extends \MailPoetTest {
);
for ($i = 0; $i < $sender::MAX_CONFIRMATION_EMAILS; $i++) {
expect($sender->sendConfirmationEmail($subscriber))->equals(true);
expect($sender->sendConfirmationEmail($this->subscriber))->equals(true);
}
expect($sender->sendConfirmationEmail($subscriber))->equals(true);
expect($sender->sendConfirmationEmail($this->subscriber))->equals(true);
}
public function _after() {
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
ORM::raw_execute('TRUNCATE ' . Segment::$_table);
ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
$this->truncateEntity(SubscriberEntity::class);
$this->truncateEntity(SegmentEntity::class);
$this->truncateEntity(SubscriberSegmentEntity::class);
}
}