Remove usages of MailPoet\Tasks\Sending from welcome scheduler

[MAILPOET-4375]
This commit is contained in:
Jan Jakes
2023-10-24 09:58:25 +02:00
committed by Aschepikov
parent 728e1781c6
commit b42d579b67
4 changed files with 69 additions and 58 deletions

View File

@@ -19,7 +19,6 @@ use MailPoet\Subscribers\SubscriberListingRepository;
use MailPoet\Subscribers\SubscriberSaveController; use MailPoet\Subscribers\SubscriberSaveController;
use MailPoet\Subscribers\SubscriberSegmentRepository; use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon; use MailPoetVendor\Carbon\Carbon;
@@ -314,17 +313,14 @@ class Subscribers {
* @throws APIException * @throws APIException
*/ */
protected function _scheduleWelcomeNotification(SubscriberEntity $subscriber, array $segments) { protected function _scheduleWelcomeNotification(SubscriberEntity $subscriber, array $segments) {
$result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification($subscriber->getId(), $segments); try {
if (is_array($result)) { $this->welcomeScheduler->scheduleSubscriberWelcomeNotification($subscriber->getId(), $segments);
foreach ($result as $queue) { } catch (\Throwable $e) {
if ($queue instanceof Sending && $queue->getErrors()) { throw new APIException(
throw new APIException( // translators: %s is an error message
// translators: %s is a comma-separated list of errors sprintf(__('Subscriber added, but welcome email failed to send: %s', 'mailpoet'), $e->getMessage()),
sprintf(__('Subscriber added, but welcome email failed to send: %s', 'mailpoet'), strtolower(implode(', ', $queue->getErrors()))), APIException::WELCOME_FAILED_TO_SEND
APIException::WELCOME_FAILED_TO_SEND );
);
}
}
} }
} }

View File

@@ -2,9 +2,11 @@
namespace MailPoet\Newsletter\Scheduler; namespace MailPoet\Newsletter\Scheduler;
use MailPoet\Cron\Workers\SendingQueue\SendingQueue;
use MailPoet\Entities\NewsletterEntity; use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\NewsletterOptionFieldEntity; use MailPoet\Entities\NewsletterOptionFieldEntity;
use MailPoet\Entities\ScheduledTaskEntity; use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\ScheduledTaskSubscriberEntity;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
@@ -12,12 +14,15 @@ use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository; use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending as SendingTask; use MailPoetVendor\Doctrine\ORM\EntityManager;
class WelcomeScheduler { class WelcomeScheduler {
const WORDPRESS_ALL_ROLES = 'mailpoet_all'; const WORDPRESS_ALL_ROLES = 'mailpoet_all';
/** @var EntityManager */
private $entityManager;
/** @var SubscribersRepository */ /** @var SubscribersRepository */
private $subscribersRepository; private $subscribersRepository;
@@ -34,12 +39,14 @@ class WelcomeScheduler {
private $scheduler; private $scheduler;
public function __construct( public function __construct(
EntityManager $entityManager,
SubscribersRepository $subscribersRepository, SubscribersRepository $subscribersRepository,
SegmentsRepository $segmentsRepository, SegmentsRepository $segmentsRepository,
NewslettersRepository $newslettersRepository, NewslettersRepository $newslettersRepository,
ScheduledTasksRepository $scheduledTasksRepository, ScheduledTasksRepository $scheduledTasksRepository,
Scheduler $scheduler Scheduler $scheduler
) { ) {
$this->entityManager = $entityManager;
$this->subscribersRepository = $subscribersRepository; $this->subscribersRepository = $subscribersRepository;
$this->segmentsRepository = $segmentsRepository; $this->segmentsRepository = $segmentsRepository;
$this->newslettersRepository = $newslettersRepository; $this->newslettersRepository = $newslettersRepository;
@@ -47,22 +54,16 @@ class WelcomeScheduler {
$this->scheduler = $scheduler; $this->scheduler = $scheduler;
} }
public function scheduleSubscriberWelcomeNotification($subscriberId, $segments) { public function scheduleSubscriberWelcomeNotification($subscriberId, $segments): void {
$newsletters = $this->newslettersRepository->findActiveByTypes([NewsletterEntity::TYPE_WELCOME]); $newsletters = $this->newslettersRepository->findActiveByTypes([NewsletterEntity::TYPE_WELCOME]);
if (empty($newsletters)) return false;
$result = [];
foreach ($newsletters as $newsletter) { foreach ($newsletters as $newsletter) {
if ( if (
$newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) === 'segment' && $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) === 'segment' &&
in_array($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SEGMENT), $segments) in_array($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SEGMENT), $segments)
) { ) {
$sendingTask = $this->createWelcomeNotificationSendingTask($newsletter, $subscriberId); $this->createWelcomeNotificationSendingTask($newsletter, $subscriberId);
if ($sendingTask) {
$result[] = $sendingTask;
}
} }
} }
return $result ?: false;
} }
public function scheduleWPUserWelcomeNotification( public function scheduleWPUserWelcomeNotification(
@@ -97,7 +98,7 @@ class WelcomeScheduler {
} }
} }
public function createWelcomeNotificationSendingTask(NewsletterEntity $newsletter, $subscriberId) { public function createWelcomeNotificationSendingTask(NewsletterEntity $newsletter, $subscriberId): void {
$subscriber = $this->subscribersRepository->findOneById($subscriberId); $subscriber = $this->subscribersRepository->findOneById($subscriberId);
if (!($subscriber instanceof SubscriberEntity) || $subscriber->getDeletedAt() !== null) { if (!($subscriber instanceof SubscriberEntity) || $subscriber->getDeletedAt() !== null) {
return; return;
@@ -118,28 +119,31 @@ class WelcomeScheduler {
if (!empty($previouslyScheduledNotification)) { if (!empty($previouslyScheduledNotification)) {
return; return;
} }
$sendingTask = SendingTask::create();
$sendingTask->newsletterId = $newsletter->getId(); // task
$sendingTask->setSubscribers([$subscriberId]); $task = new ScheduledTaskEntity();
$sendingTask->status = SendingQueueEntity::STATUS_SCHEDULED; $task->setType(SendingQueue::TASK_TYPE);
$sendingTask->priority = SendingQueueEntity::PRIORITY_HIGH; $task->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED);
$sendingTask->scheduledAt = $this->scheduler->getScheduledTimeWithDelay( $task->setPriority(ScheduledTaskEntity::PRIORITY_HIGH);
$task->setScheduledAt($this->scheduler->getScheduledTimeWithDelay(
$newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE), $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE),
$newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_NUMBER) $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_NUMBER)
); ));
$this->entityManager->persist($task);
$savedSendingTask = $sendingTask->save(); // queue
$queue = new SendingQueueEntity();
$queue->setTask($task);
$queue->setNewsletter($newsletter);
$queue->setSubscribers((string)$subscriberId);
$task->setSendingQueue($queue);
$this->entityManager->persist($queue);
// Refreshing this entity here is needed while we are still using Paris to create the scheduled tasks and queues // task subscriber
// in the code above using \MailPoet\Tasks\Sending class. Doing this should avoid bugs where the loaded entity contain $taskSubscriber = new ScheduledTaskSubscriberEntity($task, $subscriber);
// stale data after the corresponding entry in the database is updated using Paris. This code can be removed once $task->getSubscribers()->add($taskSubscriber);
// https://mailpoet.atlassian.net/browse/MAILPOET-4375 is finished. Currently, if this code is removed a few integration $this->entityManager->persist($taskSubscriber);
// tests fail (see https://app.circleci.com/pipelines/github/mailpoet/mailpoet/14806/workflows/0d441848-16db-461a-88ec-87bed101fe36/jobs/251385/tests#failed-test-0).
$scheduledTaskEntity = $this->scheduledTasksRepository->findOneScheduledByNewsletterAndSubscriber($newsletter, $subscriber);
if ($scheduledTaskEntity instanceof ScheduledTaskEntity) {
$this->scheduledTasksRepository->refresh($scheduledTaskEntity);
}
return $savedSendingTask; $this->entityManager->flush();
} }
} }

View File

@@ -15,8 +15,6 @@ use MailPoet\CustomFields\CustomFieldsRepository;
use MailPoet\Entities\CustomFieldEntity; use MailPoet\Entities\CustomFieldEntity;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Models\ScheduledTask;
use MailPoet\Models\SendingQueue;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler; use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
@@ -26,7 +24,6 @@ use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\SubscriberSaveController; use MailPoet\Subscribers\SubscriberSaveController;
use MailPoet\Subscribers\SubscriberSegmentRepository; use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending;
use MailPoet\Test\DataFactories\Segment as SegmentFactory; use MailPoet\Test\DataFactories\Segment as SegmentFactory;
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory; use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
use MailPoetVendor\Carbon\Carbon; use MailPoetVendor\Carbon\Carbon;
@@ -610,15 +607,13 @@ class SubscribersTest extends \MailPoetTest {
public function testItThrowsIfWelcomeEmailFails() { public function testItThrowsIfWelcomeEmailFails() {
$settings = SettingsController::getInstance(); $settings = SettingsController::getInstance();
$settings->set('signup_confirmation.enabled', false); $settings->set('signup_confirmation.enabled', false);
$task = ScheduledTask::create();
$task->type = 'sending';
$task->setError("Big Error");
$sendingStub = Sending::create($task, SendingQueue::create());
$segment = $this->getSegment(); $segment = $this->getSegment();
$subscribers = Stub::copy($this->getSubscribers(), [ $subscribers = Stub::copy($this->getSubscribers(), [
'welcomeScheduler' => $this->make('MailPoet\Newsletter\Scheduler\WelcomeScheduler', [ 'welcomeScheduler' => $this->make('MailPoet\Newsletter\Scheduler\WelcomeScheduler', [
'scheduleSubscriberWelcomeNotification' => [$sendingStub], 'scheduleSubscriberWelcomeNotification' => function () {
throw new \Exception();
},
]), ]),
]); ]);
$API = $this->getApi($subscribers); $API = $this->getApi($subscribers);

View File

@@ -9,18 +9,23 @@ use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Newsletter\NewslettersRepository; use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository; use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending as SendingTask; use MailPoet\Tasks\Sending as SendingTask;
use MailPoet\Test\DataFactories\NewsletterOption; use MailPoet\Test\DataFactories\NewsletterOption;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon; use MailPoetVendor\Carbon\Carbon;
use MailPoetVendor\Doctrine\ORM\EntityManager;
class WelcomeTest extends \MailPoetTest { class WelcomeTest extends \MailPoetTest {
/** @var SegmentsRepository */ /** @var SegmentsRepository */
private $segmentRepository; private $segmentRepository;
/** @var SendingQueuesRepository */
private $sendingQueuesRepository;
/** @var WelcomeScheduler */ /** @var WelcomeScheduler */
private $welcomeScheduler; private $welcomeScheduler;
@@ -39,6 +44,7 @@ class WelcomeTest extends \MailPoetTest {
public function _before() { public function _before() {
parent::_before(); parent::_before();
$this->segmentRepository = $this->diContainer->get(SegmentsRepository::class); $this->segmentRepository = $this->diContainer->get(SegmentsRepository::class);
$this->sendingQueuesRepository = $this->diContainer->get(SendingQueuesRepository::class);
$this->welcomeScheduler = $this->diContainer->get(WelcomeScheduler::class); $this->welcomeScheduler = $this->diContainer->get(WelcomeScheduler::class);
$this->subscriber = $this->createSubscriber('welcome_test_1@example.com'); $this->subscriber = $this->createSubscriber('welcome_test_1@example.com');
$this->segment = $this->segmentRepository->createOrUpdate('welcome_segment'); $this->segment = $this->segmentRepository->createOrUpdate('welcome_segment');
@@ -203,7 +209,7 @@ class WelcomeTest extends \MailPoetTest {
$segment3 = $this->segmentRepository->createOrUpdate('Segment 3'); $segment3 = $this->segmentRepository->createOrUpdate('Segment 3');
// queue is created and scheduled for delivery one day later // queue is created and scheduled for delivery one day later
$result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification( $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
$this->subscriber->getId(), $this->subscriber->getId(),
$segments = [ $segments = [
$this->segment->getId(), $this->segment->getId(),
@@ -222,7 +228,10 @@ class WelcomeTest extends \MailPoetTest {
$this->assertInstanceOf(\DateTimeInterface::class, $scheduledAt); $this->assertInstanceOf(\DateTimeInterface::class, $scheduledAt);
verify($scheduledAt->format('Y-m-d H:i')) verify($scheduledAt->format('Y-m-d H:i'))
->equals($currentTime->addDay()->format('Y-m-d H:i')); ->equals($currentTime->addDay()->format('Y-m-d H:i'));
verify($result[0]->id())->equals($queue->getId());
$queues = $this->sendingQueuesRepository->findAll();
$this->assertCount(1, $queues);
$this->assertSame($queue, $queues[0]);
} }
public function testItDoesNotScheduleWelcomeNotificationWhenSubscriberIsInTrash() { public function testItDoesNotScheduleWelcomeNotificationWhenSubscriberIsInTrash() {
@@ -239,11 +248,13 @@ class WelcomeTest extends \MailPoetTest {
$trashedSubscriber->setDeletedAt(Carbon::now()); $trashedSubscriber->setDeletedAt(Carbon::now());
$this->entityManager->flush(); $this->entityManager->flush();
// subscriber welcome notification is not scheduled // subscriber welcome notification is not scheduled
$result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification( $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
$trashedSubscriber->getId(), $trashedSubscriber->getId(),
$segments = [$this->segment->getId()] $segments = [$this->segment->getId()]
); );
verify($result)->false();
$queues = $this->sendingQueuesRepository->findAll();
$this->assertEmpty($queues);
} }
public function testItDoesNotScheduleWelcomeNotificationWhenSegmentIsInTrash() { public function testItDoesNotScheduleWelcomeNotificationWhenSegmentIsInTrash() {
@@ -259,27 +270,31 @@ class WelcomeTest extends \MailPoetTest {
$this->segment->setDeletedAt(Carbon::now()); $this->segment->setDeletedAt(Carbon::now());
$this->entityManager->flush(); $this->entityManager->flush();
// subscriber welcome notification is not scheduled // subscriber welcome notification is not scheduled
$result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification( $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
$this->subscriber->getId(), $this->subscriber->getId(),
$segments = [$this->segment->getId()] $segments = [$this->segment->getId()]
); );
verify($result)->false();
$queues = $this->sendingQueuesRepository->findAll();
$this->assertEmpty($queues);
} }
public function itDoesNotScheduleAnythingWhenNewsletterDoesNotExist() { public function itDoesNotScheduleAnythingWhenNewsletterDoesNotExist() {
// subscriber welcome notification is not scheduled // subscriber welcome notification is not scheduled
$result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification( $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
$this->subscriber->getId(), $this->subscriber->getId(),
$segments = [] $segments = []
); );
verify($result)->false(); $queues = $this->sendingQueuesRepository->findAll();
$this->assertEmpty($queues);
// WP user welcome notification is not scheduled // WP user welcome notification is not scheduled
$result = $this->welcomeScheduler->scheduleWPUserWelcomeNotification( $this->welcomeScheduler->scheduleWPUserWelcomeNotification(
$this->subscriber->getId(), $this->subscriber->getId(),
$wpUser = ['roles' => ['editor']] $wpUser = ['roles' => ['editor']]
); );
verify($result)->false(); $queues = $this->sendingQueuesRepository->findAll();
$this->assertEmpty($queues);
} }
public function testItDoesNotScheduleWPUserWelcomeNotificationWhenRoleHasNotChanged() { public function testItDoesNotScheduleWPUserWelcomeNotificationWhenRoleHasNotChanged() {
@@ -453,6 +468,7 @@ class WelcomeTest extends \MailPoetTest {
->method('currentTime') ->method('currentTime')
->willReturn($currentTime->getTimestamp()); ->willReturn($currentTime->getTimestamp());
return new WelcomeScheduler( return new WelcomeScheduler(
$this->diContainer->get(EntityManager::class),
$this->diContainer->get(SubscribersRepository::class), $this->diContainer->get(SubscribersRepository::class),
$this->segmentRepository, $this->segmentRepository,
$this->diContainer->get(NewslettersRepository::class), $this->diContainer->get(NewslettersRepository::class),