Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
fb51765d3f | |||
088ad5fb42 | |||
2f5b3c0c0a | |||
04ac4d896c | |||
f3b96af863 | |||
eb42b0b98d | |||
304667eb49 | |||
dad1082cd7 | |||
37cf0f3d29 | |||
d61c6dff58 | |||
3734ac578d | |||
b3f56c9d8e | |||
3603eeee77 | |||
59d30cc139 | |||
6ff3bbbb72 | |||
a561e10156 | |||
99f2cf6702 | |||
c6b72e729b | |||
c5bc0f36a4 | |||
efc5c34bf9 | |||
3929efbdd9 | |||
0e0c41882e | |||
79cc708fc6 | |||
8fa98879b8 | |||
331ba385e9 | |||
71ce46d78d | |||
c493de6569 | |||
ff2c2ace86 | |||
7fa789cfd1 | |||
ae6269eb63 | |||
a8f4779bfe | |||
6868142e35 | |||
133d123919 | |||
05c128d12d | |||
bdab0c12fa | |||
75b94690e2 | |||
80fddd6c58 | |||
c807ead5fd | |||
f004bb5368 |
40
RoboFile.php
40
RoboFile.php
@ -102,31 +102,51 @@ class RoboFile extends \Robo\Tasks {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testUnit($file = null) {
|
function testUnit($opts=['file' => null, 'xml' => false]) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build');
|
||||||
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
|
|
||||||
|
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : '');
|
||||||
|
|
||||||
|
if($opts['xml']) {
|
||||||
|
$command .= ' --xml';
|
||||||
|
}
|
||||||
|
return $this->_exec($command);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCoverage($file = null) {
|
function testCoverage($opts=['file' => null, 'xml' => false]) {
|
||||||
$this->loadEnv();
|
$this->loadEnv();
|
||||||
$this->_exec('vendor/bin/codecept build');
|
$this->_exec('vendor/bin/codecept build');
|
||||||
$this->_exec(join(' ', array(
|
$command = join(' ', array(
|
||||||
'vendor/bin/codecept run',
|
'vendor/bin/codecept run',
|
||||||
(($file) ? $file : ''),
|
(($opts['file']) ? $opts['file'] : ''),
|
||||||
'--coverage',
|
'--coverage',
|
||||||
'--coverage-html'
|
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
|
||||||
)));
|
));
|
||||||
|
|
||||||
|
if($opts['xml']) {
|
||||||
|
$command .= ' --xml';
|
||||||
|
}
|
||||||
|
return $this->_exec($command);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testJavascript() {
|
function testJavascript($xml_output_file = null) {
|
||||||
$this->compileJs();
|
$this->compileJs();
|
||||||
|
|
||||||
$this->_exec(join(' ', array(
|
$command = join(' ', array(
|
||||||
'./node_modules/.bin/mocha',
|
'./node_modules/.bin/mocha',
|
||||||
'-r tests/javascript/mochaTestHelper.js',
|
'-r tests/javascript/mochaTestHelper.js',
|
||||||
'tests/javascript/testBundles/**/*.js'
|
'tests/javascript/testBundles/**/*.js'
|
||||||
)));
|
));
|
||||||
|
|
||||||
|
if(!empty($xml_output_file)) {
|
||||||
|
$command .= sprintf(
|
||||||
|
' --reporter xunit --reporter-options output="%s"',
|
||||||
|
$xml_output_file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_exec($command);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDebug() {
|
function testDebug() {
|
||||||
|
@ -35,7 +35,12 @@ define([
|
|||||||
|
|
||||||
Module.ALCSupervisor = SuperModel.extend({
|
Module.ALCSupervisor = SuperModel.extend({
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.listenTo(App.getChannel(), 'automatedLatestContentRefresh', this.refresh);
|
var DELAY_REFRESH_FOR_MS = 500;
|
||||||
|
this.listenTo(
|
||||||
|
App.getChannel(),
|
||||||
|
'automatedLatestContentRefresh',
|
||||||
|
_.debounce(this.refresh, DELAY_REFRESH_FOR_MS)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
var models = App.findModels(function(model) {
|
var models = App.findModels(function(model) {
|
||||||
@ -107,9 +112,7 @@ define([
|
|||||||
this.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this);
|
this.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:featuredImagePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this);
|
||||||
this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
|
this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
|
||||||
this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts);
|
this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts);
|
||||||
this.on('add remove update reset', function(model, collection, options) {
|
this.on('add remove update reset', this._scheduleFetchPosts);
|
||||||
App.getChannel().trigger('automatedLatestContentRefresh');
|
|
||||||
});
|
|
||||||
this.on('refreshPosts', this.updatePosts, this);
|
this.on('refreshPosts', this.updatePosts, this);
|
||||||
},
|
},
|
||||||
updatePosts: function(posts) {
|
updatePosts: function(posts) {
|
||||||
@ -120,16 +123,7 @@ define([
|
|||||||
* ALC posts on each model change
|
* ALC posts on each model change
|
||||||
*/
|
*/
|
||||||
_scheduleFetchPosts: function() {
|
_scheduleFetchPosts: function() {
|
||||||
var TIMEOUT = 500,
|
|
||||||
that = this;
|
|
||||||
if (this._fetchPostsTimer !== undefined) {
|
|
||||||
clearTimeout(this._fetchPostsTimer);
|
|
||||||
}
|
|
||||||
this._fetchPostsTimer = setTimeout(function() {
|
|
||||||
//that.fetchPosts();
|
|
||||||
App.getChannel().trigger('automatedLatestContentRefresh');
|
App.getChannel().trigger('automatedLatestContentRefresh');
|
||||||
that._fetchPostsTimer = undefined;
|
|
||||||
}, TIMEOUT);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
53
circle.yml
Normal file
53
circle.yml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
machine:
|
||||||
|
timezone:
|
||||||
|
UTC
|
||||||
|
|
||||||
|
hosts:
|
||||||
|
mailpoet.loc: 127.0.0.1
|
||||||
|
|
||||||
|
## Customize dependencies
|
||||||
|
dependencies:
|
||||||
|
pre:
|
||||||
|
- composer install
|
||||||
|
- ./do install
|
||||||
|
|
||||||
|
# Set up Wordpress
|
||||||
|
# No password is required for the MySQL user `ubuntu`
|
||||||
|
- mysql -u ubuntu -e "create database wordpress"
|
||||||
|
# Use cURL to fetch WP-CLI
|
||||||
|
- curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
||||||
|
# Make sure WP-CLI is executable
|
||||||
|
- chmod +x wp-cli.phar
|
||||||
|
# Download WordPress into `wordpress` directory
|
||||||
|
- ./wp-cli.phar core download --allow-root --path=wordpress
|
||||||
|
# Generate `wp-config.php` file
|
||||||
|
- echo "define(\"WP_DEBUG\", true);" | ./wp-cli.phar core config --allow-root --dbname=wordpress --dbuser=ubuntu --dbhost=127.0.0.1:3306 --path=wordpress --extra-php
|
||||||
|
# Install WordPress
|
||||||
|
- ./wp-cli.phar core install --allow-root --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc:8080 --title=WordPress --path=wordpress
|
||||||
|
# Softlink MailPoet to plugin path
|
||||||
|
- ln -s ../../.. wordpress/wp-content/plugins/mailpoet
|
||||||
|
# Activate MailPoet
|
||||||
|
- ./wp-cli.phar plugin activate mailpoet --path=wordpress
|
||||||
|
# Create .env file with correct path to WP installation
|
||||||
|
- echo "WP_TEST_PATH=\"/home/ubuntu/mailpoet/wordpress\"" > .env
|
||||||
|
|
||||||
|
# Enable XDebug for coverage reports.
|
||||||
|
# Comment out if not running PHP coverage reports, for performance
|
||||||
|
#- sed -i 's/^;//' /opt/circleci/php/$(phpenv global)/etc/conf.d/xdebug.ini
|
||||||
|
|
||||||
|
## tests override
|
||||||
|
test:
|
||||||
|
override:
|
||||||
|
# Run JS tests
|
||||||
|
- mkdir $CIRCLE_TEST_REPORTS/mocha
|
||||||
|
- ./do t:j $CIRCLE_TEST_REPORTS/mocha/junit.xml
|
||||||
|
|
||||||
|
# Run PHP tests
|
||||||
|
- ./do t:u --xml
|
||||||
|
# Uncomment to run coverage tests instead
|
||||||
|
#- ./do t:c --xml
|
||||||
|
# Copy the report
|
||||||
|
- mkdir $CIRCLE_TEST_REPORTS/codeception
|
||||||
|
- cp tests/_output/report.xml $CIRCLE_TEST_REPORTS/codeception/report.xml
|
||||||
|
# Uncomment to copy PHP coverage report
|
||||||
|
#- cp tests/_output/coverage.xml $CIRCLE_TEST_REPORTS/codeception/coverage.xml
|
@ -10,6 +10,7 @@ settings:
|
|||||||
colors: true
|
colors: true
|
||||||
memory_limit: 1024M
|
memory_limit: 1024M
|
||||||
log: true
|
log: true
|
||||||
|
strict_xml: true
|
||||||
extensions:
|
extensions:
|
||||||
enabled:
|
enabled:
|
||||||
- Codeception\Extension\RunFailed
|
- Codeception\Extension\RunFailed
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
use MailPoet\Models;
|
|
||||||
use MailPoet\Cron\CronTrigger;
|
use MailPoet\Cron\CronTrigger;
|
||||||
use MailPoet\Router;
|
use MailPoet\Router;
|
||||||
use MailPoet\API;
|
use MailPoet\API;
|
||||||
@ -122,7 +121,7 @@ class Initializer {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$this->setupAPI();
|
$this->setupAPI();
|
||||||
$this->setupFrontRouter();
|
$this->setupRouter();
|
||||||
$this->setupPages();
|
$this->setupPages();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
$this->handleFailedInitialization($e);
|
$this->handleFailedInitialization($e);
|
||||||
@ -187,8 +186,8 @@ class Initializer {
|
|||||||
$api->init();
|
$api->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupFrontRouter() {
|
function setupRouter() {
|
||||||
$router = new Router\Front();
|
$router = new Router\Router();
|
||||||
$router->init();
|
$router->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use MailPoet\Models\CustomField;
|
|||||||
use MailPoet\Models\Form;
|
use MailPoet\Models\Form;
|
||||||
use MailPoet\Models\Segment;
|
use MailPoet\Models\Segment;
|
||||||
use MailPoet\Models\Setting;
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Newsletter\Shortcodes\ShortcodesHelper;
|
use MailPoet\Newsletter\Shortcodes\ShortcodesHelper;
|
||||||
use MailPoet\Settings\Hosts;
|
use MailPoet\Settings\Hosts;
|
||||||
use MailPoet\Settings\Pages;
|
use MailPoet\Settings\Pages;
|
||||||
@ -368,6 +369,7 @@ class Menu {
|
|||||||
$data = array(
|
$data = array(
|
||||||
'shortcodes' => ShortcodesHelper::getShortcodes(),
|
'shortcodes' => ShortcodesHelper::getShortcodes(),
|
||||||
'settings' => Setting::getAll(),
|
'settings' => Setting::getAll(),
|
||||||
|
'current_wp_user' => Subscriber::getCurrentWPUser(),
|
||||||
'sub_menu' => 'mailpoet-newsletters'
|
'sub_menu' => 'mailpoet-newsletters'
|
||||||
);
|
);
|
||||||
wp_enqueue_media();
|
wp_enqueue_media();
|
||||||
|
@ -3,7 +3,7 @@ namespace MailPoet\Cron;
|
|||||||
|
|
||||||
use MailPoet\Models\Setting;
|
use MailPoet\Models\Setting;
|
||||||
use MailPoet\Router\Endpoints\Queue as QueueEndpoint;
|
use MailPoet\Router\Endpoints\Queue as QueueEndpoint;
|
||||||
use MailPoet\Router\Front as FrontRouter;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Util\Security;
|
use MailPoet\Util\Security;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
@ -55,7 +55,7 @@ class CronHelper {
|
|||||||
|
|
||||||
static function accessDaemon($token, $timeout = self::DAEMON_REQUEST_TIMEOUT) {
|
static function accessDaemon($token, $timeout = self::DAEMON_REQUEST_TIMEOUT) {
|
||||||
$data = array('token' => $token);
|
$data = array('token' => $token);
|
||||||
$url = FrontRouter::buildRequest(
|
$url = Router::buildRequest(
|
||||||
QueueEndpoint::ENDPOINT,
|
QueueEndpoint::ENDPOINT,
|
||||||
QueueEndpoint::ACTION_RUN,
|
QueueEndpoint::ACTION_RUN,
|
||||||
$data
|
$data
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
namespace MailPoet\Newsletter\Links;
|
namespace MailPoet\Newsletter\Links;
|
||||||
|
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Router\Front as FrontRouter;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Router\Endpoints\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;
|
||||||
@ -35,12 +35,14 @@ class Links {
|
|||||||
// extract shortcodes with [link:*] format
|
// extract shortcodes with [link:*] format
|
||||||
$shortcodes = new Shortcodes();
|
$shortcodes = new Shortcodes();
|
||||||
$shortcodes = $shortcodes->extract($content, $categories = array('link'));
|
$shortcodes = $shortcodes->extract($content, $categories = array('link'));
|
||||||
$extracted_links = array_map(function ($shortcode) {
|
if($shortcodes) {
|
||||||
|
$extracted_links = array_map(function($shortcode) {
|
||||||
return array(
|
return array(
|
||||||
'html' => $shortcode,
|
'html' => $shortcode,
|
||||||
'link' => $shortcode
|
'link' => $shortcode
|
||||||
);
|
);
|
||||||
}, $shortcodes);
|
}, $shortcodes);
|
||||||
|
}
|
||||||
// extract urls with href="url" format
|
// extract urls with href="url" format
|
||||||
preg_match_all($regex, $content, $matched_urls);
|
preg_match_all($regex, $content, $matched_urls);
|
||||||
$matched_urls_count = count($matched_urls[0]);
|
$matched_urls_count = count($matched_urls[0]);
|
||||||
@ -121,7 +123,7 @@ class Links {
|
|||||||
$router_action = ($matches[2][$index] === self::DATA_TAG_CLICK) ?
|
$router_action = ($matches[2][$index] === self::DATA_TAG_CLICK) ?
|
||||||
TrackEndpoint::ACTION_CLICK :
|
TrackEndpoint::ACTION_CLICK :
|
||||||
TrackEndpoint::ACTION_OPEN;
|
TrackEndpoint::ACTION_OPEN;
|
||||||
$link = FrontRouter::buildRequest(
|
$link = Router::buildRequest(
|
||||||
TrackEndpoint::ENDPOINT,
|
TrackEndpoint::ENDPOINT,
|
||||||
$router_action,
|
$router_action,
|
||||||
$data
|
$data
|
||||||
|
@ -13,8 +13,9 @@ class Renderer {
|
|||||||
const NEWSLETTER_TEMPLATE = 'Template.html';
|
const NEWSLETTER_TEMPLATE = 'Template.html';
|
||||||
const POST_PROCESS_FILTER = 'mailpoet_rendering_post_process';
|
const POST_PROCESS_FILTER = 'mailpoet_rendering_post_process';
|
||||||
|
|
||||||
function __construct(array $newsletter, $preview = false) {
|
function __construct($newsletter, $preview = false) {
|
||||||
$this->newsletter = $newsletter;
|
// TODO: remove ternary condition, refactor to use model objects
|
||||||
|
$this->newsletter = (is_object($newsletter)) ? $newsletter->asArray() : $newsletter;
|
||||||
$this->preview = $preview;
|
$this->preview = $preview;
|
||||||
$this->blocks_renderer = new Blocks\Renderer($this->newsletter, $this->preview);
|
$this->blocks_renderer = new Blocks\Renderer($this->newsletter, $this->preview);
|
||||||
$this->columns_renderer = new Columns\Renderer();
|
$this->columns_renderer = new Columns\Renderer();
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Newsletter;
|
namespace MailPoet\Newsletter;
|
||||||
|
|
||||||
use MailPoet\Models\Newsletter;
|
|
||||||
use MailPoet\Models\SendingQueue;
|
use MailPoet\Models\SendingQueue;
|
||||||
use MailPoet\Router\Front as FrontRouter;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Router\Endpoints\ViewInBrowser as ViewInBrowserEndpoint;
|
use MailPoet\Router\Endpoints\ViewInBrowser as ViewInBrowserEndpoint;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ class Url {
|
|||||||
$queue,
|
$queue,
|
||||||
'preview' => $preview
|
'preview' => $preview
|
||||||
);
|
);
|
||||||
return FrontRouter::buildRequest(
|
return Router::buildRequest(
|
||||||
ViewInBrowserEndpoint::ENDPOINT,
|
ViewInBrowserEndpoint::ENDPOINT,
|
||||||
ViewInBrowserEndpoint::ACTION_VIEW,
|
ViewInBrowserEndpoint::ACTION_VIEW,
|
||||||
$data
|
$data
|
||||||
|
@ -1,73 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Newsletter;
|
namespace MailPoet\Newsletter;
|
||||||
|
|
||||||
use MailPoet\Models\Newsletter;
|
|
||||||
use MailPoet\Models\SendingQueue;
|
|
||||||
use MailPoet\Models\Setting;
|
use MailPoet\Models\Setting;
|
||||||
use MailPoet\Models\Subscriber;
|
|
||||||
use MailPoet\Newsletter\Links\Links;
|
use MailPoet\Newsletter\Links\Links;
|
||||||
use MailPoet\Newsletter\Renderer\Renderer;
|
use MailPoet\Newsletter\Renderer\Renderer;
|
||||||
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
||||||
|
|
||||||
class ViewInBrowser {
|
class ViewInBrowser {
|
||||||
static function view($data) {
|
function view($data) {
|
||||||
$data = self::preProcessData($data);
|
$wp_user_preview = ($data->preview && $data->subscriber->isWPUser());
|
||||||
if(!self::validateData($data)) self::abort();
|
return $this->renderNewsletter(
|
||||||
$rendered_newsletter =
|
|
||||||
self::getAndRenderNewsletter(
|
|
||||||
$data->newsletter,
|
$data->newsletter,
|
||||||
$data->subscriber,
|
$data->subscriber,
|
||||||
$data->queue,
|
$data->queue,
|
||||||
$data->preview
|
$wp_user_preview
|
||||||
);
|
);
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
|
||||||
echo $rendered_newsletter;
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static function preProcessData($data) {
|
function renderNewsletter($newsletter, $subscriber, $queue, $wp_user_preview) {
|
||||||
$data = (object)$data;
|
|
||||||
if(empty($data->subscriber_id) ||
|
|
||||||
empty($data->subscriber_token) ||
|
|
||||||
empty($data->newsletter_id)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$data->newsletter = Newsletter::findOne($data->newsletter_id);
|
|
||||||
$data->subscriber = Subscriber::findOne($data->subscriber_id);
|
|
||||||
$data->queue = ($data->queue_id) ?
|
|
||||||
SendingQueue::findOne($data->queue_id) :
|
|
||||||
false;
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function validateData($data) {
|
|
||||||
if(!$data || !$data->subscriber || !$data->newsletter) return false;
|
|
||||||
$subscriber_token_match =
|
|
||||||
Subscriber::verifyToken($data->subscriber->email, $data->subscriber_token);
|
|
||||||
if(!$subscriber_token_match) return false;
|
|
||||||
// return if this is a WP user previewing the newsletter
|
|
||||||
if($data->subscriber->isWPUser() && $data->preview) {
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
// if queue exists, check if the newsletter was sent to the subscriber
|
|
||||||
if($data->queue && !$data->queue->isSubscriberProcessed($data->subscriber->id)) {
|
|
||||||
$data = false;
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function getAndRenderNewsletter($newsletter, $subscriber, $queue, $preview) {
|
|
||||||
if($queue && $queue->newsletter_rendered_body) {
|
if($queue && $queue->newsletter_rendered_body) {
|
||||||
$newsletter_body = $queue->getRenderedNewsletterBody();
|
$newsletter_body = $queue->getRenderedNewsletterBody();
|
||||||
} else {
|
} else {
|
||||||
$renderer = new Renderer($newsletter, $preview);
|
$renderer = new Renderer($newsletter, $wp_user_preview);
|
||||||
$newsletter_body = $renderer->render();
|
$newsletter_body = $renderer->render();
|
||||||
}
|
}
|
||||||
$shortcodes = new Shortcodes(
|
$shortcodes = new Shortcodes(
|
||||||
$newsletter,
|
$newsletter,
|
||||||
$subscriber,
|
$subscriber,
|
||||||
$queue
|
$queue
|
||||||
|
|
||||||
);
|
);
|
||||||
$rendered_newsletter = $shortcodes->replace($newsletter_body['html']);
|
$rendered_newsletter = $shortcodes->replace($newsletter_body['html']);
|
||||||
if($queue && (boolean)Setting::getValue('tracking.enabled')) {
|
if($queue && (boolean)Setting::getValue('tracking.enabled')) {
|
||||||
@ -75,14 +36,9 @@ class ViewInBrowser {
|
|||||||
$subscriber->id,
|
$subscriber->id,
|
||||||
$queue->id,
|
$queue->id,
|
||||||
$rendered_newsletter,
|
$rendered_newsletter,
|
||||||
$preview
|
$wp_user_preview
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return $rendered_newsletter;
|
return $rendered_newsletter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function abort() {
|
|
||||||
status_header(404);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -8,9 +8,15 @@ if(!defined('ABSPATH')) exit;
|
|||||||
class Queue {
|
class Queue {
|
||||||
const ENDPOINT = 'queue';
|
const ENDPOINT = 'queue';
|
||||||
const ACTION_RUN = 'run';
|
const ACTION_RUN = 'run';
|
||||||
|
public $allowed_actions = array(self::ACTION_RUN);
|
||||||
|
public $data;
|
||||||
|
|
||||||
static function run($data) {
|
function __construct($data) {
|
||||||
$queue = new Daemon($data);
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
$queue = new Daemon($this->data);
|
||||||
$queue->run();
|
$queue->run();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,18 +7,31 @@ if(!defined('ABSPATH')) exit;
|
|||||||
|
|
||||||
class Subscription {
|
class Subscription {
|
||||||
const ENDPOINT = 'subscription';
|
const ENDPOINT = 'subscription';
|
||||||
|
const ACTION_CONFIRM = 'confirm';
|
||||||
|
const ACTION_MANAGE = 'manage';
|
||||||
|
const ACTION_UNSUBSCRIBE = 'unsubscribe';
|
||||||
|
public $allowed_actions = array(
|
||||||
|
self::ACTION_CONFIRM,
|
||||||
|
self::ACTION_MANAGE,
|
||||||
|
self::ACTION_UNSUBSCRIBE
|
||||||
|
);
|
||||||
|
public $data;
|
||||||
|
|
||||||
static function confirm($data) {
|
function __construct($data) {
|
||||||
$subscription = new UserSubscription\Pages('confirm', $data);
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirm() {
|
||||||
|
$subscription = new UserSubscription\Pages('confirm', $this->data);
|
||||||
$subscription->confirm();
|
$subscription->confirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
static function manage($data) {
|
function manage() {
|
||||||
$subscription = new UserSubscription\Pages('manage', $data);
|
$subscription = new UserSubscription\Pages('manage', $this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function unsubscribe($data) {
|
function unsubscribe() {
|
||||||
$subscription = new UserSubscription\Pages('unsubscribe', $data);
|
$subscription = new UserSubscription\Pages('unsubscribe', $this->data);
|
||||||
$subscription->unsubscribe();
|
$subscription->unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,18 +14,27 @@ class Track {
|
|||||||
const ENDPOINT = 'track';
|
const ENDPOINT = 'track';
|
||||||
const ACTION_CLICK = 'click';
|
const ACTION_CLICK = 'click';
|
||||||
const ACTION_OPEN = 'open';
|
const ACTION_OPEN = 'open';
|
||||||
|
public $allowed_actions = array(
|
||||||
|
self::ACTION_CLICK,
|
||||||
|
self::ACTION_OPEN
|
||||||
|
);
|
||||||
|
public $data;
|
||||||
|
|
||||||
static function click($data) {
|
function __construct($data) {
|
||||||
|
$this->data = $this->_processTrackData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function click() {
|
||||||
$click_event = new Clicks();
|
$click_event = new Clicks();
|
||||||
return $click_event->track(self::_processTrackData($data));
|
return $click_event->track($this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function open($data) {
|
function open() {
|
||||||
$open_event = new Opens();
|
$open_event = new Opens();
|
||||||
return $open_event->track(self::_processTrackData($data));
|
return $open_event->track($this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function _processTrackData($data) {
|
function _processTrackData($data) {
|
||||||
$data = (object)$data;
|
$data = (object)$data;
|
||||||
if(empty($data->queue_id) ||
|
if(empty($data->queue_id) ||
|
||||||
empty($data->subscriber_id) ||
|
empty($data->subscriber_id) ||
|
||||||
@ -41,10 +50,10 @@ class Track {
|
|||||||
if(!empty($data->link_hash)) {
|
if(!empty($data->link_hash)) {
|
||||||
$data->link = NewsletterLink::getByHash($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;
|
if(!$data->subscriber || !$data->queue || !$data->newsletter) return false;
|
||||||
$subscriber_token_match =
|
$subscriber_token_match =
|
||||||
Subscriber::verifyToken($data->subscriber->email, $data->subscriber_token);
|
Subscriber::verifyToken($data->subscriber->email, $data->subscriber_token);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Router\Endpoints;
|
namespace MailPoet\Router\Endpoints;
|
||||||
|
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\SendingQueue;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Newsletter\ViewInBrowser as NewsletterViewInBrowser;
|
use MailPoet\Newsletter\ViewInBrowser as NewsletterViewInBrowser;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
@ -8,8 +11,61 @@ if(!defined('ABSPATH')) exit;
|
|||||||
class ViewInBrowser {
|
class ViewInBrowser {
|
||||||
const ENDPOINT = 'view_in_browser';
|
const ENDPOINT = 'view_in_browser';
|
||||||
const ACTION_VIEW = 'view';
|
const ACTION_VIEW = 'view';
|
||||||
|
public $allowed_actions = array(self::ACTION_VIEW);
|
||||||
|
public $data;
|
||||||
|
|
||||||
static function view($data) {
|
function __construct($data) {
|
||||||
NewsletterViewInBrowser::view($data);
|
$this->data = $this->_processBrowserPreviewData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function view() {
|
||||||
|
$view_in_browser = new NewsletterViewInBrowser();
|
||||||
|
return $this->_displayNewsletter($view_in_browser->view($this->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _processBrowserPreviewData($data) {
|
||||||
|
$data = (object)$data;
|
||||||
|
if(empty($data->subscriber_id) ||
|
||||||
|
empty($data->subscriber_token) ||
|
||||||
|
empty($data->newsletter_id)
|
||||||
|
) {
|
||||||
|
$this->_abort();
|
||||||
|
} else {
|
||||||
|
$data->newsletter = Newsletter::findOne($data->newsletter_id);
|
||||||
|
$data->subscriber = Subscriber::findOne($data->subscriber_id);
|
||||||
|
$data->queue = ($data->queue_id) ?
|
||||||
|
SendingQueue::findOne($data->queue_id) :
|
||||||
|
false;
|
||||||
|
return ($this->_validateBrowserPreviewData($data)) ?
|
||||||
|
$data :
|
||||||
|
$this->_abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _validateBrowserPreviewData($data) {
|
||||||
|
if(!$data || !$data->subscriber || !$data->newsletter) return false;
|
||||||
|
$subscriber_token_match =
|
||||||
|
Subscriber::verifyToken($data->subscriber->email, $data->subscriber_token);
|
||||||
|
if(!$subscriber_token_match) return false;
|
||||||
|
// return if this is a WP user previewing the newsletter
|
||||||
|
if($data->subscriber->isWPUser() && $data->preview) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
// if queue exists, check if the newsletter was sent to the subscriber
|
||||||
|
if($data->queue && !$data->queue->isSubscriberProcessed($data->subscriber->id)) {
|
||||||
|
$data = false;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _displayNewsletter($result) {
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
echo $result;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _abort() {
|
||||||
|
status_header(404);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Router;
|
namespace MailPoet\Router;
|
||||||
|
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class Front {
|
class Router {
|
||||||
public $api_request;
|
public $api_request;
|
||||||
public $endpoint;
|
public $endpoint;
|
||||||
public $action;
|
public $action;
|
||||||
public $data;
|
public $data;
|
||||||
const NAME = 'mailpoet_api';
|
const NAME = 'mailpoet_router';
|
||||||
const RESPONSE_ERROR = 404;
|
const RESPONSE_ERROR = 404;
|
||||||
|
|
||||||
function __construct($api_data = false) {
|
function __construct($api_data = false) {
|
||||||
@ -27,43 +28,31 @@ class Front {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$class = __NAMESPACE__ . "\\Endpoints\\" . ucfirst($this->endpoint);
|
$endpoint_class = __NAMESPACE__ . "\\Endpoints\\" . ucfirst($this->endpoint);
|
||||||
|
|
||||||
if(!$this->api_request) return;
|
if(!$this->api_request) return;
|
||||||
if(!$this->endpoint || !class_exists($class)) {
|
if(!$this->endpoint || !class_exists($endpoint_class)) {
|
||||||
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid Router endpoint.'));
|
return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint.'));
|
||||||
}
|
}
|
||||||
$this->callEndpoint(
|
$endpoint = new $endpoint_class($this->data);
|
||||||
$class,
|
if(!method_exists($endpoint, $this->action) || !in_array($this->action, $endpoint->allowed_actions)) {
|
||||||
$this->action,
|
return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint action.'));
|
||||||
$this->data
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return call_user_func(
|
||||||
function callEndpoint($endpoint, $action, $data) {
|
|
||||||
if(!method_exists($endpoint, $action)) {
|
|
||||||
self::terminateRequest(self::RESPONSE_ERROR, __('Invalid Router action.'));
|
|
||||||
}
|
|
||||||
call_user_func(
|
|
||||||
array(
|
array(
|
||||||
$endpoint,
|
$endpoint,
|
||||||
$action
|
$this->action
|
||||||
),
|
)
|
||||||
$data
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function decodeRequestData($data) {
|
static function decodeRequestData($data) {
|
||||||
$data = base64_decode($data);
|
$data = base64_decode($data);
|
||||||
|
|
||||||
if(is_serialized($data)) {
|
if(is_serialized($data)) {
|
||||||
$data = unserialize($data);
|
$data = unserialize($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_array($data)) {
|
if(!is_array($data)) {
|
||||||
$data = array();
|
$data = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +71,7 @@ class Front {
|
|||||||
return add_query_arg($params, home_url());
|
return add_query_arg($params, home_url());
|
||||||
}
|
}
|
||||||
|
|
||||||
static function terminateRequest($code, $message) {
|
function terminateRequest($code, $message) {
|
||||||
status_header($code, $message);
|
status_header($code, $message);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Subscription;
|
namespace MailPoet\Subscription;
|
||||||
|
|
||||||
use MailPoet\Router\Front as FrontRouter;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Router\Endpoints\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;
|
||||||
@ -45,10 +45,10 @@ class Url {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$params = array(
|
$params = array(
|
||||||
FrontRouter::NAME,
|
Router::NAME,
|
||||||
'endpoint='.SubscriptionEndpoint::ENDPOINT,
|
'endpoint='.SubscriptionEndpoint::ENDPOINT,
|
||||||
'action='.$action,
|
'action='.$action,
|
||||||
'data='.FrontRouter::encodeRequestData($data)
|
'data='.Router::encodeRequestData($data)
|
||||||
);
|
);
|
||||||
|
|
||||||
// add parameters
|
// add parameters
|
||||||
|
@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
|
|||||||
use \MailPoet\Config\Initializer;
|
use \MailPoet\Config\Initializer;
|
||||||
/*
|
/*
|
||||||
* Plugin Name: MailPoet
|
* Plugin Name: MailPoet
|
||||||
* Version: 0.0.41
|
* Version: 0.0.42
|
||||||
* Plugin URI: http://www.mailpoet.com
|
* Plugin URI: http://www.mailpoet.com
|
||||||
* Description: MailPoet Newsletters.
|
* Description: MailPoet Newsletters.
|
||||||
* Author: MailPoet
|
* Author: MailPoet
|
||||||
@ -22,7 +22,7 @@ use \MailPoet\Config\Initializer;
|
|||||||
|
|
||||||
require 'vendor/autoload.php';
|
require 'vendor/autoload.php';
|
||||||
|
|
||||||
define('MAILPOET_VERSION', '0.0.41');
|
define('MAILPOET_VERSION', '0.0.42');
|
||||||
|
|
||||||
$initializer = new Initializer(array(
|
$initializer = new Initializer(array(
|
||||||
'file' => __FILE__,
|
'file' => __FILE__,
|
||||||
|
152
tests/unit/Newsletter/ViewInBrowserTest.php
Normal file
152
tests/unit/Newsletter/ViewInBrowserTest.php
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Codeception\Util\Stub;
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\SendingQueue;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Newsletter\ViewInBrowser;
|
||||||
|
use MailPoet\Router\Router;
|
||||||
|
|
||||||
|
class ViewInBrowserTest extends MailPoetTest {
|
||||||
|
function __construct() {
|
||||||
|
$this->newsletter = array(
|
||||||
|
'body' => json_decode(
|
||||||
|
'{
|
||||||
|
"content": {
|
||||||
|
"type": "container",
|
||||||
|
"orientation": "vertical",
|
||||||
|
"styles": {
|
||||||
|
"block": {
|
||||||
|
"backgroundColor": "transparent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"type": "container",
|
||||||
|
"orientation": "horizontal",
|
||||||
|
"styles": {
|
||||||
|
"block": {
|
||||||
|
"backgroundColor": "transparent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"type": "container",
|
||||||
|
"orientation": "vertical",
|
||||||
|
"styles": {
|
||||||
|
"block": {
|
||||||
|
"backgroundColor": "transparent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "<p>Rendered newsletter. Hello, [subscriber:firstname | default:reader] & [link:newsletter_view_in_browser_url]</p>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}', true),
|
||||||
|
'id' => 1,
|
||||||
|
'subject' => 'Some subject',
|
||||||
|
'preheader' => 'Some preheader',
|
||||||
|
'type' => 'standard',
|
||||||
|
'status' => 'active'
|
||||||
|
);
|
||||||
|
$this->queue_rendered_newsletter_without_tracking = json_encode(
|
||||||
|
array(
|
||||||
|
'html' => 'Newsletter from queue. Hello, [subscriber:firstname] &
|
||||||
|
[link:newsletter_view_in_browser_url]'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->queue_rendered_newsletter_with_tracking = json_encode(
|
||||||
|
array(
|
||||||
|
'html' => 'Newsletter from queue. Hello, [subscriber:firstname] &
|
||||||
|
[mailpoet_click_data]-90e56'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// instantiate class
|
||||||
|
$this->view_in_browser = new ViewInBrowser();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
// create newsletter
|
||||||
|
$newsletter = Newsletter::create();
|
||||||
|
$newsletter->hydrate($this->newsletter);
|
||||||
|
$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->newsletter_rendered_body = $this->queue_rendered_newsletter_without_tracking;
|
||||||
|
$queue->subscribers = array('processed' => array($subscriber->id));
|
||||||
|
$this->queue = $queue->save();
|
||||||
|
// build browser preview data
|
||||||
|
$this->browser_preview_data = (object)array(
|
||||||
|
'queue' => $this->queue,
|
||||||
|
'subscriber' => $this->subscriber,
|
||||||
|
'newsletter' => $this->newsletter,
|
||||||
|
'preview' => false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItRendersNewsletter() {
|
||||||
|
$rendered_body = ViewInBrowser::renderNewsletter(
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber,
|
||||||
|
$queue = false,
|
||||||
|
$preview = true
|
||||||
|
);
|
||||||
|
expect($rendered_body)->regExp('/Rendered newsletter/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItReusesRenderedNewsletterBodyWhenQueueExists() {
|
||||||
|
$rendered_body = ViewInBrowser::renderNewsletter(
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber,
|
||||||
|
$this->queue,
|
||||||
|
$preview = true
|
||||||
|
);
|
||||||
|
expect($rendered_body)->regExp('/Newsletter from queue/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItConvertsShortcodes() {
|
||||||
|
Setting::setValue('tracking.enabled', false);
|
||||||
|
$rendered_body = ViewInBrowser::renderNewsletter(
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber,
|
||||||
|
$this->queue,
|
||||||
|
$preview = true
|
||||||
|
);
|
||||||
|
expect($rendered_body)->contains('Hello, First');
|
||||||
|
expect($rendered_body)->contains(Router::NAME . '&endpoint=view_in_browser');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItProcessesLinksWhenTrackingIsEnabled() {
|
||||||
|
Setting::setValue('tracking.enabled', true);
|
||||||
|
$queue = $this->queue;
|
||||||
|
$queue->newsletter_rendered_body = $this->queue_rendered_newsletter_with_tracking;
|
||||||
|
$rendered_body = ViewInBrowser::renderNewsletter(
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber,
|
||||||
|
$queue,
|
||||||
|
$preview = true
|
||||||
|
);
|
||||||
|
expect($rendered_body)->contains(Router::NAME . '&endpoint=track');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
||||||
|
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||||
|
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||||
|
}
|
||||||
|
}
|
@ -39,21 +39,23 @@ class TrackTest extends MailPoetTest {
|
|||||||
'link_hash' => $link->hash,
|
'link_hash' => $link->hash,
|
||||||
'preview' => false
|
'preview' => false
|
||||||
);
|
);
|
||||||
|
// instantiate class
|
||||||
|
$this->track = new Track($this->track_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItReturnsFalseWhenTrackDataIsMissing() {
|
function testItReturnsFalseWhenTrackDataIsMissing() {
|
||||||
// queue ID is required
|
// queue ID is required
|
||||||
$data = $this->track_data;
|
$data = $this->track_data;
|
||||||
unset($data['queue_id']);
|
unset($data['queue_id']);
|
||||||
expect(Track::_processTrackData($data))->false();
|
expect($this->track->_processTrackData($data))->false();
|
||||||
// subscriber ID is required
|
// subscriber ID is required
|
||||||
$data = $this->track_data;
|
$data = $this->track_data;
|
||||||
unset($data['subscriber_id']);
|
unset($data['subscriber_id']);
|
||||||
expect(Track::_processTrackData($data))->false();
|
expect($this->track->_processTrackData($data))->false();
|
||||||
// subscriber token is required
|
// subscriber token is required
|
||||||
$data = $this->track_data;
|
$data = $this->track_data;
|
||||||
unset($data['subscriber_token']);
|
unset($data['subscriber_token']);
|
||||||
expect(Track::_processTrackData($data))->false();
|
expect($this->track->_processTrackData($data))->false();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItFailsWhenSubscriberTokenDoesNotMatch() {
|
function testItFailsWhenSubscriberTokenDoesNotMatch() {
|
||||||
@ -66,7 +68,7 @@ class TrackTest extends MailPoetTest {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
$data->subscriber->email = 'random@email.com';
|
$data->subscriber->email = 'random@email.com';
|
||||||
expect(Track::_validateTrackData($data))->false();
|
expect($this->track->_validateTrackData($data))->false();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItFailsWhenSubscriberIsNotOnProcessedList() {
|
function testItFailsWhenSubscriberIsNotOnProcessedList() {
|
||||||
@ -79,7 +81,7 @@ class TrackTest extends MailPoetTest {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
$data->subscriber->id = 99;
|
$data->subscriber->id = 99;
|
||||||
expect(Track::_validateTrackData($data))->false();
|
expect($this->track->_validateTrackData($data))->false();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItDoesNotRequireWpUsersToBeOnProcessedListWhenPreviewIsEnabled() {
|
function testItDoesNotRequireWpUsersToBeOnProcessedListWhenPreviewIsEnabled() {
|
||||||
@ -93,18 +95,26 @@ class TrackTest extends MailPoetTest {
|
|||||||
);
|
);
|
||||||
$data->subscriber->wp_user_id = 99;
|
$data->subscriber->wp_user_id = 99;
|
||||||
$data->preview = true;
|
$data->preview = true;
|
||||||
expect(Track::_validateTrackData($data))->equals($data);
|
expect($this->track->_validateTrackData($data))->equals($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItCanGetNewsletterFromQueue() {
|
function testItRequiresValidQueueToGetNewsletter() {
|
||||||
$data = $this->track_data;
|
$data = $this->track_data;
|
||||||
$data['newsletter_id'] = false;
|
$data['newsletter_id'] = false;
|
||||||
$processed_data = Track::_processTrackData($this->track_data);
|
$data['queue_id'] = 99;
|
||||||
|
$processed_data = $this->track->_processTrackData($data);
|
||||||
|
expect($processed_data)->false();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItGetsNewsletterFromQueue() {
|
||||||
|
$data = $this->track_data;
|
||||||
|
$data['newsletter_id'] = false;
|
||||||
|
$processed_data = $this->track->_processTrackData($data);
|
||||||
expect($processed_data->newsletter->id)->equals($this->newsletter->id);
|
expect($processed_data->newsletter->id)->equals($this->newsletter->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItCanProcessTrackData() {
|
function testItProcessesTrackData() {
|
||||||
$processed_data = Track::_processTrackData($this->track_data);
|
$processed_data = $this->track->_processTrackData($this->track_data);
|
||||||
expect($processed_data->queue->id)->equals($this->queue->id);
|
expect($processed_data->queue->id)->equals($this->queue->id);
|
||||||
expect($processed_data->subscriber->id)->equals($this->subscriber->id);
|
expect($processed_data->subscriber->id)->equals($this->subscriber->id);
|
||||||
expect($processed_data->newsletter->id)->equals($this->newsletter->id);
|
expect($processed_data->newsletter->id)->equals($this->newsletter->id);
|
||||||
|
134
tests/unit/Router/Endpoints/ViewInBrowserTest.php
Normal file
134
tests/unit/Router/Endpoints/ViewInBrowserTest.php
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?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($this->browser_preview_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItAbortsWhenBrowserPreviewDataIsMissing() {
|
||||||
|
$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 testItAbortsWhenBrowserPreviewDataIsInvalid() {
|
||||||
|
$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 testItProcessesBrowserPreviewData() {
|
||||||
|
$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 testItReturnsViewActionResult() {
|
||||||
|
$view_in_browser = Stub::make($this->view_in_browser, array(
|
||||||
|
'_displayNewsletter' => Stub::exactly(1, function() { })
|
||||||
|
), $this);
|
||||||
|
$view_in_browser->data = $view_in_browser->_processBrowserPreviewData($this->browser_preview_data);
|
||||||
|
$view_in_browser->view();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
||||||
|
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||||
|
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||||
|
}
|
||||||
|
}
|
130
tests/unit/Router/RouterTest.php
Normal file
130
tests/unit/Router/RouterTest.php
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Codeception\Util\Stub;
|
||||||
|
use MailPoet\Router\Router;
|
||||||
|
|
||||||
|
require_once('RouterTestMockEndpoint.php');
|
||||||
|
|
||||||
|
class FrontRouterTest extends MailPoetTest {
|
||||||
|
public $router_data;
|
||||||
|
public $router;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->router_data = array(
|
||||||
|
Router::NAME => '',
|
||||||
|
'endpoint' => 'mock_endpoint',
|
||||||
|
'action' => 'test',
|
||||||
|
'data' => base64_encode(serialize(array('data' => 'dummy data')))
|
||||||
|
);
|
||||||
|
$this->router = new Router($this->router_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanGetAPIDataFromGetRequest() {
|
||||||
|
$data = array('data' => 'dummy data');
|
||||||
|
$url = 'http://example.com/?' . Router::NAME . '&endpoint=view_in_browser&action=view&data='
|
||||||
|
. base64_encode(serialize($data));
|
||||||
|
parse_str(parse_url($url, PHP_URL_QUERY), $_GET);
|
||||||
|
$router = new Router();
|
||||||
|
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[Router::NAME]);
|
||||||
|
$router = Stub::construct(
|
||||||
|
new Router(),
|
||||||
|
array($router_data)
|
||||||
|
);
|
||||||
|
$result = $router->init();
|
||||||
|
expect($result)->null();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItTerminatesRequestWhenEndpointNotFound() {
|
||||||
|
$router_data = $this->router_data;
|
||||||
|
$router_data['endpoint'] = 'invalid_endpoint';
|
||||||
|
$router = Stub::construct(
|
||||||
|
new Router(),
|
||||||
|
array($router_data),
|
||||||
|
array(
|
||||||
|
'terminateRequest' => function($code, $error) {
|
||||||
|
return array(
|
||||||
|
$code,
|
||||||
|
$error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$result = $router->init();
|
||||||
|
expect($result)->equals(
|
||||||
|
array(
|
||||||
|
404,
|
||||||
|
'Invalid router endpoint.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItTerminatesRequestWhenEndpointActionNotFound() {
|
||||||
|
$router_data = $this->router_data;
|
||||||
|
$router_data['action'] = 'invalid_action';
|
||||||
|
$router = Stub::construct(
|
||||||
|
new Router(),
|
||||||
|
array($router_data),
|
||||||
|
array(
|
||||||
|
'terminateRequest' => function($code, $error) {
|
||||||
|
return array(
|
||||||
|
$code,
|
||||||
|
$error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$result = $router->init();
|
||||||
|
expect($result)->equals(
|
||||||
|
array(
|
||||||
|
404,
|
||||||
|
'Invalid router endpoint action.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCallsEndpointAction() {
|
||||||
|
$data = array('data' => 'dummy data');
|
||||||
|
$result = $this->router->init();
|
||||||
|
expect($result)->equals($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanEncodeRequestData() {
|
||||||
|
$data = array('data' => 'dummy data');
|
||||||
|
$result = Router::encodeRequestData($data);
|
||||||
|
expect($result)->equals(
|
||||||
|
rtrim(base64_encode(serialize($data)), '=')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItReturnsEmptyArrayWhenRequestDataIsAString() {
|
||||||
|
$encoded_data = 'test';
|
||||||
|
$result = Router::decodeRequestData($encoded_data);
|
||||||
|
expect($result)->equals(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanDecodeRequestData() {
|
||||||
|
$data = array('data' => 'dummy data');
|
||||||
|
$encoded_data = rtrim(base64_encode(serialize($data)), '=');
|
||||||
|
$result = Router::decodeRequestData($encoded_data);
|
||||||
|
expect($result)->equals($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanBuildRequest() {
|
||||||
|
$data = array('data' => 'dummy data');
|
||||||
|
$encoded_data = rtrim(base64_encode(serialize($data)), '=');
|
||||||
|
$result = Router::buildRequest(
|
||||||
|
'mock_endpoint',
|
||||||
|
'test',
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
expect($result)->contains(Router::NAME . '&endpoint=mock_endpoint&action=test&data=' . $encoded_data);
|
||||||
|
}
|
||||||
|
}
|
19
tests/unit/Router/RouterTestMockEndpoint.php
Normal file
19
tests/unit/Router/RouterTestMockEndpoint.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Router\Endpoints;
|
||||||
|
|
||||||
|
class MockEndpoint {
|
||||||
|
const ACTION_TEST = 'test';
|
||||||
|
public $allowed_actions = array(
|
||||||
|
self::ACTION_TEST
|
||||||
|
);
|
||||||
|
public $data;
|
||||||
|
|
||||||
|
function __construct($data) {
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
}
|
@ -135,7 +135,7 @@ class ClicksTest extends MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function testItDoesNotConvertRegulaUrls() {
|
function testItDoesNotConvertRegularUrls() {
|
||||||
$link = $this->clicks->processUrl(
|
$link = $this->clicks->processUrl(
|
||||||
'http://example.com',
|
'http://example.com',
|
||||||
$this->newsletter,
|
$this->newsletter,
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<div class="handlediv" title="Click to toggle"><br></div>
|
<div class="handlediv" title="Click to toggle"><br></div>
|
||||||
<h3><%= __('Preview') %></h3>
|
<h3><%= __('Preview') %></h3>
|
||||||
<div class="mailpoet_region_content">
|
<div class="mailpoet_region_content">
|
||||||
|
<iframe name="mailpoet_save_preview_email_for_autocomplete" style="display:none" src="about:blank"></iframe>
|
||||||
|
<form target="mailpoet_save_preview_email_for_autocomplete" action="about:blank">
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<label>
|
||||||
<%= __('Send preview to') %><br />
|
<%= __('Send preview to') %><br />
|
||||||
<input id="mailpoet_preview_to_email" class="mailpoet_input mailpoet_input_full" type="text" name="to_email" value="<%= settings.sender.address %>" />
|
<input id="mailpoet_preview_to_email" class="mailpoet_input mailpoet_input_full" type="text" name="to_email" value="<%= current_wp_user.email %>" autocomplete="email" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<input type="button" id="mailpoet_send_preview" class="button button-primary mailpoet_button_full" value="<%= __('Send preview') %>" />
|
<input type="submit" id="mailpoet_send_preview" class="button button-primary mailpoet_button_full" value="<%= __('Send preview') %>" />
|
||||||
</div>
|
</div>
|
||||||
|
</ofmr>
|
||||||
|
|
||||||
<hr class="mailpoet_separator" />
|
<hr class="mailpoet_separator" />
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user