Added API/Endpoint abstract class

- (re)Added Endpoints folder to both API and Router
- fixed syntax in namespaces
- xhr.responseJSON is returned to the fail()
- fixed Router endpoints (view in browser, cron,...)
This commit is contained in:
Jonathan Labreuille
2016-08-02 17:08:43 +02:00
parent ed30d8f639
commit 2e88d7cce0
40 changed files with 99 additions and 111 deletions

View File

@ -16,9 +16,6 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
post: function(options) { post: function(options) {
return this.request('post', options); return this.request('post', options);
}, },
delete: function(options) {
return this.request('delete', options);
},
init: function(options) { init: function(options) {
// merge options // merge options
this.options = jQuery.extend({}, this.defaults, options); this.options = jQuery.extend({}, this.defaults, options);
@ -48,7 +45,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
// set request params // set request params
var params = this.getParams(); var params = this.getParams();
var jqXHR; var deferred = jQuery.Deferred();
// remove null values from the data object // remove null values from the data object
if (_.isObject(params.data)) { if (_.isObject(params.data)) {
@ -59,25 +56,29 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
// make ajax request depending on method // make ajax request depending on method
if(method === 'get') { if(method === 'get') {
jqXHR = jQuery.get( jQuery.get(
this.options.url, this.options.url,
params, params,
this.options.onSuccess, null,
'json' 'json'
); );
} else { } else {
jqXHR = jQuery.ajax({ jQuery.post(
url: this.options.url, this.options.url,
type : 'post', params,
data: params, null,
dataType: 'json' 'json'
).then(function(data) {
deferred.resolve();
}, function(xhr) {
deferred.reject(xhr.responseJSON);
}); });
} }
// clear options // clear options
this.options = {}; this.options = {};
return jqXHR; return deferred;
} }
}; };
}); });

View File

@ -36,19 +36,19 @@ class API {
function setupAdmin() { function setupAdmin() {
if($this->checkToken() === false) { if($this->checkToken() === false) {
$this->errorResponse( (new ErrorResponse(
array('unauthorized' => __('This request is not authorized.')), array('unauthorized' => __('This request is not authorized.')),
array(), array(),
APIResponse::STATUS_UNAUTHORIZED Response::STATUS_UNAUTHORIZED
)->send(); ))->send();
} }
if($this->checkPermissions() === false) { if($this->checkPermissions() === false) {
$this->errorResponse( (new ErrorResponse(
array('forbidden' => __('You do not have the required permissions.')), array('forbidden' => __('You do not have the required permissions.')),
array(), array(),
APIResponse::STATUS_FORBIDDEN Response::STATUS_FORBIDDEN
)->send(); ))->send();
} }
$this->processRoute(); $this->processRoute();
@ -56,9 +56,9 @@ class API {
function setupPublic() { function setupPublic() {
if($this->checkToken() === false) { if($this->checkToken() === false) {
$response = new APIErrorResponse(array( $response = new ErrorResponse(array(
'unauthorized' => __('This request is not authorized.') 'unauthorized' => __('This request is not authorized.')
), APIResponse::STATUS_UNAUTHORIZED); ), Response::STATUS_UNAUTHORIZED);
$response->send(); $response->send();
} }
@ -67,7 +67,7 @@ class API {
function processRoute() { function processRoute() {
$class = ucfirst($_POST['endpoint']); $class = ucfirst($_POST['endpoint']);
$endpoint = __NAMESPACE__ . "\\" . $class; $endpoint = __NAMESPACE__ . "\\Endpoints\\" . $class;
$method = $_POST['method']; $method = $_POST['method'];
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX); $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
@ -101,9 +101,7 @@ class API {
wp_send_json($response); wp_send_json($response);
} }
} catch(\Exception $e) { } catch(\Exception $e) {
$this->errorResponse(array( (new ErrorResponse(array($e->getMessage())))->send();
$e->getMessage()
))->send();
} }
} }
@ -125,22 +123,4 @@ class API {
wp_verify_nonce($_POST['token'], 'mailpoet_token') wp_verify_nonce($_POST['token'], 'mailpoet_token')
); );
} }
function successResponse(
$data = array(), $meta = array(), $status = APIResponse::STATUS_OK
) {
return new APISuccessResponse($data, $meta, $status);
}
function errorResponse(
$errors = array(), $meta = array(), $status = APIResponse::STATUS_NOT_FOUND
) {
return new APIErrorResponse($errors, $meta, $status);
}
function badRequest($errors = array(), $meta = array()) {
return new APIErrorResponse($errors, $meta, APIResponse::STATUS_BAD_REQUEST);
}
} }

25
lib/API/Endpoint.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace MailPoet\API;
if(!defined('ABSPATH')) exit;
abstract class Endpoint {
function successResponse(
$data = array(), $meta = array(), $status = Response::STATUS_OK
) {
return new SuccessResponse($data, $meta, $status);
}
function errorResponse(
$errors = array(), $meta = array(), $status = Response::STATUS_NOT_FOUND
) {
return new ErrorResponse($errors, $meta, $status);
}
function badRequest($errors = array(), $meta = array()) {
return new ErrorResponse($errors, $meta, Response::STATUS_BAD_REQUEST);
}
}

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Cron\CronHelper; use MailPoet\Cron\CronHelper;
use MailPoet\Cron\Supervisor; use MailPoet\Cron\Supervisor;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use \MailPoet\Models\CustomField; use \MailPoet\Models\CustomField;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use \MailPoet\Models\Form; use \MailPoet\Models\Form;
use \MailPoet\Models\StatisticsForms; use \MailPoet\Models\StatisticsForms;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Subscribers\ImportExport\Import\MailChimp; use MailPoet\Subscribers\ImportExport\Import\MailChimp;
use MailPoet\Models\CustomField; use MailPoet\Models\CustomField;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Models\NewsletterTemplate; use MailPoet\Models\NewsletterTemplate;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use \MailPoet\Models\Segment; use \MailPoet\Models\Segment;
use \MailPoet\Models\SubscriberSegment; use \MailPoet\Models\SubscriberSegment;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Mailer\Mailer; use MailPoet\Mailer\Mailer;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;

View File

@ -1,10 +1,11 @@
<?php <?php
namespace MailPoet\API; namespace MailPoet\API\Endpoints;
use \MailPoet\API\Endpoint as APIEndpoint;
use \MailPoet\Models\Setting; use \MailPoet\Models\Setting;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Settings extends API { class Settings extends APIEndpoint {
function __construct() { function __construct() {
} }
@ -20,7 +21,7 @@ class Settings extends API {
foreach($settings as $name => $value) { foreach($settings as $name => $value) {
Setting::setValue($name, $value); Setting::setValue($name, $value);
} }
return $this->successResponse(); return $this->successResponse(Setting::getAll());
} }
} }
} }

View File

@ -1,7 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use \MailPoet\Config\Activator; use \MailPoet\Config\Activator;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\API namespace MailPoet\API\Endpoints;
;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;

View File

@ -3,7 +3,7 @@ namespace MailPoet\API;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class APIErrorResponse extends APIResponse { class ErrorResponse extends Response {
public $errors; public $errors;
function __construct($errors = array(), $meta = array(), $status = self::STATUS_NOT_FOUND) { function __construct($errors = array(), $meta = array(), $status = self::STATUS_NOT_FOUND) {

View File

@ -3,7 +3,7 @@ namespace MailPoet\API;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
abstract class APIResponse { abstract class Response {
const STATUS_OK = 200; const STATUS_OK = 200;
const STATUS_BAD_REQUEST = 400; const STATUS_BAD_REQUEST = 400;
const STATUS_UNAUTHORIZED = 401; const STATUS_UNAUTHORIZED = 401;

View File

@ -3,7 +3,7 @@ namespace MailPoet\API;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class APISuccessResponse extends APIResponse { class SuccessResponse extends Response {
public $data; public $data;
function __construct($data = array(), $meta = array(), $status = self::STATUS_OK) { function __construct($data = array(), $meta = array(), $status = self::STATUS_OK) {

View File

@ -74,13 +74,6 @@ class Populator {
private function createDefaultSettings() { private function createDefaultSettings() {
$current_user = wp_get_current_user(); $current_user = wp_get_current_user();
if(!Setting::getValue('task_scheduler')) {
// disable task scheduler (cron) be default
Setting::setValue('task_scheduler', array(
'method' => 'WordPress'
));
}
// default sender info based on current user // default sender info based on current user
$sender = array( $sender = array(
'name' => $current_user->display_name, 'name' => $current_user->display_name,

View File

@ -2,7 +2,7 @@
namespace MailPoet\Cron; namespace MailPoet\Cron;
use MailPoet\Router\Front as FrontRouter; use MailPoet\Router\Front as FrontRouter;
use MailPoet\Router\Queue as QueueEndpoint; use MailPoet\Router\Endpoints\Queue as QueueEndpoint;
use MailPoet\Models\Setting; use MailPoet\Models\Setting;
use MailPoet\Util\Security; use MailPoet\Util\Security;

View File

@ -38,6 +38,9 @@ class Setting extends Model {
'interval' => self::DEFAULT_SENDING_FREQUENCY_INTERVAL 'interval' => self::DEFAULT_SENDING_FREQUENCY_INTERVAL
) )
), ),
'task_scheduler' => array(
'method' => 'WordPress'
),
'signup_confirmation' => array( 'signup_confirmation' => array(
'enabled' => true, 'enabled' => true,
'subject' => sprintf(__('Confirm your subscription to %1$s'), get_option('blogname')), 'subject' => sprintf(__('Confirm your subscription to %1$s'), get_option('blogname')),

View File

@ -2,7 +2,7 @@
namespace MailPoet\Newsletter\Links; namespace MailPoet\Newsletter\Links;
use MailPoet\Router\Front as FrontRouter; use MailPoet\Router\Front as FrontRouter;
use MailPoet\Router\Track as TrackEndpoint; use MailPoet\Router\Endpoints\Track as TrackEndpoint;
use MailPoet\Models\NewsletterLink; use MailPoet\Models\NewsletterLink;
use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Newsletter\Shortcodes\Shortcodes;
use MailPoet\Util\Security; use MailPoet\Util\Security;

View File

@ -2,7 +2,7 @@
namespace MailPoet\Newsletter; namespace MailPoet\Newsletter;
use MailPoet\Router\Front as FrontRouter; use MailPoet\Router\Front as FrontRouter;
use MailPoet\Router\ViewInBrowser as ViewInBrowserEndpoint; use MailPoet\Router\Endpoints\ViewInBrowser as ViewInBrowserEndpoint;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
class Url { class Url {

View File

@ -1,5 +1,5 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router\Endpoints;
use MailPoet\Cron\Daemon; use MailPoet\Cron\Daemon;

View File

@ -1,5 +1,5 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router\Endpoints;
use MailPoet\Subscription as UserSubscription; use MailPoet\Subscription as UserSubscription;

View File

@ -1,5 +1,5 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router\Endpoints;
use MailPoet\Statistics\Track\Clicks; use MailPoet\Statistics\Track\Clicks;
use MailPoet\Statistics\Track\Opens; use MailPoet\Statistics\Track\Opens;

View File

@ -1,5 +1,5 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router\Endpoints;
use MailPoet\Newsletter\ViewInBrowser as NewsletterViewInBrowser; use MailPoet\Newsletter\ViewInBrowser as NewsletterViewInBrowser;

View File

@ -1,6 +1,5 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
@ -28,13 +27,14 @@ class Front {
} }
function init() { function init() {
$endpoint = ucfirst($this->endpoint); $class = __NAMESPACE__ . "\\Endpoints\\" . ucfirst($this->endpoint);
if(!$this->api_request) return; if(!$this->api_request) return;
if(!$this->endpoint || !class_exists($endpoint)) { if(!$this->endpoint || !class_exists($class)) {
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid Router endpoint.')); self::terminateRequest(self::RESPONSE_ERROR, __('Invalid Router endpoint.'));
} }
$this->callEndpoint( $this->callEndpoint(
$endpoint, $class,
$this->action, $this->action,
$this->data $this->data
); );

View File

@ -1,7 +1,6 @@
<?php <?php
namespace MailPoet\Subscription; namespace MailPoet\Subscription;
use \MailPoet\Router\Subscribers;
use \MailPoet\Models\Subscriber; use \MailPoet\Models\Subscriber;
use \MailPoet\Models\SubscriberSegment; use \MailPoet\Models\SubscriberSegment;
use \MailPoet\Models\CustomField; use \MailPoet\Models\CustomField;

View File

@ -2,7 +2,7 @@
namespace MailPoet\Subscription; namespace MailPoet\Subscription;
use MailPoet\Router\Front as FrontRouter; use MailPoet\Router\Front as FrontRouter;
use MailPoet\Router\Subscription as SubscriptionEndpoint; use MailPoet\Router\Endpoints\Subscription as SubscriptionEndpoint;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Models\Setting; use MailPoet\Models\Setting;

View File

@ -1,6 +1,6 @@
<?php <?php
use \MailPoet\API\CustomFields; use \MailPoet\API\Endpoints\CustomFields;
use \MailPoet\Models\CustomField; use \MailPoet\Models\CustomField;
class CustomFieldsTest extends MailPoetTest { class CustomFieldsTest extends MailPoetTest {

View File

@ -1,5 +1,5 @@
<?php <?php
use \MailPoet\API\Forms; use \MailPoet\API\Endpoints\Forms;
use \MailPoet\Models\Form; use \MailPoet\Models\Form;
use \MailPoet\Models\Segment; use \MailPoet\Models\Segment;

View File

@ -1,5 +1,5 @@
<?php <?php
use \MailPoet\API\NewsletterTemplates; use \MailPoet\API\Endpoints\NewsletterTemplates;
use \MailPoet\Models\NewsletterTemplate; use \MailPoet\Models\NewsletterTemplate;
class NewsletterTemplatesTest extends MailPoetTest { class NewsletterTemplatesTest extends MailPoetTest {

View File

@ -1,5 +1,5 @@
<?php <?php
use \MailPoet\API\Newsletters; use \MailPoet\API\Endpoints\Newsletters;
use \MailPoet\Models\Newsletter; use \MailPoet\Models\Newsletter;
use \MailPoet\Models\NewsletterSegment; use \MailPoet\Models\NewsletterSegment;
use \MailPoet\Models\NewsletterTemplate; use \MailPoet\Models\NewsletterTemplate;

View File

@ -1,5 +1,5 @@
<?php <?php
use \MailPoet\API\Segments; use \MailPoet\API\Endpoints\Segments;
use \MailPoet\Models\Segment; use \MailPoet\Models\Segment;
class SegmentsTest extends MailPoetTest { class SegmentsTest extends MailPoetTest {

View File

@ -1,6 +1,6 @@
<?php <?php
use \MailPoet\API\APIResponse; use \MailPoet\API\Response;
use \MailPoet\API\Settings; use \MailPoet\API\Endpoints\Settings;
use \MailPoet\Models\Setting; use \MailPoet\Models\Setting;
class SettingsTest extends MailPoetTest { class SettingsTest extends MailPoetTest {
@ -12,14 +12,14 @@ class SettingsTest extends MailPoetTest {
$router = new Settings(); $router = new Settings();
$response = $router->get(); $response = $router->get();
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(Response::STATUS_OK);
expect($response->data)->notEmpty(); expect($response->data)->notEmpty();
expect($response->data['some']['setting']['key'])->true(); expect($response->data['some']['setting']['key'])->true();
Setting::deleteMany(); Setting::deleteMany();
$response = $router->get(); $response = $router->get();
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(Response::STATUS_OK);
expect($response->data)->equals(Setting::getDefaults()); expect($response->data)->equals(Setting::getDefaults());
} }
@ -36,13 +36,13 @@ class SettingsTest extends MailPoetTest {
$router = new Settings(); $router = new Settings();
$response = $router->set(/* missing data */); $response = $router->set(/* missing data */);
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST); expect($response->status)->equals(Response::STATUS_BAD_REQUEST);
$response = $router->set($new_settings); $response = $router->set($new_settings);
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(Response::STATUS_OK);
$response = $router->get(); $response = $router->get();
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(Response::STATUS_OK);
expect($response->data['some']['setting'])->hasntKey('key'); expect($response->data['some']['setting'])->hasntKey('key');
expect($response->data['some']['setting']['new_key'])->true(); expect($response->data['some']['setting']['new_key'])->true();
expect($response->data['some']['new_setting'])->true(); expect($response->data['some']['new_setting'])->true();

View File

@ -1,5 +1,5 @@
<?php <?php
use \MailPoet\API\Setup; use \MailPoet\API\Endpoints\Setup;
use \MailPoet\Models\Setting; use \MailPoet\Models\Setting;
class SetupTest extends MailPoetTest { class SetupTest extends MailPoetTest {

View File

@ -1,6 +1,6 @@
<?php <?php
use \MailPoet\API\Subscribers; use \MailPoet\API\Endpoints\Subscribers;
use \MailPoet\Models\Subscriber; use \MailPoet\Models\Subscriber;
use \MailPoet\Models\Segment; use \MailPoet\Models\Segment;

View File

@ -77,15 +77,14 @@
endpoint: 'settings', endpoint: 'settings',
action: 'set', action: 'set',
data: settings_data data: settings_data
}).done(function() { }).done(function(response) {
MailPoet.Notice.success( MailPoet.Notice.success(
"<%= __('Settings saved') %>", "<%= __('Settings saved') %>",
{ scroll: true } { scroll: true }
); );
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
}).error(function(xhr) { }).fail(function(response) {
var response = xhr.responseJSON; if (response.errors !== undefined) {
if(response.errors !== undefined) {
MailPoet.Notice.error( MailPoet.Notice.error(
response.errors.map(function(error) { return error.message; }), response.errors.map(function(error) { return error.message; }),
{ scroll: true } { scroll: true }