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: {},
|
filters: {},
|
||||||
filter: {},
|
filter: {},
|
||||||
selected_ids: [],
|
selected_ids: [],
|
||||||
selection: false
|
selection: false,
|
||||||
|
meta: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getParam: function(param) {
|
getParam: function(param) {
|
||||||
@@ -463,15 +464,21 @@ const Listing = React.createClass({
|
|||||||
items: response.data || [],
|
items: response.data || [],
|
||||||
filters: response.meta.filters || {},
|
filters: response.meta.filters || {},
|
||||||
groups: response.meta.groups || [],
|
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 viewing an empty trash
|
||||||
if (this.state.group === 'trash' && response.meta.count === 0) {
|
if (this.state.group === 'trash' && response.meta.count === 0) {
|
||||||
// redirect to default group
|
// redirect to default group
|
||||||
this.handleGroup('all');
|
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) {
|
if (response.errors.length > 0) {
|
||||||
MailPoet.Notice.error(
|
MailPoet.Notice.error(
|
||||||
response.errors.map(function(error) { return error.message; }),
|
response.errors.map(function(error) { return error.message; }),
|
||||||
@@ -711,7 +718,7 @@ const Listing = React.createClass({
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
handleRenderItem: function(item, actions) {
|
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;
|
return render.props.children;
|
||||||
},
|
},
|
||||||
handleRefreshItems: function() {
|
handleRefreshItems: function() {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
import MailPoet from 'mailpoet'
|
import MailPoet from 'mailpoet'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
@@ -42,11 +43,15 @@ const _QueueMixin = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
renderQueueStatus: function(newsletter) {
|
renderQueueStatus: function(newsletter, mailer_log) {
|
||||||
if (!newsletter.queue) {
|
if (!newsletter.queue) {
|
||||||
return (
|
return (
|
||||||
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||||
);
|
);
|
||||||
|
} else if (mailer_log.status === 'paused') {
|
||||||
|
return (
|
||||||
|
<span>{MailPoet.I18n.t('paused')}</span>
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (newsletter.queue.status === 'scheduled') {
|
if (newsletter.queue.status === 'scheduled') {
|
||||||
return (
|
return (
|
||||||
@@ -72,14 +77,8 @@ const _QueueMixin = {
|
|||||||
<span>
|
<span>
|
||||||
{
|
{
|
||||||
MailPoet.I18n.t('newsletterQueueCompleted')
|
MailPoet.I18n.t('newsletterQueueCompleted')
|
||||||
.replace(
|
.replace("%$1d",newsletter.queue.count_processed)
|
||||||
"%$1d",
|
.replace("%$2d", newsletter.queue.count_total)
|
||||||
newsletter.queue.count_processed - newsletter.queue.count_failed
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
"%$2d",
|
|
||||||
newsletter.queue.count_total
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</span>
|
</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 { _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 Listing from 'listing/listing.jsx'
|
||||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||||
|
|
||||||
|
import { MailerMixin } from 'newsletters/listings/mixins.jsx'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
import MailPoet from 'mailpoet'
|
import MailPoet from 'mailpoet'
|
||||||
@@ -16,6 +18,8 @@ import {
|
|||||||
nthWeekDayValues
|
nthWeekDayValues
|
||||||
} from 'newsletters/scheduling/common.jsx'
|
} from 'newsletters/scheduling/common.jsx'
|
||||||
|
|
||||||
|
const mailpoet_settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash: (response) => {
|
onTrash: (response) => {
|
||||||
const count = ~~response.meta.count;
|
const count = ~~response.meta.count;
|
||||||
@@ -153,6 +157,7 @@ const newsletter_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const NewsletterListNotification = React.createClass({
|
const NewsletterListNotification = React.createClass({
|
||||||
|
mixins: [ MailerMixin ],
|
||||||
updateStatus: function(e) {
|
updateStatus: function(e) {
|
||||||
// make the event persist so that we can still override the selected value
|
// make the event persist so that we can still override the selected value
|
||||||
// in the ajax callback
|
// in the ajax callback
|
||||||
@@ -328,6 +333,7 @@ const NewsletterListNotification = React.createClass({
|
|||||||
auto_refresh={ true }
|
auto_refresh={ true }
|
||||||
sort_by="updated_at"
|
sort_by="updated_at"
|
||||||
sort_order="desc"
|
sort_order="desc"
|
||||||
|
afterGetItems={ this.checkMailerStatus }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -7,9 +7,14 @@ import MailPoet from 'mailpoet'
|
|||||||
import Listing from 'listing/listing.jsx'
|
import Listing from 'listing/listing.jsx'
|
||||||
import ListingTabs from 'newsletters/listings/tabs.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_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||||
|
const mailpoet_settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -49,7 +54,7 @@ const newsletter_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const NewsletterListNotificationHistory = React.createClass({
|
const NewsletterListNotificationHistory = React.createClass({
|
||||||
mixins: [QueueMixin, StatisticsMixin],
|
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
|
||||||
renderItem: function(newsletter, actions) {
|
renderItem: function(newsletter, actions) {
|
||||||
const rowClasses = classNames(
|
const rowClasses = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
@@ -61,6 +66,8 @@ const NewsletterListNotificationHistory = React.createClass({
|
|||||||
return segment.name
|
return segment.name
|
||||||
}).join(', ');
|
}).join(', ');
|
||||||
|
|
||||||
|
const mailer_log = window.mailpoet_settings.mta_log || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<td className={ rowClasses }>
|
<td className={ rowClasses }>
|
||||||
@@ -73,7 +80,7 @@ const NewsletterListNotificationHistory = React.createClass({
|
|||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||||
{ this.renderQueueStatus(newsletter) }
|
{ this.renderQueueStatus(newsletter, mailpoet_mailer_log) }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||||
{ segments }
|
{ segments }
|
||||||
@@ -116,6 +123,7 @@ const NewsletterListNotificationHistory = React.createClass({
|
|||||||
auto_refresh={ true }
|
auto_refresh={ true }
|
||||||
sort_by="updated_at"
|
sort_by="updated_at"
|
||||||
sort_order="desc"
|
sort_order="desc"
|
||||||
|
afterGetItems={ this.checkMailerStatus }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -7,9 +7,14 @@ import MailPoet from 'mailpoet'
|
|||||||
import Listing from 'listing/listing.jsx'
|
import Listing from 'listing/listing.jsx'
|
||||||
import ListingTabs from 'newsletters/listings/tabs.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_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||||
|
const mailpoet_settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash: (response) => {
|
onTrash: (response) => {
|
||||||
@@ -85,7 +90,6 @@ const columns = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const bulk_actions = [
|
const bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'trash',
|
name: 'trash',
|
||||||
@@ -148,8 +152,8 @@ const newsletter_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const NewsletterListStandard = React.createClass({
|
const NewsletterListStandard = React.createClass({
|
||||||
mixins: [QueueMixin, StatisticsMixin],
|
mixins: [ QueueMixin, StatisticsMixin, MailerMixin ],
|
||||||
renderItem: function(newsletter, actions) {
|
renderItem: function(newsletter, actions, meta) {
|
||||||
const rowClasses = classNames(
|
const rowClasses = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
'column-primary',
|
'column-primary',
|
||||||
@@ -172,7 +176,7 @@ const NewsletterListStandard = React.createClass({
|
|||||||
{ actions }
|
{ actions }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||||
{ this.renderQueueStatus(newsletter) }
|
{ this.renderQueueStatus(newsletter, meta.mta_log) }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||||
{ segments }
|
{ segments }
|
||||||
@@ -212,6 +216,7 @@ const NewsletterListStandard = React.createClass({
|
|||||||
auto_refresh={ true }
|
auto_refresh={ true }
|
||||||
sort_by="updated_at"
|
sort_by="updated_at"
|
||||||
sort_order="desc"
|
sort_order="desc"
|
||||||
|
afterGetItems={ this.checkMailerStatus }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -5,6 +5,8 @@ import { createHashHistory } from 'history'
|
|||||||
import Listing from 'listing/listing.jsx'
|
import Listing from 'listing/listing.jsx'
|
||||||
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
import ListingTabs from 'newsletters/listings/tabs.jsx'
|
||||||
|
|
||||||
|
import { MailerMixin } from 'newsletters/listings/mixins.jsx'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
import MailPoet from 'mailpoet'
|
import MailPoet from 'mailpoet'
|
||||||
@@ -13,6 +15,7 @@ import _ from 'underscore'
|
|||||||
const mailpoet_roles = window.mailpoet_roles || {};
|
const mailpoet_roles = window.mailpoet_roles || {};
|
||||||
const mailpoet_segments = window.mailpoet_segments || {};
|
const mailpoet_segments = window.mailpoet_segments || {};
|
||||||
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||||
|
const mailpoet_settings = window.mailpoet_settings || {};
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash: (response) => {
|
onTrash: (response) => {
|
||||||
@@ -151,6 +154,7 @@ const newsletter_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const NewsletterListWelcome = React.createClass({
|
const NewsletterListWelcome = React.createClass({
|
||||||
|
mixins: [ MailerMixin ],
|
||||||
updateStatus: function(e) {
|
updateStatus: function(e) {
|
||||||
// make the event persist so that we can still override the selected value
|
// make the event persist so that we can still override the selected value
|
||||||
// in the ajax callback
|
// in the ajax callback
|
||||||
@@ -358,6 +362,7 @@ const NewsletterListWelcome = React.createClass({
|
|||||||
auto_refresh={ true }
|
auto_refresh={ true }
|
||||||
sort_by="updated_at"
|
sort_by="updated_at"
|
||||||
sort_order="desc"
|
sort_order="desc"
|
||||||
|
afterGetItems={ this.checkMailerStatus }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -27,7 +27,7 @@ const App = React.createClass({
|
|||||||
const container = document.getElementById('newsletters_container');
|
const container = document.getElementById('newsletters_container');
|
||||||
|
|
||||||
if(container) {
|
if(container) {
|
||||||
ReactDOM.render((
|
const mailpoet_listing = ReactDOM.render((
|
||||||
<Router history={ history }>
|
<Router history={ history }>
|
||||||
<Route path="/" component={ App }>
|
<Route path="/" component={ App }>
|
||||||
<IndexRedirect to="standard" />
|
<IndexRedirect to="standard" />
|
||||||
@@ -49,4 +49,6 @@ if(container) {
|
|||||||
</Route>
|
</Route>
|
||||||
</Router>
|
</Router>
|
||||||
), container);
|
), container);
|
||||||
|
|
||||||
|
window.mailpoet_listing = mailpoet_listing;
|
||||||
}
|
}
|
||||||
|
@@ -5,14 +5,14 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
MailPoet Notice:
|
MailPoet Notice:
|
||||||
|
|
||||||
description: Handles notices
|
description: Handles notices
|
||||||
version: 0.2
|
version: 1.0
|
||||||
author: Jonathan Labreuille
|
author: Jonathan Labreuille
|
||||||
company: Wysija
|
company: Wysija
|
||||||
dependencies: jQuery
|
dependencies: jQuery
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
// success message (static: false)
|
// success message (static: false)
|
||||||
MailPoet.Notice.success('Yatta!');
|
MailPoet.Notice.success('Yatta!');
|
||||||
|
|
||||||
// error message (static: false)
|
// error message (static: false)
|
||||||
@@ -21,199 +21,206 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
// system message (static: true)
|
// system message (static: true)
|
||||||
MailPoet.Notice.system('You need to updated ASAP!');
|
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 = {
|
MailPoet.Notice = {
|
||||||
version: 0.2,
|
version: 1.0,
|
||||||
// default options
|
// default options
|
||||||
defaults: {
|
defaults: {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: '',
|
message: '',
|
||||||
static: false,
|
static: false,
|
||||||
hideClose: false,
|
hideClose: false,
|
||||||
id: null,
|
id: null,
|
||||||
positionAfter: false,
|
positionAfter: false,
|
||||||
scroll: false,
|
scroll: false,
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
onOpen: null,
|
onOpen: null,
|
||||||
onClose: null
|
onClose: null
|
||||||
},
|
},
|
||||||
options: {},
|
options: {},
|
||||||
init: function(options) {
|
init: function(options) {
|
||||||
// set options
|
// set options
|
||||||
this.options = jQuery.extend({}, this.defaults, options);
|
this.options = jQuery.extend({}, this.defaults, options);
|
||||||
|
|
||||||
// clone element
|
return this;
|
||||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
},
|
||||||
|
createNotice: function() {
|
||||||
|
// clone element
|
||||||
|
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||||
|
|
||||||
// add data-id to the element
|
// add data-id to the element
|
||||||
if (this.options.id) this.element.attr('data-id', 'notice_' + this.options.id);
|
if (this.options.id) {
|
||||||
|
this.element.attr(
|
||||||
// remove id from clone
|
'data-id',
|
||||||
this.element.removeAttr('id');
|
this.options.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
namespace MailPoet\API\Endpoints;
|
||||||
use MailPoet\API\Endpoint as APIEndpoint;
|
use MailPoet\API\Endpoint as APIEndpoint;
|
||||||
use MailPoet\API\Error as APIError;
|
use MailPoet\API\Error as APIError;
|
||||||
|
use MailPoet\Mailer\MailerLog;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@@ -20,12 +21,19 @@ class Mailer extends APIEndpoint {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if($result === false) {
|
if($result['response'] === false) {
|
||||||
return $this->errorResponse(array(
|
$error = sprintf(
|
||||||
APIError::BAD_REQUEST => __("The email could not be sent. Please check your settings.", 'mailpoet')
|
__('The email could not be sent: %s', 'mailpoet'),
|
||||||
));
|
$result['error']
|
||||||
|
);
|
||||||
|
return $this->errorResponse(array(APIError::BAD_REQUEST => $error));
|
||||||
} else {
|
} else {
|
||||||
return $this->successResponse(null);
|
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\Endpoint as APIEndpoint;
|
||||||
use MailPoet\API\Error as APIError;
|
use MailPoet\API\Error as APIError;
|
||||||
use MailPoet\Listing;
|
use MailPoet\Listing;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
use MailPoet\Models\Newsletter;
|
use MailPoet\Models\Newsletter;
|
||||||
use MailPoet\Models\NewsletterTemplate;
|
use MailPoet\Models\NewsletterTemplate;
|
||||||
use MailPoet\Models\NewsletterSegment;
|
use MailPoet\Models\NewsletterSegment;
|
||||||
@@ -275,10 +276,19 @@ class Newsletters extends APIEndpoint {
|
|||||||
$sender = false,
|
$sender = false,
|
||||||
$reply_to = false
|
$reply_to = false
|
||||||
);
|
);
|
||||||
$mailer->send($newsletter, $data['subscriber']);
|
$result = $mailer->send($newsletter, $data['subscriber']);
|
||||||
return $this->successResponse(
|
|
||||||
Newsletter::findOne($id)->asArray()
|
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) {
|
} catch(\Exception $e) {
|
||||||
return $this->errorResponse(array(
|
return $this->errorResponse(array(
|
||||||
$e->getCode() => $e->getMessage()
|
$e->getCode() => $e->getMessage()
|
||||||
@@ -337,7 +347,9 @@ class Newsletters extends APIEndpoint {
|
|||||||
return $this->successResponse($data, array(
|
return $this->successResponse($data, array(
|
||||||
'count' => $listing_data['count'],
|
'count' => $listing_data['count'],
|
||||||
'filters' => $listing_data['filters'],
|
'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_total mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
'count_to_process 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,',
|
'scheduled_at TIMESTAMP NULL,',
|
||||||
'processed_at TIMESTAMP NULL,',
|
'processed_at TIMESTAMP NULL,',
|
||||||
'created_at TIMESTAMP NULL,',
|
'created_at TIMESTAMP NULL,',
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
use MailPoet\Cron\CronTrigger;
|
use MailPoet\Cron\CronTrigger;
|
||||||
|
use MailPoet\Mailer\MailerLog;
|
||||||
use \MailPoet\Models\Segment;
|
use \MailPoet\Models\Segment;
|
||||||
use \MailPoet\Segments\WP;
|
use \MailPoet\Segments\WP;
|
||||||
use \MailPoet\Models\Setting;
|
use \MailPoet\Models\Setting;
|
||||||
@@ -85,26 +86,26 @@ class Populator {
|
|||||||
private function createDefaultSettings() {
|
private function createDefaultSettings() {
|
||||||
$current_user = wp_get_current_user();
|
$current_user = wp_get_current_user();
|
||||||
|
|
||||||
|
// set cron trigger option to default method
|
||||||
if(!Setting::getValue(CronTrigger::SETTING_NAME)) {
|
if(!Setting::getValue(CronTrigger::SETTING_NAME)) {
|
||||||
// disable task scheduler (cron) be default
|
|
||||||
Setting::setValue(CronTrigger::SETTING_NAME, array(
|
Setting::setValue(CronTrigger::SETTING_NAME, array(
|
||||||
'method' => CronTrigger::DEFAULT_METHOD
|
'method' => CronTrigger::DEFAULT_METHOD
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default sender info based on current user
|
// set default sender info based on current user
|
||||||
$sender = array(
|
$sender = array(
|
||||||
'name' => $current_user->display_name,
|
'name' => $current_user->display_name,
|
||||||
'address' => $current_user->user_email
|
'address' => $current_user->user_email
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// set default from name & address
|
||||||
if(!Setting::getValue('sender')) {
|
if(!Setting::getValue('sender')) {
|
||||||
// default from name & address
|
|
||||||
Setting::setValue('sender', $sender);
|
Setting::setValue('sender', $sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable signup confirmation by default
|
||||||
if(!Setting::getValue('signup_confirmation')) {
|
if(!Setting::getValue('signup_confirmation')) {
|
||||||
// enable signup confirmation by default
|
|
||||||
Setting::setValue('signup_confirmation', array(
|
Setting::setValue('signup_confirmation', array(
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'from' => array(
|
'from' => array(
|
||||||
@@ -115,9 +116,13 @@ class Populator {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set installation date
|
||||||
if(!Setting::getValue('installed_at')) {
|
if(!Setting::getValue('installed_at')) {
|
||||||
Setting::setValue('installed_at', date("Y-m-d H:i:s"));
|
Setting::setValue('installed_at', date("Y-m-d H:i:s"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset mailer log
|
||||||
|
MailerLog::resetMailerLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createDefaultSegments() {
|
private function createDefaultSegments() {
|
||||||
|
@@ -9,9 +9,9 @@ use MailPoet\Util\Security;
|
|||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class CronHelper {
|
class CronHelper {
|
||||||
const DAEMON_EXECUTION_LIMIT = 20;
|
const DAEMON_EXECUTION_LIMIT = 20; // seconds
|
||||||
const DAEMON_EXECUTION_TIMEOUT = 35;
|
const DAEMON_EXECUTION_TIMEOUT = 35; // seconds
|
||||||
const DAEMON_REQUEST_TIMEOUT = 2;
|
const DAEMON_REQUEST_TIMEOUT = 2; // seconds
|
||||||
const DAEMON_SETTING = 'cron_daemon';
|
const DAEMON_SETTING = 'cron_daemon';
|
||||||
|
|
||||||
static function createDaemon($token) {
|
static function createDaemon($token) {
|
||||||
|
@@ -10,7 +10,7 @@ class Daemon {
|
|||||||
public $daemon;
|
public $daemon;
|
||||||
public $request_data;
|
public $request_data;
|
||||||
public $timer;
|
public $timer;
|
||||||
const REQUEST_TIMEOUT = 5;
|
const REQUEST_TIMEOUT = 5; // seconds
|
||||||
|
|
||||||
function __construct($request_data = false) {
|
function __construct($request_data = false) {
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
|
@@ -21,8 +21,10 @@ class SendingQueue {
|
|||||||
$this->mailer_task = ($mailer_task) ? $mailer_task : new MailerTask();
|
$this->mailer_task = ($mailer_task) ? $mailer_task : new MailerTask();
|
||||||
$this->newsletter_task = ($newsletter_task) ? $newsletter_task : new NewsletterTask();
|
$this->newsletter_task = ($newsletter_task) ? $newsletter_task : new NewsletterTask();
|
||||||
$this->timer = ($timer) ? $timer : microtime(true);
|
$this->timer = ($timer) ? $timer : microtime(true);
|
||||||
// abort if execution or sending limit are reached
|
// abort if execution limit is reached
|
||||||
CronHelper::enforceExecutionLimit($this->timer);
|
CronHelper::enforceExecutionLimit($this->timer);
|
||||||
|
// abort if mailing is paused or sending limit has been reached
|
||||||
|
MailerLog::enforceExecutionRequirements();
|
||||||
}
|
}
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
@@ -70,8 +72,8 @@ class SendingQueue {
|
|||||||
if($queue->status === SendingQueueModel::STATUS_COMPLETED) {
|
if($queue->status === SendingQueueModel::STATUS_COMPLETED) {
|
||||||
$this->newsletter_task->markNewsletterAsSent($newsletter);
|
$this->newsletter_task->markNewsletterAsSent($newsletter);
|
||||||
}
|
}
|
||||||
// abort if sending limit is reached
|
// abort if sending limit has been reached
|
||||||
MailerLog::enforceSendingLimit();
|
MailerLog::enforceExecutionRequirements();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,8 +120,8 @@ class SendingQueue {
|
|||||||
$prepared_subscribers_ids = array();
|
$prepared_subscribers_ids = array();
|
||||||
$statistics = array();
|
$statistics = array();
|
||||||
}
|
}
|
||||||
// abort if sending limit is reached
|
// abort if sending limit has been reached
|
||||||
MailerLog::enforceSendingLimit();
|
MailerLog::enforceExecutionRequirements();
|
||||||
}
|
}
|
||||||
if($processing_method === 'bulk') {
|
if($processing_method === 'bulk') {
|
||||||
$queue = $this->sendNewsletters(
|
$queue = $this->sendNewsletters(
|
||||||
@@ -142,20 +144,22 @@ class SendingQueue {
|
|||||||
$prepared_newsletters,
|
$prepared_newsletters,
|
||||||
$prepared_subscribers
|
$prepared_subscribers
|
||||||
);
|
);
|
||||||
if(!$send_result) {
|
// log error message and schedule retry/pause sending
|
||||||
// update failed/to process list
|
if($send_result['response'] === false) {
|
||||||
$queue->updateFailedSubscribers($prepared_subscribers_ids);
|
MailerLog::processSendingError(
|
||||||
} else {
|
$send_result['operation'],
|
||||||
// update processed/to process list
|
$send_result['error_message']
|
||||||
$queue->updateProcessedSubscribers($prepared_subscribers_ids);
|
);
|
||||||
// log statistics
|
}
|
||||||
StatisticsNewslettersModel::createMultiple($statistics);
|
// update processed/to process list
|
||||||
// update the sent count
|
$queue->updateProcessedSubscribers($prepared_subscribers_ids);
|
||||||
$this->mailer_task->updateSentCount();
|
// log statistics
|
||||||
// enforce sending limit if there are still subscribers left to process
|
StatisticsNewslettersModel::createMultiple($statistics);
|
||||||
if($queue->count_to_process) {
|
// update the sent count
|
||||||
MailerLog::enforceSendingLimit();
|
$this->mailer_task->updateSentCount();
|
||||||
}
|
// abort if sending limit has been reached
|
||||||
|
if($queue->count_to_process) {
|
||||||
|
MailerLog::enforceExecutionRequirements();
|
||||||
}
|
}
|
||||||
return $queue;
|
return $queue;
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,6 @@ class Mailer {
|
|||||||
const MAILER_CONFIG_SETTING_NAME = 'mta';
|
const MAILER_CONFIG_SETTING_NAME = 'mta';
|
||||||
const SENDING_LIMIT_INTERVAL_MULTIPLIER = 60;
|
const SENDING_LIMIT_INTERVAL_MULTIPLIER = 60;
|
||||||
const METHOD_MAILPOET = 'MailPoet';
|
const METHOD_MAILPOET = 'MailPoet';
|
||||||
const METHOD_MAILGUN = 'MailGun';
|
|
||||||
const METHOD_ELASTICEMAIL = 'ElasticEmail';
|
|
||||||
const METHOD_AMAZONSES = 'AmazonSES';
|
const METHOD_AMAZONSES = 'AmazonSES';
|
||||||
const METHOD_SENDGRID = 'SendGrid';
|
const METHOD_SENDGRID = 'SendGrid';
|
||||||
const METHOD_PHPMAIL = 'PHPMail';
|
const METHOD_PHPMAIL = 'PHPMail';
|
||||||
@@ -44,21 +42,6 @@ class Mailer {
|
|||||||
$this->reply_to
|
$this->reply_to
|
||||||
);
|
);
|
||||||
break;
|
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:
|
case self::METHOD_MAILPOET:
|
||||||
$mailer_instance = new $this->mailer_config['class'](
|
$mailer_instance = new $this->mailer_config['class'](
|
||||||
$this->mailer_config['mailpoet_api_key'],
|
$this->mailer_config['mailpoet_api_key'],
|
||||||
@@ -168,7 +151,29 @@ class Mailer {
|
|||||||
|
|
||||||
function encodeAddressNamePart($name) {
|
function encodeAddressNamePart($name) {
|
||||||
if(mb_detect_encoding($name) === 'ASCII') return $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));
|
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 {
|
class MailerLog {
|
||||||
const SETTING_NAME = 'mta_log';
|
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);
|
$mailer_log = Setting::getValue(self::SETTING_NAME);
|
||||||
if(!$mailer_log) {
|
if(!$mailer_log) {
|
||||||
$mailer_log = self::createMailerLog();
|
$mailer_log = self::createMailerLog();
|
||||||
@@ -18,8 +22,12 @@ class MailerLog {
|
|||||||
|
|
||||||
static function createMailerLog() {
|
static function createMailerLog() {
|
||||||
$mailer_log = array(
|
$mailer_log = array(
|
||||||
'sent' => 0,
|
'sent' => null,
|
||||||
'started' => time()
|
'started' => time(),
|
||||||
|
'status' => null,
|
||||||
|
'retry_attempt' => null,
|
||||||
|
'retry_at' => null,
|
||||||
|
'error' => null
|
||||||
);
|
);
|
||||||
Setting::setValue(self::SETTING_NAME, $mailer_log);
|
Setting::setValue(self::SETTING_NAME, $mailer_log);
|
||||||
return $mailer_log;
|
return $mailer_log;
|
||||||
@@ -34,15 +42,73 @@ class MailerLog {
|
|||||||
return $mailer_log;
|
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() {
|
static function incrementSentCount() {
|
||||||
$mailer_log = self::getMailerLog();
|
$mailer_log = self::getMailerLog();
|
||||||
|
// clear previous retry count, errors, etc.
|
||||||
|
if($mailer_log['error']) {
|
||||||
|
$mailer_log = self::clearSendingErrorLog($mailer_log);
|
||||||
|
}
|
||||||
(int)$mailer_log['sent']++;
|
(int)$mailer_log['sent']++;
|
||||||
return self::updateMailerLog($mailer_log);
|
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_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'];
|
$elapsed_time = time() - (int)$mailer_log['started'];
|
||||||
if($mailer_log['sent'] === $mailer_config['frequency_limit']) {
|
if($mailer_log['sent'] === $mailer_config['frequency_limit']) {
|
||||||
if($elapsed_time <= $mailer_config['frequency_interval']) return true;
|
if($elapsed_time <= $mailer_config['frequency_interval']) return true;
|
||||||
@@ -51,10 +117,4 @@ class MailerLog {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function enforceSendingLimit() {
|
|
||||||
if(self::isSendingLimitReached()) {
|
|
||||||
throw new \Exception(__('Sending frequency limit has been reached.', 'mailpoet'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class AmazonSES {
|
class AmazonSES {
|
||||||
@@ -48,10 +50,17 @@ class AmazonSES {
|
|||||||
$this->url,
|
$this->url,
|
||||||
$this->request($newsletter, $subscriber)
|
$this->request($newsletter, $subscriber)
|
||||||
);
|
);
|
||||||
return (
|
if(is_wp_error($result)) {
|
||||||
!is_wp_error($result) === true &&
|
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||||
wp_remote_retrieve_response_code($result) === 200
|
}
|
||||||
);
|
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) {
|
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
|
<?php
|
||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class MailPoet {
|
class MailPoet {
|
||||||
@@ -21,10 +23,16 @@ class MailPoet {
|
|||||||
$this->url,
|
$this->url,
|
||||||
$this->request($message_body)
|
$this->request($message_body)
|
||||||
);
|
);
|
||||||
return (
|
if(is_wp_error($result)) {
|
||||||
!is_wp_error($result) === true &&
|
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||||
wp_remote_retrieve_response_code($result) === 201
|
}
|
||||||
);
|
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) {
|
function processSubscriber($subscriber) {
|
||||||
@@ -41,7 +49,7 @@ class MailPoet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBody($newsletter, $subscriber) {
|
function getBody($newsletter, $subscriber) {
|
||||||
$composeBody = function ($newsletter, $subscriber) {
|
$composeBody = function($newsletter, $subscriber) {
|
||||||
$body = array(
|
$body = array(
|
||||||
'to' => (array(
|
'to' => (array(
|
||||||
'address' => $subscriber['email'],
|
'address' => $subscriber['email'],
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class PHPMail {
|
class PHPMail {
|
||||||
@@ -19,9 +21,13 @@ class PHPMail {
|
|||||||
$message = $this->createMessage($newsletter, $subscriber);
|
$message = $this->createMessage($newsletter, $subscriber);
|
||||||
$result = $this->mailer->send($message);
|
$result = $this->mailer->send($message);
|
||||||
} catch(\Exception $e) {
|
} 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() {
|
function buildMailer() {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class SMTP {
|
class SMTP {
|
||||||
@@ -33,9 +35,13 @@ class SMTP {
|
|||||||
$message = $this->createMessage($newsletter, $subscriber);
|
$message = $this->createMessage($newsletter, $subscriber);
|
||||||
$result = $this->mailer->send($message);
|
$result = $this->mailer->send($message);
|
||||||
} catch(\Exception $e) {
|
} 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() {
|
function buildMailer() {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Mailer\Methods;
|
namespace MailPoet\Mailer\Methods;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class SendGrid {
|
class SendGrid {
|
||||||
@@ -20,13 +22,17 @@ class SendGrid {
|
|||||||
$this->url,
|
$this->url,
|
||||||
$this->request($newsletter, $subscriber)
|
$this->request($newsletter, $subscriber)
|
||||||
);
|
);
|
||||||
$result_body = json_decode($result['body'], true);
|
if(is_wp_error($result)) {
|
||||||
return (
|
return Mailer::formatMailerConnectionErrorResult($result->get_error_message());
|
||||||
!is_wp_error($result) === true &&
|
}
|
||||||
!preg_match('!invalid!', $result['body']) === true &&
|
if(wp_remote_retrieve_response_code($result) !== 200) {
|
||||||
!isset($result_body['errors']) === true &&
|
$response = json_decode($result['body'], true);
|
||||||
wp_remote_retrieve_response_code($result) === 200
|
$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) {
|
function getBody($newsletter, $subscriber) {
|
||||||
|
@@ -67,9 +67,6 @@ class SendingQueue extends Model {
|
|||||||
if(empty($subscribers['processed'])) {
|
if(empty($subscribers['processed'])) {
|
||||||
$subscribers['processed'] = array();
|
$subscribers['processed'] = array();
|
||||||
}
|
}
|
||||||
if(empty($subscribers['failed'])) {
|
|
||||||
$subscribers['failed'] = array();
|
|
||||||
}
|
|
||||||
return $subscribers;
|
return $subscribers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,22 +101,6 @@ class SendingQueue extends Model {
|
|||||||
$this->updateCount();
|
$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) {
|
function updateProcessedSubscribers($processed_subscribers) {
|
||||||
$subscribers = $this->getSubscribers();
|
$subscribers = $this->getSubscribers();
|
||||||
$subscribers['processed'] = array_merge(
|
$subscribers['processed'] = array_merge(
|
||||||
@@ -138,10 +119,8 @@ class SendingQueue extends Model {
|
|||||||
|
|
||||||
function updateCount() {
|
function updateCount() {
|
||||||
$this->subscribers = $this->getSubscribers();
|
$this->subscribers = $this->getSubscribers();
|
||||||
$this->count_processed =
|
$this->count_processed = count($this->subscribers['processed']);
|
||||||
count($this->subscribers['processed']) + count($this->subscribers['failed']);
|
|
||||||
$this->count_to_process = count($this->subscribers['to_process']);
|
$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;
|
$this->count_total = $this->count_processed + $this->count_to_process;
|
||||||
if(!$this->count_to_process) {
|
if(!$this->count_to_process) {
|
||||||
$this->processed_at = current_time('mysql');
|
$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(
|
$this->queue->subscribers = serialize(
|
||||||
array(
|
array(
|
||||||
'to_process' => array($this->subscriber->id),
|
'to_process' => array($this->subscriber->id),
|
||||||
'processed' => array(),
|
'processed' => array()
|
||||||
'failed' => array()
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$this->queue->count_total = 1;
|
$this->queue->count_total = 1;
|
||||||
@@ -118,18 +117,16 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
$updated_queue = SendingQueue::findOne($this->queue->id);
|
$updated_queue = SendingQueue::findOne($this->queue->id);
|
||||||
expect($updated_queue->status)->equals(SendingQueue::STATUS_COMPLETED);
|
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();
|
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||||
expect($updated_queue->subscribers)->equals(
|
expect($updated_queue->subscribers)->equals(
|
||||||
array(
|
array(
|
||||||
'to_process' => array(),
|
'to_process' => array(),
|
||||||
'failed' => array(),
|
|
||||||
'processed' => array($this->subscriber->id)
|
'processed' => array($this->subscriber->id)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect($updated_queue->count_total)->equals(1);
|
expect($updated_queue->count_total)->equals(1);
|
||||||
expect($updated_queue->count_processed)->equals(1);
|
expect($updated_queue->count_processed)->equals(1);
|
||||||
expect($updated_queue->count_failed)->equals(0);
|
|
||||||
expect($updated_queue->count_to_process)->equals(0);
|
expect($updated_queue->count_to_process)->equals(0);
|
||||||
|
|
||||||
// statistics entry should be created
|
// statistics entry should be created
|
||||||
@@ -166,18 +163,16 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
$updated_queue = SendingQueue::findOne($this->queue->id);
|
$updated_queue = SendingQueue::findOne($this->queue->id);
|
||||||
expect($updated_queue->status)->equals(SendingQueue::STATUS_COMPLETED);
|
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();
|
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||||
expect($updated_queue->subscribers)->equals(
|
expect($updated_queue->subscribers)->equals(
|
||||||
array(
|
array(
|
||||||
'to_process' => array(),
|
'to_process' => array(),
|
||||||
'failed' => array(),
|
|
||||||
'processed' => array($this->subscriber->id)
|
'processed' => array($this->subscriber->id)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect($updated_queue->count_total)->equals(1);
|
expect($updated_queue->count_total)->equals(1);
|
||||||
expect($updated_queue->count_processed)->equals(1);
|
expect($updated_queue->count_processed)->equals(1);
|
||||||
expect($updated_queue->count_failed)->equals(0);
|
|
||||||
expect($updated_queue->count_to_process)->equals(0);
|
expect($updated_queue->count_to_process)->equals(0);
|
||||||
|
|
||||||
// statistics entry should be created
|
// statistics entry should be created
|
||||||
@@ -196,8 +191,7 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
$this->subscriber->id(),
|
$this->subscriber->id(),
|
||||||
123
|
123
|
||||||
),
|
),
|
||||||
'processed' => array(),
|
'processed' => array()
|
||||||
'failed' => array()
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$queue->count_total = 2;
|
$queue->count_total = 2;
|
||||||
@@ -210,18 +204,16 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
$sending_queue_worker->process();
|
$sending_queue_worker->process();
|
||||||
|
|
||||||
$updated_queue = SendingQueue::findOne($queue->id);
|
$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();
|
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||||
expect($updated_queue->subscribers)->equals(
|
expect($updated_queue->subscribers)->equals(
|
||||||
array(
|
array(
|
||||||
'to_process' => array(),
|
'to_process' => array(),
|
||||||
'failed' => array(),
|
|
||||||
'processed' => array($this->subscriber->id)
|
'processed' => array($this->subscriber->id)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect($updated_queue->count_total)->equals(1);
|
expect($updated_queue->count_total)->equals(1);
|
||||||
expect($updated_queue->count_processed)->equals(1);
|
expect($updated_queue->count_processed)->equals(1);
|
||||||
expect($updated_queue->count_failed)->equals(0);
|
|
||||||
expect($updated_queue->count_to_process)->equals(0);
|
expect($updated_queue->count_to_process)->equals(0);
|
||||||
|
|
||||||
// statistics entry should be created only for 1 subscriber
|
// statistics entry should be created only for 1 subscriber
|
||||||
@@ -237,8 +229,7 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
123,
|
123,
|
||||||
456
|
456
|
||||||
),
|
),
|
||||||
'processed' => array(),
|
'processed' => array()
|
||||||
'failed' => array()
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$queue->count_total = 2;
|
$queue->count_total = 2;
|
||||||
@@ -251,54 +242,19 @@ class SendingQueueTest extends MailPoetTest {
|
|||||||
$sending_queue_worker->process();
|
$sending_queue_worker->process();
|
||||||
|
|
||||||
$updated_queue = SendingQueue::findOne($queue->id);
|
$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();
|
$updated_queue->subscribers = $updated_queue->getSubscribers();
|
||||||
expect($updated_queue->subscribers)->equals(
|
expect($updated_queue->subscribers)->equals(
|
||||||
array(
|
array(
|
||||||
'to_process' => array(),
|
'to_process' => array(),
|
||||||
'failed' => array(),
|
|
||||||
'processed' => array()
|
'processed' => array()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect($updated_queue->count_total)->equals(0);
|
expect($updated_queue->count_total)->equals(0);
|
||||||
expect($updated_queue->count_processed)->equals(0);
|
expect($updated_queue->count_processed)->equals(0);
|
||||||
expect($updated_queue->count_failed)->equals(0);
|
|
||||||
expect($updated_queue->count_to_process)->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() {
|
function testItDoesNotSendToTrashedSubscribers() {
|
||||||
$sending_queue_worker = $this->sending_queue_worker;
|
$sending_queue_worker = $this->sending_queue_worker;
|
||||||
$sending_queue_worker->mailer_task = Stub::make(
|
$sending_queue_worker->mailer_task = Stub::make(
|
||||||
|
@@ -51,8 +51,7 @@ class MailerTaskTest extends MailPoetTest {
|
|||||||
|
|
||||||
function testItGetsMailerLog() {
|
function testItGetsMailerLog() {
|
||||||
$mailer_log = $this->mailer_task->getMailerLog();
|
$mailer_log = $this->mailer_task->getMailerLog();
|
||||||
expect(isset($mailer_log['sent']))->true();
|
expect(is_array($mailer_log))->true();
|
||||||
expect(isset($mailer_log['started']))->true();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItUpdatesMailerLogSentCount() {
|
function testItUpdatesMailerLogSentCount() {
|
||||||
|
@@ -51,7 +51,8 @@ class MailerLogTest extends MailPoetTest {
|
|||||||
function testItIncrementsSentCount() {
|
function testItIncrementsSentCount() {
|
||||||
$mailer_log = array(
|
$mailer_log = array(
|
||||||
'sent' => 1,
|
'sent' => 1,
|
||||||
'started' => time()
|
'started' => time(),
|
||||||
|
'error' => null
|
||||||
);
|
);
|
||||||
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
||||||
MailerLog::incrementSentCount();
|
MailerLog::incrementSentCount();
|
||||||
@@ -107,29 +108,126 @@ class MailerLogTest extends MailPoetTest {
|
|||||||
expect($updated_mailer_log['sent'])->equals(0);
|
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(
|
$mailer_config = array(
|
||||||
'frequency' => array(
|
'frequency' => array(
|
||||||
'emails' => 2,
|
'emails' => 2,
|
||||||
'interval' => 1
|
'interval' => 1
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$mailer_log = array(
|
$mailer_log = MailerLog::createMailerLog();
|
||||||
'sent' => 2,
|
$mailer_log['sent'] = 2;
|
||||||
'started' => time()
|
$mailer_log['started'] = time();
|
||||||
);
|
|
||||||
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
Setting::setValue(MailerLog::SETTING_NAME, $mailer_log);
|
||||||
Setting::setValue(Mailer::MAILER_CONFIG_SETTING_NAME, $mailer_config);
|
Setting::setValue(Mailer::MAILER_CONFIG_SETTING_NAME, $mailer_config);
|
||||||
|
|
||||||
// exception is thrown when sending limit is reached
|
// exception is thrown when sending limit is reached
|
||||||
try {
|
try {
|
||||||
MailerLog::enforceSendingLimit();
|
MailerLog::enforceExecutionRequirements();
|
||||||
self::fail('Sending frequency exception was not thrown.');
|
self::fail('Sending frequency exception was not thrown.');
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
expect($e->getMessage())->equals('Sending frequency limit has been reached.');
|
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() {
|
function _after() {
|
||||||
ORM::raw_execute('TRUNCATE ' . Setting::$_table);
|
ORM::raw_execute('TRUNCATE ' . Setting::$_table);
|
||||||
}
|
}
|
||||||
|
@@ -11,15 +11,6 @@ class MailerTest extends MailPoetTest {
|
|||||||
'access_key' => '1234567890',
|
'access_key' => '1234567890',
|
||||||
'secret_key' => 'abcdefghijk',
|
'secret_key' => 'abcdefghijk',
|
||||||
),
|
),
|
||||||
array(
|
|
||||||
'method' => 'ElasticEmail',
|
|
||||||
'api_key' => 'abcdefghijk'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'method' => 'MailGun',
|
|
||||||
'domain' => 'example.com',
|
|
||||||
'api_key' => 'abcdefghijk'
|
|
||||||
),
|
|
||||||
array(
|
array(
|
||||||
'method' => 'MailPoet',
|
'method' => 'MailPoet',
|
||||||
'mailpoet_api_key' => 'abcdefghijk'
|
'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'),
|
'sentToXSubscribers': __('Sent to %$1d subscribers'),
|
||||||
'resume': __('Resume'),
|
'resume': __('Resume'),
|
||||||
'pause': __('Pause'),
|
'pause': __('Pause'),
|
||||||
|
'paused': __('Paused'),
|
||||||
'new': __('Add New'),
|
'new': __('Add New'),
|
||||||
|
|
||||||
'templateFileMalformedError': __('This template file appears to be damaged. Please try another one.'),
|
'templateFileMalformedError': __('This template file appears to be damaged. Please try another one.'),
|
||||||
@@ -232,6 +233,12 @@
|
|||||||
|
|
||||||
'backToPostNotifications': __('Back to Post notifications'),
|
'backToPostNotifications': __('Back to Post notifications'),
|
||||||
'sentOn': __('Sent on'),
|
'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