diff --git a/mailpoet/lib/AdminPages/Pages/Help.php b/mailpoet/lib/AdminPages/Pages/Help.php index f4006cb430..4fe420c8b4 100644 --- a/mailpoet/lib/AdminPages/Pages/Help.php +++ b/mailpoet/lib/AdminPages/Pages/Help.php @@ -6,13 +6,16 @@ use MailPoet\AdminPages\PageRenderer; use MailPoet\Cron\ActionScheduler\Actions\DaemonRun; use MailPoet\Cron\ActionScheduler\Actions\DaemonTrigger; use MailPoet\Cron\CronHelper; +use MailPoet\Entities\ScheduledTaskEntity; use MailPoet\Helpscout\Beacon; use MailPoet\Mailer\MailerLog; use MailPoet\Newsletter\Sending\ScheduledTasksRepository; +use MailPoet\Newsletter\Sending\SendingQueuesRepository; use MailPoet\Router\Endpoints\CronDaemon; use MailPoet\Services\Bridge; use MailPoet\Tasks\Sending; use MailPoet\Tasks\State; +use MailPoet\WP\DateTime; class Help { /** @var PageRenderer */ @@ -33,13 +36,17 @@ class Help { /*** @var ScheduledTasksRepository */ private $scheduledTasksRepository; + /*** @var SendingQueuesRepository */ + private $sendingQueuesRepository; + public function __construct( PageRenderer $pageRenderer, State $tasksState, CronHelper $cronHelper, Beacon $helpscoutBeacon, Bridge $bridge, - ScheduledTasksRepository $scheduledTasksRepository + ScheduledTasksRepository $scheduledTasksRepository, + SendingQueuesRepository $sendingQueuesRepository ) { $this->pageRenderer = $pageRenderer; $this->tasksState = $tasksState; @@ -47,6 +54,7 @@ class Help { $this->helpscoutBeacon = $helpscoutBeacon; $this->bridge = $bridge; $this->scheduledTasksRepository = $scheduledTasksRepository; + $this->sendingQueuesRepository = $sendingQueuesRepository; } public function render() { @@ -76,7 +84,9 @@ class Help { ]; $systemStatusData['cronStatus']['accessible'] = $this->cronHelper->isDaemonAccessible(); $systemStatusData['queueStatus']['tasksStatusCounts'] = $this->scheduledTasksRepository->getCountsPerStatus(); - $systemStatusData['queueStatus']['latestTasks'] = $this->tasksState->getLatestTasks(Sending::TASK_TYPE); + $systemStatusData['queueStatus']['latestTasks'] = array_map(function ($task) { + return $this->buildTaskData($task); + }, $this->scheduledTasksRepository->getLatestTasks(Sending::TASK_TYPE)); $this->pageRenderer->displayPage( 'help.html', [ @@ -117,4 +127,33 @@ class Help { } return null; } + + private function buildTaskData(ScheduledTaskEntity $task): array { + $queue = $newsletter = null; + if ($task->getType() === Sending::TASK_TYPE) { + $queue = $this->sendingQueuesRepository->findOneBy(['task' => $task->getId()]); + $newsletter = $queue ? $queue->getNewsletter() : null; + } + return [ + 'id' => $task->getId(), + 'type' => $task->getType(), + 'priority' => $task->getPriority(), + 'updated_at' => $task->getUpdatedAt()->format(DateTime::DEFAULT_DATE_TIME_FORMAT), + 'scheduled_at' => $task->getScheduledAt() ? + $task->getScheduledAt()->format(DateTime::DEFAULT_DATE_TIME_FORMAT) + : null, + 'status' => $task->getStatus(), + 'newsletter' => $queue && $newsletter ? [ + 'newsletter_id' => $newsletter->getId(), + 'queue_id' => $queue->getId(), + 'subject' => $queue->getNewsletterRenderedSubject() ?: $newsletter->getSubject(), + 'preview_url' => $this->newsletterUrl->getViewInBrowserUrl($newsletter, null, $queue), + ] : [ + 'newsletter_id' => null, + 'queue_id' => null, + 'subject' => null, + 'preview_url' => null, + ], + ]; + } } diff --git a/mailpoet/lib/Newsletter/Sending/ScheduledTasksRepository.php b/mailpoet/lib/Newsletter/Sending/ScheduledTasksRepository.php index a25059fdce..26a7635683 100644 --- a/mailpoet/lib/Newsletter/Sending/ScheduledTasksRepository.php +++ b/mailpoet/lib/Newsletter/Sending/ScheduledTasksRepository.php @@ -2,6 +2,7 @@ namespace MailPoet\Newsletter\Sending; +use MailPoet\Cron\Workers\Scheduler; use MailPoet\Cron\Workers\SendingQueue\SendingQueue; use MailPoet\Doctrine\Repository; use MailPoet\Entities\NewsletterEntity; @@ -154,6 +155,43 @@ class ScheduledTasksRepository extends Repository { return $stats; } + /** + * @param string|null $type + * @param array $statuses + * @param int $limit + * @return array + */ + public function getLatestTasks( + $type = null, + $statuses = [ + ScheduledTaskEntity::STATUS_COMPLETED, + ScheduledTaskEntity::STATUS_SCHEDULED, + ScheduledTaskEntity::VIRTUAL_STATUS_RUNNING, + ], + $limit = Scheduler::TASK_BATCH_SIZE + ) { + + $tasksQuery = $this->doctrineRepository->createQueryBuilder('st') + ->select('st') + ->where('st.deletedAt IS NULL') + ->where('st.status IN (:statuses)') + ->setParameter('statuses', $statuses) + ->setMaxResults($limit); + + if ($type) { + $tasksQuery = $tasksQuery->andWhere('st.type = :type') + ->setParameter('type', $type); + } + + if (in_array(ScheduledTaskEntity::VIRTUAL_STATUS_RUNNING, $statuses)) { + $tasksQuery = $tasksQuery->orWhere('st.status IS NULL'); + } + + return $tasksQuery + ->getQuery() + ->getResult(); + } + /** * @return ScheduledTaskEntity[] */ diff --git a/mailpoet/tests/integration/Newsletter/Sending/ScheduledTasksRepositoryTest.php b/mailpoet/tests/integration/Newsletter/Sending/ScheduledTasksRepositoryTest.php index 62fada1f43..7ba01f4e96 100644 --- a/mailpoet/tests/integration/Newsletter/Sending/ScheduledTasksRepositoryTest.php +++ b/mailpoet/tests/integration/Newsletter/Sending/ScheduledTasksRepositoryTest.php @@ -2,8 +2,12 @@ namespace MailPoet\Newsletter\Sending; +use MailPoet\Cron\Workers\SendingQueue\Migration; +use MailPoet\Entities\NewsletterEntity; use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker; use MailPoet\Entities\ScheduledTaskEntity; +use MailPoet\Entities\SendingQueueEntity; +use MailPoet\Tasks\Sending as SendingTask; use MailPoet\Test\DataFactories\ScheduledTask as ScheduledTaskFactory; use MailPoet\Test\DataFactories\SendingQueue; use MailPoetVendor\Carbon\Carbon; @@ -108,7 +112,50 @@ class ScheduledTasksRepositoryTest extends \MailPoetTest { ScheduledTaskEntity::STATUS_COMPLETED => 0, ], $counts); } + + public function testItCanFetchBasicTasksData() { + $this->scheduledTaskFactory->create(SendingTask::TASK_TYPE, ScheduledTaskEntity::STATUS_SCHEDULED, Carbon::now()->addDay()); + $this->scheduledTaskFactory->create(Migration::TASK_TYPE, ScheduledTaskEntity::VIRTUAL_STATUS_RUNNING, Carbon::now()->addDay()); + $data = $this->repository->getLatestTasks(); + expect(count($data))->equals(2); + $ids = array_map(function ($d){ return $d->getId(); }, $data); + $types = array_map(function ($d){ return $d->getType(); }, $data); + $this->assertContains(1, $ids); + $this->assertContains(2, $ids); + $this->assertContains(SendingTask::TASK_TYPE, $types); + $this->assertContains(Migration::TASK_TYPE, $types); + expect(is_int($data[1]->getPriority()))->true(); + expect($data[1]->getUpdatedAt())->isInstanceOf(\DateTimeInterface::class); + expect($data[1]->getStatus())->notEmpty(); + expect($data[0])->isInstanceOf(ScheduledTaskEntity::class); + expect($data[1])->isInstanceOf(ScheduledTaskEntity::class); + } + + public function testItCanFilterTasksByType() { + $this->scheduledTaskFactory->create(SendingTask::TASK_TYPE, ScheduledTaskEntity::STATUS_COMPLETED, Carbon::now()->addDay()); + $this->scheduledTaskFactory->create(Migration::TASK_TYPE, ScheduledTaskEntity::STATUS_COMPLETED, Carbon::now()->addDay()); + $data = $this->repository->getLatestTasks(Migration::TASK_TYPE); + expect(count($data))->equals(1); + expect($data[0]->getType())->equals(Migration::TASK_TYPE); + } + + public function testItCanFilterTasksByStatus() { + $this->scheduledTaskFactory->create(SendingTask::TASK_TYPE, ScheduledTaskEntity::STATUS_COMPLETED, Carbon::now()->addDay()); + $this->scheduledTaskFactory->create(SendingTask::TASK_TYPE, ScheduledTaskEntity::STATUS_PAUSED, Carbon::now()->addDay()); + $data = $this->repository->getLatestTasks(null, [ScheduledTaskEntity::STATUS_COMPLETED]); + expect(count($data))->equals(1); + expect($data[0]->getStatus())->equals(ScheduledTaskEntity::STATUS_COMPLETED); + } + + public function testItDoesNotFailForSendingTaskWithoutQueue() { + $this->scheduledTaskFactory->create(SendingTask::TASK_TYPE, 'any', Carbon::now()->addDay()); + $data = $this->repository->getLatestTasks(); + expect(count($data))->equals(1); + } + public function cleanup() { $this->truncateEntity(ScheduledTaskEntity::class); + $this->truncateEntity(NewsletterEntity::class); + $this->truncateEntity(SendingQueueEntity::class); } }