- Places supervisor/daemon/worker under the new Cron class

- Updates endpoints
- Integrates queue worker with MailPoet mailer
- Fixes script activation check logic
This commit is contained in:
MrCasual
2015-12-02 22:48:15 -05:00
parent 48fbce22e7
commit d2e5fb89c2
31 changed files with 700 additions and 299 deletions

View File

@ -2,22 +2,20 @@ define(
[
'react',
'react-dom',
'mailpoet',
'classnames'
'mailpoet'
],
function (
React,
ReactDOM,
MailPoet,
classNames
MailPoet
) {
var QueueControl = React.createClass({
var CronControl = React.createClass({
getInitialState: function () {
return (queueDaemon) ? queueDaemon : null;
return (cronDaemon) ? cronDaemon : null;
},
getDaemonData: function () {
MailPoet.Ajax.post({
endpoint: 'queue',
endpoint: 'cron',
action: 'getDaemonStatus'
}).done(function (response) {
jQuery('.button-primary').removeClass('disabled');
@ -37,7 +35,7 @@ define(
controlDaemon: function (action) {
jQuery('.button-primary').addClass('disabled');
MailPoet.Ajax.post({
endpoint: 'queue',
endpoint: 'cron',
action: 'controlDaemon',
data: {'action': action}
}).done(function (response) {
@ -60,7 +58,7 @@ define(
return (
<div>
<div>
Queue daemon is running.
Cron daemon is running.
<br/>
<br/>
It was started
@ -89,11 +87,11 @@ define(
}
}
});
let container = document.getElementById('queue_container');
let container = document.getElementById('cron_container');
if (container) {
ReactDOM.render(
<QueueControl />,
document.getElementById('queue_status')
<CronControl />,
document.getElementById('cron_status')
)
}
}

View File

@ -94,7 +94,7 @@ define(
],
handleSend: function() {
MailPoet.Ajax.post({
endpoint: 'queue',
endpoint: 'sendingQueue',
action: 'addQueue',
data: {
newsletter_id: this.props.params.id,

View File

@ -77,10 +77,15 @@ class Env {
static function isPluginActivated() {
$activatesPlugins = get_option('active_plugins');
$isActivated =
$isActivated = (
in_array(
sprintf('%s/%s.php', basename(self::$path), self::$plugin_name),
$activatesPlugins
) ||
in_array(
sprintf('%s/%s.php', explode('/', plugin_basename(__FILE__))[0], self::$plugin_name),
$activatesPlugins
)
);
return ($isActivated) ? true : false;
}

View File

@ -2,7 +2,7 @@
namespace MailPoet\Config;
use MailPoet\Models;
use MailPoet\Queue\Supervisor;
use MailPoet\Cron\Supervisor;
use MailPoet\Router;
if(!defined('ABSPATH')) exit;
@ -55,7 +55,7 @@ class Initializer {
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
$newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields';
$newsletter_option = Env::$db_prefix . 'newsletter_option';
$queues = Env::$db_prefix . 'queues';
$sending_queue = Env::$db_prefix . 'sending_queue';
$newsletter_statistics = Env::$db_prefix . 'newsletter_statistics';
define('MP_SUBSCRIBERS_TABLE', $subscribers);
@ -72,7 +72,7 @@ class Initializer {
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
define('MP_QUEUES_TABLE', $queues);
define('MP_SENDING_QUEUE_TABLE', $sending_queue);
define('MP_NEWSLETTER_STATISTICS_TABLE', $newsletter_statistics);
}

View File

@ -172,13 +172,13 @@ class Menu {
add_submenu_page(
'mailpoet',
__('Queue'),
__('Queue'),
__('Cron'),
__('Cron'),
'manage_options',
'mailpoet-queue',
'mailpoet-cron',
array(
$this,
'queue'
'cron'
)
);
}
@ -374,9 +374,9 @@ class Menu {
echo $this->renderer->render('form/editor.html', $data);
}
function queue() {
$daemon = new \MailPoet\Queue\BootStrapMenu();
function cron() {
$daemon = new \MailPoet\Cron\BootStrapMenu();
$data['daemon'] = json_encode($daemon->bootstrap());
echo $this->renderer->render('queue.html', $data);
echo $this->renderer->render('cron.html', $data);
}
}

View File

@ -21,7 +21,7 @@ class Migrator {
'subscriber_custom_field',
'newsletter_option_fields',
'newsletter_option',
'queues',
'sending_queue',
'newsletter_statistics',
'forms'
);
@ -205,12 +205,12 @@ class Migrator {
return $this->sqlify(__FUNCTION__, $attributes);
}
function queues() {
function sending_queue() {
$attributes = array(
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
'newsletter_id mediumint(9) NOT NULL,',
'subscribers longtext,',
'status varchar(12) NOT NULL,',
'status varchar(12) NULL DEFAULT NULL,',
'priority mediumint(9) NOT NULL DEFAULT 0,',
'count_total mediumint(9) NOT NULL DEFAULT 0,',
'count_processed mediumint(9) NOT NULL DEFAULT 0,',

View File

@ -1,7 +1,7 @@
<?php
namespace MailPoet\Config;
use MailPoet\Queue\Daemon;
use MailPoet\Cron\Daemon;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;

View File

@ -1,18 +1,16 @@
<?php
namespace MailPoet\Queue;
namespace MailPoet\Cron;
use Carbon\Carbon;
use MailPoet\Models\Queue;
use MailPoet\Models\Setting;
class BootStrapMenu {
function __construct() {
$this->daemon = Setting::where('name', 'daemon')
$this->daemon = Setting::where('name', 'cron_daemon')
->findOne();
}
function bootStrap() {
$queues = Queue::findMany();
return ($this->daemon) ?
array_merge(
array(
@ -21,13 +19,15 @@ class BootStrapMenu {
'Y-m-d H:i:s',
$this->daemon->created_at,
'UTC'
)->diffForHumans(),
)
->diffForHumans(),
'timeSinceUpdate' =>
Carbon::createFromFormat(
'Y-m-d H:i:s',
$this->daemon->updated_at,
'UTC'
)->diffForHumans()
)
->diffForHumans()
),
json_decode($this->daemon->value, true)
) :

View File

@ -1,5 +1,5 @@
<?php
namespace MailPoet\Queue;
namespace MailPoet\Cron;
use MailPoet\Models\Setting;
use MailPoet\Util\Security;
@ -27,29 +27,25 @@ class Daemon {
$daemonData = $this->daemonData;
if(!$daemon) {
$daemon = Setting::create();
$daemon->name = 'daemon';
$daemon->value = json_encode(
array(
'status' => 'stopped',
));
$daemon->name = 'cron_daemon';
$daemonData = array(
'status' => null,
'counter' => 0
);
$daemon->value = json_encode($daemonData);
$daemon->save();
}
if($daemonData['status'] !== 'started') {
$_SESSION['daemon'] = 'started';
$daemonData = array(
'status' => 'started',
'token' => $this->refreshedToken,
'counter' => $daemonData['status'] === 'paused' ?
$daemonData['counter'] :
0
);
$_SESSION['daemon'] = array('result' => true);
$_SESSION['cron_daemon'] = 'started';
$daemonData['status'] = 'started';
$daemonData['token'] = $this->refreshedToken;
$_SESSION['cron_daemon'] = array('result' => true);
$this->manageSession('end');
$daemon->value = json_encode($daemonData);
$daemon->save();
$this->callSelf();
} else {
$_SESSION['daemon'] = array(
$_SESSION['cron_daemon'] = array(
'result' => false,
'error' => 'already started'
);
@ -67,7 +63,7 @@ class Daemon {
$this->abortWithError('invalid token');
}
$worker = new Worker();
$worker = new Worker($this->timer);
$worker->process();
$elapsedTime = microtime(true) - $this->timer;
if($elapsedTime < 30) {
@ -84,7 +80,7 @@ class Daemon {
}
function getDaemon() {
$daemon = Setting::where('name', 'daemon')
$daemon = Setting::where('name', 'cron_daemon')
->findOne();
return array(
($daemon) ? $daemon : null,

View File

@ -1,5 +1,5 @@
<?php
namespace MailPoet\Queue;
namespace MailPoet\Cron;
use Carbon\Carbon;
use MailPoet\Config\Env;
@ -19,12 +19,8 @@ class Supervisor {
function checkDaemon() {
if(!$this->daemon) {
return $this->startDaemon();
} else {
if(!$this->forceStart && (
$this->daemonData['status'] === 'paused' ||
$this->daemonData['status'] === 'stopped'
)
) {
}
if(!$this->forceStart && $this->daemonData['status'] === 'stopped') {
return;
}
$currentTime = Carbon::now('UTC');
@ -33,37 +29,31 @@ class Supervisor {
$this->daemon->updated_at, 'UTC'
);
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
if(!$this->forceStart && $timeSinceLastStart < 50) return;
if(
($this->forceStart && $this->daemonData['status'] === 'paused') ||
!$this->forceStart
) {
$this->daemonData['status'] = 'paused';
}
if($timeSinceLastStart < 40) return;
$this->daemonData['status'] = null;
$this->daemon->value = json_encode($this->daemonData);
$this->daemon->save();
return $this->startDaemon();
}
}
function startDaemon() {
if(!session_id()) session_start();
$sessionId = session_id();
session_write_close();
$_SESSION['daemon'] = null;
$_SESSION['cron_daemon'] = null;
$payload = json_encode(array('session' => $sessionId));
self::getRemoteUrl(
'/?mailpoet-api&section=queue&action=start&payload=' . urlencode($payload)
);
session_start();
$daemonStatus = $_SESSION['daemon'];
$daemonStatus = $_SESSION['cron_daemon'];
unset($_SESSION['daemon']);
session_write_close();
return $daemonStatus;
}
function getDaemon() {
$daemon = Setting::where('name', 'daemon')
$daemon = Setting::where('name', 'cron_daemon')
->findOne();
$daemonData = ($daemon) ? json_decode($daemon->value, true) : false;
return array(

102
lib/Cron/Worker.php Normal file
View File

@ -0,0 +1,102 @@
<?php
namespace MailPoet\Cron;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterStatistics;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Router\Mailer;
if(!defined('ABSPATH')) exit;
class Worker {
function __construct($timer = false) {
$this->timer = ($timer) ? $timer : microtime(true);
}
function process() {
$queues =
SendingQueue::orderByDesc('priority')
->whereNull('deleted_at')
->whereNull('status')
->findResultSet();
// TODO: usee Mailer's method to get the mailer from DB
$mailer = new Mailer();
$mailer->mailer['method'] = 'MailPoet';
$mailer->mailer['class'] = 'MailPoet\\Mailer\\MailPoet';
$mailer->mailer['api_key'] = Setting::getValue('api_key', 'dhNSqj1XHkVltIliyQDvMiKzQShOA5rs0m_DdRUVZHU');
foreach($queues as $queue) {
if($this->checkExecutionTimer()) break;
$newsletter = Newsletter::findOne($queue->newsletter_id);
if(!$newsletter) {
continue;
};
$newsletter = $newsletter->asArray();
// TODO: render newsletter
$newsletter = array(
'subject' => $newsletter['subject'],
'id' => $newsletter['id'],
'body' => array(
'html' => 'rendering not yet implemented',
'text' => 'rendering not yet implemented'
)
);
$subscribers = json_decode($queue->subscribers, true);
$subscribersToProcess = $subscribers['to_process'];
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
foreach(array_chunk($subscribersToProcess, 200) as $subscriberIds) {
if($this->checkExecutionTimer()) break;
$dbSubscribers = Subscriber::whereIn('id', $subscriberIds)
->findArray();
foreach($dbSubscribers as $i => $dbSubscriber) {
if($this->checkExecutionTimer()) break;
// TODO: replace shortcodes in the newsletter
$result = $mailer->send(
$newsletter,
sprintf(
"%s %s <%s>",
$dbSubscriber['first_name'],
$dbSubscriber['last_name'],
$dbSubscriber['email']
)
);
$newsletterStatistics = NewsletterStatistics::create();
$newsletterStatistics->subscriber_id = $dbSubscriber['id'];
$newsletterStatistics->newsletter_id = $newsletter['id'];
$newsletterStatistics->queue_id = $queue->id;
$newsletterStatistics->save();
if($result) {
$subscribers['processed'][] = $dbSubscriber['id'];
} else {
$subscribers['failed'][] = $dbSubscriber['id'];
}
$subscribers['to_process'] = array_values(
array_diff(
$subscribers['to_process'],
array_merge($subscribers['processed'], $subscribers['failed'])
)
);
$queue->count_processed =
count($subscribers['processed']) + count($subscribers['failed']);
$queue->count_to_process = count($subscribers['to_process']);
$queue->count_failed = count($subscribers['failed']);
$queue->count_total =
$queue->count_processed + $queue->count_to_process;
if(!$queue->count_to_process) {
$queue->processed_at = date('Y-m-d H:i:s');
$queue->status = 'completed';
}
$queue->subscribers = json_encode($subscribers);
$queue->save();
}
}
}
}
function checkExecutionTimer() {
$elapsedTime = microtime(true) - $this->timer;
return ($elapsedTime >= 28) ? true : false;
}
}

View File

@ -3,8 +3,8 @@ namespace MailPoet\Models;
if(!defined('ABSPATH')) exit;
class Queue extends Model {
public static $_table = MP_QUEUES_TABLE;
class SendingQueue extends Model {
public static $_table = MP_SENDING_QUEUE_TABLE;
function __construct() {
parent::__construct();

View File

@ -1,66 +0,0 @@
<?php
namespace MailPoet\Queue;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterStatistics;
use MailPoet\Models\Queue;
if(!defined('ABSPATH')) exit;
class Worker {
function __construct($timer = false) {
$this->timer = $timer;
$this->timer = microtime(true);
}
function process() {
$queues =
Queue::orderByDesc('priority')
->whereNull('deleted_at')
->whereNotIn('status', array(
'paused',
'completed'
))
->findResultSet();
foreach($queues as $queue) {
$newsletter = Newsletter::findOne($queue->newsletter_id);
if(!$newsletter) {
continue;
};
$newsletter = $newsletter->asArray();
$subscribers = json_decode($queue->subscribers, true);
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
$subscribersToProcess = $subscribers['to_process'];
foreach($subscribersToProcess as $subscriber) {
$elapsedTime = microtime(true) - $this->timer;
if($elapsedTime >= 28) break;
// TODO: hook up to mailer
sleep(1);
$newsletterStatistics = NewsletterStatistics::create();
$newsletterStatistics->subscriber_id = $subscriber;
$newsletterStatistics->newsletter_id = $newsletter['id'];
$newsletterStatistics->queue_id = $queue->id;
$newsletterStatistics->save();
$subscribers['processed'][] = $subscriber;
$subscribers['to_process'] = array_values(
array_diff(
$subscribers['to_process'],
$subscribers['processed']
)
);
$queue->count_processed = count($subscribers['processed']);
$queue->count_to_process = count($subscribers['to_process']);
$queue->count_failed = count($subscribers['failed']);
$queue->count_total =
$queue->count_processed + $queue->count_to_process + $queue->count_failed;
if(!$queue->count_to_process) {
$queue->processed_at = date('Y-m-d H:i:s');
$queue->status = 'completed';
}
$queue->subscribers = json_encode($subscribers);
$queue->save();
}
}
}
}

194
lib/Router/Cron.php Normal file
View File

@ -0,0 +1,194 @@
<?php
namespace MailPoet\Router;
use MailPoet\Models\Segment;
use MailPoet\Models\SendingQueue;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
class Cron {
function controlDaemon($data) {
switch($data['action']) {
case 'start':
$supervisor = new Supervisor($forceStart = true);
wp_send_json(
array(
'result' => $supervisor->checkDaemon() ?
true :
false
)
);
break;
case 'stop':
$status = 'stopped';
break;
default:
$status = 'paused';
break;
}
$daemon = new Daemon();
if(!$daemon->daemon || $daemon->daemonData['status'] !== 'started') {
$result = false;
} else {
$daemon->daemonData['status'] = $status;
$daemon->daemon->value = json_encode($daemon->daemonData);
$result = $daemon->daemon->save();
}
wp_send_json(
array(
'result' => $result
)
);
}
function getDaemonStatus() {
$daemon = new \MailPoet\Cron\BootStrapMenu();
wp_send_json($daemon->bootStrap());
}
function addQueue($data) {
$queue = SendingQueue::where('newsletter_id', $data['newsletter_id'])
->whereNull('status')
->findArray();
!d($queue);
exit;
$queue = SendingQueue::create();
$queue->newsletter_id = $data['newsletter_id'];
$subscriber_ids = array();
$segments = Segment::whereIn('id', $data['segments'])
->findMany();
foreach($segments as $segment) {
$subscriber_ids = array_merge($subscriber_ids, Helpers::arrayColumn(
$segment->subscribers()
->findArray(),
'id'
));
}
$subscriber_ids = array_unique($subscriber_ids);
$queue->subscribers = json_encode(
array(
'to_process' => $subscriber_ids
)
);
$queue->count_total = $queue->count_to_process = count($subscriber_ids);
$queue->save();
wp_send_json(
!$queue->save() ?
array(
'result' => false,
'error' => 'Queue could not be created.'
) :
array(
'result' => true,
'data' => array($queue->id)
)
);
}
function addQueues($data) {
$result = array_map(function ($queueData) {
$queue = SendingQueue::create();
$queue->newsletter_id = $queueData['newsletter_id'];
$queue->subscribers = json_encode(
array(
'to_process' => $queueData['subscribers']
)
);
$queue->count_total = $queue->count_to_process = count($queueData['subscribers']);
$queue->save();
return array(
'newsletter_id' => $queue->newsletter_id,
'queue_id' => $queue->id
);
}, $data);
$result = Helpers::arrayColumn($result, 'queue_id', 'newsletter_id');
wp_send_json(
count($data) != count($result) ?
array(
'result' => false,
'error' => __('Some queues could not be created.'),
'data' => $result
) :
array(
'result' => true,
'data' => $result
)
);
}
function deleteQueue($data) {
$queue = SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id']);
if(!$queue) {
wp_send_json(
array(
'result' => false,
'error' => __('Queue not found.')
)
);
}
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
wp_send_json(array('result' => true));
}
function deleteQueues($data) {
$queues = SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findResultSet();
if(!$queues->count()) {
wp_send_json(
array(
'result' => false,
'error' => __('Queues not found.')
)
);
}
foreach($queues as $queue) {
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
}
wp_send_json(array('result' => true));
}
function getQueueStatus($data) {
$queue = SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id'])
->asArray();
wp_send_json(
!$queue ?
array(
'result' => false,
'error' => __('Queue not found.')
) :
array(
'result' => true,
'data' => $queue
)
);
}
function getQueuesStatus($data) {
$queues = SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findArray();
wp_send_json(
!$queues ?
array(
'result' => false,
'error' => __('Queue not found.')
) :
array(
'result' => true,
'data' => $queues
)
);
}
}

View File

@ -1,12 +1,15 @@
<?php
namespace MailPoet\Router;
use MailPoet\Models\Setting;
require_once(ABSPATH . 'wp-includes/pluggable.php');
if(!defined('ABSPATH')) exit;
class Mailer {
function __construct() {
$this->fromName = $this->getSetting('from_name');
$this->fromEmail = $this->getSetting('from_address');
list($this->fromName, $this->fromEmail) = $this->getSetting('sender');
$this->mailer = $this->getSetting('mailer');
$this->from = sprintf('%s <%s>', $this->fromName, $this->fromEmail);
}
@ -14,11 +17,11 @@ class Mailer {
function send($newsletter, $subscriber) {
$subscriber = $this->transformSubscriber($subscriber);
$mailer = $this->buildMailer();
return wp_send_json($mailer->send($newsletter, $subscriber));
return $mailer->send($newsletter, $subscriber);
}
function buildMailer() {
switch ($this->mailer['name']) {
switch($this->mailer['method']) {
case 'AmazonSES':
$mailer = new $this->mailer['class'](
$this->mailer['region'],
@ -84,42 +87,44 @@ class Mailer {
}
function getSetting($setting) {
if($setting === 'mailer') {
$mailers = array(
switch($setting) {
case 'mailer':
// TODO: remove
/* $mailers = array(
array(
'name' => 'AmazonSES',
'method' => 'AmazonSES',
'type' => 'API',
'access_key' => 'AKIAJM6Y5HMGXBLDNSRA',
'secret_key' => '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',
'region' => 'us-east-1'
),
array(
'name' => 'ElasticEmail',
'method' => 'ElasticEmail',
'type' => 'API',
'api_key' => '997f1f7f-41de-4d7f-a8cb-86c8481370fa'
),
array(
'name' => 'MailGun',
'method' => 'MailGun',
'type' => 'API',
'api_key' => 'key-6cf5g5qjzenk-7nodj44gdt8phe6vam2',
'domain' => 'mrcasual.com'
),
array(
'name' => 'MailPoet',
'method' => 'MailPoet',
'api_key' => 'dhNSqj1XHkVltIliyQDvMiKzQShOA5rs0m_DdRUVZHU'
),
array(
'name' => 'Mandrill',
'method' => 'Mandrill',
'type' => 'API',
'api_key' => '692ys1B7REEoZN7R-dYwNA'
),
array(
'name' => 'SendGrid',
'method' => 'SendGrid',
'type' => 'API',
'api_key' => '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'
),
array(
'name' => 'SMTP',
'method' => 'SMTP',
'host' => 'email-smtp.us-west-2.amazonaws.com',
'port' => 587,
'authentication' => array(
@ -129,20 +134,25 @@ class Mailer {
'encryption' => 'tls'
),
array(
'name' => 'WPMail'
'method' => 'WPMail'
)
);
$mailer = $mailers[array_rand($mailers)];
);*/
$mailer = Setting::getValue('mta', null);
if(!$mailer) throw new \Exception('Mailing method has not been configured.');
$mailer['class'] = 'MailPoet\\Mailer\\' .
((isset($mailer['type'])) ?
$mailer['type'] . '\\' . $mailer['name'] :
$mailer['name']
$mailer['type'] . '\\' . $mailer['method'] :
$mailer['method']
);
return $mailer;
break;;
case 'sender':
$sender = Setting::getValue($setting, null);
return array($sender['name'], $sender['address']);
break;
default:
return Setting::getValue($setting, null);
break;
}
if($setting === 'from_name') return 'Sender';
if($setting === 'from_address') return 'staff@mailpoet.com';
return Setting::where('name', $setting)
->findOne()->value;
}
}

View File

@ -12,7 +12,7 @@ use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterOption;
use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Models\Queue as SendingQueue;
use MailPoet\Models\SendingQueue;
if(!defined('ABSPATH')) exit;
@ -231,6 +231,7 @@ class Newsletters {
// get queue
$queue = SendingQueue::where('newsletter_id', $item['id'])
->orderByDesc('updated_at')
->findOne();
$item['queue'] = ($queue !== false) ? $queue->asArray() : null;
}

View File

@ -1,10 +1,8 @@
<?php
namespace MailPoet\Router;
use MailPoet\Queue\Daemon;
use MailPoet\Queue\Supervisor;
use MailPoet\Models\Queue as SendingQueue;
use MailPoet\Models\Segment;
use MailPoet\Models\SendingQueue;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
@ -45,20 +43,29 @@ class Queue {
}
function getDaemonStatus() {
$daemon = new \MailPoet\Queue\BootStrapMenu();
$daemon = new \MailPoet\Cron\BootStrapMenu();
wp_send_json($daemon->bootStrap());
}
function addQueue($data) {
$queue = SendingQueue::where('newsletter_id', $data['newsletter_id'])
->whereNull('status')
->findArray();
!d($queue);
exit;
$queue = SendingQueue::create();
$queue->newsletter_id = $data['newsletter_id'];
$subscriber_ids = array();
$segments = Segment::whereIn('id', $data['segments'])->findMany();
$segments = Segment::whereIn('id', $data['segments'])
->findMany();
foreach($segments as $segment) {
$subscriber_ids = array_merge($subscriber_ids, Helpers::arrayColumn(
$segment->subscribers()->findArray(),
$segment->subscribers()
->findArray(),
'id'
));
}

167
lib/Router/SendingQueue.php Normal file
View File

@ -0,0 +1,167 @@
<?php
namespace MailPoet\Router;
use MailPoet\Models\Segment;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
class SendingQueue {
function addQueue($data) {
$queue = \MailPoet\Models\SendingQueue::where('newsletter_id', $data['newsletter_id'])
->whereNull('status')
->findArray();
if(count($queue)) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Send operation is already in progress.'))
)
);
}
$queue = \MailPoet\Models\SendingQueue::create();
$queue->newsletter_id = $data['newsletter_id'];
$subscriber_ids = array();
$segments = Segment::whereIn('id', $data['segments'])
->findMany();
foreach($segments as $segment) {
$subscriber_ids = array_merge($subscriber_ids, Helpers::arrayColumn(
$segment->subscribers()
->findArray(),
'id'
));
}
$subscriber_ids = array_unique($subscriber_ids);
$queue->subscribers = json_encode(
array(
'to_process' => $subscriber_ids
)
);
$queue->count_total = $queue->count_to_process = count($subscriber_ids);
$queue->save();
wp_send_json(
!$queue->save() ?
array(
'result' => false,
'errors' => array(__('Queue could not be created.'))
) :
array(
'result' => true,
'data' => array($queue->id)
)
);
}
function addQueues($data) {
$newsletterIds = Helpers::arrayColumn($data, 'newsletter_id');
$queues = \MailPoet\Models\SendingQueue::whereIn('newsletter_id', $newsletterIds)
->whereNull('status')
->findArray();
if(count($queues)) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Send operation is already in progress.'))
)
);
}
$result = array_map(function ($queueData) {
$queue = \MailPoet\Models\SendingQueue::create();
$queue->newsletter_id = $queueData['newsletter_id'];
$queue->subscribers = json_encode(
array(
'to_process' => $queueData['subscribers']
)
);
$queue->count_total = $queue->count_to_process = count($queueData['subscribers']);
$queue->save();
return array(
'newsletter_id' => $queue->newsletter_id,
'queue_id' => $queue->id
);
}, $data);
$result = Helpers::arrayColumn($result, 'queue_id', 'newsletter_id');
wp_send_json(
count($data) != count($result) ?
array(
'result' => false,
'errors' => array(__('Some queues could not be created.')),
'data' => $result
) :
array(
'result' => true,
'data' => $result
)
);
}
function deleteQueue($data) {
$queue = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id']);
if(!$queue) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Queue not found.'))
)
);
}
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
wp_send_json(array('result' => true));
}
function deleteQueues($data) {
$queues = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findResultSet();
if(!$queues->count()) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Queues not found.'))
)
);
}
foreach($queues as $queue) {
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
}
wp_send_json(array('result' => true));
}
function getQueueStatus($data) {
$queue = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id'])
->asArray();
wp_send_json(
!$queue ?
array(
'result' => false,
'errors' => array(__('Queue not found.'))
) :
array(
'result' => true,
'data' => $queue
)
);
}
function getQueuesStatus($data) {
$queues = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findArray();
wp_send_json(
!$queues ?
array(
'result' => false,
'errors' => array(__('Queue not found.'))
) :
array(
'result' => true,
'data' => $queues
)
);
}
}

View File

@ -63,7 +63,7 @@ class Import {
);
}
}
} catch (\PDOException $e) {
} catch(\PDOException $e) {
return array(
'result' => false,
'error' => $e->getMessage()
@ -145,7 +145,7 @@ class Import {
);
if(!$existingTrashedRecords) return;
$existingTrashedRecords = Helpers::flattenArray($existingTrashedRecords);
foreach (array_chunk($existingTrashedRecords, 200) as $subscriberIds) {
foreach(array_chunk($existingTrashedRecords, 200) as $subscriberIds) {
Subscriber::whereIn('id', $subscriberIds)
->deleteMany();
SubscriberSegment::whereIn('subscriber_id', $subscriberIds)
@ -247,7 +247,7 @@ class Import {
}, $subscriberFields);
}, range(0, $subscribersCount));
$currentTime = ($action === 'update') ? date('Y-m-d H:i:s') : $this->currentTime;
foreach (array_chunk($subscribers, 200) as $data) {
foreach(array_chunk($subscribers, 100) as $data) {
if($action == 'create') {
Subscriber::createMultiple(
$subscriberFields,
@ -310,7 +310,7 @@ class Import {
);
}, $count, $subscribersData[$column]);
}, $subscriberCustomFields)[0];
foreach (array_chunk($subscribers, 200) as $data) {
foreach(array_chunk($subscribers, 200) as $data) {
if($action === 'create') {
SubscriberCustomField::createMultiple(
$data
@ -325,7 +325,7 @@ class Import {
}
function addSubscribersToSegments($subscribers, $segments) {
foreach (array_chunk($subscribers, 200) as $data) {
foreach(array_chunk($subscribers, 200) as $data) {
SubscriberSegment::createMultiple($segments, $data);
}
}

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\API\AmazonSES;
class AmazonSESCest {
function _before() {
$this->settings = array(
'name' => 'AmazonSES',
'method' => 'AmazonSES',
'type' => 'API',
'access_key' => 'AKIAJM6Y5HMGXBLDNSRA',
'secret_key' => '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',

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\API\ElasticEmail;
class ElasticEmailCest {
function _before() {
$this->settings = array(
'name' => 'ElasticEmail',
'method' => 'ElasticEmail',
'type' => 'API',
'api_key' => '997f1f7f-41de-4d7f-a8cb-86c8481370fa'
);

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\API\MailGun;
class MailGunCest {
function _before() {
$this->settings = array(
'name' => 'MailGun',
'method' => 'MailGun',
'type' => 'API',
'api_key' => 'key-6cf5g5qjzenk-7nodj44gdt8phe6vam2',
'domain' => 'mrcasual.com'

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\API\Mandrill;
class MandrillCest {
function _before() {
$this->settings = array(
'name' => 'Mandrill',
'method' => 'Mandrill',
'type' => 'API',
'api_key' => '692ys1B7REEoZN7R-dYwNA'
);

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\API\SendGrid;
class SendGridCest {
function _before() {
$this->settings = array(
'name' => 'SendGrid',
'method' => 'SendGrid',
'type' => 'API',
'api_key' => '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'
);

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\MailPoet;
class MailPoetCest {
function _before() {
$this->settings = array(
'name' => 'MailPoet',
'method' => 'MailPoet',
'api_key' => 'dhNSqj1XHkVltIliyQDvMiKzQShOA5rs0m_DdRUVZHU'
);
$this->fromEmail = 'staff@mailpoet.com';

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\SMTP;
class SMTPCest {
function _before() {
$this->settings = array(
'name' => 'SMTP',
'method' => 'SMTP',
'host' => 'email-smtp.us-west-2.amazonaws.com',
'port' => 587,
'authentication' => array(

View File

@ -5,7 +5,7 @@ use MailPoet\Mailer\WPMail;
class WPMailCest {
function _before() {
$this->settings = array(
'name' => 'WPMail'
'method' => 'WPMail'
);
$this->fromEmail = 'staff@mailpoet.com';
$this->fromName = 'Sender';

View File

@ -43,8 +43,8 @@ class MailerCest {
$mailer = $this->router->buildMailer();
$class = 'Mailpoet\\Mailer\\' .
((isset($this->router->mailer['type'])) ?
$this->router->mailer['type'] . '\\' . $this->router->mailer['name'] :
$this->router->mailer['name']
$this->router->mailer['type'] . '\\' . $this->router->mailer['method'] :
$this->router->mailer['method']
);
expect($mailer instanceof $class)->true();
expect(method_exists($mailer, 'send'))->true();
@ -52,7 +52,7 @@ class MailerCest {
function itCanSend() {
$newsletter = array(
'subject' => 'testing Mailer router with ' . $this->router->mailer['name'],
'subject' => 'testing Mailer router with ' . $this->router->mailer['method'],
'body' => array(
'html' => 'HTML body',
'text' => 'TEXT body'

10
views/cron.html Normal file
View File

@ -0,0 +1,10 @@
<% extends 'layout.html' %>
<% block content %>
<div id="cron_container">
<div id="cron_status"></div>
</div>
<script>
var cronDaemon = <%= daemon|raw %>
</script>
<% endblock %>

View File

@ -1,13 +0,0 @@
<% extends 'layout.html' %>
<% block content %>
<div id="queue_container">
<div id="queue_status"></div>
<div id="queue_control"></div>
</div>
<script type="text/javascript">
</script>
<script>
var queueDaemon = <%= daemon|raw %>
</script>
<% endblock %>

View File

@ -103,7 +103,7 @@ config.push(_.extend({}, baseConfig, {
'subscribers/importExport/import.js',
'subscribers/importExport/export.js',
'helpscout',
'queue.jsx'
'cron.jsx'
],
form_editor: [
'form_editor/form_editor.js',