Merge pull request #1017 from mailpoet/rerender-newsletter
Rerender newsletter [MAILPOET-675]
This commit is contained in:
@ -180,6 +180,7 @@ define([
|
|||||||
<select
|
<select
|
||||||
id={ this.props.field.id || this.props.field.name }
|
id={ this.props.field.id || this.props.field.name }
|
||||||
ref="select"
|
ref="select"
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
data-placeholder={ this.props.field.placeholder }
|
data-placeholder={ this.props.field.placeholder }
|
||||||
multiple={ this.props.field.multiple }
|
multiple={ this.props.field.multiple }
|
||||||
defaultValue={ this.getSelectedValues() }
|
defaultValue={ this.getSelectedValues() }
|
||||||
|
@ -97,6 +97,17 @@ const bulk_actions = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const confirmEdit = (newsletter) => {
|
||||||
|
if(
|
||||||
|
!newsletter.queue
|
||||||
|
|| newsletter.status != 'sending'
|
||||||
|
|| newsletter.queue.status !== null
|
||||||
|
|| window.confirm(MailPoet.I18n.t('confirmEdit'))
|
||||||
|
) {
|
||||||
|
window.location.href = `?page=mailpoet-newsletter-editor&id=${ newsletter.id }`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let newsletter_actions = [
|
let newsletter_actions = [
|
||||||
{
|
{
|
||||||
name: 'view',
|
name: 'view',
|
||||||
@ -110,13 +121,8 @@ let newsletter_actions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
link: function (newsletter) {
|
label: MailPoet.I18n.t('edit'),
|
||||||
return (
|
onClick: confirmEdit,
|
||||||
<a href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }>
|
|
||||||
{MailPoet.I18n.t('edit')}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'duplicate',
|
name: 'duplicate',
|
||||||
@ -172,7 +178,8 @@ const NewsletterListStandard = React.createClass({
|
|||||||
<strong>
|
<strong>
|
||||||
<a
|
<a
|
||||||
className="row-title"
|
className="row-title"
|
||||||
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }
|
href="javascript:;"
|
||||||
|
onClick={() => confirmEdit(newsletter)}
|
||||||
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
|
>{ newsletter.queue.newsletter_rendered_subject || newsletter.subject }</a>
|
||||||
</strong>
|
</strong>
|
||||||
{ actions }
|
{ actions }
|
||||||
|
@ -168,6 +168,40 @@ define(
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
handleResume: function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!this.isValid()) {
|
||||||
|
jQuery('#mailpoet_newsletter').parsley().validate();
|
||||||
|
} else {
|
||||||
|
this._save(e).done(() => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
}).done(() => {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
api_version: window.mailpoet_api_version,
|
||||||
|
endpoint: 'sendingQueue',
|
||||||
|
action: 'resume',
|
||||||
|
data: {
|
||||||
|
newsletter_id: this.state.item.id,
|
||||||
|
},
|
||||||
|
}).done(() => {
|
||||||
|
this.context.router.push(`/${ this.state.item.type || '' }`);
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
MailPoet.I18n.t('newsletterSendingHasBeenResumed')
|
||||||
|
);
|
||||||
|
}).fail((response) => {
|
||||||
|
if (response.errors.length > 0) {
|
||||||
|
MailPoet.Notice.error(
|
||||||
|
response.errors.map((error) => { return error.message; }),
|
||||||
|
{ scroll: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).fail(this._showError).always(() => {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
handleSave: function (e) {
|
handleSave: function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -193,6 +227,7 @@ define(
|
|||||||
},
|
},
|
||||||
_save: function () {
|
_save: function () {
|
||||||
const data = this.state.item;
|
const data = this.state.item;
|
||||||
|
data.queue = undefined;
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
|
|
||||||
// Store only properties that can be changed on this page
|
// Store only properties that can be changed on this page
|
||||||
@ -234,6 +269,15 @@ define(
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
const isPaused = this.state.item.status == 'sending'
|
||||||
|
&& this.state.item.queue
|
||||||
|
&& this.state.item.queue.status == 'paused';
|
||||||
|
const fields = this.state.fields.map((field) => {
|
||||||
|
if (field.name == 'segments' || field.name == 'options') {
|
||||||
|
field.disabled = isPaused;
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
|
||||||
@ -242,20 +286,29 @@ define(
|
|||||||
|
|
||||||
<Form
|
<Form
|
||||||
id="mailpoet_newsletter"
|
id="mailpoet_newsletter"
|
||||||
fields={ this.state.fields }
|
fields={ fields }
|
||||||
item={ this.state.item }
|
item={ this.state.item }
|
||||||
loading={ this.state.loading }
|
loading={ this.state.loading }
|
||||||
onChange={this.handleFormChange}
|
onChange={this.handleFormChange}
|
||||||
onSubmit={this.handleSave}
|
onSubmit={this.handleSave}
|
||||||
>
|
>
|
||||||
<p className="submit">
|
<p className="submit">
|
||||||
<input
|
{
|
||||||
|
isPaused ?
|
||||||
|
<input
|
||||||
|
className="button button-primary"
|
||||||
|
type="button"
|
||||||
|
onClick={ this.handleResume }
|
||||||
|
value={MailPoet.I18n.t('resume')} />
|
||||||
|
:
|
||||||
|
<input
|
||||||
className="button button-primary"
|
className="button button-primary"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={ this.handleSend }
|
onClick={ this.handleSend }
|
||||||
value={MailPoet.I18n.t('send')}
|
value={MailPoet.I18n.t('send')}
|
||||||
{...this.getSendButtonOptions()}
|
{...this.getSendButtonOptions()}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="button button-secondary"
|
className="button button-secondary"
|
||||||
|
@ -155,6 +155,7 @@ define(
|
|||||||
name={this.getFieldName()}
|
name={this.getFieldName()}
|
||||||
value={this.getDisplayDate(this.props.value)}
|
value={this.getDisplayDate(this.props.value)}
|
||||||
readOnly={ true }
|
readOnly={ true }
|
||||||
|
disabled={this.props.disabled}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
ref="dateInput"
|
ref="dateInput"
|
||||||
{...this.props.validation} />
|
{...this.props.validation} />
|
||||||
@ -180,6 +181,7 @@ define(
|
|||||||
<select
|
<select
|
||||||
name={this.props.name || 'time'}
|
name={this.props.name || 'time'}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
disabled={this.props.disabled}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
{...this.props.validation}
|
{...this.props.validation}
|
||||||
>
|
>
|
||||||
@ -235,11 +237,13 @@ define(
|
|||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
displayFormat={dateDisplayFormat}
|
displayFormat={dateDisplayFormat}
|
||||||
storageFormat={dateStorageFormat}
|
storageFormat={dateStorageFormat}
|
||||||
|
disabled={this.props.disabled}
|
||||||
validation={this.props.dateValidation}/>
|
validation={this.props.dateValidation}/>
|
||||||
<TimeSelect
|
<TimeSelect
|
||||||
name="time"
|
name="time"
|
||||||
value={this.state.time}
|
value={this.state.time}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={this.props.disabled}
|
||||||
validation={this.props.timeValidation} />
|
validation={this.props.timeValidation} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -292,6 +296,7 @@ define(
|
|||||||
name="scheduledAt"
|
name="scheduledAt"
|
||||||
value={this._getCurrentValue().scheduledAt}
|
value={this._getCurrentValue().scheduledAt}
|
||||||
onChange={this.handleValueChange}
|
onChange={this.handleValueChange}
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
dateValidation={this.getDateValidation()} />
|
dateValidation={this.getDateValidation()} />
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
@ -300,7 +305,6 @@ define(
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
@ -308,6 +312,7 @@ define(
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
value="1"
|
value="1"
|
||||||
checked={this.isScheduled()}
|
checked={this.isScheduled()}
|
||||||
|
disabled={this.props.field.disabled}
|
||||||
name="isScheduled"
|
name="isScheduled"
|
||||||
onChange={this.handleCheckboxChange} />
|
onChange={this.handleCheckboxChange} />
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ class Newsletters extends APIEndpoint {
|
|||||||
$newsletter = $newsletter
|
$newsletter = $newsletter
|
||||||
->withSegments()
|
->withSegments()
|
||||||
->withOptions()
|
->withOptions()
|
||||||
|
->withSendingQueue()
|
||||||
->asArray();
|
->asArray();
|
||||||
$newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter);
|
$newsletter = Hooks::applyFilters('mailpoet_api_newsletters_get_after', $newsletter);
|
||||||
return $this->successResponse($newsletter);
|
return $this->successResponse($newsletter);
|
||||||
@ -110,6 +111,13 @@ class Newsletters extends APIEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$queue = $newsletter->getQueue();
|
||||||
|
if($queue) {
|
||||||
|
$queue->newsletter_rendered_body = null;
|
||||||
|
$queue->newsletter_rendered_subject = null;
|
||||||
|
$queue->save();
|
||||||
|
}
|
||||||
|
|
||||||
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
|
Hooks::doAction('mailpoet_api_newsletters_save_after', $newsletter);
|
||||||
|
|
||||||
return $this->successResponse($newsletter->asArray());
|
return $this->successResponse($newsletter->asArray());
|
||||||
@ -455,4 +463,4 @@ class Newsletters extends APIEndpoint {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,4 +190,4 @@ class SendingQueue {
|
|||||||
->whereNull('type')
|
->whereNull('type')
|
||||||
->findMany();
|
->findMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,15 @@ if(!defined('ABSPATH')) exit;
|
|||||||
class Links {
|
class Links {
|
||||||
static function process($rendered_newsletter, $newsletter, $queue) {
|
static function process($rendered_newsletter, $newsletter, $queue) {
|
||||||
list($rendered_newsletter, $links) =
|
list($rendered_newsletter, $links) =
|
||||||
self::hashAndReplaceLinks($rendered_newsletter);
|
self::hashAndReplaceLinks($rendered_newsletter, $newsletter->id, $queue->id);
|
||||||
self::saveLinks($links, $newsletter, $queue);
|
self::saveLinks($links, $newsletter, $queue);
|
||||||
return $rendered_newsletter;
|
return $rendered_newsletter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hashAndReplaceLinks($rendered_newsletter) {
|
static function hashAndReplaceLinks($rendered_newsletter, $newsletter_id, $queue_id) {
|
||||||
// join HTML and TEXT rendered body into a text string
|
// join HTML and TEXT rendered body into a text string
|
||||||
$content = Helpers::joinObject($rendered_newsletter);
|
$content = Helpers::joinObject($rendered_newsletter);
|
||||||
list($content, $links) = NewsletterLinks::process($content);
|
list($content, $links) = NewsletterLinks::process($content, $newsletter_id, $queue_id);
|
||||||
// split the processed body with hashed links back to HTML and TEXT
|
// split the processed body with hashed links back to HTML and TEXT
|
||||||
list($rendered_newsletter['html'], $rendered_newsletter['text'])
|
list($rendered_newsletter['html'], $rendered_newsletter['text'])
|
||||||
= Helpers::splitObject($content);
|
= Helpers::splitObject($content);
|
||||||
|
@ -175,4 +175,4 @@ class Newsletter {
|
|||||||
__('There was an error processing your newsletter during sending. If possible, please contact us and report this issue.')
|
__('There was an error processing your newsletter during sending. If possible, please contact us and report this issue.')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
|||||||
use MailPoet\Router\Endpoints\Track as TrackEndpoint;
|
use MailPoet\Router\Endpoints\Track as TrackEndpoint;
|
||||||
use MailPoet\Router\Router;
|
use MailPoet\Router\Router;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\Util\pQuery\pQuery as DomParser;
|
|
||||||
use MailPoet\Util\Security;
|
use MailPoet\Util\Security;
|
||||||
|
use MailPoet\Util\pQuery\pQuery as DomParser;
|
||||||
|
|
||||||
class Links {
|
class Links {
|
||||||
const DATA_TAG_CLICK = '[mailpoet_click_data]';
|
const DATA_TAG_CLICK = '[mailpoet_click_data]';
|
||||||
@ -17,9 +17,10 @@ class Links {
|
|||||||
const LINK_TYPE_SHORTCODE = 'shortcode';
|
const LINK_TYPE_SHORTCODE = 'shortcode';
|
||||||
const LINK_TYPE_URL = 'link';
|
const LINK_TYPE_URL = 'link';
|
||||||
|
|
||||||
static function process($content) {
|
static function process($content, $newsletter_id, $queue_id) {
|
||||||
$extracted_links = self::extract($content);
|
$extracted_links = self::extract($content);
|
||||||
$processed_links = self::hash($extracted_links);
|
$saved_links = self::load($newsletter_id, $queue_id);
|
||||||
|
$processed_links = self::hash($extracted_links, $saved_links);
|
||||||
return self::replace($content, $processed_links);
|
return self::replace($content, $processed_links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,13 +52,31 @@ class Links {
|
|||||||
return array_unique($extracted_links, SORT_REGULAR);
|
return array_unique($extracted_links, SORT_REGULAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hash($extracted_links) {
|
static function load($newsletter_id, $queue_id) {
|
||||||
$processed_links = array();
|
$links = NewsletterLink::whereEqual('newsletter_id', $newsletter_id)
|
||||||
|
->whereEqual('queue_id', $queue_id)
|
||||||
|
->findMany();
|
||||||
|
$saved_links = array();
|
||||||
|
foreach($links as $link) {
|
||||||
|
$saved_links[$link->url] = $link->asArray();
|
||||||
|
}
|
||||||
|
return $saved_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function hash($extracted_links, $saved_links) {
|
||||||
|
$processed_links = array_map(function(&$link) {
|
||||||
|
$link['type'] = Links::LINK_TYPE_URL;
|
||||||
|
$link['link'] = $link['url'];
|
||||||
|
$link['processed_link'] = self::DATA_TAG_CLICK . '-' . $link['hash'];
|
||||||
|
return $link;
|
||||||
|
}, $saved_links);
|
||||||
foreach($extracted_links as $extracted_link) {
|
foreach($extracted_links as $extracted_link) {
|
||||||
|
$link = $extracted_link['link'];
|
||||||
|
if (array_key_exists($link, $processed_links))
|
||||||
|
continue;
|
||||||
$hash = Security::generateHash();
|
$hash = Security::generateHash();
|
||||||
// Use URL as a key to map between extracted and processed links
|
// Use URL as a key to map between extracted and processed links
|
||||||
// regardless of their sequential position (useful for link skips etc.)
|
// regardless of their sequential position (useful for link skips etc.)
|
||||||
$link = $extracted_link['link'];
|
|
||||||
$processed_links[$link] = array(
|
$processed_links[$link] = array(
|
||||||
'type' => $extracted_link['type'],
|
'type' => $extracted_link['type'],
|
||||||
'hash' => $hash,
|
'hash' => $hash,
|
||||||
@ -137,6 +156,8 @@ class Links {
|
|||||||
|
|
||||||
static function save(array $links, $newsletter_id, $queue_id) {
|
static function save(array $links, $newsletter_id, $queue_id) {
|
||||||
foreach($links as $link) {
|
foreach($links as $link) {
|
||||||
|
if (isset($link['id']))
|
||||||
|
continue;
|
||||||
if(empty($link['hash']) || empty($link['link'])) continue;
|
if(empty($link['hash']) || empty($link['link'])) continue;
|
||||||
$newsletter_link = NewsletterLink::create();
|
$newsletter_link = NewsletterLink::create();
|
||||||
$newsletter_link->newsletter_id = $newsletter_id;
|
$newsletter_link->newsletter_id = $newsletter_id;
|
||||||
@ -198,4 +219,4 @@ class Links {
|
|||||||
$transformed_data['preview'] = (!empty($data[4])) ? $data[4] : false;
|
$transformed_data['preview'] = (!empty($data[4])) ? $data[4] : false;
|
||||||
return $transformed_data;
|
return $transformed_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,7 @@ class NewslettersTest extends \MailPoetTest {
|
|||||||
Newsletter::findOne($this->newsletter->id)
|
Newsletter::findOne($this->newsletter->id)
|
||||||
->withSegments()
|
->withSegments()
|
||||||
->withOptions()
|
->withOptions()
|
||||||
|
->withSendingQueue()
|
||||||
->asArray()
|
->asArray()
|
||||||
);
|
);
|
||||||
$hook_name = 'mailpoet_api_newsletters_get_after';
|
$hook_name = 'mailpoet_api_newsletters_get_after';
|
||||||
@ -163,6 +164,31 @@ class NewslettersTest extends \MailPoetTest {
|
|||||||
expect($updated_newsletter->subject)->equals('My Updated Newsletter');
|
expect($updated_newsletter->subject)->equals('My Updated Newsletter');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testItCanClearRenderedQueueUponSave() {
|
||||||
|
$sending_queue = SendingQueue::create();
|
||||||
|
$sending_queue->newsletter_id = $this->newsletter->id;
|
||||||
|
$sending_queue->status = SendingQueue::STATUS_SCHEDULED;
|
||||||
|
$sending_queue->newsletter_rendered_body = 'Rendered body ...';
|
||||||
|
$sending_queue->newsletter_rendered_subject = 'Rendered subject ...';
|
||||||
|
$sending_queue->save();
|
||||||
|
|
||||||
|
$router = new Newsletters();
|
||||||
|
$newsletter_data = array(
|
||||||
|
'id' => $this->newsletter->id,
|
||||||
|
'subject' => 'My Updated Newsletter'
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = $router->save($newsletter_data);
|
||||||
|
$updated_newsletter = Newsletter::findOne($this->newsletter->id)
|
||||||
|
->withSendingQueue()
|
||||||
|
->asArray();
|
||||||
|
$updated_queue = $updated_newsletter['queue'];
|
||||||
|
|
||||||
|
expect($response->status)->equals(APIResponse::STATUS_OK);
|
||||||
|
expect(unserialize($updated_queue['newsletter_rendered_body']))->equals(null);
|
||||||
|
expect(unserialize($updated_queue['newsletter_rendered_subject']))->equals(null);
|
||||||
|
}
|
||||||
|
|
||||||
function testItCanUpdatePostNotificationScheduleUponSave() {
|
function testItCanUpdatePostNotificationScheduleUponSave() {
|
||||||
$newsletter_options = array(
|
$newsletter_options = array(
|
||||||
'intervalType',
|
'intervalType',
|
||||||
|
@ -30,7 +30,7 @@ class LinksTest extends \MailPoetTest {
|
|||||||
'html' => '<a href="http://example.com">Example Link</a>',
|
'html' => '<a href="http://example.com">Example Link</a>',
|
||||||
'text' => '<a href="http://example.com">Example Link</a>'
|
'text' => '<a href="http://example.com">Example Link</a>'
|
||||||
);
|
);
|
||||||
$result = Links::hashAndReplaceLinks($rendered_newsletter);
|
$result = Links::hashAndReplaceLinks($rendered_newsletter, 0, 0);
|
||||||
$processed_rendered_newsletter_body = $result[0];
|
$processed_rendered_newsletter_body = $result[0];
|
||||||
$processed_and_hashed_links = $result[1];
|
$processed_and_hashed_links = $result[1];
|
||||||
expect($processed_rendered_newsletter_body['html'])
|
expect($processed_rendered_newsletter_body['html'])
|
||||||
@ -59,4 +59,4 @@ class LinksTest extends \MailPoetTest {
|
|||||||
\ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
\ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
||||||
\ORM::raw_execute('TRUNCATE ' . NewsletterLink::$_table);
|
\ORM::raw_execute('TRUNCATE ' . NewsletterLink::$_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class LinksTest extends \MailPoetTest {
|
|||||||
|
|
||||||
function testItOnlyHashesAndReplacesLinksInAnchorTags() {
|
function testItOnlyHashesAndReplacesLinksInAnchorTags() {
|
||||||
$template = '<a href="http://example.com"><img src="http://example.com" /></a>';
|
$template = '<a href="http://example.com"><img src="http://example.com" /></a>';
|
||||||
$result = Links::process($template);
|
$result = Links::process($template, 0, 0);
|
||||||
expect($result[0])->equals(
|
expect($result[0])->equals(
|
||||||
sprintf(
|
sprintf(
|
||||||
'<a href="%s-%s"><img src="http://example.com" /></a>',
|
'<a href="%s-%s"><img src="http://example.com" /></a>',
|
||||||
@ -34,6 +34,25 @@ class LinksTest extends \MailPoetTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testItDoesNotRehashExistingLinks() {
|
||||||
|
$link = NewsletterLink::create();
|
||||||
|
$link->newsletter_id = 3;
|
||||||
|
$link->queue_id = 3;
|
||||||
|
$link->hash = 123;
|
||||||
|
$link->url = 'http://example.com';
|
||||||
|
$link->save();
|
||||||
|
|
||||||
|
$template = '<a href="http://example.com"><img src="http://example.com" /></a>';
|
||||||
|
$result = Links::process($template, 3, 3);
|
||||||
|
expect($result[0])->equals(
|
||||||
|
sprintf(
|
||||||
|
'<a href="%s-%s"><img src="http://example.com" /></a>',
|
||||||
|
Links::DATA_TAG_CLICK,
|
||||||
|
123
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function testItCanExtactLinkShortcodes() {
|
function testItCanExtactLinkShortcodes() {
|
||||||
$template = '[notlink:shortcode] [link:some_link_shortcode]';
|
$template = '[notlink:shortcode] [link:some_link_shortcode]';
|
||||||
$result = Links::extract($template);
|
$result = Links::extract($template);
|
||||||
@ -48,7 +67,7 @@ class LinksTest extends \MailPoetTest {
|
|||||||
|
|
||||||
function testItHashesAndReplacesLinks() {
|
function testItHashesAndReplacesLinks() {
|
||||||
$template = '<a href="http://example.com">some site</a> [link:some_link_shortcode]';
|
$template = '<a href="http://example.com">some site</a> [link:some_link_shortcode]';
|
||||||
list($updated_content, $hashed_links) = Links::process($template);
|
list($updated_content, $hashed_links) = Links::process($template, 0, 0);
|
||||||
|
|
||||||
// 2 links were hashed
|
// 2 links were hashed
|
||||||
expect(count($hashed_links))->equals(2);
|
expect(count($hashed_links))->equals(2);
|
||||||
@ -63,7 +82,7 @@ class LinksTest extends \MailPoetTest {
|
|||||||
|
|
||||||
function testItHashesAndReplacesLinksWithSpecialCharacters() {
|
function testItHashesAndReplacesLinksWithSpecialCharacters() {
|
||||||
$template = '<a href="http://сайт.cóm/彌撒時間">some site</a>';
|
$template = '<a href="http://сайт.cóm/彌撒時間">some site</a>';
|
||||||
$result = Links::process($template);
|
$result = Links::process($template, 0, 0);
|
||||||
expect($result[0])->equals(
|
expect($result[0])->equals(
|
||||||
sprintf(
|
sprintf(
|
||||||
'<a href="%s-%s">some site</a>',
|
'<a href="%s-%s">some site</a>',
|
||||||
@ -171,6 +190,28 @@ class LinksTest extends \MailPoetTest {
|
|||||||
expect($newsltter_link->url)->equals('http://example.com');
|
expect($newsltter_link->url)->equals('http://example.com');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testItCanLoadLinks() {
|
||||||
|
$link = NewsletterLink::create();
|
||||||
|
$link->newsletter_id = 1;
|
||||||
|
$link->queue_id = 2;
|
||||||
|
$link->hash = 123;
|
||||||
|
$link->url = 'http://example.com';
|
||||||
|
$link->save();
|
||||||
|
|
||||||
|
$link = NewsletterLink::create();
|
||||||
|
$link->newsletter_id = 1;
|
||||||
|
$link->queue_id = 3;
|
||||||
|
$link->hash = 456;
|
||||||
|
$link->url = 'http://demo.com';
|
||||||
|
$link->save();
|
||||||
|
|
||||||
|
$links = Links::load(1, 2);
|
||||||
|
expect(is_array($links))->true();
|
||||||
|
expect(count($links))->equals(1);
|
||||||
|
expect($links['http://example.com']['hash'])->equals(123);
|
||||||
|
expect($links['http://example.com']['url'])->equals('http://example.com');
|
||||||
|
}
|
||||||
|
|
||||||
function testItMatchesHashedLinks() {
|
function testItMatchesHashedLinks() {
|
||||||
$regex = Links::getLinkRegex();
|
$regex = Links::getLinkRegex();
|
||||||
expect((boolean)preg_match($regex, '[some_tag]-123'))->false();
|
expect((boolean)preg_match($regex, '[some_tag]-123'))->false();
|
||||||
|
@ -350,6 +350,7 @@
|
|||||||
'unsavedChangesWillBeLost': __('There are unsaved changes which will be lost if you leave this page.'),
|
'unsavedChangesWillBeLost': __('There are unsaved changes which will be lost if you leave this page.'),
|
||||||
'selectColor': _x('Select', 'select color'),
|
'selectColor': _x('Select', 'select color'),
|
||||||
'cancelColorSelection': _x('Cancel', 'cancel color selection'),
|
'cancelColorSelection': _x('Cancel', 'cancel color selection'),
|
||||||
|
'newsletterIsPaused': __('Email sending has been paused.'),
|
||||||
}) %>
|
}) %>
|
||||||
<% endblock %>
|
<% endblock %>
|
||||||
|
|
||||||
@ -1223,6 +1224,26 @@
|
|||||||
newsletter: response.data,
|
newsletter: response.data,
|
||||||
config: config,
|
config: config,
|
||||||
});
|
});
|
||||||
|
var queue = response.data.queue;
|
||||||
|
if (response.data.status == 'sending' && queue && queue.status === null) {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
api_version: window.mailpoet_api_version,
|
||||||
|
endpoint: 'sending_queue',
|
||||||
|
action: 'pause',
|
||||||
|
data: {
|
||||||
|
newsletter_id: response.data.id
|
||||||
|
}
|
||||||
|
}).done(response =>
|
||||||
|
MailPoet.Notice.success(MailPoet.I18n.t('newsletterIsPaused'))
|
||||||
|
).fail(function(response) {
|
||||||
|
if (response.errors.length > 0) {
|
||||||
|
MailPoet.Notice.error(
|
||||||
|
response.errors.map(function(error) { return error.message; }),
|
||||||
|
{ scroll: true, static: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
if (response.errors.length > 0) {
|
if (response.errors.length > 0) {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
|
@ -231,6 +231,7 @@
|
|||||||
'previous': __('Previous'),
|
'previous': __('Previous'),
|
||||||
'newsletterBeingSent': __('The newsletter is being sent...'),
|
'newsletterBeingSent': __('The newsletter is being sent...'),
|
||||||
'newsletterHasBeenScheduled': __('The newsletter has been scheduled.'),
|
'newsletterHasBeenScheduled': __('The newsletter has been scheduled.'),
|
||||||
|
'newsletterSendingHasBeenResumed': __('The newsletter sending has been resumed.'),
|
||||||
'welcomeEmailActivated': __('Your Welcome Email is now activated!'),
|
'welcomeEmailActivated': __('Your Welcome Email is now activated!'),
|
||||||
'welcomeEmailActivationFailed': __('Your Welcome Email could not be activated, please check the settings.'),
|
'welcomeEmailActivationFailed': __('Your Welcome Email could not be activated, please check the settings.'),
|
||||||
'postNotificationActivated': __('Your post notification is now active!'),
|
'postNotificationActivated': __('Your post notification is now active!'),
|
||||||
@ -256,7 +257,8 @@
|
|||||||
'mailerConnectionErrorNotice': __('Sending is paused because the following connection issue prevents MailPoet from delivering emails: %$1s'),
|
'mailerConnectionErrorNotice': __('Sending is paused because the following connection issue prevents MailPoet from delivering emails: %$1s'),
|
||||||
'mailerCheckSettingsNotice': __('Check your [link]sending method settings[/link].'),
|
'mailerCheckSettingsNotice': __('Check your [link]sending method settings[/link].'),
|
||||||
'mailerResumeSendingButton': __('Resume sending'),
|
'mailerResumeSendingButton': __('Resume sending'),
|
||||||
'mailerSendingResumedNotice': __('Sending has been resumed.')
|
'mailerSendingResumedNotice': __('Sending has been resumed.'),
|
||||||
|
'confirmEdit': __('Sending is in progress. Do you want to pause sending and edit the newsletter?')
|
||||||
}) %>
|
}) %>
|
||||||
<% endblock %>
|
<% endblock %>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user