diff --git a/assets/js/src/ajax.js b/assets/js/src/ajax.js
index 3878a3582a..e76f3ad76d 100644
--- a/assets/js/src/ajax.js
+++ b/assets/js/src/ajax.js
@@ -5,6 +5,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
options: {},
defaults: {
url: null,
+ api_version: null,
endpoint: null,
action: null,
token: null,
@@ -30,6 +31,7 @@ define('ajax', ['mailpoet', 'jquery', 'underscore'], function(MailPoet, jQuery,
getParams: function() {
return {
action: 'mailpoet',
+ api_version: this.options.api_version,
token: this.options.token,
endpoint: this.options.endpoint,
method: this.options.action,
diff --git a/assets/js/src/form/form.jsx b/assets/js/src/form/form.jsx
index ca61b30d8c..bfffe4eb86 100644
--- a/assets/js/src/form/form.jsx
+++ b/assets/js/src/form/form.jsx
@@ -64,6 +64,7 @@ define(
this.setState({ loading: true });
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'get',
data: {
@@ -112,6 +113,7 @@ define(
}
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'save',
data: item
diff --git a/assets/js/src/forms/list.jsx b/assets/js/src/forms/list.jsx
index 43d3c7f261..979374c58e 100644
--- a/assets/js/src/forms/list.jsx
+++ b/assets/js/src/forms/list.jsx
@@ -97,6 +97,7 @@ const item_actions = [
label: MailPoet.I18n.t('duplicate'),
onClick: function(item, refresh) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'forms',
action: 'duplicate',
data: {
@@ -125,6 +126,7 @@ const item_actions = [
const FormList = React.createClass({
createForm() {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'forms',
action: 'create'
}).done((response) => {
diff --git a/assets/js/src/listing/listing.jsx b/assets/js/src/listing/listing.jsx
index 0af6825e7f..2c28bf5cbb 100644
--- a/assets/js/src/listing/listing.jsx
+++ b/assets/js/src/listing/listing.jsx
@@ -445,6 +445,7 @@ const Listing = React.createClass({
this.clearSelection();
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'listing',
data: {
@@ -495,6 +496,7 @@ const Listing = React.createClass({
});
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'restore',
data: {
@@ -522,6 +524,7 @@ const Listing = React.createClass({
});
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'trash',
data: {
@@ -549,6 +552,7 @@ const Listing = React.createClass({
});
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'delete',
data: {
@@ -611,6 +615,7 @@ const Listing = React.createClass({
}
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: this.props.endpoint,
action: 'bulkAction',
data: data
diff --git a/assets/js/src/newsletter_editor/components/communication.js b/assets/js/src/newsletter_editor/components/communication.js
index 56368103dc..2b765b8144 100644
--- a/assets/js/src/newsletter_editor/components/communication.js
+++ b/assets/js/src/newsletter_editor/components/communication.js
@@ -9,6 +9,7 @@ define([
Module._query = function(args) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'automatedLatestContent',
action: args.action,
data: args.options || {}
@@ -81,6 +82,7 @@ define([
Module.saveNewsletter = function(options) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'save',
data: options || {}
@@ -89,6 +91,7 @@ define([
Module.previewNewsletter = function(options) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'sendPreview',
data: options || {}
diff --git a/assets/js/src/newsletter_editor/components/save.js b/assets/js/src/newsletter_editor/components/save.js
index e09d592455..2c45fa0ba2 100644
--- a/assets/js/src/newsletter_editor/components/save.js
+++ b/assets/js/src/newsletter_editor/components/save.js
@@ -109,6 +109,7 @@ define([
});
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'save',
data: data
diff --git a/assets/js/src/newsletter_editor/components/sidebar.js b/assets/js/src/newsletter_editor/components/sidebar.js
index 4419b7bf05..cbc57def62 100644
--- a/assets/js/src/newsletter_editor/components/sidebar.js
+++ b/assets/js/src/newsletter_editor/components/sidebar.js
@@ -243,6 +243,7 @@ define([
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'showPreview',
data: json,
diff --git a/assets/js/src/newsletters/listings/mixins.jsx b/assets/js/src/newsletters/listings/mixins.jsx
index 3973ff9e65..98555a8815 100644
--- a/assets/js/src/newsletters/listings/mixins.jsx
+++ b/assets/js/src/newsletters/listings/mixins.jsx
@@ -8,6 +8,7 @@ import jQuery from 'jquery'
const _QueueMixin = {
pauseSending: function(newsletter) {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'sendingQueue',
action: 'pause',
data: {
@@ -27,6 +28,7 @@ const _QueueMixin = {
},
resumeSending: function(newsletter) {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'sendingQueue',
action: 'resume',
data: {
@@ -225,6 +227,7 @@ const _MailerMixin = {
},
resumeMailerSending() {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'mailer',
action: 'resumeSending'
}).done(function() {
diff --git a/assets/js/src/newsletters/listings/notification.jsx b/assets/js/src/newsletters/listings/notification.jsx
index 1f59fc36d4..256bcf4046 100644
--- a/assets/js/src/newsletters/listings/notification.jsx
+++ b/assets/js/src/newsletters/listings/notification.jsx
@@ -129,6 +129,7 @@ const newsletter_actions = [
label: MailPoet.I18n.t('duplicate'),
onClick: function(newsletter, refresh) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'duplicate',
data: {
@@ -164,6 +165,7 @@ const NewsletterListNotification = React.createClass({
e.persist();
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'setStatus',
data: {
diff --git a/assets/js/src/newsletters/listings/standard.jsx b/assets/js/src/newsletters/listings/standard.jsx
index 1c56229585..f399df617e 100644
--- a/assets/js/src/newsletters/listings/standard.jsx
+++ b/assets/js/src/newsletters/listings/standard.jsx
@@ -124,6 +124,7 @@ const newsletter_actions = [
label: MailPoet.I18n.t('duplicate'),
onClick: function(newsletter, refresh) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'duplicate',
data: {
diff --git a/assets/js/src/newsletters/listings/welcome.jsx b/assets/js/src/newsletters/listings/welcome.jsx
index bae199461f..ac4d269089 100644
--- a/assets/js/src/newsletters/listings/welcome.jsx
+++ b/assets/js/src/newsletters/listings/welcome.jsx
@@ -126,6 +126,7 @@ const newsletter_actions = [
label: MailPoet.I18n.t('duplicate'),
onClick: function(newsletter, refresh) {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'duplicate',
data: {
@@ -161,6 +162,7 @@ const NewsletterListWelcome = React.createClass({
e.persist();
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'setStatus',
data: {
diff --git a/assets/js/src/newsletters/send.jsx b/assets/js/src/newsletters/send.jsx
index 1874b12513..7ccc781b94 100644
--- a/assets/js/src/newsletters/send.jsx
+++ b/assets/js/src/newsletters/send.jsx
@@ -64,6 +64,7 @@ define(
this.setState({ loading: true });
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'get',
data: {
@@ -97,6 +98,7 @@ define(
case 'notification':
case 'welcome':
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'setStatus',
data: {
@@ -120,6 +122,7 @@ define(
}).fail(this._showError);
default:
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'sendingQueue',
action: 'add',
data: {
@@ -184,6 +187,7 @@ define(
);
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'save',
data: newsletterData,
diff --git a/assets/js/src/newsletters/send/notification.jsx b/assets/js/src/newsletters/send/notification.jsx
index 539616778c..d66f637f4a 100644
--- a/assets/js/src/newsletters/send/notification.jsx
+++ b/assets/js/src/newsletters/send/notification.jsx
@@ -37,8 +37,9 @@ define(
tip: MailPoet.I18n.t('segmentsTip'),
type: 'selection',
placeholder: MailPoet.I18n.t('selectSegmentPlaceholder'),
- id: "mailpoet_segments",
- endpoint: "segments",
+ id: 'mailpoet_segments',
+ api_version: window.mailpoet_api_version,
+ endpoint: 'segments',
multiple: true,
filter: function(segment) {
return !!(!segment.deleted_at);
diff --git a/assets/js/src/newsletters/send/standard.jsx b/assets/js/src/newsletters/send/standard.jsx
index fcf5ece48b..a8187521b8 100644
--- a/assets/js/src/newsletters/send/standard.jsx
+++ b/assets/js/src/newsletters/send/standard.jsx
@@ -341,8 +341,9 @@ define(
tip: MailPoet.I18n.t('segmentsTip'),
type: 'selection',
placeholder: MailPoet.I18n.t('selectSegmentPlaceholder'),
- id: "mailpoet_segments",
- endpoint: "segments",
+ id: 'mailpoet_segments',
+ api_version: window.mailpoet_api_version,
+ endpoint: 'segments',
multiple: true,
filter: function(segment) {
return !!(!segment.deleted_at);
diff --git a/assets/js/src/newsletters/templates.jsx b/assets/js/src/newsletters/templates.jsx
index 5ef22ff2a6..f292c5a0ff 100644
--- a/assets/js/src/newsletters/templates.jsx
+++ b/assets/js/src/newsletters/templates.jsx
@@ -27,6 +27,7 @@ define(
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'save',
data: template
@@ -97,6 +98,7 @@ define(
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'getAll',
}).always(() => {
@@ -130,6 +132,7 @@ define(
}
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'save',
data: {
@@ -158,6 +161,7 @@ define(
)
) {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'delete',
data: {
diff --git a/assets/js/src/newsletters/types.jsx b/assets/js/src/newsletters/types.jsx
index 65cadff270..dca520ac69 100644
--- a/assets/js/src/newsletters/types.jsx
+++ b/assets/js/src/newsletters/types.jsx
@@ -22,6 +22,7 @@ define(
},
createNewsletter: function(type) {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: {
diff --git a/assets/js/src/newsletters/types/notification/notification.jsx b/assets/js/src/newsletters/types/notification/notification.jsx
index 591eea0955..10210b7a02 100644
--- a/assets/js/src/newsletters/types/notification/notification.jsx
+++ b/assets/js/src/newsletters/types/notification/notification.jsx
@@ -44,6 +44,7 @@ define(
},
handleNext: function() {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: _.extend({}, this.state, {
diff --git a/assets/js/src/newsletters/types/standard.jsx b/assets/js/src/newsletters/types/standard.jsx
index 5762902826..9d776a0c66 100644
--- a/assets/js/src/newsletters/types/standard.jsx
+++ b/assets/js/src/newsletters/types/standard.jsx
@@ -22,6 +22,7 @@ define(
componentDidMount: function() {
// No options for this type, create a newsletter upon mounting
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: {
diff --git a/assets/js/src/newsletters/types/welcome/scheduling.jsx b/assets/js/src/newsletters/types/welcome/scheduling.jsx
index c7e1fa2418..d43593514d 100644
--- a/assets/js/src/newsletters/types/welcome/scheduling.jsx
+++ b/assets/js/src/newsletters/types/welcome/scheduling.jsx
@@ -104,6 +104,7 @@ const WelcomeScheduling = React.createClass({
},
handleNext: function() {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: {
diff --git a/assets/js/src/newsletters/types/welcome/welcome.jsx b/assets/js/src/newsletters/types/welcome/welcome.jsx
index 18bb917065..78facf4009 100644
--- a/assets/js/src/newsletters/types/welcome/welcome.jsx
+++ b/assets/js/src/newsletters/types/welcome/welcome.jsx
@@ -52,6 +52,7 @@ define(
},
handleNext: function() {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: _.extend({}, this.state, {
diff --git a/assets/js/src/public.js b/assets/js/src/public.js
index ca97653ed9..4b3d570603 100644
--- a/assets/js/src/public.js
+++ b/assets/js/src/public.js
@@ -31,7 +31,7 @@ function(
});
form.parsley().on('form:submit', function(parsley) {
- var data = form.serializeObject() || {};
+ var form_data = form.serializeObject() || {};
// check if we're on the same domain
if(isSameDomain(MailPoetForm.ajax_url) === false) {
// non ajax post request
@@ -40,10 +40,11 @@ function(
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
- token: data.token,
+ token: form_data.token,
+ api_version: form_data.api_version,
endpoint: 'subscribers',
action: 'subscribe',
- data: data
+ data: form_data.data
}).fail(function(response) {
form.find('.mailpoet_validate_error').html(
response.errors.map(function(error) {
diff --git a/assets/js/src/segments/list.jsx b/assets/js/src/segments/list.jsx
index cfc15bc4f1..f27ebfacef 100644
--- a/assets/js/src/segments/list.jsx
+++ b/assets/js/src/segments/list.jsx
@@ -112,6 +112,7 @@ const item_actions = [
label: MailPoet.I18n.t('duplicate'),
onClick: (item, refresh) => {
return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'segments',
action: 'duplicate',
data: {
@@ -153,6 +154,7 @@ const item_actions = [
onClick: function(item, refresh) {
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'segments',
action: 'synchronize'
}).done(function(response) {
diff --git a/assets/js/src/subscribers/form.jsx b/assets/js/src/subscribers/form.jsx
index cdccd7e310..7e5964b798 100644
--- a/assets/js/src/subscribers/form.jsx
+++ b/assets/js/src/subscribers/form.jsx
@@ -60,7 +60,8 @@ define(
label: MailPoet.I18n.t('lists'),
type: 'selection',
placeholder: MailPoet.I18n.t('selectList'),
- endpoint: "segments",
+ api_version: window.mailpoet_api_version,
+ endpoint: 'segments',
multiple: true,
selected: function(subscriber) {
if (Array.isArray(subscriber.subscriptions) === false) {
diff --git a/assets/js/src/subscribers/importExport/export.js b/assets/js/src/subscribers/importExport/export.js
index 07989cec42..f17c78273a 100644
--- a/assets/js/src/subscribers/importExport/export.js
+++ b/assets/js/src/subscribers/importExport/export.js
@@ -138,6 +138,7 @@ define(
}
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'ImportExport',
action: 'processExport',
data: JSON.stringify({
diff --git a/assets/js/src/subscribers/importExport/import.js b/assets/js/src/subscribers/importExport/import.js
index d2ae4da01d..e263ed90be 100644
--- a/assets/js/src/subscribers/importExport/import.js
+++ b/assets/js/src/subscribers/importExport/import.js
@@ -190,6 +190,7 @@ define(
mailChimpKeyVerifyButtonElement.click(function () {
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'importExport',
action: 'getMailChimpLists',
data: {
@@ -225,6 +226,7 @@ define(
}
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'importExport',
action: 'getMailChimpSubscribers',
data: {
@@ -572,6 +574,7 @@ define(
var segmentDescription = jQuery('#new_segment_description').val().trim();
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'ImportExport',
action: 'addSegment',
data: {
@@ -729,6 +732,7 @@ define(
// save custom field
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'customFields',
action: 'save',
data: data
@@ -990,6 +994,7 @@ define(
queue.add(function(queue) {
queue.pause();
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'ImportExport',
action: 'processImport',
data: JSON.stringify({
diff --git a/assets/js/src/subscribers/list.jsx b/assets/js/src/subscribers/list.jsx
index 7f3d1dd279..cb263a5501 100644
--- a/assets/js/src/subscribers/list.jsx
+++ b/assets/js/src/subscribers/list.jsx
@@ -91,6 +91,7 @@ const bulk_actions = [
onSelect: function() {
let field = {
id: 'move_to_segment',
+ api_version: window.mailpoet_api_version,
endpoint: 'segments',
filter: function(segment) {
return !!(
@@ -122,6 +123,7 @@ const bulk_actions = [
onSelect: function() {
let field = {
id: 'add_to_segment',
+ api_version: window.mailpoet_api_version,
endpoint: 'segments',
filter: function(segment) {
return !!(
@@ -153,6 +155,7 @@ const bulk_actions = [
onSelect: function() {
let field = {
id: 'remove_from_segment',
+ api_version: window.mailpoet_api_version,
endpoint: 'segments',
filter: function(segment) {
return !!(
@@ -255,7 +258,7 @@ const SubscriberList = React.createClass({
case 'unsubscribed':
status = MailPoet.I18n.t('unsubscribed');
break;
-
+
case 'bounced':
status = MailPoet.I18n.t('bounced');
break;
diff --git a/lib/API/API.php b/lib/API/API.php
index 030ffdd408..d03247684e 100644
--- a/lib/API/API.php
+++ b/lib/API/API.php
@@ -1,6 +1,7 @@
addEndpointNamespace(__NAMESPACE__ . "\\Endpoints");
+ foreach($this->_available_api_versions as $available_api_version) {
+ $this->addEndpointNamespace(
+ sprintf('%s\%s\%s', __NAMESPACE__, self::ENDPOINTS_LOCATION, $available_api_version),
+ $available_api_version
+ );
+ }
}
function init() {
- // Admin Security token
+ // admin security token and API version
add_action(
'admin_head',
- array($this, 'setToken')
+ array($this, 'setTokenAndAPIVersion')
);
// ajax (logged in users)
@@ -42,73 +53,67 @@ class API {
function setupAjax() {
Hooks::doAction('mailpoet_api_setup', array($this));
-
- $this->getRequestData($_POST);
+ $this->setRequestData($_POST);
if($this->checkToken() === false) {
- $error_response = new ErrorResponse(
- array(
- Error::UNAUTHORIZED => __('Invalid request', 'mailpoet')
- ),
- array(),
- Response::STATUS_UNAUTHORIZED
- );
- $error_response->send();
+ $error_message = __('Invalid API request.', 'mailpoet');
+ $error_response = $this->createErrorResponse(Error::UNAUTHORIZED, $error_message, Response::STATUS_UNAUTHORIZED);
+ return $error_response->send();
}
$response = $this->processRoute();
$response->send();
}
- function getRequestData($data) {
- $this->_endpoint = isset($data['endpoint'])
+ function setRequestData($data) {
+ $this->_request_api_version = !empty($data['api_version']) ? $data['api_version']: false;
+
+ $this->_request_endpoint = isset($data['endpoint'])
? Helpers::underscoreToCamelCase(trim($data['endpoint']))
: null;
// JS part of /wp-admin/customize.php does not like a 'method' field in a form widget
$method_param_name = isset($data['mailpoet_method']) ? 'mailpoet_method' : 'method';
- $this->_method = isset($data[$method_param_name])
+ $this->_request_method = isset($data[$method_param_name])
? Helpers::underscoreToCamelCase(trim($data[$method_param_name]))
: null;
- $this->_token = isset($data['token'])
+ $this->_request_token = isset($data['token'])
? trim($data['token'])
: null;
- if(!$this->_endpoint || !$this->_method) {
- // throw exception bad request
- $error_response = new ErrorResponse(
- array(
- Error::BAD_REQUEST => __('Invalid request', 'mailpoet')
- ),
- array(),
- Response::STATUS_BAD_REQUEST
- );
- $error_response->send();
- } else {
- foreach($this->_endpoint_namespaces as $namespace) {
- $class_name = $namespace . "\\" . ucfirst($this->_endpoint);
- if(class_exists($class_name)) {
- $this->_endpoint_class = $class_name;
+ if(!$this->_request_endpoint || !$this->_request_method || !$this->_request_api_version) {
+ $error_message = __('Invalid API request.', 'mailpoet');
+ $error_response = $this->createErrorResponse(Error::BAD_REQUEST, $error_message, Response::STATUS_BAD_REQUEST);
+ return $error_response;
+ } else if(!empty($this->_endpoint_namespaces[$this->_request_api_version])) {
+ foreach($this->_endpoint_namespaces[$this->_request_api_version] as $namespace) {
+ $endpoint_class = sprintf(
+ '%s\%s',
+ $namespace,
+ ucfirst($this->_request_endpoint)
+ );
+ if(class_exists($endpoint_class)) {
+ $this->_request_endpoint_class = $endpoint_class;
}
}
-
- $this->_data = isset($data['data'])
+ $this->_request_data = isset($data['data'])
? stripslashes_deep($data['data'])
: array();
// remove reserved keywords from data
- if(is_array($this->_data) && !empty($this->_data)) {
+ if(is_array($this->_request_data) && !empty($this->_request_data)) {
// filter out reserved keywords from data
$reserved_keywords = array(
'token',
'endpoint',
'method',
+ 'api_version',
'mailpoet_method', // alias of 'method'
'mailpoet_redirect'
);
- $this->_data = array_diff_key(
- $this->_data,
+ $this->_request_data = array_diff_key(
+ $this->_request_data,
array_flip($reserved_keywords)
);
}
@@ -117,67 +122,79 @@ class API {
function processRoute() {
try {
- if(empty($this->_endpoint_class)) {
- throw new \Exception('Invalid endpoint');
+ if(empty($this->_request_endpoint_class)) {
+ throw new \Exception(__('Invalid API endpoint.', 'mailpoet'));
}
- $endpoint = new $this->_endpoint_class();
+ $endpoint = new $this->_request_endpoint_class();
// check the accessibility of the requested endpoint's action
// by default, an endpoint's action is considered "private"
$permissions = $endpoint->permissions;
- if(
- array_key_exists($this->_method, $permissions) === false
- ||
- $permissions[$this->_method] !== Access::ALL
+ if(array_key_exists($this->_request_method, $permissions) === false ||
+ $permissions[$this->_request_method] !== Access::ALL
) {
if($this->checkPermissions() === false) {
- $error_response = new ErrorResponse(
- array(
- Error::FORBIDDEN => __(
- 'You do not have the required permissions.',
- 'mailpoet'
- )
- ),
- array(),
- Response::STATUS_FORBIDDEN
- );
+ $error_message = __('You do not have the required permissions.', 'mailpoet');
+ $error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN);
return $error_response;
}
}
- $response = $endpoint->{$this->_method}($this->_data);
+ $response = $endpoint->{$this->_request_method}($this->_request_data);
return $response;
} catch(\Exception $e) {
- $error_response = new ErrorResponse(
- array($e->getCode() => $e->getMessage())
- );
+ $error_message = $e->getMessage();
+ $error_response = $this->createErrorResponse(Error::BAD_REQUEST, $error_message, Response::STATUS_BAD_REQUEST);
return $error_response;
}
}
function checkPermissions() {
- return current_user_can('manage_options');
+ return current_user_can(Env::$required_permission);
}
function checkToken() {
- return wp_verify_nonce($this->_token, 'mailpoet_token');
+ return wp_verify_nonce($this->_request_token, 'mailpoet_token');
}
- function setToken() {
+ function setTokenAndAPIVersion() {
$global = '';
- echo $global;
+ echo sprintf(
+ $global,
+ Security::generateToken(),
+ self::CURRENT_VERSION
+ );
}
- function addEndpointNamespace($namespace) {
- $this->_endpoint_namespaces[] = $namespace;
+ function addEndpointNamespace($namespace, $version) {
+ if(!empty($this->_endpoint_namespaces[$version][$namespace])) return;
+ $this->_endpoint_namespaces[$version][] = $namespace;
}
function getEndpointNamespaces() {
return $this->_endpoint_namespaces;
}
-}
+
+ function getRequestedEndpointClass() {
+ return $this->_request_endpoint_class;
+ }
+
+ function getRequestedAPIVersion() {
+ return $this->_request_api_version;
+ }
+
+ function createErrorResponse($error_type, $error_message, $response_status) {
+ $error_response = new ErrorResponse(
+ array(
+ $error_type => $error_message
+ ),
+ array(),
+ $response_status
+ );
+ return $error_response;
+ }
+}
\ No newline at end of file
diff --git a/lib/API/Endpoints/AutomatedLatestContent.php b/lib/API/Endpoints/v1/AutomatedLatestContent.php
similarity index 98%
rename from lib/API/Endpoints/AutomatedLatestContent.php
rename to lib/API/Endpoints/v1/AutomatedLatestContent.php
index f45a59b90f..510e4c2c04 100644
--- a/lib/API/Endpoints/AutomatedLatestContent.php
+++ b/lib/API/Endpoints/v1/AutomatedLatestContent.php
@@ -1,5 +1,5 @@
subscribe($data);
-
+ $api = new API();
+ $api->setRequestData($_REQUEST);
+ $form_id = (!empty($_REQUEST['data']['form_id'])) ? (int)$_REQUEST['data']['form_id'] : false;
+ $response = $api->processRoute();
if($response->status !== APIResponse::STATUS_OK) {
- Url::redirectBack(array(
- 'mailpoet_error' => isset($data['form_id']) ? $data['form_id'] : true,
- 'mailpoet_success' => null
- ));
+ Url::redirectBack(
+ array(
+ 'mailpoet_error' => ($form_id) ? $form_id : true,
+ 'mailpoet_success' => null
+ )
+ );
} else {
- if(isset($response->meta['redirect_url'])) {
- Url::redirectTo($response->meta['redirect_url']);
- } else {
- Url::redirectBack(array(
- 'mailpoet_success' => $form_id,
- 'mailpoet_error' => null
- ));
- }
+ (isset($response->meta['redirect_url'])) ?
+ Url::redirectTo($response->meta['redirect_url']) :
+ Url::redirectBack(
+ array(
+ 'mailpoet_success' => $form_id,
+ 'mailpoet_error' => null
+ )
+ );
}
}
}
\ No newline at end of file
diff --git a/tests/unit/API/APITest.php b/tests/unit/API/APITest.php
index 694f639464..81559d1956 100644
--- a/tests/unit/API/APITest.php
+++ b/tests/unit/API/APITest.php
@@ -1,11 +1,14 @@
api->getEndpointNamespaces())->count(1);
- $namespace = "MailPoet\\Dummy\\Name\\Space";
- $this->api->addEndpointNamespace($namespace);
+ $namespace = array(
+ 'name' => 'MailPoet\\Dummy\\Name\\Space',
+ 'version' => 'v2'
+ );
+ $this->api->addEndpointNamespace($namespace['name'], $namespace['version']);
$namespaces = $this->api->getEndpointNamespaces();
expect($namespaces)->count(2);
- expect($namespaces[1])->equals($namespace);
+ expect($namespaces[$namespace['version']][0])->equals($namespace['name']);
}
- function testItCanCallAddedEndpoints() {
- $namespace = "MailPoet\\Some\\Name\\Space\\Endpoints";
- $this->api->addEndpointNamespace($namespace);
+ function testItReturns400ErrorWhenAPIVersionIsNotSpecified() {
+ $data = array(
+ 'endpoint' => 'namespaced_endpoint_stub',
+ 'method' => 'test'
+ );
+
+ $response = $this->api->setRequestData($data);
+ expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
+ }
+
+ function testItAcceptsAndProcessesAPIVersion() {
+ $namespace = array(
+ 'name' => 'MailPoet\API\Endpoints\v2',
+ 'version' => 'v2'
+ );
+ $this->api->addEndpointNamespace($namespace['name'], $namespace['version']);
+
+ $data = array(
+ 'endpoint' => 'namespaced_endpoint_stub',
+ 'api_version' => 'v2',
+ 'method' => 'test'
+ );
+ $this->api->setRequestData($data);
+
+ expect($this->api->getRequestedAPIVersion())->equals('v2');
+ expect($this->api->getRequestedEndpointClass())->equals(
+ 'MailPoet\API\Endpoints\v2\NamespacedEndpointStub'
+ );
+ }
+
+ function testItCallsAddedEndpoints() {
+ $namespace = array(
+ 'name' => 'MailPoet\API\Endpoints\v1',
+ 'version' => 'v1'
+ );
+ $this->api->addEndpointNamespace($namespace['name'], $namespace['version']);
$data = array(
'endpoint' => 'namespaced_endpoint_stub',
'method' => 'test',
+ 'api_version' => 'v1',
'data' => array('test' => 'data')
);
- $this->api->getRequestData($data);
+ $this->api->setRequestData($data);
$response = $this->api->processRoute();
expect($response->getData()['data'])->equals($data['data']);
}
+ function testItCallsAddedEndpointsForSpecificAPIVersion() {
+ $namespace = array(
+ 'name' => 'MailPoet\API\Endpoints\v2',
+ 'version' => 'v2'
+ );
+ $this->api->addEndpointNamespace($namespace['name'], $namespace['version']);
+
+ $data = array(
+ 'endpoint' => 'namespaced_endpoint_stub',
+ 'api_version' => 'v2',
+ 'method' => 'testVersion'
+ );
+ $this->api->setRequestData($data);
+ $response = $this->api->processRoute();
+
+ expect($response->getData()['data'])->equals($data['api_version']);
+ }
+
function _after() {
wp_delete_user($this->wp_user_id);
}
diff --git a/tests/unit/API/APITestNamespacedEndpointStub.php b/tests/unit/API/APITestNamespacedEndpointStubV1.php
similarity index 87%
rename from tests/unit/API/APITestNamespacedEndpointStub.php
rename to tests/unit/API/APITestNamespacedEndpointStubV1.php
index 02b196f451..724922755e 100644
--- a/tests/unit/API/APITestNamespacedEndpointStub.php
+++ b/tests/unit/API/APITestNamespacedEndpointStubV1.php
@@ -1,6 +1,6 @@
APIAccess::ALL
+ );
+
+ function testVersion() {
+ return $this->successResponse('v2');
+ }
+}
diff --git a/tests/unit/API/Endpoints/CustomFieldsTest.php b/tests/unit/API/Endpoints/v1/CustomFieldsTest.php
similarity index 98%
rename from tests/unit/API/Endpoints/CustomFieldsTest.php
rename to tests/unit/API/Endpoints/v1/CustomFieldsTest.php
index f1bba2aef0..a5a07298af 100644
--- a/tests/unit/API/Endpoints/CustomFieldsTest.php
+++ b/tests/unit/API/Endpoints/v1/CustomFieldsTest.php
@@ -1,6 +1,6 @@
"
)) {
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'customFields',
action: 'delete',
data: {
diff --git a/views/form/templates/settings/field_form.hbs b/views/form/templates/settings/field_form.hbs
index 90717a4729..61d6927d4e 100644
--- a/views/form/templates/settings/field_form.hbs
+++ b/views/form/templates/settings/field_form.hbs
@@ -74,6 +74,7 @@
// save custom field
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'customFields',
action: 'save',
data: data
diff --git a/views/form/widget.html b/views/form/widget.html
index 4a8a8f24c4..bbe0062345 100644
--- a/views/form/widget.html
+++ b/views/form/widget.html
@@ -13,8 +13,9 @@
class="mailpoet_form mailpoet_form_<%= form_type %>"
novalidate
>
-
+
+
diff --git a/views/newsletter/editor.html b/views/newsletter/editor.html
index a982925cea..176d3f3a79 100644
--- a/views/newsletter/editor.html
+++ b/views/newsletter/editor.html
@@ -1201,6 +1201,7 @@
};
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'get',
data: {
diff --git a/views/settings.html b/views/settings.html
index a3b4f9a93e..82f379e056 100644
--- a/views/settings.html
+++ b/views/settings.html
@@ -74,6 +74,7 @@
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'settings',
action: 'set',
data: settings_data
diff --git a/views/settings/advanced.html b/views/settings/advanced.html
index 62dc2152ac..8dc8d47ab6 100644
--- a/views/settings/advanced.html
+++ b/views/settings/advanced.html
@@ -175,6 +175,7 @@
)) {
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ 'api_version': window.mailpoet_api_version,
'endpoint': 'setup',
'action': 'reset'
}).always(function() {
diff --git a/views/settings/mta.html b/views/settings/mta.html
index f464c43649..1ed9a8e999 100644
--- a/views/settings/mta.html
+++ b/views/settings/mta.html
@@ -707,6 +707,7 @@
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'mailer',
action: 'send',
data: {
@@ -751,6 +752,7 @@
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: 'services',
action: 'verifyMailPoetKey',
data: {
diff --git a/views/welcome.html b/views/welcome.html
index cc301df2d2..3257a095a9 100644
--- a/views/welcome.html
+++ b/views/welcome.html
@@ -118,6 +118,7 @@ jQuery(function($) {
$("#mailpoet_analytics_enabled").on("click", function() {
var is_enabled = $(this).is(":checked") ? true : "";
MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
endpoint: "settings",
action: "set",
data: {