- Refactors front router and endpoints to use dynamic methods
This commit is contained in:
@@ -14,19 +14,24 @@ class Track {
|
||||
const ENDPOINT = 'track';
|
||||
const ACTION_CLICK = 'click';
|
||||
const ACTION_OPEN = 'open';
|
||||
public $allowed_actions = array(
|
||||
const ALLOWED_ACTIONS = array(
|
||||
self::ACTION_CLICK,
|
||||
self::ACTION_OPEN
|
||||
);
|
||||
public $data;
|
||||
|
||||
function click($data) {
|
||||
$click_event = new Clicks();
|
||||
return $click_event->track(self::_processTrackData($data));
|
||||
function __construct($data) {
|
||||
$this->data = $this->_processTrackData($data);
|
||||
}
|
||||
|
||||
function open($data) {
|
||||
function click() {
|
||||
$click_event = new Clicks();
|
||||
return $click_event->track($this->data);
|
||||
}
|
||||
|
||||
function open() {
|
||||
$open_event = new Opens();
|
||||
return $open_event->track(self::_processTrackData($data));
|
||||
return $open_event->track($this->data);
|
||||
}
|
||||
|
||||
function _processTrackData($data) {
|
||||
@@ -45,10 +50,10 @@ class Track {
|
||||
if(!empty($data->link_hash)) {
|
||||
$data->link = NewsletterLink::getByHash($data->link_hash);
|
||||
}
|
||||
return self::_validateTrackData($data);
|
||||
return $this->_validateTrackData($data);
|
||||
}
|
||||
|
||||
static function _validateTrackData($data) {
|
||||
function _validateTrackData($data) {
|
||||
if(!$data->subscriber || !$data->queue || !$data->newsletter) return false;
|
||||
$subscriber_token_match =
|
||||
Subscriber::verifyToken($data->subscriber->email, $data->subscriber_token);
|
||||
|
@@ -12,11 +12,15 @@ class ViewInBrowser {
|
||||
const ENDPOINT = 'view_in_browser';
|
||||
const ACTION_VIEW = 'view';
|
||||
public $allowed_actions = array(self::ACTION_VIEW);
|
||||
public $data;
|
||||
|
||||
function view($data) {
|
||||
$data = $this->_processBrowserPreviewData($data);
|
||||
function __construct($data) {
|
||||
$this->data = $this->_processBrowserPreviewData($data);
|
||||
}
|
||||
|
||||
function view() {
|
||||
$view_in_browser = new NewsletterViewInBrowser();
|
||||
return $this->_displayNewsletter($view_in_browser->view($data));
|
||||
return $this->_displayNewsletter($view_in_browser->view($this->data));
|
||||
}
|
||||
|
||||
function _processBrowserPreviewData($data) {
|
||||
@@ -54,9 +58,9 @@ class ViewInBrowser {
|
||||
return $data;
|
||||
}
|
||||
|
||||
function _displayNewsletter($rendered_newsletter) {
|
||||
function _displayNewsletter($result) {
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
echo $rendered_newsletter;
|
||||
echo $result;
|
||||
exit;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@@ -27,44 +28,31 @@ class Front {
|
||||
}
|
||||
|
||||
function init() {
|
||||
$class = __NAMESPACE__ . "\\Endpoints\\" . ucfirst($this->endpoint);
|
||||
|
||||
$endpoint_class = __NAMESPACE__ . "\\Endpoints\\" . ucfirst($this->endpoint);
|
||||
if(!$this->api_request) return;
|
||||
if(!$this->endpoint || !class_exists($class)) {
|
||||
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint.'));
|
||||
if(!$this->endpoint || !class_exists($endpoint_class)) {
|
||||
return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint.'));
|
||||
}
|
||||
$this->callEndpoint(
|
||||
$class,
|
||||
$this->action,
|
||||
$this->data
|
||||
);
|
||||
}
|
||||
|
||||
function callEndpoint($endpoint, $action, $data) {
|
||||
$endpoint = new $endpoint();
|
||||
if(!method_exists($endpoint, $action) || !in_array($action, $endpoint->allowed_actions)) {
|
||||
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid router action.'));
|
||||
$endpoint = new $endpoint_class($this->data);
|
||||
if(!method_exists($endpoint, $this->action) || !in_array($this->action, $endpoint->allowed_actions)) {
|
||||
return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router action.'));
|
||||
}
|
||||
call_user_func(
|
||||
return call_user_func(
|
||||
array(
|
||||
$endpoint,
|
||||
$action
|
||||
),
|
||||
$data
|
||||
$this->action
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static function decodeRequestData($data) {
|
||||
$data = base64_decode($data);
|
||||
|
||||
if(is_serialized($data)) {
|
||||
$data = unserialize($data);
|
||||
}
|
||||
|
||||
if(!is_array($data)) {
|
||||
$data = array();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -83,7 +71,7 @@ class Front {
|
||||
return add_query_arg($params, home_url());
|
||||
}
|
||||
|
||||
static function terminateRequest($code, $message) {
|
||||
function terminateRequest($code, $message) {
|
||||
status_header($code, $message);
|
||||
exit;
|
||||
}
|
||||
|
133
tests/unit/Router/FrontTest.php
Normal file
133
tests/unit/Router/FrontTest.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
use Codeception\Util\Stub;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Router\Endpoints\ViewInBrowser;
|
||||
|
||||
class ViewInBrowserRouterTest extends MailPoetTest {
|
||||
function _before() {
|
||||
// create newsletter
|
||||
$newsletter = Newsletter::create();
|
||||
$newsletter->type = 'type';
|
||||
$this->newsletter = $newsletter->save();
|
||||
// create subscriber
|
||||
$subscriber = Subscriber::create();
|
||||
$subscriber->email = 'test@example.com';
|
||||
$subscriber->first_name = 'First';
|
||||
$subscriber->last_name = 'Last';
|
||||
$this->subscriber = $subscriber->save();
|
||||
// create queue
|
||||
$queue = SendingQueue::create();
|
||||
$queue->newsletter_id = $newsletter->id;
|
||||
$queue->subscribers = array('processed' => array($subscriber->id));
|
||||
$this->queue = $queue->save();
|
||||
// build browser preview data
|
||||
$this->browser_preview_data = array(
|
||||
'queue_id' => $queue->id,
|
||||
'subscriber_id' => $subscriber->id,
|
||||
'newsletter_id' => $newsletter->id,
|
||||
'subscriber_token' => Subscriber::generateToken($subscriber->email),
|
||||
'preview' => false
|
||||
);
|
||||
// instantiate class
|
||||
$this->view_in_browser = new ViewInBrowser();
|
||||
}
|
||||
|
||||
function testItAbortsWhenTrackDataIsMissing() {
|
||||
$view_in_browser = Stub::make($this->view_in_browser, array(
|
||||
'_abort' => Stub::exactly(3, function() { })
|
||||
), $this);
|
||||
// newsletter ID is required
|
||||
$data = $this->browser_preview_data;
|
||||
unset($data['newsletter_id']);
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
// subscriber ID is required
|
||||
$data = $this->browser_preview_data;
|
||||
unset($data['subscriber_id']);
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
// subscriber token is required
|
||||
$data = $this->browser_preview_data;
|
||||
unset($data['subscriber_token']);
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
}
|
||||
|
||||
function testItAbortsWhenTrackDataIsInvalid() {
|
||||
$view_in_browser = Stub::make($this->view_in_browser, array(
|
||||
'_abort' => Stub::exactly(3, function() { })
|
||||
), $this);
|
||||
// newsletter ID is invalid
|
||||
$data = $this->browser_preview_data;
|
||||
$data['newsletter_id'] = 99;
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
// subscriber ID is invalid
|
||||
$data = $this->browser_preview_data;
|
||||
$data['subscriber_id'] = 99;
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
// subscriber token is invalid
|
||||
$data = $this->browser_preview_data;
|
||||
$data['subscriber_token'] = 'invalid';
|
||||
$view_in_browser->_processBrowserPreviewData($data);
|
||||
}
|
||||
|
||||
function testItFailsValidationWhenSubscriberTokenDoesNotMatch() {
|
||||
$data = (object)array_merge(
|
||||
$this->browser_preview_data,
|
||||
array(
|
||||
'queue' => $this->queue,
|
||||
'subscriber' => $this->subscriber,
|
||||
'newsletter' => $this->newsletter
|
||||
)
|
||||
);
|
||||
$data->subscriber->email = 'random@email.com';
|
||||
expect($this->view_in_browser->_validateBrowserPreviewData($data))->false();
|
||||
}
|
||||
|
||||
function testItFailsValidationWhenSubscriberIsNotOnProcessedList() {
|
||||
$data = (object)array_merge(
|
||||
$this->browser_preview_data,
|
||||
array(
|
||||
'queue' => $this->queue,
|
||||
'subscriber' => $this->subscriber,
|
||||
'newsletter' => $this->newsletter
|
||||
)
|
||||
);
|
||||
$data->subscriber->id = 99;
|
||||
expect($this->view_in_browser->_validateBrowserPreviewData($data))->false();
|
||||
}
|
||||
|
||||
function testItDoesNotRequireWpUsersToBeOnProcessedListWhenPreviewIsEnabled() {
|
||||
$data = (object)array_merge(
|
||||
$this->browser_preview_data,
|
||||
array(
|
||||
'queue' => $this->queue,
|
||||
'subscriber' => $this->subscriber,
|
||||
'newsletter' => $this->newsletter
|
||||
)
|
||||
);
|
||||
$data->subscriber->wp_user_id = 99;
|
||||
$data->preview = true;
|
||||
expect($this->view_in_browser->_validateBrowserPreviewData($data))->equals($data);
|
||||
}
|
||||
|
||||
function testItCanProcessBrowserPreviewData() {
|
||||
$processed_data = $this->view_in_browser->_processBrowserPreviewData($this->browser_preview_data);
|
||||
expect($processed_data->queue->id)->equals($this->queue->id);
|
||||
expect($processed_data->subscriber->id)->equals($this->subscriber->id);
|
||||
expect($processed_data->newsletter->id)->equals($this->newsletter->id);
|
||||
}
|
||||
|
||||
function testItCanViewNewsletter() {
|
||||
$view_in_browser = Stub::make($this->view_in_browser, array(
|
||||
'_displayNewsletter' => Stub::exactly(1, function() { })
|
||||
), $this);
|
||||
$view_in_browser->view($this->browser_preview_data);
|
||||
}
|
||||
|
||||
function _after() {
|
||||
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||
}
|
||||
}
|
143
tests/unit/Router/FrontTestMockEndpoint.php
Normal file
143
tests/unit/Router/FrontTestMockEndpoint.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
use Codeception\Util\Stub;
|
||||
use MailPoet\Router\Front;
|
||||
|
||||
class FrontTest extends MailPoetTest {
|
||||
|
||||
function __construct() {
|
||||
/* $this->api_request = 'mailpoet_api';
|
||||
$this->api_endpoint = 'view_in_browser';
|
||||
$this->api_action = 'view';
|
||||
$this->api_data = base64_encode(serialize(array('data' => 'dummy data')));
|
||||
$this->url = "http://example.com/?{$this->api_request}&endpoint={$this->api_endpoint}&action={$this->api_action}&data={$this->api_data}";*/
|
||||
$this->router_data = array(
|
||||
'mailpoet_api' => '',
|
||||
'endpoint' => 'view_in_browser',
|
||||
'action' => 'view',
|
||||
'data' => base64_encode(serialize(array('data' => 'dummy data')))
|
||||
);
|
||||
$this->router = new Front($this->router_data);
|
||||
}
|
||||
|
||||
/* function testItCanGetAPIDataFromGetRequest() {
|
||||
$data = array('data' => 'dummy data');
|
||||
$url = 'http://example.com/?mailpoet_api&endpoint=view_in_browser&action=view&data='
|
||||
. base64_encode(serialize($data));
|
||||
parse_str(parse_url($url, PHP_URL_QUERY), $_GET);
|
||||
$router = new Front();
|
||||
expect($router->api_request)->equals(true);
|
||||
expect($router->endpoint)->equals('viewInBrowser');
|
||||
expect($router->action)->equals('view');
|
||||
expect($router->data)->equals($data);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
function testItContinuesExecutionWhenAPIRequestNotDetected() {
|
||||
$router_data = $this->router_data;
|
||||
unset($router_data['mailpoet_api']);
|
||||
$router = Stub::construct(
|
||||
new Front(),
|
||||
array($router_data),
|
||||
array(
|
||||
'terminateRequest' => function() { return 'terminated'; },
|
||||
'callEndpoint' => function() { return 'endpoint called'; }
|
||||
)
|
||||
);
|
||||
expect($router->init())->null();
|
||||
}
|
||||
|
||||
function testItTerminatesRequestWhenEndpointNotFound() {
|
||||
$router_data = $this->router_data;
|
||||
$router_data['endpoint'] = 'invalidEndpoint';
|
||||
$router = Stub::construct(
|
||||
new Front(),
|
||||
array($router_data),
|
||||
array(
|
||||
'terminateRequest' => function($code, $error) {
|
||||
return array(
|
||||
$code,
|
||||
$error
|
||||
);
|
||||
},
|
||||
'callEndpointActoin' => function() { return 'endpoint called'; }
|
||||
)
|
||||
);
|
||||
expect($router->init())
|
||||
->equals(
|
||||
array(
|
||||
404,
|
||||
'Invalid router endpoint.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItCallsEndpointAction() {
|
||||
$router_data = $this->router_data;
|
||||
$router = Stub::construct(
|
||||
new Front(),
|
||||
array($router_data),
|
||||
array(
|
||||
'terminateRequest' => function($code, $error) {
|
||||
return array(
|
||||
$code,
|
||||
$error
|
||||
);
|
||||
},
|
||||
'callEndpointAction' => function($class, $action, $data) {
|
||||
return array(
|
||||
$class,
|
||||
$action,
|
||||
$data
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
expect($router->init())
|
||||
->equals(
|
||||
array(
|
||||
'MailPoet\Router\Endpoints\ViewInBrowser',
|
||||
'view',
|
||||
array('data' => 'dummy data')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItAbortsWhenEndpointActionNotFound() {
|
||||
$router_data = $this->router_data;
|
||||
$router = Stub::construct(
|
||||
new Front(),
|
||||
array($router_data),
|
||||
array(
|
||||
'terminateRequest' => function($code, $error) {
|
||||
return array(
|
||||
$code,
|
||||
$error
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
expect($router->callEndpointAction())
|
||||
->equals(
|
||||
404,
|
||||
'Invalid router action.'
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
function testItCallsEndpointWhenItIsFound() {
|
||||
$router_data = $this->router_data;
|
||||
$router = Stub::construct(
|
||||
new Front(),
|
||||
array($router_data),
|
||||
array(
|
||||
'terminateRequest' => function() { return 'terminated'; },
|
||||
'callEndpoint' => function() { return 'endpoint called'; }
|
||||
)
|
||||
);
|
||||
expect($router->init())->equals('endpoint called');
|
||||
}*/
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user