Add sending service key validation [MAILPOET-743]
This commit is contained in:
57
lib/API/Endpoints/Services.php
Normal file
57
lib/API/Endpoints/Services.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\API\Endpoints;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use MailPoet\API\Endpoint as APIEndpoint;
|
||||||
|
use MailPoet\API\Error as APIError;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Services extends APIEndpoint {
|
||||||
|
function verifyMailPoetKey($data = array()) {
|
||||||
|
$key = isset($data['key']) ? trim($data['key']) : null;
|
||||||
|
|
||||||
|
if(!$key) {
|
||||||
|
return $this->badRequest(array(
|
||||||
|
APIError::BAD_REQUEST => __('You need to specify a key.', 'mailpoet')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$bridge = new Bridge($key);
|
||||||
|
$result = $bridge->checkKey();
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
return $this->errorResponse(array(
|
||||||
|
$e->getCode() => $e->getMessage()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = !empty($result['code']) ? (int)$result['code'] : null;
|
||||||
|
|
||||||
|
if($code == Bridge::MAILPOET_KEY_VALID) {
|
||||||
|
return $this->successResponse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($code) {
|
||||||
|
case Bridge::MAILPOET_KEY_INVALID:
|
||||||
|
$error = __('Your MailPoet key is invalid!', 'mailpoet');
|
||||||
|
break;
|
||||||
|
case Bridge::MAILPOET_KEY_EXPIRING:
|
||||||
|
$error = sprintf(
|
||||||
|
__('Your MailPoet key is expiring on %s!', 'mailpoet'),
|
||||||
|
Carbon::createFromTimestamp(strtotime($result['data']['expire_at']))
|
||||||
|
->format('Y-m-d')
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$error = sprintf(
|
||||||
|
__('Error validating API key, please try again later (code: %s)', 'mailpoet'),
|
||||||
|
$code
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->errorResponse(array(APIError::BAD_REQUEST => $error));
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,12 @@ class Menu {
|
|||||||
$this->assets_url = $assets_url;
|
$this->assets_url = $assets_url;
|
||||||
$subscribers_feature = new SubscribersFeature();
|
$subscribers_feature = new SubscribersFeature();
|
||||||
$this->subscribers_over_limit = $subscribers_feature->check();
|
$this->subscribers_over_limit = $subscribers_feature->check();
|
||||||
|
if(self::isOnMailPoetAdminPage()) {
|
||||||
|
$show_notices = isset($_REQUEST['page'])
|
||||||
|
&& stripos($_REQUEST['page'], 'mailpoet-newsletters') === false;
|
||||||
|
$checker = new ServicesChecker();
|
||||||
|
$this->mp_api_key_valid = $checker->checkMailPoetAPIKeyValid($show_notices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@ -387,6 +393,9 @@ class Menu {
|
|||||||
|
|
||||||
function newsletters() {
|
function newsletters() {
|
||||||
if($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
|
if($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
|
||||||
|
if(isset($this->mp_api_key_valid) && $this->mp_api_key_valid === false) {
|
||||||
|
return $this->displayMailPoetAPIKeyInvalidTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
global $wp_roles;
|
global $wp_roles;
|
||||||
|
|
||||||
@ -483,6 +492,30 @@ class Menu {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function displayMailPoetAPIKeyInvalidTemplate() {
|
||||||
|
$this->displayPage('invalidkey.html', array(
|
||||||
|
'subscriber_count' => Subscriber::getTotalSubscribers()
|
||||||
|
));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function isOnMailPoetAdminPage(array $exclude = null, $screen_id = null) {
|
||||||
|
if(is_null($screen_id)) {
|
||||||
|
if(empty($_REQUEST['page'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$screen_id = $_REQUEST['page'];
|
||||||
|
}
|
||||||
|
if(!empty($exclude)) {
|
||||||
|
foreach($exclude as $slug) {
|
||||||
|
if(stripos($screen_id, $slug) !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (stripos($screen_id, 'mailpoet-') !== false);
|
||||||
|
}
|
||||||
|
|
||||||
private function getLimitPerPage($model = null) {
|
private function getLimitPerPage($model = null) {
|
||||||
if($model === null) {
|
if($model === null) {
|
||||||
return Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
|
return Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
|
||||||
|
48
lib/Config/ServicesChecker.php
Normal file
48
lib/Config/ServicesChecker.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
use MailPoet\WP\Notice as WPNotice;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class ServicesChecker {
|
||||||
|
function checkMailPoetAPIKeyValid($display_error_notice = true) {
|
||||||
|
if(!Bridge::isMPSendingServiceEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = Setting::getValue('mta.mailpoet_api_key_state');
|
||||||
|
if(empty($state['code']) || $state['code'] == Bridge::MAILPOET_KEY_VALID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($state['code'] == Bridge::MAILPOET_KEY_INVALID) {
|
||||||
|
$error = Helpers::replaceLinkTags(
|
||||||
|
__('All sending is currently paused! Your key to send with MailPoet is invalid. [link]Visit MailPoet.com to purchase a key[/link]', 'mailpoet'),
|
||||||
|
'https://account.mailpoet.com?s=' . Subscriber::getTotalSubscribers()
|
||||||
|
);
|
||||||
|
if($display_error_notice) {
|
||||||
|
WPNotice::displayError($error);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} elseif($state['code'] == Bridge::MAILPOET_KEY_EXPIRING) {
|
||||||
|
$date = date('Y-m-d', strtotime($state['data']['expire_at']));
|
||||||
|
$error = Helpers::replaceLinkTags(
|
||||||
|
__('Your newsletters are awesome! Don\'t forget to [link]upgrade your MailPoet email plan[/link] by %s to keep sending them to your subscribers.', 'mailpoet'),
|
||||||
|
'https://account.mailpoet.com?s=' . Subscriber::getTotalSubscribers()
|
||||||
|
);
|
||||||
|
$error = sprintf($error, $date);
|
||||||
|
if($display_error_notice) {
|
||||||
|
WPNotice::displayWarning($error);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ namespace MailPoet\Cron;
|
|||||||
use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
|
use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
|
||||||
use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
|
use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
|
||||||
use MailPoet\Cron\Workers\Bounce as BounceWorker;
|
use MailPoet\Cron\Workers\Bounce as BounceWorker;
|
||||||
|
use MailPoet\Cron\Workers\SendingServiceKeyCheck as SSKeyCheckWorker;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||||
@ -48,6 +49,7 @@ class Daemon {
|
|||||||
try {
|
try {
|
||||||
$this->executeScheduleWorker();
|
$this->executeScheduleWorker();
|
||||||
$this->executeQueueWorker();
|
$this->executeQueueWorker();
|
||||||
|
$this->executeSSKeyCheckWorker();
|
||||||
$this->executeBounceWorker();
|
$this->executeBounceWorker();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
// continue processing, no need to handle errors
|
// continue processing, no need to handle errors
|
||||||
@ -80,6 +82,11 @@ class Daemon {
|
|||||||
return $queue->process();
|
return $queue->process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function executeSSKeyCheckWorker() {
|
||||||
|
$worker = new SSKeyCheckWorker($this->timer);
|
||||||
|
return $worker->process();
|
||||||
|
}
|
||||||
|
|
||||||
function executeBounceWorker() {
|
function executeBounceWorker() {
|
||||||
$bounce = new BounceWorker($this->timer);
|
$bounce = new BounceWorker($this->timer);
|
||||||
return $bounce->process();
|
return $bounce->process();
|
||||||
|
@ -5,7 +5,9 @@ use MailPoet\Cron\CronHelper;
|
|||||||
use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
|
use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
|
||||||
use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
|
use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
|
||||||
use MailPoet\Cron\Workers\Bounce as BounceWorker;
|
use MailPoet\Cron\Workers\Bounce as BounceWorker;
|
||||||
|
use MailPoet\Cron\Workers\SendingServiceKeyCheck as SSKeyCheckWorker;
|
||||||
use MailPoet\Mailer\MailerLog;
|
use MailPoet\Mailer\MailerLog;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -17,14 +19,21 @@ class WordPress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function checkExecutionRequirements() {
|
static function checkExecutionRequirements() {
|
||||||
|
// sending queue
|
||||||
$scheduled_queues = SchedulerWorker::getScheduledQueues();
|
$scheduled_queues = SchedulerWorker::getScheduledQueues();
|
||||||
$running_queues = SendingQueueWorker::getRunningQueues();
|
$running_queues = SendingQueueWorker::getRunningQueues();
|
||||||
$sending_limit_reached = MailerLog::isSendingLimitReached();
|
$sending_limit_reached = MailerLog::isSendingLimitReached();
|
||||||
$bounce_sync_available = BounceWorker::checkBounceSyncAvailable();
|
// sending service
|
||||||
|
$mp_sending_enabled = Bridge::isMPSendingServiceEnabled();
|
||||||
|
// bounce sync
|
||||||
$bounce_due_queues = BounceWorker::getAllDueQueues();
|
$bounce_due_queues = BounceWorker::getAllDueQueues();
|
||||||
$bounce_future_queues = BounceWorker::getFutureQueues();
|
$bounce_future_queues = BounceWorker::getFutureQueues();
|
||||||
|
// sending service key check
|
||||||
|
$sskeycheck_due_queues = SSKeyCheckWorker::getAllDueQueues();
|
||||||
|
$sskeycheck_future_queues = SSKeyCheckWorker::getFutureQueues();
|
||||||
return (($scheduled_queues || $running_queues) && !$sending_limit_reached)
|
return (($scheduled_queues || $running_queues) && !$sending_limit_reached)
|
||||||
|| ($bounce_sync_available && ($bounce_due_queues || !$bounce_future_queues));
|
|| ($mp_sending_enabled && ($bounce_due_queues || !$bounce_future_queues))
|
||||||
|
|| ($mp_sending_enabled && ($sskeycheck_due_queues || !$sskeycheck_future_queues));
|
||||||
}
|
}
|
||||||
|
|
||||||
static function cleanup() {
|
static function cleanup() {
|
||||||
|
@ -6,15 +6,18 @@ use MailPoet\Cron\CronHelper;
|
|||||||
use MailPoet\Mailer\Mailer;
|
use MailPoet\Mailer\Mailer;
|
||||||
use MailPoet\Models\SendingQueue;
|
use MailPoet\Models\SendingQueue;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class Bounce {
|
class Bounce {
|
||||||
|
const TASK_TYPE = 'bounce';
|
||||||
|
const BATCH_SIZE = 100;
|
||||||
|
|
||||||
const BOUNCED_HARD = 'hard';
|
const BOUNCED_HARD = 'hard';
|
||||||
const BOUNCED_SOFT = 'soft';
|
const BOUNCED_SOFT = 'soft';
|
||||||
const NOT_BOUNCED = null;
|
const NOT_BOUNCED = null;
|
||||||
const BATCH_SIZE = 100;
|
|
||||||
|
|
||||||
public $timer;
|
public $timer;
|
||||||
public $api;
|
public $api;
|
||||||
@ -25,12 +28,6 @@ class Bounce {
|
|||||||
CronHelper::enforceExecutionLimit($this->timer);
|
CronHelper::enforceExecutionLimit($this->timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function checkBounceSyncAvailable() {
|
|
||||||
$mailer_config = Mailer::getMailerConfig();
|
|
||||||
return !empty($mailer_config['method'])
|
|
||||||
&& $mailer_config['method'] === Mailer::METHOD_MAILPOET;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initApi() {
|
function initApi() {
|
||||||
if(!$this->api) {
|
if(!$this->api) {
|
||||||
$mailer_config = Mailer::getMailerConfig();
|
$mailer_config = Mailer::getMailerConfig();
|
||||||
@ -39,7 +36,7 @@ class Bounce {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
if(!self::checkBounceSyncAvailable()) {
|
if(!Bridge::isMPSendingServiceEnabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +61,7 @@ class Bounce {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function scheduleBounceSync() {
|
static function scheduleBounceSync() {
|
||||||
$already_scheduled = SendingQueue::where('type', 'bounce')
|
$already_scheduled = SendingQueue::where('type', self::TASK_TYPE)
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->where('status', SendingQueue::STATUS_SCHEDULED)
|
->where('status', SendingQueue::STATUS_SCHEDULED)
|
||||||
->findMany();
|
->findMany();
|
||||||
@ -72,7 +69,7 @@ class Bounce {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$queue = SendingQueue::create();
|
$queue = SendingQueue::create();
|
||||||
$queue->type = 'bounce';
|
$queue->type = self::TASK_TYPE;
|
||||||
$queue->status = SendingQueue::STATUS_SCHEDULED;
|
$queue->status = SendingQueue::STATUS_SCHEDULED;
|
||||||
$queue->priority = SendingQueue::PRIORITY_LOW;
|
$queue->priority = SendingQueue::PRIORITY_LOW;
|
||||||
$queue->scheduled_at = self::getNextRunDate();
|
$queue->scheduled_at = self::getNextRunDate();
|
||||||
@ -170,7 +167,7 @@ class Bounce {
|
|||||||
|
|
||||||
static function getScheduledQueues($future = false) {
|
static function getScheduledQueues($future = false) {
|
||||||
$dateWhere = ($future) ? 'whereGt' : 'whereLte';
|
$dateWhere = ($future) ? 'whereGt' : 'whereLte';
|
||||||
return SendingQueue::where('type', 'bounce')
|
return SendingQueue::where('type', self::TASK_TYPE)
|
||||||
->$dateWhere('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
->$dateWhere('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->where('status', SendingQueue::STATUS_SCHEDULED)
|
->where('status', SendingQueue::STATUS_SCHEDULED)
|
||||||
@ -178,7 +175,7 @@ class Bounce {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function getRunningQueues() {
|
static function getRunningQueues() {
|
||||||
return SendingQueue::where('type', 'bounce')
|
return SendingQueue::where('type', self::TASK_TYPE)
|
||||||
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->whereNull('status')
|
->whereNull('status')
|
||||||
|
144
lib/Cron/Workers/SendingServiceKeyCheck.php
Normal file
144
lib/Cron/Workers/SendingServiceKeyCheck.php
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Cron\Workers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use MailPoet\Cron\CronHelper;
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
use MailPoet\Models\SendingQueue;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class SendingServiceKeyCheck {
|
||||||
|
const TASK_TYPE = 'sskeycheck';
|
||||||
|
const UNAVAILABLE_SERVICE_RESCHEDULE_TIMEOUT = 60;
|
||||||
|
|
||||||
|
public $timer;
|
||||||
|
public $bridge;
|
||||||
|
|
||||||
|
function __construct($timer = false) {
|
||||||
|
$this->timer = ($timer) ? $timer : microtime(true);
|
||||||
|
// abort if execution limit is reached
|
||||||
|
CronHelper::enforceExecutionLimit($this->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initApi() {
|
||||||
|
if(!$this->bridge) {
|
||||||
|
$mailer_config = Mailer::getMailerConfig();
|
||||||
|
$this->bridge = new Bridge($mailer_config['mailpoet_api_key']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function process() {
|
||||||
|
if(!Bridge::isMPSendingServiceEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initApi();
|
||||||
|
|
||||||
|
$scheduled_queues = self::getScheduledQueues();
|
||||||
|
$running_queues = self::getRunningQueues();
|
||||||
|
|
||||||
|
if(!$scheduled_queues && !$running_queues) {
|
||||||
|
self::schedule();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($scheduled_queues as $i => $queue) {
|
||||||
|
$this->prepareQueue($queue);
|
||||||
|
}
|
||||||
|
foreach($running_queues as $i => $queue) {
|
||||||
|
$this->processQueue($queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function schedule() {
|
||||||
|
$already_scheduled = SendingQueue::where('type', self::TASK_TYPE)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('status', SendingQueue::STATUS_SCHEDULED)
|
||||||
|
->findMany();
|
||||||
|
if($already_scheduled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$queue = SendingQueue::create();
|
||||||
|
$queue->type = self::TASK_TYPE;
|
||||||
|
$queue->status = SendingQueue::STATUS_SCHEDULED;
|
||||||
|
$queue->priority = SendingQueue::PRIORITY_LOW;
|
||||||
|
$queue->scheduled_at = self::getNextRunDate();
|
||||||
|
$queue->newsletter_id = 0;
|
||||||
|
$queue->save();
|
||||||
|
return $queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareQueue(SendingQueue $queue) {
|
||||||
|
$queue->status = null;
|
||||||
|
$queue->save();
|
||||||
|
|
||||||
|
// abort if execution limit is reached
|
||||||
|
CronHelper::enforceExecutionLimit($this->timer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processQueue(SendingQueue $queue) {
|
||||||
|
// abort if execution limit is reached
|
||||||
|
CronHelper::enforceExecutionLimit($this->timer);
|
||||||
|
|
||||||
|
$result = $this->bridge->checkKey();
|
||||||
|
|
||||||
|
if(empty($result['code']) || $result['code'] == 503) {
|
||||||
|
// reschedule the check
|
||||||
|
$scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'));
|
||||||
|
$queue->scheduled_at = $scheduled_at->addMinutes(
|
||||||
|
self::UNAVAILABLE_SERVICE_RESCHEDULE_TIMEOUT
|
||||||
|
);
|
||||||
|
$queue->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$queue->processed_at = current_time('mysql');
|
||||||
|
$queue->status = SendingQueue::STATUS_COMPLETED;
|
||||||
|
$queue->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getNextRunDate() {
|
||||||
|
$date = Carbon::createFromTimestamp(current_time('timestamp'));
|
||||||
|
// Random day of the next week
|
||||||
|
$date->setISODate($date->format('o'), $date->format('W') + 1, mt_rand(1, 7));
|
||||||
|
$date->startOfDay();
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getScheduledQueues($future = false) {
|
||||||
|
$dateWhere = ($future) ? 'whereGt' : 'whereLte';
|
||||||
|
return SendingQueue::where('type', self::TASK_TYPE)
|
||||||
|
->$dateWhere('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('status', SendingQueue::STATUS_SCHEDULED)
|
||||||
|
->findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getRunningQueues() {
|
||||||
|
return SendingQueue::where('type', self::TASK_TYPE)
|
||||||
|
->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->whereNull('status')
|
||||||
|
->findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getAllDueQueues() {
|
||||||
|
$scheduled_queues = self::getScheduledQueues();
|
||||||
|
$running_queues = self::getRunningQueues();
|
||||||
|
return array_merge((array)$scheduled_queues, (array)$running_queues);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getFutureQueues() {
|
||||||
|
return self::getScheduledQueues(true);
|
||||||
|
}
|
||||||
|
}
|
@ -2,22 +2,30 @@
|
|||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
use MailPoet\Mailer\Mailer;
|
use MailPoet\Mailer\Mailer;
|
||||||
|
use MailPoet\Config\ServicesChecker;
|
||||||
|
use MailPoet\Services\Bridge;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class MailPoet {
|
class MailPoet {
|
||||||
public $url = 'https://bridge.mailpoet.com/api/messages';
|
public $url = 'https://bridge.mailpoet.com/api/v0/messages';
|
||||||
public $api_key;
|
public $api_key;
|
||||||
public $sender;
|
public $sender;
|
||||||
public $reply_to;
|
public $reply_to;
|
||||||
|
public $services_checker;
|
||||||
|
|
||||||
function __construct($api_key, $sender, $reply_to) {
|
function __construct($api_key, $sender, $reply_to) {
|
||||||
$this->api_key = $api_key;
|
$this->api_key = $api_key;
|
||||||
$this->sender = $sender;
|
$this->sender = $sender;
|
||||||
$this->reply_to = $reply_to;
|
$this->reply_to = $reply_to;
|
||||||
|
$this->services_checker = new ServicesChecker(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function send($newsletter, $subscriber, $extra_params = array()) {
|
function send($newsletter, $subscriber, $extra_params = array()) {
|
||||||
|
if(!$this->services_checker->checkMailPoetAPIKeyValid()) {
|
||||||
|
$response = __('MailPoet API key is invalid!', 'mailpoet');
|
||||||
|
return Mailer::formatMailerSendErrorResult($response);
|
||||||
|
}
|
||||||
$message_body = $this->getBody($newsletter, $subscriber);
|
$message_body = $this->getBody($newsletter, $subscriber);
|
||||||
$result = wp_remote_post(
|
$result = wp_remote_post(
|
||||||
$this->url,
|
$this->url,
|
||||||
@ -26,7 +34,11 @@ class MailPoet {
|
|||||||
if(is_wp_error($result)) {
|
if(is_wp_error($result)) {
|
||||||
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||||
}
|
}
|
||||||
if(wp_remote_retrieve_response_code($result) !== 201) {
|
$response_code = wp_remote_retrieve_response_code($result);
|
||||||
|
if($response_code !== 201) {
|
||||||
|
if($response_code === 401) {
|
||||||
|
Bridge::invalidateKey();
|
||||||
|
}
|
||||||
$response = (wp_remote_retrieve_body($result)) ?
|
$response = (wp_remote_retrieve_body($result)) ?
|
||||||
wp_remote_retrieve_body($result) :
|
wp_remote_retrieve_body($result) :
|
||||||
wp_remote_retrieve_response_message($result);
|
wp_remote_retrieve_response_message($result);
|
||||||
|
48
lib/Services/Bridge.php
Normal file
48
lib/Services/Bridge.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Services;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Bridge {
|
||||||
|
const MAILPOET_KEY_VALID = 200;
|
||||||
|
const MAILPOET_KEY_INVALID = 401;
|
||||||
|
const MAILPOET_KEY_EXPIRING = 402;
|
||||||
|
|
||||||
|
public $api;
|
||||||
|
|
||||||
|
function __construct($api_key) {
|
||||||
|
$this->api = new Bridge\API($api_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function isMPSendingServiceEnabled() {
|
||||||
|
$mailer_config = Mailer::getMailerConfig();
|
||||||
|
return !empty($mailer_config['method'])
|
||||||
|
&& $mailer_config['method'] === Mailer::METHOD_MAILPOET;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkKey() {
|
||||||
|
$result = $this->api->checkKey();
|
||||||
|
return $this->processResult($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processResult(array $result) {
|
||||||
|
if(empty($result['code'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Setting::setValue(
|
||||||
|
'mta.mailpoet_api_key_state',
|
||||||
|
array(
|
||||||
|
'code' => (int)$result['code'],
|
||||||
|
'data' => !empty($result['data']) ? $result['data'] : null,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function invalidateKey() {
|
||||||
|
Setting::setValue('mta.mailpoet_api_key_state', array('code' => 401));
|
||||||
|
}
|
||||||
|
}
|
56
lib/Services/Bridge/API.php
Normal file
56
lib/Services/Bridge/API.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Services\Bridge;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class API {
|
||||||
|
public $url = 'https://bridge.mailpoet.com/api/v0/me';
|
||||||
|
public $api_key;
|
||||||
|
|
||||||
|
function __construct($api_key) {
|
||||||
|
$this->api_key = $api_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkKey() {
|
||||||
|
$result = wp_remote_post(
|
||||||
|
$this->url,
|
||||||
|
$this->request(array('site' => home_url()))
|
||||||
|
);
|
||||||
|
return $this->processResponse($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processResponse($result) {
|
||||||
|
$code = wp_remote_retrieve_response_code($result);
|
||||||
|
switch($code) {
|
||||||
|
case 200:
|
||||||
|
case 402:
|
||||||
|
$body = json_decode(wp_remote_retrieve_body($result), true);
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
$body = wp_remote_retrieve_body($result);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$body = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('code' => $code, 'data' => $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function auth() {
|
||||||
|
return 'Basic ' . base64_encode('api:' . $this->api_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function request($body) {
|
||||||
|
return array(
|
||||||
|
'timeout' => 10,
|
||||||
|
'httpversion' => '1.0',
|
||||||
|
'method' => 'POST',
|
||||||
|
'headers' => array(
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Authorization' => $this->auth()
|
||||||
|
),
|
||||||
|
'body' => json_encode($body)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
16
views/invalidkey.html
Normal file
16
views/invalidkey.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<% extends 'layout.html' %>
|
||||||
|
|
||||||
|
<% block content %>
|
||||||
|
|
||||||
|
<div class="wrap about-wrap">
|
||||||
|
<h1><%= __("All sending is currently paused!") %></h1>
|
||||||
|
|
||||||
|
<p class="about-text">
|
||||||
|
<%= __("Your key to send with MailPoet is invalid.") %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a class="button button-primary" target="_blank" href="https://account.mailpoet.com?s=<%= subscriber_count %>"><%= __('Visit MailPoet.com to purchase a key') %></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% endblock %>
|
@ -150,6 +150,10 @@
|
|||||||
name="mta[mailpoet_api_key]"
|
name="mta[mailpoet_api_key]"
|
||||||
value="<%=- settings.mta.mailpoet_api_key -%>"
|
value="<%=- settings.mta.mailpoet_api_key -%>"
|
||||||
/>
|
/>
|
||||||
|
<a
|
||||||
|
id="mailpoet_api_key_verify"
|
||||||
|
class="button-secondary"
|
||||||
|
><%= __('Verify') %></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -687,7 +691,7 @@
|
|||||||
if(settings.sender.address.length === 0) {
|
if(settings.sender.address.length === 0) {
|
||||||
// validation
|
// validation
|
||||||
return MailPoet.Notice.error(
|
return MailPoet.Notice.error(
|
||||||
'The email could not be sent. Make sure the option "Email notifications" has a FROM email address in the Basics tab.',
|
'<%= __('The email could not be sent. Make sure the option "Email notifications" has a FROM email address in the Basics tab.') %>',
|
||||||
{ scroll: true, static: true }
|
{ scroll: true, static: true }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -727,6 +731,43 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// verifying api key
|
||||||
|
$('#mailpoet_api_key_verify').on('click', function() {
|
||||||
|
// get api key
|
||||||
|
var key = $('#mailpoet_api_key').val();
|
||||||
|
|
||||||
|
if(key.length === 0) {
|
||||||
|
// validation
|
||||||
|
return MailPoet.Notice.error(
|
||||||
|
'<%= __('Please specify an API key before validating it.') %>',
|
||||||
|
{ scroll: true, static: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MailPoet.Modal.loading(true);
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'services',
|
||||||
|
action: 'verifyMailPoetKey',
|
||||||
|
data: {
|
||||||
|
key: key
|
||||||
|
}
|
||||||
|
}).always(function() {
|
||||||
|
MailPoet.Modal.loading(false);
|
||||||
|
}).done(function(response) {
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
"<%= __('Your MailPoet API key is valid!') %>",
|
||||||
|
{ scroll: true }
|
||||||
|
);
|
||||||
|
}).fail(function(response) {
|
||||||
|
if (response.errors.length > 0) {
|
||||||
|
MailPoet.Notice.error(
|
||||||
|
response.errors.map(function(error) { return error.message; }),
|
||||||
|
{ scroll: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// sending frequency update based on selected provider
|
// sending frequency update based on selected provider
|
||||||
$('#mailpoet_smtp_provider').on('change keyup', setProviderForm);
|
$('#mailpoet_smtp_provider').on('change keyup', setProviderForm);
|
||||||
$('#mailpoet_web_host').on('change keyup', renderHostSendingFrequency);
|
$('#mailpoet_web_host').on('change keyup', renderHostSendingFrequency);
|
||||||
|
Reference in New Issue
Block a user