Merge pull request #709 from mailpoet/sending_restart
Sending retry/pause/restart [MAILPOET-653]
This commit is contained in:
@ -298,7 +298,8 @@ const Listing = React.createClass({
|
||||
filters: {},
|
||||
filter: {},
|
||||
selected_ids: [],
|
||||
selection: false
|
||||
selection: false,
|
||||
meta: {}
|
||||
};
|
||||
},
|
||||
getParam: function(param) {
|
||||
@ -463,15 +464,21 @@ const Listing = React.createClass({
|
||||
items: response.data || [],
|
||||
filters: response.meta.filters || {},
|
||||
groups: response.meta.groups || [],
|
||||
count: response.meta.count || 0
|
||||
count: response.meta.count || 0,
|
||||
meta: _.omit(response.meta, ['filters', 'groups', 'count'])
|
||||
}, () => {
|
||||
// if viewing an empty trash
|
||||
if (this.state.group === 'trash' && response.meta.count === 0) {
|
||||
// redirect to default group
|
||||
this.handleGroup('all');
|
||||
}
|
||||
|
||||
// trigger afterGetItems callback if specified
|
||||
if (this.props.afterGetItems !== undefined) {
|
||||
this.props.afterGetItems(this.state);
|
||||
}
|
||||
});
|
||||
}).fail(function(response) {
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
@ -711,7 +718,7 @@ const Listing = React.createClass({
|
||||
}.bind(this));
|
||||
},
|
||||
handleRenderItem: function(item, actions) {
|
||||
const render = this.props.onRenderItem(item, actions);
|
||||
const render = this.props.onRenderItem(item, actions, this.state.meta);
|
||||
return render.props.children;
|
||||
},
|
||||
handleRefreshItems: function() {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import MailPoet from 'mailpoet'
|
||||
import classNames from 'classnames'
|
||||
import jQuery from 'jquery'
|
||||
@ -42,11 +43,15 @@ const _QueueMixin = {
|
||||
}
|
||||
});
|
||||
},
|
||||
renderQueueStatus: function(newsletter) {
|
||||
renderQueueStatus: function(newsletter, mailer_log) {
|
||||
if (!newsletter.queue) {
|
||||
return (
|
||||
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||
);
|
||||
} else if (mailer_log.status === 'paused') {
|
||||
return (
|
||||
<span>{MailPoet.I18n.t('paused')}</span>
|
||||
)
|
||||
} else {
|
||||
if (newsletter.queue.status === 'scheduled') {
|
||||
return (
|
||||
@ -72,14 +77,8 @@ const _QueueMixin = {
|
||||
<span>
|
||||
{
|
||||
MailPoet.I18n.t('newsletterQueueCompleted')
|
||||
.replace(
|
||||
"%$1d",
|
||||
newsletter.queue.count_processed - newsletter.queue.count_failed
|
||||
)
|
||||
.replace(
|
||||
"%$2d",
|
||||
newsletter.queue.count_total
|
||||
)
|
||||
.replace("%$1d",newsletter.queue.count_processed)
|
||||
.replace("%$2d", newsletter.queue.count_total)
|
||||
}
|
||||
</span>
|
||||
);
|
||||
@ -175,5 +174,66 @@ const _StatisticsMixin = {
|
||||
}
|
||||
}
|
||||
|
||||
const _MailerMixin = {
|
||||
checkMailerStatus: function(state) {
|
||||
if (state.meta.mta_log.error && state.meta.mta_log.status === 'paused') {
|
||||
MailPoet.Notice.error(
|
||||
'',
|
||||
{ static: true, id: 'mailpoet_mailer_error' }
|
||||
);
|
||||
|
||||
ReactDOM.render(
|
||||
this.getMailerError(state),
|
||||
jQuery('[data-id="mailpoet_mailer_error"]')[0]
|
||||
);
|
||||
} else {
|
||||
MailPoet.Notice.hide('mailpoet_mailer_error');
|
||||
}
|
||||
},
|
||||
getMailerError(state) {
|
||||
let mailer_error_notice;
|
||||
if (state.meta.mta_log.error.operation === 'send') {
|
||||
mailer_error_notice =
|
||||
MailPoet.I18n.t('mailerSendErrorNotice')
|
||||
.replace('%$1s', state.meta.mta_method)
|
||||
.replace('%$2s', state.meta.mta_log.error.error_message);
|
||||
} else {
|
||||
mailer_error_notice =
|
||||
MailPoet.I18n.t('mailerConnectionErrorNotice')
|
||||
.replace('%$1s', state.meta.mta_log.error.error_message);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p>{ mailer_error_notice }</p>
|
||||
<p>{ MailPoet.I18n.t('mailerResumeSendingNotice') }</p>
|
||||
<p>
|
||||
<a href="javascript:;"
|
||||
className="button"
|
||||
onClick={ this.resumeMailerSending }
|
||||
>{ MailPoet.I18n.t('mailerResumeSendingButton') }</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
resumeMailerSending() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'mailer',
|
||||
action: 'resumeSending'
|
||||
}).done(function() {
|
||||
MailPoet.Notice.hide('mailpoet_mailer_error');
|
||||
MailPoet.Notice.success(MailPoet.I18n.t('mailerSendingResumedNotice'));
|
||||
window.mailpoet_listing.forceUpdate();
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map(function(error) { return error.message; }),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { _QueueMixin as QueueMixin };
|
||||
export { _StatisticsMixin as StatisticsMixin };
|
||||
export { _StatisticsMixin as StatisticsMixin };
|
||||
export { _MailerMixin as MailerMixin };
|
@ -5,6 +5,8 @@ import { createHashHistory } from 'history'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||
|
||||
import { MailerMixin } from 'newsletters/listings/mixins.jsx'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -16,6 +18,8 @@ import {
|
||||
nthWeekDayValues
|
||||
} from 'newsletters/scheduling/common.jsx'
|
||||
|
||||
const mailpoet_settings = window.mailpoet_settings || {};
|
||||
|
||||
const messages = {
|
||||
onTrash: (response) => {
|
||||
const count = ~~response.meta.count;
|
||||
@ -153,6 +157,7 @@ const newsletter_actions = [
|
||||
];
|
||||
|
||||
const NewsletterListNotification = React.createClass({
|
||||
mixins: [ MailerMixin ],
|
||||
updateStatus: function(e) {
|
||||
// make the event persist so that we can still override the selected value
|
||||
// in the ajax callback
|
||||
@ -328,6 +333,7 @@ const NewsletterListNotification = React.createClass({
|
||||
auto_refresh={ true }
|
||||
sort_by="updated_at"
|
||||
sort_order="desc"
|
||||
afterGetItems={ this.checkMailerStatus }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -7,9 +7,14 @@ import MailPoet from 'mailpoet'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||
|
||||
import { QueueMixin, StatisticsMixin } from 'newsletters/listings/mixins.jsx'
|
||||
import {
|
||||
QueueMixin,
|
||||
StatisticsMixin,
|
||||
MailerMixin
|
||||
} from 'newsletters/listings/mixins.jsx'
|
||||
|
||||
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||
const mailpoet_settings = window.mailpoet_settings || {};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -49,7 +54,7 @@ const newsletter_actions = [
|
||||
];
|
||||
|
||||
const NewsletterListNotificationHistory = React.createClass({
|
||||
mixins: [QueueMixin, StatisticsMixin],
|
||||
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
|
||||
renderItem: function(newsletter, actions) {
|
||||
const rowClasses = classNames(
|
||||
'manage-column',
|
||||
@ -61,6 +66,8 @@ const NewsletterListNotificationHistory = React.createClass({
|
||||
return segment.name
|
||||
}).join(', ');
|
||||
|
||||
const mailer_log = window.mailpoet_settings.mta_log || {};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<td className={ rowClasses }>
|
||||
@ -73,7 +80,7 @@ const NewsletterListNotificationHistory = React.createClass({
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||
{ this.renderQueueStatus(newsletter) }
|
||||
{ this.renderQueueStatus(newsletter, mailpoet_mailer_log) }
|
||||
</td>
|
||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||
{ segments }
|
||||
@ -116,6 +123,7 @@ const NewsletterListNotificationHistory = React.createClass({
|
||||
auto_refresh={ true }
|
||||
sort_by="updated_at"
|
||||
sort_order="desc"
|
||||
afterGetItems={ this.checkMailerStatus }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -7,9 +7,14 @@ import MailPoet from 'mailpoet'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||
|
||||
import { QueueMixin, StatisticsMixin } from 'newsletters/listings/mixins.jsx'
|
||||
import {
|
||||
QueueMixin,
|
||||
StatisticsMixin,
|
||||
MailerMixin
|
||||
} from 'newsletters/listings/mixins.jsx'
|
||||
|
||||
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||
const mailpoet_settings = window.mailpoet_settings || {};
|
||||
|
||||
const messages = {
|
||||
onTrash: (response) => {
|
||||
@ -85,7 +90,6 @@ const columns = [
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
@ -148,8 +152,8 @@ const newsletter_actions = [
|
||||
];
|
||||
|
||||
const NewsletterListStandard = React.createClass({
|
||||
mixins: [QueueMixin, StatisticsMixin],
|
||||
renderItem: function(newsletter, actions) {
|
||||
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
|
||||
renderItem: function(newsletter, actions, meta) {
|
||||
const rowClasses = classNames(
|
||||
'manage-column',
|
||||
'column-primary',
|
||||
@ -172,7 +176,7 @@ const NewsletterListStandard = React.createClass({
|
||||
{ actions }
|
||||
</td>
|
||||
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||
{ this.renderQueueStatus(newsletter) }
|
||||
{ this.renderQueueStatus(newsletter, meta.mta_log) }
|
||||
</td>
|
||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||
{ segments }
|
||||
@ -212,6 +216,7 @@ const NewsletterListStandard = React.createClass({
|
||||
auto_refresh={ true }
|
||||
sort_by="updated_at"
|
||||
sort_order="desc"
|
||||
afterGetItems={ this.checkMailerStatus }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -5,6 +5,8 @@ import { createHashHistory } from 'history'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||
|
||||
import { MailerMixin } from 'newsletters/listings/mixins.jsx'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -13,6 +15,7 @@ import _ from 'underscore'
|
||||
const mailpoet_roles = window.mailpoet_roles || {};
|
||||
const mailpoet_segments = window.mailpoet_segments || {};
|
||||
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||
const mailpoet_settings = window.mailpoet_settings || {};
|
||||
|
||||
const messages = {
|
||||
onTrash: (response) => {
|
||||
@ -151,6 +154,7 @@ const newsletter_actions = [
|
||||
];
|
||||
|
||||
const NewsletterListWelcome = React.createClass({
|
||||
mixins: [ MailerMixin ],
|
||||
updateStatus: function(e) {
|
||||
// make the event persist so that we can still override the selected value
|
||||
// in the ajax callback
|
||||
@ -358,6 +362,7 @@ const NewsletterListWelcome = React.createClass({
|
||||
auto_refresh={ true }
|
||||
sort_by="updated_at"
|
||||
sort_order="desc"
|
||||
afterGetItems={ this.checkMailerStatus }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -27,7 +27,7 @@ const App = React.createClass({
|
||||
const container = document.getElementById('newsletters_container');
|
||||
|
||||
if(container) {
|
||||
ReactDOM.render((
|
||||
const mailpoet_listing = ReactDOM.render((
|
||||
<Router history={ history }>
|
||||
<Route path="/" component={ App }>
|
||||
<IndexRedirect to="standard" />
|
||||
@ -49,4 +49,6 @@ if(container) {
|
||||
</Route>
|
||||
</Router>
|
||||
), container);
|
||||
|
||||
window.mailpoet_listing = mailpoet_listing;
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
MailPoet Notice:
|
||||
|
||||
description: Handles notices
|
||||
version: 0.2
|
||||
version: 1.0
|
||||
author: Jonathan Labreuille
|
||||
company: Wysija
|
||||
dependencies: jQuery
|
||||
|
||||
Usage:
|
||||
|
||||
// success message (static: false)
|
||||
// success message (static: false)
|
||||
MailPoet.Notice.success('Yatta!');
|
||||
|
||||
// error message (static: false)
|
||||
@ -21,199 +21,206 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
// system message (static: true)
|
||||
MailPoet.Notice.system('You need to updated ASAP!');
|
||||
|
||||
Examples:
|
||||
|
||||
MailPoet.Notice.success('- success #1 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.success('- success #2 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.error('- error -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.system('- system -');
|
||||
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.hide();
|
||||
}, 2500);
|
||||
}, 300);
|
||||
}, 400);
|
||||
}, 500);
|
||||
|
||||
==================================================================================================*/
|
||||
|
||||
MailPoet.Notice = {
|
||||
version: 0.2,
|
||||
// default options
|
||||
defaults: {
|
||||
type: 'success',
|
||||
message: '',
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
positionAfter: false,
|
||||
scroll: false,
|
||||
timeout: 5000,
|
||||
onOpen: null,
|
||||
onClose: null
|
||||
},
|
||||
options: {},
|
||||
init: function(options) {
|
||||
// set options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
version: 1.0,
|
||||
// default options
|
||||
defaults: {
|
||||
type: 'success',
|
||||
message: '',
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
positionAfter: false,
|
||||
scroll: false,
|
||||
timeout: 5000,
|
||||
onOpen: null,
|
||||
onClose: null
|
||||
},
|
||||
options: {},
|
||||
init: function(options) {
|
||||
// set options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||
return this;
|
||||
},
|
||||
createNotice: function() {
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||
|
||||
// add data-id to the element
|
||||
if (this.options.id) this.element.attr('data-id', 'notice_' + this.options.id);
|
||||
|
||||
// remove id from clone
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
var positionAfter;
|
||||
if (typeof this.options.positionAfter === 'object') {
|
||||
positionAfter = this.options.positionAfter;
|
||||
} else if (typeof this.options.positionAfter === 'string') {
|
||||
positionAfter = jQuery(this.options.positionAfter);
|
||||
} else {
|
||||
positionAfter = jQuery('#mailpoet_notice_'+this.options.type);
|
||||
}
|
||||
positionAfter.after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
if(this.options.onClose !== null) {
|
||||
onClose = this.options.onClose;
|
||||
}
|
||||
|
||||
// listen to remove event
|
||||
jQuery(this.element).on('close', function() {
|
||||
jQuery(this).fadeOut(200, function() {
|
||||
// on close callback
|
||||
if(onClose !== null) {
|
||||
onClose();
|
||||
}
|
||||
// remove notice
|
||||
jQuery(this).remove();
|
||||
});
|
||||
}.bind(this.element));
|
||||
|
||||
// listen to message event
|
||||
jQuery(this.element).on('message', function(e, message) {
|
||||
MailPoet.Notice.setMessage(message);
|
||||
}.bind(this.element));
|
||||
|
||||
return this;
|
||||
},
|
||||
isHTML: function(str) {
|
||||
var a = document.createElement('div');
|
||||
a.innerHTML = str;
|
||||
for(var c = a.childNodes, i = c.length; i--;) {
|
||||
if(c[i].nodeType == 1) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setMessage: function(message) {
|
||||
// if it's not an html message, let's sugar coat the message with a fancy <p>
|
||||
if(this.isHTML(message) === false) {
|
||||
message = '<p>'+message+'</p>';
|
||||
}
|
||||
// set message
|
||||
return this.element.html(message);
|
||||
},
|
||||
show: function(options) {
|
||||
// initialize
|
||||
this.init(options);
|
||||
|
||||
// show notice
|
||||
this.showNotice();
|
||||
|
||||
// return this;
|
||||
},
|
||||
showNotice: function() {
|
||||
// set message
|
||||
this.setMessage(this.options.message);
|
||||
|
||||
// position notice
|
||||
this.element.insertAfter(jQuery('h2.title'));
|
||||
|
||||
// set class name
|
||||
switch(this.options.type) {
|
||||
case 'success':
|
||||
this.element.addClass('updated');
|
||||
break;
|
||||
case 'system':
|
||||
this.element.addClass('update-nag');
|
||||
break;
|
||||
case 'error':
|
||||
this.element.addClass('error');
|
||||
break;
|
||||
}
|
||||
|
||||
// make the notice appear
|
||||
this.element.fadeIn(200);
|
||||
|
||||
// if scroll option is enabled, scroll to the notice
|
||||
if(this.options.scroll === true) {
|
||||
this.element.get(0).scrollIntoView(false);
|
||||
}
|
||||
|
||||
// if the notice is not static, it has to disappear after a timeout
|
||||
if(this.options.static === false) {
|
||||
this.element.delay(this.options.timeout).trigger('close');
|
||||
} else if (this.options.hideClose === false) {
|
||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||
jQuery(this).trigger('close');
|
||||
});
|
||||
}
|
||||
|
||||
// call onOpen callback
|
||||
if(this.options.onOpen !== null) {
|
||||
this.options.onOpen(this.element);
|
||||
}
|
||||
},
|
||||
hide: function(all) {
|
||||
if(all !== undefined && all === true) {
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
for (var id in all) {
|
||||
jQuery('[data-id="notice_' + all[id] + '"]')
|
||||
.trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
jQuery('[data-id="notice_' + all + '"]')
|
||||
.trigger('close');
|
||||
} else {
|
||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||
.trigger('close');
|
||||
}
|
||||
},
|
||||
error: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'error',
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
success: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'success',
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
system: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'system',
|
||||
static: true,
|
||||
message: '<p>'+this.formatMessage(message)+'</p>'
|
||||
}, options));
|
||||
},
|
||||
formatMessage: function(message) {
|
||||
if(Array.isArray(message)) {
|
||||
return message.join('<br />');
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
// add data-id to the element
|
||||
if (this.options.id) {
|
||||
this.element.attr(
|
||||
'data-id',
|
||||
this.options.id
|
||||
);
|
||||
}
|
||||
|
||||
// remove id from clone
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
var positionAfter;
|
||||
if (typeof this.options.positionAfter === 'object') {
|
||||
positionAfter = this.options.positionAfter;
|
||||
} else if (typeof this.options.positionAfter === 'string') {
|
||||
positionAfter = jQuery(this.options.positionAfter);
|
||||
} else {
|
||||
positionAfter = jQuery('#mailpoet_notice_'+this.options.type);
|
||||
}
|
||||
positionAfter.after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
if (this.options.onClose !== null) {
|
||||
onClose = this.options.onClose;
|
||||
}
|
||||
|
||||
// listen to remove event
|
||||
jQuery(this.element).on('close', function() {
|
||||
jQuery(this).fadeOut(200, function() {
|
||||
// on close callback
|
||||
if (onClose !== null) {
|
||||
onClose();
|
||||
}
|
||||
// remove notice
|
||||
jQuery(this).remove();
|
||||
});
|
||||
}.bind(this.element));
|
||||
|
||||
// listen to message event
|
||||
jQuery(this.element).on('setMessage', function(e, message) {
|
||||
MailPoet.Notice.setMessage(message);
|
||||
}.bind(this.element));
|
||||
|
||||
return this;
|
||||
},
|
||||
updateNotice: function() {
|
||||
// update notice's message
|
||||
jQuery('[data-id="'+this.options.id+'"').first().trigger(
|
||||
'setMessage', this.options.message
|
||||
);
|
||||
},
|
||||
isHTML: function(str) {
|
||||
var a = document.createElement('div');
|
||||
a.innerHTML = str;
|
||||
for (var c = a.childNodes, i = c.length; i--;) {
|
||||
if (c[i].nodeType == 1) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setMessage: function(message) {
|
||||
message = this.formatMessage(message);
|
||||
|
||||
// if it's not an html message
|
||||
// let's sugar coat the message with a fancy <p>
|
||||
if (this.isHTML(message) === false) {
|
||||
message = '<p>'+message+'</p>';
|
||||
}
|
||||
// set message
|
||||
return this.element.html(message);
|
||||
},
|
||||
formatMessage: function(message) {
|
||||
if (Array.isArray(message)) {
|
||||
return message.join('<br />');
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
},
|
||||
show: function(options) {
|
||||
// initialize
|
||||
this.init(options);
|
||||
|
||||
if (
|
||||
this.options.id !== null
|
||||
&&
|
||||
jQuery('[data-id="'+this.options.id+'"').length > 0
|
||||
) {
|
||||
this.updateNotice();
|
||||
} else {
|
||||
this.createNotice();
|
||||
}
|
||||
this.showNotice();
|
||||
},
|
||||
showNotice: function() {
|
||||
// set message
|
||||
this.setMessage(this.options.message);
|
||||
|
||||
// position notice
|
||||
this.element.insertAfter(jQuery('h2.title'));
|
||||
|
||||
// set class name
|
||||
switch (this.options.type) {
|
||||
case 'success':
|
||||
this.element.addClass('updated');
|
||||
break;
|
||||
case 'system':
|
||||
this.element.addClass('update-nag');
|
||||
break;
|
||||
case 'error':
|
||||
this.element.addClass('error');
|
||||
break;
|
||||
}
|
||||
|
||||
// make the notice appear
|
||||
this.element.fadeIn(200);
|
||||
|
||||
// if scroll option is enabled, scroll to the notice
|
||||
if (this.options.scroll === true) {
|
||||
this.element.get(0).scrollIntoView(false);
|
||||
}
|
||||
|
||||
// if the notice is not static, it has to disappear after a timeout
|
||||
if (this.options.static === false) {
|
||||
this.element.delay(this.options.timeout).trigger('close');
|
||||
} else if (this.options.hideClose === false) {
|
||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||
jQuery(this).trigger('close');
|
||||
});
|
||||
}
|
||||
|
||||
// call onOpen callback
|
||||
if (this.options.onOpen !== null) {
|
||||
this.options.onOpen(this.element);
|
||||
}
|
||||
},
|
||||
hide: function(all) {
|
||||
if (all !== undefined && all === true) {
|
||||
// all notices
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
// array of ids
|
||||
for (var id in all) {
|
||||
jQuery('[data-id="' + all[id] + '"]').trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
// single id
|
||||
jQuery('[data-id="' + all + '"]').trigger('close');
|
||||
} else {
|
||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||
.trigger('close');
|
||||
}
|
||||
},
|
||||
error: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'error',
|
||||
message: message
|
||||
}, options));
|
||||
},
|
||||
success: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'success',
|
||||
message: message
|
||||
}, options));
|
||||
},
|
||||
system: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'system',
|
||||
static: true,
|
||||
message: message
|
||||
}, options));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace MailPoet\API\Endpoints;
|
||||
use MailPoet\API\Endpoint as APIEndpoint;
|
||||
use MailPoet\API\Error as APIError;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -20,12 +21,19 @@ class Mailer extends APIEndpoint {
|
||||
));
|
||||
}
|
||||
|
||||
if($result === false) {
|
||||
return $this->errorResponse(array(
|
||||
APIError::BAD_REQUEST => __("The email could not be sent. Please check your settings.", 'mailpoet')
|
||||
));
|
||||
if($result['response'] === false) {
|
||||
$error = sprintf(
|
||||
__('The email could not be sent: %s', 'mailpoet'),
|
||||
$result['error']
|
||||
);
|
||||
return $this->errorResponse(array(APIError::BAD_REQUEST => $error));
|
||||
} else {
|
||||
return $this->successResponse(null);
|
||||
}
|
||||
}
|
||||
|
||||
function resumeSending() {
|
||||
MailerLog::resumeSending();
|
||||
return $this->successResponse(null);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace MailPoet\API\Endpoints;
|
||||
use MailPoet\API\Endpoint as APIEndpoint;
|
||||
use MailPoet\API\Error as APIError;
|
||||
use MailPoet\Listing;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterTemplate;
|
||||
use MailPoet\Models\NewsletterSegment;
|
||||
@ -275,10 +276,19 @@ class Newsletters extends APIEndpoint {
|
||||
$sender = false,
|
||||
$reply_to = false
|
||||
);
|
||||
$mailer->send($newsletter, $data['subscriber']);
|
||||
return $this->successResponse(
|
||||
Newsletter::findOne($id)->asArray()
|
||||
);
|
||||
$result = $mailer->send($newsletter, $data['subscriber']);
|
||||
|
||||
if($result['response'] === false) {
|
||||
$error = sprintf(
|
||||
__('The email could not be sent: %s', 'mailpoet'),
|
||||
$result['error']
|
||||
);
|
||||
return $this->errorResponse(array(APIError::BAD_REQUEST => $error));
|
||||
} else {
|
||||
return $this->successResponse(
|
||||
Newsletter::findOne($id)->asArray()
|
||||
);
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
return $this->errorResponse(array(
|
||||
$e->getCode() => $e->getMessage()
|
||||
@ -337,7 +347,9 @@ class Newsletters extends APIEndpoint {
|
||||
return $this->successResponse($data, array(
|
||||
'count' => $listing_data['count'],
|
||||
'filters' => $listing_data['filters'],
|
||||
'groups' => $listing_data['groups']
|
||||
'groups' => $listing_data['groups'],
|
||||
'mta_log' => Setting::getValue('mta_log'),
|
||||
'mta_method' => Setting::getValue('mta.method')
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,6 @@ class Migrator {
|
||||
'count_total mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
||||
'scheduled_at TIMESTAMP NULL,',
|
||||
'processed_at TIMESTAMP NULL,',
|
||||
'created_at TIMESTAMP NULL,',
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Cron\CronTrigger;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
use \MailPoet\Models\Segment;
|
||||
use \MailPoet\Segments\WP;
|
||||
use \MailPoet\Models\Setting;
|
||||
@ -85,26 +86,26 @@ class Populator {
|
||||
private function createDefaultSettings() {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
// set cron trigger option to default method
|
||||
if(!Setting::getValue(CronTrigger::SETTING_NAME)) {
|
||||
// disable task scheduler (cron) be default
|
||||
Setting::setValue(CronTrigger::SETTING_NAME, array(
|
||||
'method' => CronTrigger::DEFAULT_METHOD
|
||||
));
|
||||
}
|
||||
|
||||
// default sender info based on current user
|
||||
// set default sender info based on current user
|
||||
$sender = array(
|
||||
'name' => $current_user->display_name,
|
||||
'address' => $current_user->user_email
|
||||
);
|
||||
|
||||
// set default from name & address
|
||||
if(!Setting::getValue('sender')) {
|
||||
// default from name & address
|
||||
Setting::setValue('sender', $sender);
|
||||
}
|
||||
|
||||
// enable signup confirmation by default
|
||||
if(!Setting::getValue('signup_confirmation')) {
|
||||
// enable signup confirmation by default
|
||||
Setting::setValue('signup_confirmation', array(
|
||||
'enabled' => true,
|
||||
'from' => array(
|
||||
@ -115,9 +116,13 @@ class Populator {
|
||||
));
|
||||
}
|
||||
|
||||
// set installation date
|
||||
if(!Setting::getValue('installed_at')) {
|
||||
Setting::setValue('installed_at', date("Y-m-d H:i:s"));
|
||||
}
|
||||
|
||||
// reset mailer log
|
||||
MailerLog::resetMailerLog();
|
||||
}
|
||||
|
||||
private function createDefaultSegments() {
|
||||
|
@ -9,9 +9,9 @@ use MailPoet\Util\Security;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class CronHelper {
|
||||
const DAEMON_EXECUTION_LIMIT = 20;
|
||||
const DAEMON_EXECUTION_TIMEOUT = 35;
|
||||
const DAEMON_REQUEST_TIMEOUT = 2;
|
||||
const DAEMON_EXECUTION_LIMIT = 20; // seconds
|
||||
const DAEMON_EXECUTION_TIMEOUT = 35; // seconds
|
||||
const DAEMON_REQUEST_TIMEOUT = 2; // seconds
|
||||
const DAEMON_SETTING = 'cron_daemon';
|
||||
|
||||
static function createDaemon($token) {
|
||||
|
@ -10,7 +10,7 @@ class Daemon {
|
||||
public $daemon;
|
||||
public $request_data;
|
||||
public $timer;
|
||||
const REQUEST_TIMEOUT = 5;
|
||||
const REQUEST_TIMEOUT = 5; // seconds
|
||||
|
||||
function __construct($request_data = false) {
|
||||
$this->request_data = $request_data;
|
||||
|
@ -21,8 +21,10 @@ class SendingQueue {
|
||||
$this->mailer_task = ($mailer_task) ? $mailer_task : new MailerTask();
|
||||
$this->newsletter_task = ($newsletter_task) ? $newsletter_task : new NewsletterTask();
|
||||
$this->timer = ($timer) ? $timer : microtime(true);
|
||||
// abort if execution or sending limit are reached
|
||||
// abort if execution limit is reached
|
||||
CronHelper::enforceExecutionLimit($this->timer);
|
||||
// abort if mailing is paused or sending limit has been reached
|
||||
MailerLog::enforceExecutionRequirements();
|
||||
}
|
||||
|
||||
function process() {
|
||||
@ -70,8 +72,8 @@ class SendingQueue {
|
||||
if($queue->status === SendingQueueModel::STATUS_COMPLETED) {
|
||||
$this->newsletter_task->markNewsletterAsSent($newsletter);
|
||||
}
|
||||
// abort if sending limit is reached
|
||||
MailerLog::enforceSendingLimit();
|
||||
// abort if sending limit has been reached
|
||||
MailerLog::enforceExecutionRequirements();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,8 +120,8 @@ class SendingQueue {
|
||||
$prepared_subscribers_ids = array();
|
||||
$statistics = array();
|
||||
}
|
||||
// abort if sending limit is reached
|
||||
MailerLog::enforceSendingLimit();
|
||||
// abort if sending limit has been reached
|
||||
MailerLog::enforceExecutionRequirements();
|
||||
}
|
||||
if($processing_method === 'bulk') {
|
||||
$queue = $this->sendNewsletters(
|
||||
@ -142,20 +144,22 @@ class SendingQueue {
|
||||
$prepared_newsletters,
|
||||
$prepared_subscribers
|
||||
);
|
||||
if(!$send_result) {
|
||||
// update failed/to process list
|
||||
$queue->updateFailedSubscribers($prepared_subscribers_ids);
|
||||
} else {
|
||||
// update processed/to process list
|
||||
$queue->updateProcessedSubscribers($prepared_subscribers_ids);
|
||||
// log statistics
|
||||
StatisticsNewslettersModel::createMultiple($statistics);
|
||||
// update the sent count
|
||||
$this->mailer_task->updateSentCount();
|
||||
// enforce sending limit if there are still subscribers left to process
|
||||
if($queue->count_to_process) {
|
||||
MailerLog::enforceSendingLimit();
|
||||
}
|
||||
// log error message and schedule retry/pause sending
|
||||
if($send_result['response'] === false) {
|
||||
MailerLog::processSendingError(
|
||||
$send_result['operation'],
|
||||
$send_result['error_message']
|
||||
);
|
||||
}
|
||||
// update processed/to process list
|
||||
$queue->updateProcessedSubscribers($prepared_subscribers_ids);
|
||||
// log statistics
|
||||
StatisticsNewslettersModel::createMultiple($statistics);
|
||||
// update the sent count
|
||||
$this->mailer_task->updateSentCount();
|
||||
// abort if sending limit has been reached
|
||||
if($queue->count_to_process) {
|
||||
MailerLog::enforceExecutionRequirements();
|
||||
}
|
||||
return $queue;
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ class Mailer {
|
||||
const MAILER_CONFIG_SETTING_NAME = 'mta';
|
||||
const SENDING_LIMIT_INTERVAL_MULTIPLIER = 60;
|
||||
const METHOD_MAILPOET = 'MailPoet';
|
||||
const METHOD_MAILGUN = 'MailGun';
|
||||
const METHOD_ELASTICEMAIL = 'ElasticEmail';
|
||||
const METHOD_AMAZONSES = 'AmazonSES';
|
||||
const METHOD_SENDGRID = 'SendGrid';
|
||||
const METHOD_PHPMAIL = 'PHPMail';
|
||||
@ -44,21 +42,6 @@ class Mailer {
|
||||
$this->reply_to
|
||||
);
|
||||
break;
|
||||
case self::METHOD_ELASTICEMAIL:
|
||||
$mailer_instance = new $this->mailer_config['class'](
|
||||
$this->mailer_config['api_key'],
|
||||
$this->sender,
|
||||
$this->reply_to
|
||||
);
|
||||
break;
|
||||
case self::METHOD_MAILGUN:
|
||||
$mailer_instance = new $this->mailer_config['class'](
|
||||
$this->mailer_config['domain'],
|
||||
$this->mailer_config['api_key'],
|
||||
$this->sender,
|
||||
$this->reply_to
|
||||
);
|
||||
break;
|
||||
case self::METHOD_MAILPOET:
|
||||
$mailer_instance = new $this->mailer_config['class'](
|
||||
$this->mailer_config['mailpoet_api_key'],
|
||||
@ -168,7 +151,29 @@ class Mailer {
|
||||
|
||||
function encodeAddressNamePart($name) {
|
||||
if(mb_detect_encoding($name) === 'ASCII') return $name;
|
||||
// bse64_encode non-ASCII string as per RFC 2047 (https://www.ietf.org/rfc/rfc2047.txt)
|
||||
// encode non-ASCII string as per RFC 2047 (https://www.ietf.org/rfc/rfc2047.txt)
|
||||
return sprintf('=?utf-8?B?%s?=', base64_encode($name));
|
||||
}
|
||||
|
||||
static function formatMailerConnectionErrorResult($error_message) {
|
||||
return array(
|
||||
'response' => false,
|
||||
'operation' => 'connect',
|
||||
'error_message' => $error_message
|
||||
);
|
||||
}
|
||||
|
||||
static function formatMailerSendErrorResult($error_message) {
|
||||
return array(
|
||||
'response' => false,
|
||||
'operation' => 'send',
|
||||
'error_message' => $error_message
|
||||
);
|
||||
}
|
||||
|
||||
static function formatMailerSendSuccessResult() {
|
||||
return array(
|
||||
'response' => true
|
||||
);
|
||||
}
|
||||
}
|
@ -7,8 +7,12 @@ if(!defined('ABSPATH')) exit;
|
||||
|
||||
class MailerLog {
|
||||
const SETTING_NAME = 'mta_log';
|
||||
const STATUS_PAUSED = 'paused';
|
||||
const RETRY_ATTEMPTS_LIMIT = 3;
|
||||
const RETRY_INTERVAL = 120; // seconds
|
||||
|
||||
static function getMailerLog() {
|
||||
static function getMailerLog($mailer_log = false) {
|
||||
if($mailer_log) return $mailer_log;
|
||||
$mailer_log = Setting::getValue(self::SETTING_NAME);
|
||||
if(!$mailer_log) {
|
||||
$mailer_log = self::createMailerLog();
|
||||
@ -18,8 +22,12 @@ class MailerLog {
|
||||
|
||||
static function createMailerLog() {
|
||||
$mailer_log = array(
|
||||
'sent' => 0,
|
||||
'started' => time()
|
||||
'sent' => null,
|
||||
'started' => time(),
|
||||
'status' => null,
|
||||
'retry_attempt' => null,
|
||||
'retry_at' => null,
|
||||
'error' => null
|
||||
);
|
||||
Setting::setValue(self::SETTING_NAME, $mailer_log);
|
||||
return $mailer_log;
|
||||
@ -34,15 +42,73 @@ class MailerLog {
|
||||
return $mailer_log;
|
||||
}
|
||||
|
||||
static function enforceExecutionRequirements($mailer_log = false) {
|
||||
$mailer_log = self::getMailerLog($mailer_log);
|
||||
if($mailer_log['retry_attempt'] === self::RETRY_ATTEMPTS_LIMIT) {
|
||||
$mailer_log = self::pauseSending($mailer_log);
|
||||
}
|
||||
if($mailer_log['status'] === self::STATUS_PAUSED) {
|
||||
throw new \Exception(__('Sending has been paused.', 'mailpoet'));
|
||||
}
|
||||
if(!is_null($mailer_log['retry_at'])) {
|
||||
if(time() <= $mailer_log['retry_at']) {
|
||||
throw new \Exception(__('Sending is waiting to be retried.', 'mailpoet'));
|
||||
} else {
|
||||
$mailer_log['retry_at'] = null;
|
||||
self::updateMailerLog($mailer_log);
|
||||
}
|
||||
}
|
||||
// ensure that sending frequency has not been reached
|
||||
if(self::isSendingLimitReached($mailer_log)) {
|
||||
throw new \Exception(__('Sending frequency limit has been reached.', 'mailpoet'));
|
||||
}
|
||||
}
|
||||
|
||||
static function pauseSending($mailer_log) {
|
||||
$mailer_log['status'] = self::STATUS_PAUSED;
|
||||
$mailer_log['retry_attempt'] = null;
|
||||
$mailer_log['retry_at'] = null;
|
||||
return self::updateMailerLog($mailer_log);
|
||||
}
|
||||
|
||||
static function resumeSending() {
|
||||
return self::resetMailerLog();
|
||||
}
|
||||
|
||||
static function processSendingError($operation, $error_message) {
|
||||
$mailer_log = self::getMailerLog();
|
||||
(int)$mailer_log['retry_attempt']++;
|
||||
$mailer_log['retry_at'] = time() + self::RETRY_INTERVAL;
|
||||
$mailer_log['error'] = array(
|
||||
'operation' => $operation,
|
||||
'error_message' => $error_message
|
||||
);
|
||||
self::updateMailerLog($mailer_log);
|
||||
return self::enforceExecutionRequirements();
|
||||
}
|
||||
|
||||
static function incrementSentCount() {
|
||||
$mailer_log = self::getMailerLog();
|
||||
// clear previous retry count, errors, etc.
|
||||
if($mailer_log['error']) {
|
||||
$mailer_log = self::clearSendingErrorLog($mailer_log);
|
||||
}
|
||||
(int)$mailer_log['sent']++;
|
||||
return self::updateMailerLog($mailer_log);
|
||||
}
|
||||
|
||||
static function isSendingLimitReached() {
|
||||
static function clearSendingErrorLog($mailer_log) {
|
||||
$mailer_log['retry_attempt'] = null;
|
||||
$mailer_log['retry_at'] = null;
|
||||
$mailer_log['error'] = null;
|
||||
return self::updateMailerLog($mailer_log);
|
||||
}
|
||||
|
||||
static function isSendingLimitReached($mailer_log = false) {
|
||||
$mailer_config = Mailer::getMailerConfig();
|
||||
$mailer_log = self::getMailerLog();
|
||||
// do not enforce sending limit for MailPoet's sending method
|
||||
if($mailer_config['method'] === Mailer::METHOD_MAILPOET) return false;
|
||||
$mailer_log = self::getMailerLog($mailer_log);
|
||||
$elapsed_time = time() - (int)$mailer_log['started'];
|
||||
if($mailer_log['sent'] === $mailer_config['frequency_limit']) {
|
||||
if($elapsed_time <= $mailer_config['frequency_interval']) return true;
|
||||
@ -51,10 +117,4 @@ class MailerLog {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function enforceSendingLimit() {
|
||||
if(self::isSendingLimitReached()) {
|
||||
throw new \Exception(__('Sending frequency limit has been reached.', 'mailpoet'));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class AmazonSES {
|
||||
@ -48,10 +50,17 @@ class AmazonSES {
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
if(is_wp_error($result)) {
|
||||
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||
}
|
||||
if(wp_remote_retrieve_response_code($result) !== 200) {
|
||||
$response = simplexml_load_string(wp_remote_retrieve_body($result));
|
||||
$response = ($response) ?
|
||||
$response->Error->Message->__toString() :
|
||||
sprintf(__('%s has returned an unknown error.', 'mailpoet'), Mailer::METHOD_AMAZONSES);
|
||||
return Mailer::formatMailerSendErrorResult($response);
|
||||
}
|
||||
return Mailer::formatMailerSendSuccessResult();
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class ElasticEmail {
|
||||
public $url = 'https://api.elasticemail.com/mailer/send';
|
||||
public $api_key;
|
||||
public $sender;
|
||||
public $reply_to;
|
||||
|
||||
function __construct($api_key, $sender, $reply_to) {
|
||||
$this->api_key = $api_key;
|
||||
$this->sender = $sender;
|
||||
$this->reply_to = $reply_to;
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$result = wp_remote_post(
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber));
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
!preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $result['body']) === false
|
||||
);
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'api_key' => $this->api_key,
|
||||
'to' => $subscriber,
|
||||
'from' => $this->sender['from_email'],
|
||||
'from_name' => $this->sender['from_name'],
|
||||
'reply_to' => $this->reply_to['reply_to_email'],
|
||||
'reply_to_name' => $this->reply_to['reply_to_name'],
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['body_html'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['body_text'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
$body = $this->getBody($newsletter, $subscriber);
|
||||
return array(
|
||||
'timeout' => 10,
|
||||
'httpversion' => '1.0',
|
||||
'method' => 'POST',
|
||||
'body' => urldecode(http_build_query($body))
|
||||
);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class MailGun {
|
||||
public $url;
|
||||
public $api_key;
|
||||
public $sender;
|
||||
public $reply_to;
|
||||
|
||||
function __construct($domain, $api_key, $sender, $reply_to) {
|
||||
$this->url = sprintf('https://api.mailgun.net/v3/%s/messages', $domain);
|
||||
$this->api_key = $api_key;
|
||||
$this->sender = $sender;
|
||||
$this->reply_to = $reply_to;
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$result = wp_remote_post(
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'to' => $subscriber,
|
||||
'from' => $this->sender['from_name_email'],
|
||||
'h:Reply-To' => $this->reply_to['reply_to_name_email'],
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['html'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['text'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function auth() {
|
||||
return 'Basic ' . base64_encode('api:' . $this->api_key);
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
$body = $this->getBody($newsletter, $subscriber);
|
||||
return array(
|
||||
'timeout' => 10,
|
||||
'httpversion' => '1.0',
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Authorization' => $this->auth()
|
||||
),
|
||||
'body' => urldecode(http_build_query($body))
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class MailPoet {
|
||||
@ -21,10 +23,16 @@ class MailPoet {
|
||||
$this->url,
|
||||
$this->request($message_body)
|
||||
);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 201
|
||||
);
|
||||
if(is_wp_error($result)) {
|
||||
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||
}
|
||||
if(wp_remote_retrieve_response_code($result) !== 201) {
|
||||
$response = (wp_remote_retrieve_body($result)) ?
|
||||
wp_remote_retrieve_body($result) :
|
||||
wp_remote_retrieve_response_message($result);
|
||||
return Mailer::formatMailerSendErrorResult($response);
|
||||
}
|
||||
return Mailer::formatMailerSendSuccessResult();
|
||||
}
|
||||
|
||||
function processSubscriber($subscriber) {
|
||||
@ -41,7 +49,7 @@ class MailPoet {
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$composeBody = function ($newsletter, $subscriber) {
|
||||
$composeBody = function($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'to' => (array(
|
||||
'address' => $subscriber['email'],
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class PHPMail {
|
||||
@ -19,9 +21,13 @@ class PHPMail {
|
||||
$message = $this->createMessage($newsletter, $subscriber);
|
||||
$result = $this->mailer->send($message);
|
||||
} catch(\Exception $e) {
|
||||
$result = false;
|
||||
return Mailer::formatMailerSendErrorResult($e->getMessage());
|
||||
}
|
||||
return ($result === 1);
|
||||
return ($result === 1) ?
|
||||
Mailer::formatMailerSendSuccessResult() :
|
||||
Mailer::formatMailerSendErrorResult(
|
||||
sprintf(__('%s has returned an unknown error.', 'mailpoet'), Mailer::METHOD_PHPMAIL)
|
||||
);
|
||||
}
|
||||
|
||||
function buildMailer() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SMTP {
|
||||
@ -33,9 +35,13 @@ class SMTP {
|
||||
$message = $this->createMessage($newsletter, $subscriber);
|
||||
$result = $this->mailer->send($message);
|
||||
} catch(\Exception $e) {
|
||||
$result = false;
|
||||
return Mailer::formatMailerSendErrorResult($e->getMessage());
|
||||
}
|
||||
return ($result === 1);
|
||||
return ($result === 1) ?
|
||||
Mailer::formatMailerSendSuccessResult() :
|
||||
Mailer::formatMailerSendErrorResult(
|
||||
sprintf(__('%s has returned an unknown error.', 'mailpoet'), Mailer::METHOD_SMTP)
|
||||
);
|
||||
}
|
||||
|
||||
function buildMailer() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendGrid {
|
||||
@ -20,13 +22,17 @@ class SendGrid {
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
$result_body = json_decode($result['body'], true);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
!preg_match('!invalid!', $result['body']) === true &&
|
||||
!isset($result_body['errors']) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
if(is_wp_error($result)) {
|
||||
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||
}
|
||||
if(wp_remote_retrieve_response_code($result) !== 200) {
|
||||
$response = json_decode($result['body'], true);
|
||||
$response = (!empty($response['errors'])) ?
|
||||
$response['errors'] :
|
||||
sprintf(__('%s has returned an unknown error.', 'mailpoet'), Mailer::METHOD_SENDGRID);
|
||||
return Mailer::formatMailerSendErrorResult($response);
|
||||
}
|
||||
return Mailer::formatMailerSendSuccessResult();
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
|
@ -67,9 +67,6 @@ class SendingQueue extends Model {
|
||||
if(empty($subscribers['processed'])) {
|
||||
$subscribers['processed'] = array();
|
||||
}
|
||||
if(empty($subscribers['failed'])) {
|
||||
$subscribers['failed'] = array();
|
||||
}
|
||||
return $subscribers;
|
||||
}
|
||||
|
||||
@ -104,22 +101,6 @@ class SendingQueue extends Model {
|
||||
$this->updateCount();
|
||||
}
|
||||
|
||||
function updateFailedSubscribers($failed_subscribers) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscribers['failed'] = array_merge(
|
||||
$subscribers['failed'],
|
||||
$failed_subscribers
|
||||
);
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
$failed_subscribers
|
||||
)
|
||||
);
|
||||
$this->subscribers = $subscribers;
|
||||
$this->updateCount();
|
||||
}
|
||||
|
||||
function updateProcessedSubscribers($processed_subscribers) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscribers['processed'] = array_merge(
|
||||
@ -138,10 +119,8 @@ class SendingQueue extends Model {
|
||||
|
||||
function updateCount() {
|
||||
$this->subscribers = $this->getSubscribers();
|
||||
$this->count_processed =
|
||||
count($this->subscribers['processed']) + count($this->subscribers['failed']);
|
||||
$this->count_processed = count($this->subscribers['processed']);
|
||||
$this->count_to_process = count($this->subscribers['to_process']);
|
||||
$this->count_failed = count($this->subscribers['failed']);
|
||||
$this->count_total = $this->count_processed + $this->count_to_process;
|
||||
if(!$this->count_to_process) {
|
||||
$this->processed_at = current_time('mysql');
|
||||
|
21
tests/unit/API/Endpoints/MailerTest.php
Normal file
21
tests/unit/API/Endpoints/MailerTest.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\API\Endpoints\Mailer;
|
||||
use MailPoet\API\Response as APIResponse;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
|
||||
class MailerEndpointTest extends MailPoetTest {
|
||||
function testItResumesSending() {
|
||||
// create mailer log with a "paused" status
|
||||
$mailer_log = array('status' => MailerLog::STATUS_PAUSED);
|
||||
MailerLog::updateMailerLog($mailer_log);
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->equals(MailerLog::STATUS_PAUSED);
|
||||
// resumeSending() method should clear the mailer log's status
|
||||
$mailer_endpoint = new Mailer();
|
||||
$response = $mailer_endpoint->resumeSending();
|
||||
expect($response->status)->equals(APIResponse::STATUS_OK);
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->null();
|
||||
}
|
||||
}
|
@ -37,8 +37,7 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$this->queue->subscribers = serialize(
|
||||
array(
|
||||
'to_process' => array($this->subscriber->id),
|
||||
'processed' => array(),
|
||||
'failed' => array()
|
||||
'processed' => array()
|
||||
)
|
||||
);
|
||||
$this->queue->count_total = 1;
|
||||
@ -118,18 +117,16 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$updated_queue = SendingQueue::findOne($this->queue->id);
|
||||
expect($updated_queue->status)->equals(SendingQueue::STATUS_COMPLETED);
|
||||
|
||||
// queue subscriber processed/failed/to process count is updated
|
||||
// queue subscriber processed/to process count is updated
|
||||
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||
expect($updated_queue->subscribers)->equals(
|
||||
array(
|
||||
'to_process' => array(),
|
||||
'failed' => array(),
|
||||
'processed' => array($this->subscriber->id)
|
||||
)
|
||||
);
|
||||
expect($updated_queue->count_total)->equals(1);
|
||||
expect($updated_queue->count_processed)->equals(1);
|
||||
expect($updated_queue->count_failed)->equals(0);
|
||||
expect($updated_queue->count_to_process)->equals(0);
|
||||
|
||||
// statistics entry should be created
|
||||
@ -166,18 +163,16 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$updated_queue = SendingQueue::findOne($this->queue->id);
|
||||
expect($updated_queue->status)->equals(SendingQueue::STATUS_COMPLETED);
|
||||
|
||||
// queue subscriber processed/failed/to process count is updated
|
||||
// queue subscriber processed/to process count is updated
|
||||
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||
expect($updated_queue->subscribers)->equals(
|
||||
array(
|
||||
'to_process' => array(),
|
||||
'failed' => array(),
|
||||
'processed' => array($this->subscriber->id)
|
||||
)
|
||||
);
|
||||
expect($updated_queue->count_total)->equals(1);
|
||||
expect($updated_queue->count_processed)->equals(1);
|
||||
expect($updated_queue->count_failed)->equals(0);
|
||||
expect($updated_queue->count_to_process)->equals(0);
|
||||
|
||||
// statistics entry should be created
|
||||
@ -196,8 +191,7 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$this->subscriber->id(),
|
||||
123
|
||||
),
|
||||
'processed' => array(),
|
||||
'failed' => array()
|
||||
'processed' => array()
|
||||
)
|
||||
);
|
||||
$queue->count_total = 2;
|
||||
@ -210,18 +204,16 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$sending_queue_worker->process();
|
||||
|
||||
$updated_queue = SendingQueue::findOne($queue->id);
|
||||
// queue subscriber processed/failed/to process count is updated
|
||||
// queue subscriber processed/to process count is updated
|
||||
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||
expect($updated_queue->subscribers)->equals(
|
||||
array(
|
||||
'to_process' => array(),
|
||||
'failed' => array(),
|
||||
'processed' => array($this->subscriber->id)
|
||||
)
|
||||
);
|
||||
expect($updated_queue->count_total)->equals(1);
|
||||
expect($updated_queue->count_processed)->equals(1);
|
||||
expect($updated_queue->count_failed)->equals(0);
|
||||
expect($updated_queue->count_to_process)->equals(0);
|
||||
|
||||
// statistics entry should be created only for 1 subscriber
|
||||
@ -237,8 +229,7 @@ class SendingQueueTest extends MailPoetTest {
|
||||
123,
|
||||
456
|
||||
),
|
||||
'processed' => array(),
|
||||
'failed' => array()
|
||||
'processed' => array()
|
||||
)
|
||||
);
|
||||
$queue->count_total = 2;
|
||||
@ -251,54 +242,19 @@ class SendingQueueTest extends MailPoetTest {
|
||||
$sending_queue_worker->process();
|
||||
|
||||
$updated_queue = SendingQueue::findOne($queue->id);
|
||||
// queue subscriber processed/failed/to process count is updated
|
||||
// queue subscriber processed/to process count is updated
|
||||
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||
expect($updated_queue->subscribers)->equals(
|
||||
array(
|
||||
'to_process' => array(),
|
||||
'failed' => array(),
|
||||
'processed' => array()
|
||||
)
|
||||
);
|
||||
expect($updated_queue->count_total)->equals(0);
|
||||
expect($updated_queue->count_processed)->equals(0);
|
||||
expect($updated_queue->count_failed)->equals(0);
|
||||
expect($updated_queue->count_to_process)->equals(0);
|
||||
}
|
||||
|
||||
function testItUpdatesFailedListWhenSendingFailed() {
|
||||
$sending_queue_worker = new SendingQueueWorker(
|
||||
$timer = false,
|
||||
Stub::make(
|
||||
new MailerTask(),
|
||||
array('send' => Stub::exactly(1, function($newsletter, $subscriber) { return false; }))
|
||||
)
|
||||
);
|
||||
$sending_queue_worker->process();
|
||||
|
||||
// queue subscriber processed/failed/to process count is updated
|
||||
$updated_queue = SendingQueue::findOne($this->queue->id);
|
||||
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||
expect($updated_queue->subscribers)->equals(
|
||||
array(
|
||||
'to_process' => array(),
|
||||
'failed' => array($this->subscriber->id),
|
||||
'processed' => array()
|
||||
)
|
||||
);
|
||||
expect($updated_queue->count_total)->equals(1);
|
||||
expect($updated_queue->count_processed)->equals(1);
|
||||
expect($updated_queue->count_failed)->equals(1);
|
||||
expect($updated_queue->count_to_process)->equals(0);
|
||||
|
||||
// statistics entry should not be created
|
||||
$statistics = StatisticsNewsletters::where('newsletter_id', $this->newsletter->id)
|
||||
->where('subscriber_id', $this->subscriber->id)
|
||||
->where('queue_id', $this->queue->id)
|
||||
->findOne();
|
||||
expect($statistics)->false();
|
||||
}
|
||||
|
||||
function testItDoesNotSendToTrashedSubscribers() {
|
||||
$sending_queue_worker = $this->sending_queue_worker;
|
||||
$sending_queue_worker->mailer_task = Stub::make(
|
||||
|
@ -51,8 +51,7 @@ class MailerTaskTest extends MailPoetTest {
|
||||
|
||||
function testItGetsMailerLog() {
|
||||
$mailer_log = $this->mailer_task->getMailerLog();
|
||||
expect(isset($mailer_log['sent']))->true();
|
||||
expect(isset($mailer_log['started']))->true();
|
||||
expect(is_array($mailer_log))->true();
|
||||
}
|
||||
|
||||
function testItUpdatesMailerLogSentCount() {
|
||||
|
@ -51,7 +51,8 @@ class MailerLogTest extends MailPoetTest {
|
||||
function testItIncrementsSentCount() {
|
||||
$mailer_log = array(
|
||||
'sent' => 1,
|
||||
'started' => time()
|
||||
'started' => time(),
|
||||
'error' => null
|
||||
);
|
||||
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
||||
MailerLog::incrementSentCount();
|
||||
@ -107,29 +108,126 @@ class MailerLogTest extends MailPoetTest {
|
||||
expect($updated_mailer_log['sent'])->equals(0);
|
||||
}
|
||||
|
||||
function testItCanEnforceSendingLimit() {
|
||||
function testItResumesSending() {
|
||||
// set status to "paused"
|
||||
$mailer_log = array('status' => MailerLog::STATUS_PAUSED);
|
||||
MailerLog::updateMailerLog($mailer_log);
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->equals(MailerLog::STATUS_PAUSED);
|
||||
// status is reset when sending is resumed
|
||||
MailerLog::resumeSending();
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->null();
|
||||
}
|
||||
|
||||
function testItPausesSending() {
|
||||
$mailer_log = array(
|
||||
'status' => null,
|
||||
'retry_attempt' => MailerLog::RETRY_ATTEMPTS_LIMIT,
|
||||
'retry_at' => time() + 20
|
||||
);
|
||||
// status is set to PAUSED, retry attempt and retry at time are cleared
|
||||
MailerLog::pauseSending($mailer_log);
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->equals(MailerLog::STATUS_PAUSED);
|
||||
expect($mailer_log['retry_attempt'])->null();
|
||||
expect($mailer_log['retry_at'])->null();
|
||||
}
|
||||
|
||||
function itProcessesSendingError() {
|
||||
// retry-related mailer values should be null
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['retry_attempt'])->null();
|
||||
expect($mailer_log['retry_at'])->null();
|
||||
expect($mailer_log['error'])->null();
|
||||
// retry attempt should be incremented, error logged, retry attempt scheduled
|
||||
MailerLog::processSendingError($operation = 'send', $error = 'email rejected');
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['retry_attempt'])->equals(1);
|
||||
expect($mailer_log['retry_at'])->greaterThan(time());
|
||||
expect($mailer_log['error'])->equals(
|
||||
array(
|
||||
'operation' => 'send',
|
||||
'error_message' => 'email rejected'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItEnforcesSendingLimit() {
|
||||
$mailer_config = array(
|
||||
'frequency' => array(
|
||||
'emails' => 2,
|
||||
'interval' => 1
|
||||
)
|
||||
);
|
||||
$mailer_log = array(
|
||||
'sent' => 2,
|
||||
'started' => time()
|
||||
);
|
||||
$mailer_log = MailerLog::createMailerLog();
|
||||
$mailer_log['sent'] = 2;
|
||||
$mailer_log['started'] = time();
|
||||
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
||||
Setting::setValue(Mailer::MAILER_CONFIG_SETTING_NAME, $mailer_config);
|
||||
|
||||
// exception is thrown when sending limit is reached
|
||||
try {
|
||||
MailerLog::enforceSendingLimit();
|
||||
MailerLog::enforceExecutionRequirements();
|
||||
self::fail('Sending frequency exception was not thrown.');
|
||||
} catch(\Exception $e) {
|
||||
expect($e->getMessage())->equals('Sending frequency limit has been reached.');
|
||||
}
|
||||
}
|
||||
|
||||
function testItEnforcesRetryAtTime() {
|
||||
$mailer_log = MailerLog::createMailerLog();
|
||||
$mailer_log['retry_at'] = time() + 10;
|
||||
// exception is thrown when current time is sooner than 120 seconds
|
||||
try {
|
||||
MailerLog::enforceExecutionRequirements($mailer_log);
|
||||
self::fail('Sending waiting to be retried exception was not thrown.');
|
||||
} catch(\Exception $e) {
|
||||
expect($e->getMessage())->equals('Sending is waiting to be retried.');
|
||||
}
|
||||
}
|
||||
|
||||
function testItEnforcesRetryAttempts() {
|
||||
$mailer_log = MailerLog::createMailerLog();
|
||||
$mailer_log['retry_attempt'] = 2;
|
||||
// allow less than 3 attempts
|
||||
expect(MailerLog::enforceExecutionRequirements($mailer_log))->null();
|
||||
// pase sending and throw exception when more than 3 attempts
|
||||
$mailer_log['retry_attempt'] = MailerLog::RETRY_ATTEMPTS_LIMIT;
|
||||
try {
|
||||
MailerLog::enforceExecutionRequirements($mailer_log);
|
||||
self::fail('Sending paused exception was not thrown.');
|
||||
} catch(\Exception $e) {
|
||||
expect($e->getMessage())->equals('Sending has been paused.');
|
||||
}
|
||||
$mailer_log = MailerLog::getMailerLog();
|
||||
expect($mailer_log['status'])->equals(MailerLog::STATUS_PAUSED);
|
||||
}
|
||||
|
||||
function testItClearsSendingErrorLog() {
|
||||
$mailer_log = MailerLog::createMailerLog();
|
||||
$mailer_log['retry_attempt'] = 1;
|
||||
$mailer_log['retry_at'] = 1;
|
||||
$mailer_log['error'] = 1;
|
||||
$mailer_log['status'] = 'status';
|
||||
$mailer_log = MailerLog::clearSendingErrorLog($mailer_log);
|
||||
expect($mailer_log['retry_attempt'])->null();
|
||||
expect($mailer_log['retry_at'])->null();
|
||||
expect($mailer_log['error'])->null();
|
||||
expect($mailer_log['status'])->equals('status');
|
||||
}
|
||||
|
||||
function testItEnforcesPuasedStatus() {
|
||||
$mailer_log = MailerLog::createMailerLog();
|
||||
$mailer_log['status'] = MailerLog::STATUS_PAUSED;
|
||||
try {
|
||||
MailerLog::enforceExecutionRequirements($mailer_log);
|
||||
self::fail('Sending paused exception was not thrown.');
|
||||
} catch(\Exception $e) {
|
||||
expect($e->getMessage())->equals('Sending has been paused.');
|
||||
}
|
||||
}
|
||||
|
||||
function _after() {
|
||||
ORM::raw_execute('TRUNCATE ' . Setting::$_table);
|
||||
}
|
||||
|
@ -11,15 +11,6 @@ class MailerTest extends MailPoetTest {
|
||||
'access_key' => '1234567890',
|
||||
'secret_key' => 'abcdefghijk',
|
||||
),
|
||||
array(
|
||||
'method' => 'ElasticEmail',
|
||||
'api_key' => 'abcdefghijk'
|
||||
),
|
||||
array(
|
||||
'method' => 'MailGun',
|
||||
'domain' => 'example.com',
|
||||
'api_key' => 'abcdefghijk'
|
||||
),
|
||||
array(
|
||||
'method' => 'MailPoet',
|
||||
'mailpoet_api_key' => 'abcdefghijk'
|
||||
|
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\Mailer\Methods\ElasticEmail;
|
||||
|
||||
class ElasticEmailTest extends MailPoetTest {
|
||||
function _before() {
|
||||
$this->settings = array(
|
||||
'method' => 'ElasticEmail',
|
||||
'api_key' => getenv('WP_TEST_MAILER_ELASTICEMAIL_API') ?
|
||||
getenv('WP_TEST_MAILER_ELASTICEMAIL_API') :
|
||||
'1234567890'
|
||||
);
|
||||
$this->sender = array(
|
||||
'from_name' => 'Sender',
|
||||
'from_email' => 'staff@mailpoet.com',
|
||||
'from_name_email' => 'Sender <staff@mailpoet.com>'
|
||||
);
|
||||
$this->reply_to = array(
|
||||
'reply_to_name' => 'Reply To',
|
||||
'reply_to_email' => 'reply-to@mailpoet.com',
|
||||
'reply_to_name_email' => 'Reply To <reply-to@mailpoet.com>'
|
||||
);
|
||||
$this->mailer = new ElasticEmail(
|
||||
$this->settings['api_key'],
|
||||
$this->sender,
|
||||
$this->reply_to
|
||||
);
|
||||
$this->subscriber = 'Recipient <mailpoet-phoenix-test@mailinator.com>';
|
||||
$this->newsletter = array(
|
||||
'subject' => 'testing ElasticEmail',
|
||||
'body' => array(
|
||||
'html' => 'HTML body',
|
||||
'text' => 'TEXT body'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItCanGenerateBody() {
|
||||
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
|
||||
expect($body['api_key'])->equals($this->settings['api_key']);
|
||||
expect($body['from'])->equals($this->sender['from_email']);
|
||||
expect($body['from_name'])->equals($this->sender['from_name']);
|
||||
expect($body['reply_to'])->equals($this->reply_to['reply_to_email']);
|
||||
expect($body['reply_to_name'])->equals($this->reply_to['reply_to_name']);
|
||||
expect($body['to'])->contains($this->subscriber);
|
||||
expect($body['subject'])->equals($this->newsletter['subject']);
|
||||
expect($body['body_html'])->equals($this->newsletter['body']['html']);
|
||||
expect($body['body_text'])->equals($this->newsletter['body']['text']);
|
||||
}
|
||||
|
||||
function testItCanCreateRequest() {
|
||||
$request = $this->mailer->request($this->newsletter, $this->subscriber);
|
||||
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
|
||||
expect($request['timeout'])->equals(10);
|
||||
expect($request['httpversion'])->equals('1.0');
|
||||
expect($request['method'])->equals('POST');
|
||||
expect($request['body'])->equals(urldecode(http_build_query($body)));
|
||||
}
|
||||
|
||||
function testItCannotSendWithoutProperApiKey() {
|
||||
if(getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') return;
|
||||
$this->mailer->api_key = 'someapi';
|
||||
$result = $this->mailer->send(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->false();
|
||||
}
|
||||
|
||||
function testItCanSend() {
|
||||
if(getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') return;
|
||||
$result = $this->mailer->send(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->true();
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\Mailer\Methods\MailGun;
|
||||
|
||||
class MailGunTest extends MailPoetTest {
|
||||
function _before() {
|
||||
$this->settings = array(
|
||||
'method' => 'MailGun',
|
||||
'api_key' => getenv('WP_TEST_MAILER_MAILGUN_API') ?
|
||||
getenv('WP_TEST_MAILER_MAILGUN_API') :
|
||||
'1234567890',
|
||||
'domain' => getenv('WP_TEST_MAILER_MAILGUN_DOMAIN') ?
|
||||
getenv('WP_TEST_MAILER_MAILGUN_DOMAIN') :
|
||||
'example.com'
|
||||
);
|
||||
$this->sender = array(
|
||||
'from_name' => 'Sender',
|
||||
'from_email' => 'staff@mailpoet.com',
|
||||
'from_name_email' => 'Sender <staff@mailpoet.com>'
|
||||
);
|
||||
$this->reply_to = array(
|
||||
'reply_to_name' => 'Reply To',
|
||||
'reply_to_email' => 'reply-to@mailpoet.com',
|
||||
'reply_to_name_email' => 'Reply To <reply-to@mailpoet.com>'
|
||||
);
|
||||
$this->mailer = new MailGun(
|
||||
$this->settings['domain'],
|
||||
$this->settings['api_key'],
|
||||
$this->sender,
|
||||
$this->reply_to
|
||||
);
|
||||
$this->subscriber = 'Recipient <mailpoet-phoenix-test@mailinator.com>';
|
||||
$this->newsletter = array(
|
||||
'subject' => 'testing MailGun',
|
||||
'body' => array(
|
||||
'html' => 'HTML body',
|
||||
'text' => 'TEXT body'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItCanGenerateBody() {
|
||||
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
|
||||
expect($body['from'])->equals($this->sender['from_name_email']);
|
||||
expect($body['h:Reply-To'])->equals($this->reply_to['reply_to_name_email']);
|
||||
expect($body['to'])->equals($this->subscriber);
|
||||
expect($body['subject'])->equals($this->newsletter['subject']);
|
||||
expect($body['html'])->equals($this->newsletter['body']['html']);
|
||||
expect($body['text'])->equals($this->newsletter['body']['text']);
|
||||
}
|
||||
|
||||
function testItCanDoBasicAuth() {
|
||||
expect($this->mailer->auth())
|
||||
->equals('Basic ' . base64_encode('api:' . $this->settings['api_key']));
|
||||
}
|
||||
|
||||
function testItCanCreateRequest() {
|
||||
$request = $this->mailer->request($this->newsletter, $this->subscriber);
|
||||
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
|
||||
expect($request['timeout'])->equals(10);
|
||||
expect($request['httpversion'])->equals('1.0');
|
||||
expect($request['method'])->equals('POST');
|
||||
expect($request['headers']['Content-Type'])
|
||||
->equals('application/x-www-form-urlencoded');
|
||||
expect($request['headers']['Authorization'])
|
||||
->equals('Basic ' . base64_encode('api:' . $this->settings['api_key']));
|
||||
expect($request['body'])->equals(urldecode(http_build_query($body)));
|
||||
}
|
||||
|
||||
function testItCannotSendWithoutProperApiKey() {
|
||||
if(getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') return;
|
||||
$this->mailer->api_key = 'someapi';
|
||||
$result = $this->mailer->send(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->false();
|
||||
}
|
||||
|
||||
function testItCannotSendWithoutProperDomain() {
|
||||
if(getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') return;
|
||||
$this->mailer->url =
|
||||
str_replace($this->settings['domain'], 'somedomain', $this->mailer->url);
|
||||
$result = $this->mailer->send(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->false();
|
||||
}
|
||||
|
||||
function testItCanSend() {
|
||||
if(getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') return;
|
||||
$result = $this->mailer->send(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
expect($result)->true();
|
||||
}
|
||||
}
|
@ -85,6 +85,7 @@
|
||||
'sentToXSubscribers': __('Sent to %$1d subscribers'),
|
||||
'resume': __('Resume'),
|
||||
'pause': __('Pause'),
|
||||
'paused': __('Paused'),
|
||||
'new': __('Add New'),
|
||||
|
||||
'templateFileMalformedError': __('This template file appears to be damaged. Please try another one.'),
|
||||
@ -232,6 +233,12 @@
|
||||
|
||||
'backToPostNotifications': __('Back to Post notifications'),
|
||||
'sentOn': __('Sent on'),
|
||||
'noSubscribers': __('No subscribers!')
|
||||
'noSubscribers': __('No subscribers!'),
|
||||
|
||||
'mailerSendErrorNotice': __("We've detected an issue with the %$1s sending method that prevents us from delivering the remaining emails: %$2s"),
|
||||
'mailerConnectionErrorNotice': __("We've detected a connection issue that prevents us from delivering the remaining emails: %$1s"),
|
||||
'mailerResumeSendingNotice': __('As a result, all sending has been paused. Please resolve the issue before continuing.'),
|
||||
'mailerResumeSendingButton': __('Resume sending'),
|
||||
'mailerSendingResumedNotice': __("Sending has been resumed.")
|
||||
}) %>
|
||||
<% endblock %>
|
||||
<% endblock %>
|
Reference in New Issue
Block a user