Reschedules past due scheduled queues when reactivating notification

This commit is contained in:
Vlad
2017-08-24 20:57:43 -04:00
committed by pavel-mailpoet
parent 544bf0ddfd
commit c1e542cb5a
4 changed files with 85 additions and 7 deletions

View File

@ -1,6 +1,7 @@
<?php <?php
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use Carbon\Carbon;
use MailPoet\API\JSON\Endpoint as APIEndpoint; use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\Listing; use MailPoet\Listing;
@ -134,7 +135,7 @@ class Newsletters extends APIEndpoint {
} }
$id = (isset($data['id'])) ? (int)$data['id'] : false; $id = (isset($data['id'])) ? (int)$data['id'] : false;
$newsletter = Newsletter::findOne($id); $newsletter = Newsletter::filter('filterWithOptions')->findOne($id);
if($newsletter === false) { if($newsletter === false) {
return $this->errorResponse(array( return $this->errorResponse(array(
@ -147,11 +148,22 @@ class Newsletters extends APIEndpoint {
if(!empty($errors)) { if(!empty($errors)) {
return $this->errorResponse($errors); return $this->errorResponse($errors);
} else {
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray()
);
} }
// if there are past due notifications, reschedule them for the next send date
if($newsletter->type === Newsletter::TYPE_NOTIFICATION && $status === Newsletter::STATUS_ACTIVE) {
$next_run_date = Scheduler::getNextRunDate($newsletter->schedule);
$newsletter->queue()
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
->where('status', SendingQueue::STATUS_SCHEDULED)
->findResultSet()
->set('scheduled_at', $next_run_date)
->save();
}
return $this->successResponse(
Newsletter::findOne($newsletter->id)->asArray()
);
} }
function restore($data = array()) { function restore($data = array()) {

View File

@ -176,6 +176,18 @@ class Scheduler {
return $next_run_date; return $next_run_date;
} }
static function getPreviousRunDate($schedule, $from_timestamp = false) {
$from_timestamp = ($from_timestamp) ? $from_timestamp : current_time('timestamp');
try {
$schedule = \Cron\CronExpression::factory($schedule);
$previous_run_date = $schedule->getPreviousRunDate(Carbon::createFromTimestamp($from_timestamp))
->format('Y-m-d H:i:s');
} catch(\Exception $e) {
$previous_run_date = false;
}
return $previous_run_date;
}
static function getNewsletters($type) { static function getNewsletters($type) {
return Newsletter::getPublished() return Newsletter::getPublished()
->filter('filterType', $type) ->filter('filterType', $type)

View File

@ -8,6 +8,7 @@ use Helper\WordPressHooks as WPHooksHelper;
use MailPoet\API\JSON\v1\Newsletters; use MailPoet\API\JSON\v1\Newsletters;
use MailPoet\API\JSON\Response as APIResponse; use MailPoet\API\JSON\Response as APIResponse;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterOption;
use MailPoet\Models\NewsletterOptionField; use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterSegment; use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\Segment; use MailPoet\Models\Segment;
@ -140,7 +141,6 @@ class NewslettersTest extends \MailPoetTest {
expect(WPHooksHelper::isActionDone($hook_name))->true(); expect(WPHooksHelper::isActionDone($hook_name))->true();
expect(WPHooksHelper::getActionDone($hook_name)[0] instanceof Newsletter)->true(); expect(WPHooksHelper::getActionDone($hook_name)[0] instanceof Newsletter)->true();
$invalid_data = array( $invalid_data = array(
'subject' => 'Missing newsletter type' 'subject' => 'Missing newsletter type'
); );
@ -357,6 +357,51 @@ class NewslettersTest extends \MailPoetTest {
->equals('This newsletter does not exist.'); ->equals('This newsletter does not exist.');
} }
function testItReschedulesPastDuePostNotificationsWhenStatusIsSetBackToActive() {
$newsletter_option_field = NewsletterOptionField::create();
$newsletter_option_field->name = 'schedule';
$newsletter_option_field->newsletter_type = Newsletter::TYPE_NOTIFICATION;
$newsletter_option_field->save();
$schedule = sprintf('0 %d * * *', Carbon::createFromTimestamp(current_time('timestamp'))->hour); // every day at current hour
$random_future_date = Carbon::createFromTimestamp(current_time('timestamp'))->addDays(10)->format('Y-m-d H:i:s'); // 10 days from now
$newsletter_option = NewsletterOption::createOrUpdate(
array(
'newsletter_id' => $this->post_notification->id,
'option_field_id' => $newsletter_option_field->id,
'value' => $schedule
)
);
$sending_queue_1 = SendingQueue::create();
$sending_queue_1->newsletter_id = $this->post_notification->id;
$sending_queue_1->scheduled_at = Scheduler::getPreviousRunDate($schedule);
$sending_queue_1->status = SendingQueue::STATUS_SCHEDULED;
$sending_queue_1->save();
$sending_queue_2 = SendingQueue::create();
$sending_queue_2->newsletter_id = $this->post_notification->id;
$sending_queue_2->scheduled_at = $random_future_date;
$sending_queue_2->status = SendingQueue::STATUS_SCHEDULED;
$sending_queue_2->save();
$sending_queue_3 = SendingQueue::create();
$sending_queue_3->newsletter_id = $this->post_notification->id;
$sending_queue_3->scheduled_at = Scheduler::getPreviousRunDate($schedule);
$sending_queue_3->save();
$router = new Newsletters();
$response = $router->setStatus(
array(
'id' => $this->post_notification->id,
'status' => Newsletter::STATUS_ACTIVE
)
);
$sending_queues = SendingQueue::findMany();
// previously scheduled notification is rescheduled for future date
expect($sending_queues[0]->scheduled_at)->equals(Scheduler::getNextRunDate($schedule));
// future scheduled notifications are left intact
expect($sending_queues[1]->scheduled_at)->equals($random_future_date);
// previously unscheduled (e.g., sent/sending) notifications are left intact
expect($sending_queues[2]->scheduled_at)->equals(Scheduler::getPreviousRunDate($schedule));
}
function testItCanRestoreANewsletter() { function testItCanRestoreANewsletter() {
$this->newsletter->trash(); $this->newsletter->trash();

View File

@ -25,7 +25,7 @@ class SchedulerTest extends \MailPoetTest {
function testItGetsActiveNewslettersFilteredByType() { function testItGetsActiveNewslettersFilteredByType() {
$newsletter = $this->_createNewsletter($type = Newsletter::TYPE_WELCOME); $newsletter = $this->_createNewsletter($type = Newsletter::TYPE_WELCOME);
// no newsletters wtih type "notification" should be found // no newsletters with type "notification" should be found
expect(Scheduler::getNewsletters(Newsletter::TYPE_NOTIFICATION))->isEmpty(); expect(Scheduler::getNewsletters(Newsletter::TYPE_NOTIFICATION))->isEmpty();
// one newsletter with type "welcome" should be found // one newsletter with type "welcome" should be found
@ -41,6 +41,15 @@ class SchedulerTest extends \MailPoetTest {
expect(Scheduler::getNextRunDate('invalid CRON expression'))->false(); expect(Scheduler::getNextRunDate('invalid CRON expression'))->false();
} }
function testItCanGetPreviousRunDate() {
// it accepts cron syntax and returns previous run date
$current_time = Carbon::createFromTimestamp(current_time('timestamp'));
expect(Scheduler::getPreviousRunDate('* * * * *'))
->equals($current_time->subMinute()->format('Y-m-d H:i:00'));
// when invalid CRON expression is used, false response is returned
expect(Scheduler::getPreviousRunDate('invalid CRON expression'))->false();
}
function testItFormatsDatetimeString() { function testItFormatsDatetimeString() {
expect(Scheduler::formatDatetimeString('April 20, 2016 4pm')) expect(Scheduler::formatDatetimeString('April 20, 2016 4pm'))
->equals('2016-04-20 16:00:00'); ->equals('2016-04-20 16:00:00');