geno/wp-content/plugins/mailpoet/lib/API/JSON/v1/SendingQueue.php
2024-02-01 11:54:18 +00:00

287 lines
9.8 KiB
PHP

<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\API\JSON\v1;
if (!defined('ABSPATH')) exit;
use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError;
use MailPoet\API\JSON\Response;
use MailPoet\API\JSON\ResponseBuilders\SendingQueuesResponseBuilder;
use MailPoet\Config\AccessControl;
use MailPoet\Cron\ActionScheduler\Actions\DaemonTrigger;
use MailPoet\Cron\CronTrigger;
use MailPoet\Cron\Triggers\WordPress;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Mailer\MailerFactory;
use MailPoet\Models\SendingQueue as SendingQueueModel;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\NewsletterValidator;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\Segments\SubscribersFinder;
use MailPoet\Settings\SettingsController;
use MailPoet\Tasks\Sending as SendingTask;
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
use MailPoetVendor\Carbon\Carbon;
class SendingQueue extends APIEndpoint {
public $permissions = [
'global' => AccessControl::PERMISSION_MANAGE_EMAILS,
];
/** @var SubscribersFeature */
private $subscribersFeature;
/** @var SubscribersFinder */
private $subscribersFinder;
/** @var NewslettersRepository */
private $newsletterRepository;
/** @var SendingQueuesRepository */
private $sendingQueuesRepository;
/** @var ScheduledTasksRepository */
private $scheduledTasksRepository;
/** @var MailerFactory */
private $mailerFactory;
/** @var NewsletterValidator */
private $newsletterValidator;
/** @var Scheduler */
private $scheduler;
/** @var SettingsController */
private $settings;
/** @var DaemonTrigger */
private $actionSchedulerDaemonTriggerAction;
/** @var SendingQueuesResponseBuilder */
private $sendingQueuesResponseBuilder;
public function __construct(
SubscribersFeature $subscribersFeature,
NewslettersRepository $newsletterRepository,
SendingQueuesRepository $sendingQueuesRepository,
SubscribersFinder $subscribersFinder,
ScheduledTasksRepository $scheduledTasksRepository,
MailerFactory $mailerFactory,
Scheduler $scheduler,
SettingsController $settings,
DaemonTrigger $actionSchedulerDaemonTriggerAction,
NewsletterValidator $newsletterValidator,
SendingQueuesResponseBuilder $sendingQueuesResponseBuilder
) {
$this->subscribersFeature = $subscribersFeature;
$this->subscribersFinder = $subscribersFinder;
$this->newsletterRepository = $newsletterRepository;
$this->sendingQueuesRepository = $sendingQueuesRepository;
$this->scheduledTasksRepository = $scheduledTasksRepository;
$this->mailerFactory = $mailerFactory;
$this->scheduler = $scheduler;
$this->settings = $settings;
$this->actionSchedulerDaemonTriggerAction = $actionSchedulerDaemonTriggerAction;
$this->newsletterValidator = $newsletterValidator;
$this->sendingQueuesResponseBuilder = $sendingQueuesResponseBuilder;
}
public function add($data = []) {
if ($this->subscribersFeature->check()) {
return $this->errorResponse([
APIError::FORBIDDEN => __('Subscribers limit reached.', 'mailpoet'),
], [], Response::STATUS_FORBIDDEN);
}
$newsletterId = (isset($data['newsletter_id'])
? (int)$data['newsletter_id']
: false
);
// check that the newsletter exists
$newsletter = $this->newsletterRepository->findOneById($newsletterId);
$this->newsletterRepository->prefetchOptions([$newsletter]);
if (!$newsletter instanceof NewsletterEntity) {
return $this->errorResponse([
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet'),
]);
}
$validationError = $this->newsletterValidator->validate($newsletter);
if ($validationError) {
return $this->errorResponse([
APIError::BAD_REQUEST => $validationError,
]);
}
// check that the sending method has been configured properly by verifying that default mailer can be build
try {
$this->mailerFactory->getDefaultMailer();
} catch (\Exception $e) {
return $this->errorResponse([
$e->getCode() => $e->getMessage(),
]);
}
// add newsletter to the sending queue
$queue = SendingQueueModel::joinWithTasks()
->where('queues.newsletter_id', $newsletter->getId())
->whereNull('tasks.status')
->findOne();
if (!empty($queue)) {
return $this->errorResponse([
APIError::NOT_FOUND => __('This newsletter is already being sent.', 'mailpoet'),
]);
}
$scheduledQueue = SendingQueueModel::joinWithTasks()
->where('queues.newsletter_id', $newsletter->getId())
->where('tasks.status', SendingQueueModel::STATUS_SCHEDULED)
->findOne();
if ($scheduledQueue instanceof SendingQueueModel) {
$queue = SendingTask::createFromQueue($scheduledQueue);
} else {
$queue = SendingTask::create();
$queue->newsletterId = $newsletter->getId();
}
$taskModel = $queue->task();
$taskEntity = $this->scheduledTasksRepository->findOneById($taskModel->id);
if (!$taskEntity instanceof ScheduledTaskEntity) {
return $this->errorResponse([
APIError::NOT_FOUND => __('Unable to find scheduled task associated with this newsletter.', 'mailpoet'),
]);
}
WordPress::resetRunInterval();
if ((bool)$newsletter->getOptionValue('isScheduled')) {
// set newsletter status
$newsletter->setStatus(NewsletterEntity::STATUS_SCHEDULED);
// set queue status
$scheduledAt = $this->scheduler->formatDatetimeString($newsletter->getOptionValue('scheduledAt'));
$queue->status = SendingQueueModel::STATUS_SCHEDULED;
$queue->scheduledAt = $scheduledAt;
// we need to refresh the entity here for now while this method still uses Paris
$taskEntity->setStatus(SendingQueueModel::STATUS_SCHEDULED);
$taskEntity->setScheduledAt(new Carbon($scheduledAt));
} else {
$segments = $newsletter->getSegmentIds();
$subscribersCount = $this->subscribersFinder->addSubscribersToTaskFromSegments($taskEntity, $segments, $newsletter->getFilterSegmentId());
if (!$subscribersCount) {
return $this->errorResponse([
APIError::UNKNOWN => __('There are no subscribers in that list!', 'mailpoet'),
]);
}
$queue->updateCount();
$queue->status = null;
$queue->scheduledAt = null;
// we need to refresh the entity here for now while this method still uses Paris
$taskEntity->setStatus(null);
$taskEntity->setScheduledAt(null);
// set newsletter status
$newsletter->setStatus(NewsletterEntity::STATUS_SENDING);
}
$queue->save();
$this->newsletterRepository->flush();
// refreshing is needed while this method still uses Paris
$this->newsletterRepository->refresh($newsletter);
$latestQueue = $newsletter->getLatestQueue();
if ($latestQueue instanceof SendingQueueEntity) {
$this->sendingQueuesRepository->refresh($latestQueue);
}
$errors = $queue->getErrors();
if (!empty($errors)) {
return $this->errorResponse($errors);
} else {
$this->triggerSending($newsletter);
return $this->successResponse(
($newsletter->getLatestQueue() instanceof SendingQueueEntity) ? $this->sendingQueuesResponseBuilder->build($newsletter->getLatestQueue()) : null
);
}
}
public function pause($data = []) {
$newsletterId = (isset($data['newsletter_id'])
? (int)$data['newsletter_id']
: false
);
$newsletter = $this->newsletterRepository->findOneById($newsletterId);
if ($newsletter instanceof NewsletterEntity) {
$queue = $newsletter->getLastUpdatedQueue();
if (!$queue instanceof SendingQueueEntity) {
return $this->errorResponse([
APIError::UNKNOWN => __('This newsletter has not been sent yet.', 'mailpoet'),
]);
} else {
$this->sendingQueuesRepository->pause($queue);
return $this->successResponse();
}
} else {
return $this->errorResponse([
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet'),
]);
}
}
public function resume($data = []) {
if ($this->subscribersFeature->check()) {
return $this->errorResponse([
APIError::FORBIDDEN => __('Subscribers limit reached.', 'mailpoet'),
], [], Response::STATUS_FORBIDDEN);
}
$newsletterId = (isset($data['newsletter_id'])
? (int)$data['newsletter_id']
: false
);
$newsletter = $this->newsletterRepository->findOneById($newsletterId);
if ($newsletter instanceof NewsletterEntity) {
$queue = $newsletter->getLastUpdatedQueue();
if (!$queue instanceof SendingQueueEntity) {
return $this->errorResponse([
APIError::UNKNOWN => __('This newsletter has not been sent yet.', 'mailpoet'),
]);
} else {
$this->sendingQueuesRepository->resume($queue);
$this->triggerSending($newsletter);
return $this->successResponse();
}
} else {
return $this->errorResponse([
APIError::NOT_FOUND => __('This newsletter does not exist.', 'mailpoet'),
]);
}
}
/**
* In case the newsletter was switched to sending trigger the background job immediately.
* This is done so that user immediately sees that email is sending and doesn't have to wait on WP Cron to start it.
*/
private function triggerSending(NewsletterEntity $newsletter): void {
if (
$newsletter->getStatus() === NewsletterEntity::STATUS_SENDING
&& $this->settings->get('cron_trigger.method') === CronTrigger::METHOD_ACTION_SCHEDULER
) {
$this->actionSchedulerDaemonTriggerAction->process();
}
}
}