Compare commits
52 Commits
3.0.0-rc.2
...
3.0.0-rc.2
Author | SHA1 | Date | |
---|---|---|---|
e012bd6cbe | |||
a02e64e805 | |||
e4bb3e1133 | |||
998795e0e0 | |||
ec44b84cc9 | |||
efece061d0 | |||
e347fc74a2 | |||
027418a86c | |||
864187aa02 | |||
59ae6619c0 | |||
6aa0be8d01 | |||
657658ea2b | |||
8647128e12 | |||
c8d92b3cd2 | |||
cc8b7b45ed | |||
5b8b8c8441 | |||
7106c640ef | |||
300b84983d | |||
49c1b92838 | |||
d900827850 | |||
1688d4dbe1 | |||
856c636089 | |||
8f9e8ea185 | |||
b0b88693f1 | |||
9916eb9da8 | |||
79b5426e01 | |||
5807fd2e02 | |||
0ee39143f4 | |||
10c39bd650 | |||
20593cc5a5 | |||
f438eee842 | |||
cb4b599d97 | |||
33733219f6 | |||
737a83cdf3 | |||
9061e1b495 | |||
09199e41a1 | |||
4e91932613 | |||
227de4ecfa | |||
c1ccacf851 | |||
53f7953566 | |||
61ae2da1e3 | |||
36abd8e5e6 | |||
7e9de1fd07 | |||
7ac5e65963 | |||
cf992852b5 | |||
59482b2bfa | |||
053f9e0cdf | |||
e1cc25239b | |||
2f4452ad36 | |||
f453d685d6 | |||
2d2b4ca7f0 | |||
b9bdc86fd9 |
@ -19,11 +19,9 @@
|
||||
"guard-for-in": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-useless-concat": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"no-nested-ternary": 0,
|
||||
"semi-spacing": 0,
|
||||
"no-sequences": 0,
|
||||
"no-useless-return": 0,
|
||||
"array-callback-return": 0,
|
||||
@ -34,7 +32,6 @@
|
||||
"no-redeclare": 0,
|
||||
"no-console": 0,
|
||||
"no-empty": 0,
|
||||
"no-extra-semi": 0,
|
||||
"no-useless-escape": 0,
|
||||
"wrap-iife": 0,
|
||||
"no-unused-expressions": 0,
|
||||
@ -42,7 +39,6 @@
|
||||
"computed-property-spacing": 0,
|
||||
"no-plusplus": 0,
|
||||
"array-bracket-spacing": 0,
|
||||
"lines-around-directive": 0,
|
||||
"no-unreachable": 0,
|
||||
"default-case": 0,
|
||||
"no-lonely-if": 0,
|
||||
@ -51,7 +47,6 @@
|
||||
"no-mixed-operators": 0,
|
||||
"eqeqeq": 0,
|
||||
"space-in-parens": 0,
|
||||
"semi": 0,
|
||||
"max-len": 0,
|
||||
"no-trailing-spaces": 0,
|
||||
"global-require": 0,
|
||||
@ -79,7 +74,6 @@
|
||||
"keyword-spacing": 0,
|
||||
"eol-last": 0,
|
||||
"dot-notation": 0,
|
||||
"linebreak-style": 0,
|
||||
"indent": 0,
|
||||
"prefer-template": 0,
|
||||
"func-names": 0
|
||||
|
@ -46,7 +46,6 @@
|
||||
"array-callback-return": 0,
|
||||
"consistent-return": 0,
|
||||
"no-unreachable": 0,
|
||||
"no-extra-semi": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/extensions": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
@ -60,11 +59,9 @@
|
||||
"no-multi-spaces": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"key-spacing": 0,
|
||||
"no-multiple-empty-lines": 0,
|
||||
"space-in-parens": 0,
|
||||
"no-case-declarations": 0,
|
||||
"array-bracket-spacing": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-else-return": 0,
|
||||
"max-len": 0,
|
||||
"no-useless-concat": 0,
|
||||
|
@ -12,14 +12,10 @@
|
||||
"no-undef": 0,
|
||||
"one-var": 0,
|
||||
"indent": 0,
|
||||
"linebreak-style": 0,
|
||||
"no-whitespace-before-property": 0,
|
||||
"object-property-newline": 0,
|
||||
"global-require": 0,
|
||||
"semi": 0,
|
||||
"keyword-spacing": 0,
|
||||
"no-bitwise": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-spaced-func": 0,
|
||||
"func-call-spacing": 0,
|
||||
"max-len": 0,
|
||||
|
@ -1,12 +1,12 @@
|
||||
define('admin', [
|
||||
'jquery'
|
||||
],
|
||||
function(jQuery) {
|
||||
jQuery(function($) {
|
||||
// dom ready
|
||||
$(function() {
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
define('admin', [
|
||||
'jquery'
|
||||
],
|
||||
function(jQuery) {
|
||||
jQuery(function($) {
|
||||
// dom ready
|
||||
$(function() {
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -38,7 +38,7 @@ function exportMixpanel(mp) {
|
||||
function trackCachedEvents() {
|
||||
eventsCache.map(function (event) {
|
||||
if (window.mailpoet_analytics_enabled || event.forced) {
|
||||
window.mixpanel.track(event.name, event.data)
|
||||
window.mixpanel.track(event.name, event.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ define([
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return FormFieldDate;
|
||||
});
|
||||
|
@ -4,6 +4,7 @@
|
||||
* company: Wysija
|
||||
* framework: prototype 1.7.2
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
Event.cacheDelegated = {};
|
||||
@ -24,14 +25,14 @@ Object.extend(document, (function() {
|
||||
function findWrapper(selector, eventName, handler) {
|
||||
var c = getWrappersForSelector(selector, eventName);
|
||||
return c.find(function(wrapper) {
|
||||
return wrapper.handler === handler
|
||||
return wrapper.handler === handler;
|
||||
});
|
||||
}
|
||||
|
||||
function destroyWrapper(selector, eventName, handler) {
|
||||
var c = getCacheForSelector(selector);
|
||||
if(!c[eventName]) return false;
|
||||
var wrapper = findWrapper(selector, eventName, handler)
|
||||
var wrapper = findWrapper(selector, eventName, handler);
|
||||
c[eventName] = c[eventName].without(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
@ -77,7 +78,7 @@ Object.extend(document, (function() {
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
};
|
||||
})());
|
||||
|
||||
var Observable = (function() {
|
||||
@ -100,7 +101,7 @@ var Observable = (function() {
|
||||
function getWrapper(handler, klass) {
|
||||
return function(event) {
|
||||
return handler.call(new klass(this), event, event.memo);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function onDomLoad(selector, klass) {
|
||||
@ -125,7 +126,7 @@ var Observable = (function() {
|
||||
});
|
||||
delete this.handlers[selector];
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// override droppables
|
||||
@ -755,7 +756,7 @@ WysijaForm.Block = Class.create({
|
||||
this.element.addClassName('hover');
|
||||
try {
|
||||
this.getControls().show();
|
||||
} catch(e) {;
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -5,7 +5,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
output = '';
|
||||
for(var i = 0; i < size; i++) {
|
||||
output += arguments[i];
|
||||
};
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
@ -28,7 +28,7 @@ define('handlebars_helpers', ['handlebars'], function(Handlebars) {
|
||||
}
|
||||
} else {
|
||||
return timestamp;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('cycle', function(value, block) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
define('helpTooltip', ['mailpoet', 'react', 'react-dom', 'help-tooltip.jsx'],
|
||||
function (mp, React, ReactDOM, TooltipComponent) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
|
||||
MailPoet.helpTooltip = {
|
||||
|
@ -24,6 +24,6 @@ function KnowledgeBase() {
|
||||
<a target="_blank" href="http://beta.docs.mailpoet.com/" className="button button-primary">{MailPoet.I18n.t('knowledgeBaseButton')}</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = KnowledgeBase;
|
||||
|
@ -42,6 +42,6 @@ function KnowledgeBase() {
|
||||
{printData(data)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = KnowledgeBase;
|
||||
|
@ -38,7 +38,7 @@ function Tabs(props) {
|
||||
{ tabLinks }
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
Tabs.propTypes = { tab: React.PropTypes.string };
|
||||
Tabs.defaultProps = { tab: 'knowledgeBase' };
|
||||
|
@ -1,3 +0,0 @@
|
||||
define([], function() {
|
||||
!function(e, o, n){window.HSCW=o, window.HS=n, n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={}, t.readyQueue=[], t.config=function(e){this.userConfig=e}, t.ready=function(e){this.readyQueue.push(e)}, o.config={docs:{enabled:!0, baseUrl:"//mailpoet3.helpscoutdocs.com/"}, contact:{enabled:!0, formId:"aa21ca80-a4f5-11e6-91aa-0a5fecc78a4d"}};var r=e.getElementsByTagName("script")[0], c=e.createElement("script");c.type="text/javascript", c.async=!0, c.src="https://djtflbt20bdde.cloudfront.net/", r.parentNode.insertBefore(c, r)}(document, window.HSCW||{}, window.HS||{});
|
||||
});
|
@ -5,6 +5,7 @@ define('i18n',
|
||||
mp
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
|
||||
var translations = {};
|
||||
|
@ -1,5 +1,6 @@
|
||||
define('iframe', ['mailpoet'], function(mp) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
MailPoet.Iframe = {
|
||||
marginY: 20,
|
||||
|
@ -56,7 +56,7 @@ define([
|
||||
const promise = this.props.onBulkAction(selected_ids, data);
|
||||
if (promise !== false) {
|
||||
promise.then(onSuccess);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
@ -1,6 +1,7 @@
|
||||
define('modal', ['mailpoet', 'jquery'],
|
||||
function(mp, jQuery) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
/***************************************************************************
|
||||
MailPoet Modal:
|
||||
|
@ -1,5 +1,6 @@
|
||||
define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||
'use strict';
|
||||
|
||||
var MailPoet = mp;
|
||||
MailPoet.MP2Migrator = {
|
||||
|
||||
@ -11,7 +12,7 @@ define('mp2migrator', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||
clearTimeout(MailPoet.MP2Migrator.displayLogs_timeout);
|
||||
clearTimeout(MailPoet.MP2Migrator.updateProgressbar_timeout);
|
||||
clearTimeout(MailPoet.MP2Migrator.update_wordpress_info_timeout);
|
||||
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000)
|
||||
setTimeout(MailPoet.MP2Migrator.updateDisplay, 1000);
|
||||
},
|
||||
|
||||
stopLogger: function () {
|
||||
|
@ -50,7 +50,8 @@ define([
|
||||
if (newLength < that.options.minLength) newLength = that.options.minLength;
|
||||
|
||||
that.view.model.set(that.options.modelField, newLength + 'px');
|
||||
}).on('resizeend', function(event) {
|
||||
})
|
||||
.on('resizeend', function(event) {
|
||||
that.isBeingResized = null;
|
||||
that.$el.removeClass('mailpoet_resize_active');
|
||||
});
|
||||
|
@ -34,6 +34,8 @@ define([
|
||||
toolbar1: this.options.toolbar1,
|
||||
toolbar2: this.options.toolbar2,
|
||||
|
||||
browser_spellcheck: true,
|
||||
|
||||
valid_elements: this.options.validElements,
|
||||
invalid_elements: this.options.invalidElements,
|
||||
block_formats: this.options.blockFormats,
|
||||
|
@ -121,7 +121,7 @@ define([
|
||||
this.showChildView('toolsRegion', this.toolsView);
|
||||
this.showChildView('icons', new Module.SocialIconCollectionView({
|
||||
collection: this.model.get('icons')
|
||||
}))
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
}
|
||||
}(this, function(Marionette, Radio, _) {
|
||||
'use strict';
|
||||
|
||||
var MarionetteApplication = Marionette.Application;
|
||||
MarionetteApplication.prototype._initChannel = function () {
|
||||
this.channelName = _.result(this, 'channelName') || 'global';
|
||||
|
@ -374,8 +374,6 @@ const _MailerMixin = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
export { _QueueMixin as QueueMixin };
|
||||
export { _StatisticsMixin as StatisticsMixin };
|
||||
export { _MailerMixin as MailerMixin };
|
||||
|
@ -162,7 +162,9 @@ define(
|
||||
}
|
||||
}).fail(this._showError);
|
||||
}
|
||||
}).fail(this._showError).always(() => {
|
||||
})
|
||||
.fail(this._showError)
|
||||
.always(() => {
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
}
|
||||
@ -196,7 +198,9 @@ define(
|
||||
);
|
||||
}
|
||||
});
|
||||
}).fail(this._showError).always(() => {
|
||||
})
|
||||
.fail(this._showError)
|
||||
.always(() => {
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
define('notice', ['mailpoet', 'jquery'], function(mp, jQuery) {
|
||||
'use strict';
|
||||
|
||||
/*==================================================================================================
|
||||
|
||||
MailPoet Notice:
|
||||
|
@ -1,87 +1,87 @@
|
||||
define([
|
||||
'mailpoet',
|
||||
'jquery',
|
||||
'parsleyjs'
|
||||
],
|
||||
function(
|
||||
MailPoet,
|
||||
jQuery,
|
||||
Parsley
|
||||
) {
|
||||
jQuery(function($) {
|
||||
function isSameDomain(url) {
|
||||
var link = document.createElement('a');
|
||||
link.href = url;
|
||||
return (window.location.hostname === link.hostname);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// setup form validation
|
||||
$('form.mailpoet_form').each(function() {
|
||||
var form = $(this);
|
||||
|
||||
form.parsley().on('form:validated', function(parsley) {
|
||||
// clear messages
|
||||
form.find('.mailpoet_message > p').hide();
|
||||
|
||||
// resize iframe
|
||||
if(window.frameElement !== null) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
var form_data = form.serializeObject() || {};
|
||||
// check if we're on the same domain
|
||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||
// non ajax post request
|
||||
return true;
|
||||
} else {
|
||||
// ajax request
|
||||
MailPoet.Ajax.post({
|
||||
url: MailPoetForm.ajax_url,
|
||||
token: form_data.token,
|
||||
api_version: form_data.api_version,
|
||||
endpoint: 'subscribers',
|
||||
action: 'subscribe',
|
||||
data: form_data.data
|
||||
}).fail(function(response) {
|
||||
form.find('.mailpoet_validate_error').html(
|
||||
response.errors.map(function(error) {
|
||||
return error.message;
|
||||
}).join('<br />')
|
||||
).show();
|
||||
}).done(function(response) {
|
||||
// successfully subscribed
|
||||
if (
|
||||
response.meta !== undefined
|
||||
&& response.meta.redirect_url !== undefined
|
||||
) {
|
||||
// go to page
|
||||
window.location.href = response.meta.redirect_url;
|
||||
} else {
|
||||
// display success message
|
||||
form.find('.mailpoet_validate_success').show();
|
||||
}
|
||||
|
||||
// reset form
|
||||
form.trigger('reset');
|
||||
// reset validation
|
||||
parsley.reset();
|
||||
|
||||
// resize iframe
|
||||
if (
|
||||
window.frameElement !== null
|
||||
&& MailPoet !== undefined
|
||||
&& MailPoet['Iframe']
|
||||
) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
define([
|
||||
'mailpoet',
|
||||
'jquery',
|
||||
'parsleyjs'
|
||||
],
|
||||
function(
|
||||
MailPoet,
|
||||
jQuery,
|
||||
Parsley
|
||||
) {
|
||||
jQuery(function($) {
|
||||
function isSameDomain(url) {
|
||||
var link = document.createElement('a');
|
||||
link.href = url;
|
||||
return (window.location.hostname === link.hostname);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// setup form validation
|
||||
$('form.mailpoet_form').each(function() {
|
||||
var form = $(this);
|
||||
|
||||
form.parsley().on('form:validated', function(parsley) {
|
||||
// clear messages
|
||||
form.find('.mailpoet_message > p').hide();
|
||||
|
||||
// resize iframe
|
||||
if(window.frameElement !== null) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
|
||||
form.parsley().on('form:submit', function(parsley) {
|
||||
var form_data = form.serializeObject() || {};
|
||||
// check if we're on the same domain
|
||||
if(isSameDomain(MailPoetForm.ajax_url) === false) {
|
||||
// non ajax post request
|
||||
return true;
|
||||
} else {
|
||||
// ajax request
|
||||
MailPoet.Ajax.post({
|
||||
url: MailPoetForm.ajax_url,
|
||||
token: form_data.token,
|
||||
api_version: form_data.api_version,
|
||||
endpoint: 'subscribers',
|
||||
action: 'subscribe',
|
||||
data: form_data.data
|
||||
}).fail(function(response) {
|
||||
form.find('.mailpoet_validate_error').html(
|
||||
response.errors.map(function(error) {
|
||||
return error.message;
|
||||
}).join('<br />')
|
||||
).show();
|
||||
}).done(function(response) {
|
||||
// successfully subscribed
|
||||
if (
|
||||
response.meta !== undefined
|
||||
&& response.meta.redirect_url !== undefined
|
||||
) {
|
||||
// go to page
|
||||
window.location.href = response.meta.redirect_url;
|
||||
} else {
|
||||
// display success message
|
||||
form.find('.mailpoet_validate_success').show();
|
||||
}
|
||||
|
||||
// reset form
|
||||
form.trigger('reset');
|
||||
// reset validation
|
||||
parsley.reset();
|
||||
|
||||
// resize iframe
|
||||
if (
|
||||
window.frameElement !== null
|
||||
&& MailPoet !== undefined
|
||||
&& MailPoet['Iframe']
|
||||
) {
|
||||
MailPoet.Iframe.autoSize(window.frameElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -169,7 +169,7 @@ define(
|
||||
setTimeout(function () {
|
||||
uploadElement.parse({
|
||||
config: parseCSV(true)
|
||||
})
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
@ -433,7 +433,7 @@ define(
|
||||
MailPoet.Notice.error(errorNotice);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@ -573,14 +573,14 @@ define(
|
||||
toggleNextStepButton('on');
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
jQuery('.mailpoet_create_segment').click(function() {
|
||||
MailPoet.Modal.popup({
|
||||
title: MailPoet.I18n.t('addNewList'),
|
||||
template: jQuery('#new_segment_template').html()
|
||||
})
|
||||
});
|
||||
jQuery('#new_segment_name').keypress(function(e) {
|
||||
if (e.which == 13) {
|
||||
jQuery('#new_segment_process').click();
|
||||
@ -607,7 +607,7 @@ define(
|
||||
|
||||
var selected_values = segmentSelectElement.val();
|
||||
if (selected_values === null) {
|
||||
selected_values = [response.data.id]
|
||||
selected_values = [response.data.id];
|
||||
} else {
|
||||
selected_values.push(response.data.id);
|
||||
}
|
||||
@ -784,7 +784,7 @@ define(
|
||||
templateSelection: function (item) {
|
||||
return item.name;
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
jQuery(selectElement).data('column-id', new_column_data.id);
|
||||
jQuery(selectElement).data('validation-rule', false);
|
||||
@ -893,11 +893,11 @@ define(
|
||||
}
|
||||
else {
|
||||
for (var format in allowedDateFormats) {
|
||||
var testedFormat = allowedDateFormats[format]
|
||||
var testedFormat = allowedDateFormats[format];
|
||||
if (Moment(firstRowData, testedFormat, true).isValid()) {
|
||||
var validationRule = (typeof(testedFormat) === 'function') ?
|
||||
'datetime' :
|
||||
testedFormat
|
||||
testedFormat;
|
||||
// set validation on the column element
|
||||
jQuery(matchedColumn.element).data('validation-rule', validationRule);
|
||||
break;
|
||||
@ -931,7 +931,7 @@ define(
|
||||
+ '</span> '
|
||||
);
|
||||
preventNextStep = true;
|
||||
};
|
||||
}
|
||||
});
|
||||
if (preventNextStep && !jQuery('.mailpoet_invalidDate').length) {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('columnContainsInvalidDate'), {
|
||||
@ -1038,7 +1038,7 @@ define(
|
||||
}
|
||||
});
|
||||
batchNumber++;
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
queue.run();
|
||||
|
@ -130,6 +130,10 @@ class API {
|
||||
|
||||
$endpoint = new $this->_request_endpoint_class();
|
||||
|
||||
if(!method_exists($endpoint, $this->_request_method)) {
|
||||
throw new \Exception(__('Invalid API endpoint method.', 'mailpoet'));
|
||||
}
|
||||
|
||||
// check the accessibility of the requested endpoint's action
|
||||
// by default, an endpoint's action is considered "private"
|
||||
if(!$this->validatePermissions($this->_request_method, $endpoint->permissions)) {
|
||||
|
@ -19,8 +19,14 @@ class AutomatedLatestContent extends APIEndpoint {
|
||||
}
|
||||
|
||||
function getPostTypes() {
|
||||
$post_types = array_map(function($post_type) {
|
||||
return array(
|
||||
'name' => $post_type->name,
|
||||
'label' => $post_type->label
|
||||
);
|
||||
}, get_post_types(array(), 'objects'));
|
||||
return $this->successResponse(
|
||||
get_post_types(array(), 'objects')
|
||||
$post_types
|
||||
);
|
||||
}
|
||||
|
||||
@ -82,4 +88,4 @@ class AutomatedLatestContent extends APIEndpoint {
|
||||
|
||||
return $this->successResponse($rendered_posts);
|
||||
}
|
||||
}
|
||||
}
|
@ -267,6 +267,8 @@ class Newsletters extends APIEndpoint {
|
||||
$newsletter,
|
||||
$subscriber
|
||||
);
|
||||
// strip protocol to avoid mix content error
|
||||
$preview_url = preg_replace('{^https?:}i', '', $preview_url);
|
||||
|
||||
return $this->successResponse(
|
||||
Newsletter::findOne($newsletter->id)->asArray(),
|
||||
|
@ -74,6 +74,8 @@ class Subscribers extends APIEndpoint {
|
||||
));
|
||||
}
|
||||
|
||||
$data = $this->deobfuscateFormPayload($data);
|
||||
|
||||
$segment_ids = (!empty($data['segments'])
|
||||
? (array)$data['segments']
|
||||
: array()
|
||||
@ -81,7 +83,6 @@ class Subscribers extends APIEndpoint {
|
||||
$segment_ids = $form->filterSegments($segment_ids);
|
||||
unset($data['segments']);
|
||||
|
||||
$data = $this->deobfuscateFormPayload($data);
|
||||
|
||||
if(empty($segment_ids)) {
|
||||
return $this->badRequest(array(
|
||||
|
@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
class Hooks {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
$this->setupWPUsers();
|
||||
$this->setupImageSize();
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\API;
|
||||
@ -13,18 +14,16 @@ if(!defined('ABSPATH')) exit;
|
||||
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
||||
|
||||
class Initializer {
|
||||
const UNABLE_TO_CONNECT = 'Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.';
|
||||
const SOLVE_DB_ISSUE_URL = 'http://beta.docs.mailpoet.com/article/200-solving-database-connection-issues';
|
||||
|
||||
protected $plugin_initialized = false;
|
||||
private $access_control;
|
||||
private $renderer;
|
||||
|
||||
const INITIALIZED = 'MAILPOET_INITIALIZED';
|
||||
|
||||
function __construct($params = array(
|
||||
'file' => '',
|
||||
'version' => '1.0.0'
|
||||
)) {
|
||||
Env::init($params['file'], $params['version']);
|
||||
$this->access_control = new AccessControl();
|
||||
}
|
||||
|
||||
function init() {
|
||||
@ -40,8 +39,8 @@ class Initializer {
|
||||
$this->setupDB();
|
||||
} catch(\Exception $e) {
|
||||
return WPNotice::displayError(Helpers::replaceLinkTags(
|
||||
__(self::UNABLE_TO_CONNECT, 'mailpoet'),
|
||||
self::SOLVE_DB_ISSUE_URL,
|
||||
__('Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.', 'mailpoet'),
|
||||
'//beta.docs.mailpoet.com/article/200-solving-database-connection-issues',
|
||||
array('target' => '_blank')
|
||||
));
|
||||
}
|
||||
@ -50,8 +49,8 @@ class Initializer {
|
||||
register_activation_hook(
|
||||
Env::$file,
|
||||
array(
|
||||
'MailPoet\Config\Activator',
|
||||
'activate'
|
||||
$this,
|
||||
'runActivator'
|
||||
)
|
||||
);
|
||||
|
||||
@ -60,27 +59,20 @@ class Initializer {
|
||||
'action'
|
||||
), 10, 2);
|
||||
|
||||
add_action('admin_init', array(
|
||||
new DeferredAdminNotices,
|
||||
'printAndClean'
|
||||
));
|
||||
|
||||
add_action('plugins_loaded', array(
|
||||
$this,
|
||||
'setup'
|
||||
));
|
||||
add_action('init', array(
|
||||
$this,
|
||||
'onInit'
|
||||
));
|
||||
add_action('widgets_init', array(
|
||||
$this,
|
||||
'setupWidget'
|
||||
));
|
||||
), 0);
|
||||
|
||||
add_action('wp_loaded', array(
|
||||
$this,
|
||||
'setupHooks'
|
||||
));
|
||||
|
||||
add_action('admin_init', array(
|
||||
new DeferredAdminNotices,
|
||||
'printAndClean'
|
||||
));
|
||||
}
|
||||
|
||||
function checkRequirements() {
|
||||
@ -88,47 +80,45 @@ class Initializer {
|
||||
return $requirements->checkAllRequirements();
|
||||
}
|
||||
|
||||
function runActivator() {
|
||||
$activator = new Activator();
|
||||
return $activator->activate();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
$database = new Database();
|
||||
$database->init();
|
||||
}
|
||||
|
||||
function setup() {
|
||||
function onInit() {
|
||||
try {
|
||||
$this->setupAccessControl();
|
||||
|
||||
$this->maybeDbUpdate();
|
||||
$this->setupRenderer();
|
||||
$this->setupInstaller();
|
||||
$this->setupUpdater();
|
||||
|
||||
$this->setupRenderer();
|
||||
$this->setupWidget();
|
||||
$this->setupLocalizer();
|
||||
$this->setupMenu();
|
||||
$this->setupChangelog();
|
||||
$this->setupShortcodes();
|
||||
$this->setupImages();
|
||||
|
||||
$this->setupChangelog();
|
||||
$this->setupCronTrigger();
|
||||
$this->setupConflictResolver();
|
||||
|
||||
$this->plugin_initialized = true;
|
||||
do_action('mailpoet_initialized', MAILPOET_VERSION);
|
||||
} catch(\Exception $e) {
|
||||
$this->handleFailedInitialization($e);
|
||||
}
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
if(!$this->plugin_initialized) {
|
||||
define('MAILPOET_INITIALIZED', false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->setupJSONAPI();
|
||||
$this->setupRouter();
|
||||
$this->setupPages();
|
||||
|
||||
do_action('mailpoet_initialized', MAILPOET_VERSION);
|
||||
} catch(\Exception $e) {
|
||||
$this->handleFailedInitialization($e);
|
||||
return $this->handleFailedInitialization($e);
|
||||
}
|
||||
|
||||
define('MAILPOET_INITIALIZED', true);
|
||||
define(self::INITIALIZED, true);
|
||||
}
|
||||
|
||||
function maybeDbUpdate() {
|
||||
@ -139,28 +129,12 @@ class Initializer {
|
||||
if(!$this->access_control->validatePermission(AccessControl::PERMISSION_UPDATE_PLUGIN)) {
|
||||
throw new \Exception(__('You do not have permission to activate/deactivate MailPoet plugin.', 'mailpoet'));
|
||||
}
|
||||
$activator = new Activator();
|
||||
$activator->activate();
|
||||
$this->runActivator();
|
||||
}
|
||||
}
|
||||
|
||||
function setupWidget() {
|
||||
if(!$this->plugin_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$widget = new Widget($this->renderer);
|
||||
$widget->init();
|
||||
} catch(\Exception $e) {
|
||||
$this->handleFailedInitialization($e);
|
||||
}
|
||||
}
|
||||
|
||||
function setupRenderer() {
|
||||
$caching = !WP_DEBUG;
|
||||
$debugging = WP_DEBUG;
|
||||
$this->renderer = new Renderer($caching, $debugging);
|
||||
function setupAccessControl() {
|
||||
$this->access_control = new AccessControl();
|
||||
}
|
||||
|
||||
function setupInstaller() {
|
||||
@ -184,6 +158,17 @@ class Initializer {
|
||||
$updater->init();
|
||||
}
|
||||
|
||||
function setupRenderer() {
|
||||
$caching = !WP_DEBUG;
|
||||
$debugging = WP_DEBUG;
|
||||
$this->renderer = new Renderer($caching, $debugging);
|
||||
}
|
||||
|
||||
function setupWidget() {
|
||||
$widget = new Widget($this->renderer);
|
||||
$widget->init();
|
||||
}
|
||||
|
||||
function setupLocalizer() {
|
||||
$localizer = new Localizer($this->renderer);
|
||||
$localizer->init();
|
||||
@ -194,41 +179,18 @@ class Initializer {
|
||||
$menu->init();
|
||||
}
|
||||
|
||||
function setupChangelog() {
|
||||
$changelog = new Changelog();
|
||||
$changelog->init();
|
||||
}
|
||||
|
||||
function setupPages() {
|
||||
$pages = new \MailPoet\Settings\Pages();
|
||||
$pages->init();
|
||||
}
|
||||
|
||||
function setupShortcodes() {
|
||||
$shortcodes = new Shortcodes();
|
||||
$shortcodes->init();
|
||||
}
|
||||
|
||||
function setupHooks() {
|
||||
if(!$this->plugin_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$hooks = new Hooks();
|
||||
$hooks->init();
|
||||
} catch(\Exception $e) {
|
||||
$this->handleFailedInitialization($e);
|
||||
}
|
||||
function setupImages() {
|
||||
add_image_size('mailpoet_newsletter_max', 1320);
|
||||
}
|
||||
|
||||
function setupJSONAPI() {
|
||||
API\API::JSON($this->access_control)->init();
|
||||
}
|
||||
|
||||
function setupRouter() {
|
||||
$router = new Router\Router($this->access_control);
|
||||
$router->init();
|
||||
function setupChangelog() {
|
||||
$changelog = new Changelog();
|
||||
$changelog->init();
|
||||
}
|
||||
|
||||
function setupCronTrigger() {
|
||||
@ -239,20 +201,41 @@ class Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
function setupImages() {
|
||||
add_image_size('mailpoet_newsletter_max', 1320);
|
||||
}
|
||||
|
||||
function setupConflictResolver() {
|
||||
$conflict_resolver = new ConflictResolver();
|
||||
$conflict_resolver->init();
|
||||
}
|
||||
|
||||
function setupJSONAPI() {
|
||||
$json_api = API\API::JSON($this->access_control);
|
||||
$json_api->init();
|
||||
}
|
||||
|
||||
function setupRouter() {
|
||||
$router = new Router\Router($this->access_control);
|
||||
$router->init();
|
||||
}
|
||||
|
||||
function setupPages() {
|
||||
$pages = new \MailPoet\Settings\Pages();
|
||||
$pages->init();
|
||||
}
|
||||
|
||||
function setupHooks() {
|
||||
if(!defined(self::INITIALIZED)) return;
|
||||
try {
|
||||
$hooks = new Hooks();
|
||||
$hooks->init();
|
||||
} catch(\Exception $e) {
|
||||
$this->handleFailedInitialization($e);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFailedInitialization($exception) {
|
||||
// Check if we are able to add pages at this point
|
||||
// check if we are able to add pages at this point
|
||||
if(function_exists('wp_get_current_user')) {
|
||||
Menu::addErrorPage($this->access_control);
|
||||
}
|
||||
return WPNotice::displayError($exception);
|
||||
}
|
||||
}
|
||||
}
|
@ -59,6 +59,11 @@ class Menu {
|
||||
if(self::isOnMailPoetAdminPage()) {
|
||||
do_action('mailpoet_conflict_resolver_styles');
|
||||
do_action('mailpoet_conflict_resolver_scripts');
|
||||
|
||||
if($_REQUEST['page'] === 'mailpoet-newsletter-editor') {
|
||||
// Disable WP emojis to not interfere with the newsletter editor emoji handling
|
||||
$this->disableWPEmojis();
|
||||
}
|
||||
}
|
||||
|
||||
// Main page
|
||||
@ -314,6 +319,11 @@ class Menu {
|
||||
);
|
||||
}
|
||||
|
||||
function disableWPEmojis() {
|
||||
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
||||
remove_action('admin_print_styles', 'print_emoji_styles');
|
||||
}
|
||||
|
||||
function welcome() {
|
||||
if((bool)(defined('DOING_AJAX') && DOING_AJAX)) return;
|
||||
|
||||
@ -541,7 +551,8 @@ class Menu {
|
||||
'shortcodes' => ShortcodesHelper::getShortcodes(),
|
||||
'settings' => Setting::getAll(),
|
||||
'current_wp_user' => Subscriber::getCurrentWPUser(),
|
||||
'sub_menu' => self::MAIN_PAGE_SLUG
|
||||
'sub_menu' => self::MAIN_PAGE_SLUG,
|
||||
'mss_active' => Bridge::isMPSendingServiceEnabled()
|
||||
);
|
||||
wp_enqueue_media();
|
||||
wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
|
||||
|
@ -12,7 +12,7 @@ class PluginActivatedHook {
|
||||
}
|
||||
|
||||
public function action($plugin, $network_wide) {
|
||||
if($network_wide) {
|
||||
if($plugin === plugin_basename(Env::$file) && $network_wide) {
|
||||
$this->deferred_admin_notices->addNetworkAdminNotice(__('We noticed that you\'re using an unsupported environment. While MailPoet might work within a MultiSite environment, we don’t support it.', 'mailpoet'));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use Carbon\Carbon;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\Security;
|
||||
use MailPoet\WP\Emoji;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -79,11 +80,15 @@ class Newsletter extends Model {
|
||||
$this->set_expr('deleted_at', 'NULL');
|
||||
}
|
||||
|
||||
$this->set('body',
|
||||
is_array($this->body)
|
||||
? json_encode($this->body)
|
||||
: $this->body
|
||||
);
|
||||
if(isset($this->body)) {
|
||||
if(is_array($this->body)) {
|
||||
$this->body = json_encode($this->body);
|
||||
}
|
||||
$this->set(
|
||||
'body',
|
||||
Emoji::encodeForUTF8Column(self::$_table, 'body', $this->body)
|
||||
);
|
||||
}
|
||||
|
||||
$this->set('hash',
|
||||
($this->hash)
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
use MailPoet\WP\Emoji;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendingQueue extends Model {
|
||||
@ -55,7 +57,10 @@ class SendingQueue extends Model {
|
||||
$this->set('subscribers', serialize($this->subscribers));
|
||||
}
|
||||
if(!is_serialized($this->newsletter_rendered_body) && !is_null($this->newsletter_rendered_body)) {
|
||||
$this->set('newsletter_rendered_body', serialize($this->newsletter_rendered_body));
|
||||
$this->set(
|
||||
'newsletter_rendered_body',
|
||||
serialize($this->encodeEmojisInBody($this->newsletter_rendered_body))
|
||||
);
|
||||
}
|
||||
// set the default priority to medium
|
||||
if(!$this->priority) {
|
||||
@ -81,12 +86,34 @@ class SendingQueue extends Model {
|
||||
function getNewsletterRenderedBody($type = false) {
|
||||
$rendered_newsletter = (!is_serialized($this->newsletter_rendered_body)) ?
|
||||
$this->newsletter_rendered_body :
|
||||
unserialize($this->newsletter_rendered_body);
|
||||
$this->decodeEmojisInBody(unserialize($this->newsletter_rendered_body));
|
||||
return ($type && !empty($rendered_newsletter[$type])) ?
|
||||
$rendered_newsletter[$type] :
|
||||
$rendered_newsletter;
|
||||
}
|
||||
|
||||
function encodeEmojisInBody($newsletter_rendered_body) {
|
||||
if(is_array($newsletter_rendered_body)) {
|
||||
foreach($newsletter_rendered_body as $key => $value) {
|
||||
$newsletter_rendered_body[$key] = Emoji::encodeForUTF8Column(
|
||||
self::$_table,
|
||||
'newsletter_rendered_body',
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
return $newsletter_rendered_body;
|
||||
}
|
||||
|
||||
function decodeEmojisInBody($newsletter_rendered_body) {
|
||||
if(is_array($newsletter_rendered_body)) {
|
||||
foreach($newsletter_rendered_body as $key => $value) {
|
||||
$newsletter_rendered_body[$key] = Emoji::decodeEntities($value);
|
||||
}
|
||||
}
|
||||
return $newsletter_rendered_body;
|
||||
}
|
||||
|
||||
function isSubscriberProcessed($subscriber_id) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
return in_array($subscriber_id, $subscribers['processed']);
|
||||
|
@ -149,7 +149,11 @@ class Subscriber extends Model {
|
||||
|
||||
static function generateToken($email = null) {
|
||||
if($email !== null) {
|
||||
return substr(md5(AUTH_KEY . $email), 0, self::SUBSCRIBER_TOKEN_LENGTH);
|
||||
$auth_key = '';
|
||||
if(defined('AUTH_KEY')) {
|
||||
$auth_key = AUTH_KEY;
|
||||
}
|
||||
return substr(md5($auth_key . $email), 0, self::SUBSCRIBER_TOKEN_LENGTH);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -871,7 +875,8 @@ class Subscriber extends Model {
|
||||
static function setRequiredFieldsDefaultValues($data) {
|
||||
$required_field_default_values = array(
|
||||
'first_name' => '',
|
||||
'last_name' => ''
|
||||
'last_name' => '',
|
||||
'status' => (!Setting::getValue('signup_confirmation.enabled')) ? self::STATUS_SUBSCRIBED : self::STATUS_UNCONFIRMED
|
||||
);
|
||||
foreach($required_field_default_values as $field => $value) {
|
||||
if(!isset($data[$field])) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoet\Twig;
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -66,6 +67,11 @@ class Functions extends \Twig_Extension {
|
||||
array($this, 'getMailPoetPremiumVersion'),
|
||||
array('is_safe' => array('all'))
|
||||
),
|
||||
new \Twig_SimpleFunction(
|
||||
'mailpoet_has_valid_premium_key',
|
||||
array($this, 'hasValidPremiumKey'),
|
||||
array('is_safe' => array('all'))
|
||||
),
|
||||
new \Twig_SimpleFunction(
|
||||
'wp_time_format',
|
||||
array($this, 'getWPTimeFormat'),
|
||||
@ -151,4 +157,9 @@ class Functions extends \Twig_Extension {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function hasValidPremiumKey() {
|
||||
$checker = new ServicesChecker();
|
||||
return $checker->isPremiumKeyValid(false);
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,12 @@ class Security {
|
||||
|
||||
static function generateHash($length = false) {
|
||||
$length = ($length) ? $length : self::HASH_LENGTH;
|
||||
$auth_key = '';
|
||||
if(defined('AUTH_KEY')) {
|
||||
$auth_key = AUTH_KEY;
|
||||
}
|
||||
return substr(
|
||||
md5(AUTH_KEY . self::generateRandomString(64)),
|
||||
md5($auth_key . self::generateRandomString(64)),
|
||||
0,
|
||||
$length
|
||||
);
|
||||
|
32
lib/WP/Emoji.php
Normal file
32
lib/WP/Emoji.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace MailPoet\WP;
|
||||
|
||||
class Emoji {
|
||||
static function encodeForUTF8Column($table, $field, $value) {
|
||||
global $wpdb;
|
||||
$charset = $wpdb->get_col_charset($table, $field);
|
||||
if($charset === 'utf8') {
|
||||
$value = wp_encode_emoji($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
static function decodeEntities($content) {
|
||||
// Based on wp_staticize_emoji()
|
||||
|
||||
// Loosely match the Emoji Unicode range.
|
||||
$regex = '/(&#x[2-3][0-9a-f]{3};|[1-6][0-9a-f]{2};)/';
|
||||
|
||||
$matches = array();
|
||||
if(preg_match_all($regex, $content, $matches)) {
|
||||
if(!empty($matches[1])) {
|
||||
foreach($matches[1] as $emoji) {
|
||||
$entity = html_entity_decode($emoji, ENT_COMPAT, 'UTF-8');
|
||||
$content = str_replace($emoji, $entity, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
|
||||
|
||||
/*
|
||||
* Plugin Name: MailPoet 3 (new)
|
||||
* Version: 3.0.0-rc.2.0.0
|
||||
* Version: 3.0.0-rc.2.0.2
|
||||
* Plugin URI: http://www.mailpoet.com
|
||||
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
|
||||
* Author: MailPoet
|
||||
@ -21,7 +21,7 @@ if(!defined('ABSPATH')) exit;
|
||||
*/
|
||||
|
||||
$mailpoet_plugin = array(
|
||||
'version' => '3.0.0-rc.2.0.0',
|
||||
'version' => '3.0.0-rc.2.0.2',
|
||||
'filename' => __FILE__,
|
||||
'path' => dirname(__FILE__),
|
||||
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
||||
|
16
readme.txt
16
readme.txt
@ -4,7 +4,7 @@ Tags: newsletter, email, welcome email, post notification, autoresponder, signup
|
||||
Requires at least: 4.6
|
||||
Tested up to: 4.8
|
||||
Requires PHP: 5.3
|
||||
Stable tag: 3.0.0-rc.2.0.0
|
||||
Stable tag: 3.0.0-rc.2.0.2
|
||||
Create and send beautiful emails and newsletters from WordPress.
|
||||
|
||||
== Description ==
|
||||
@ -94,6 +94,18 @@ Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You c
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 3.0.0-rc.2.0.2 - 2017-09-05 =
|
||||
* Added: browser spellchecker in newsletter editor;
|
||||
* Improved: newsletter editor uses an optimized data object to display post types. Thanks Facundo;
|
||||
* Fixed: when signup confirmation is disabled, subscribers added via API are automatically confirmed;
|
||||
* Fixed: browser preview from within newsletter editor works on HTTP sites loaded over HTTPS. Thanks @dave2084!
|
||||
|
||||
= 3.0.0-rc.2.0.1 - 2017-08-30 =
|
||||
* Fixed: newsletters with emojis are properly saved and sent on certain hosts. Thanks Alison, Scott and Swann!
|
||||
* Fixed: plugin activates on multisite environments;
|
||||
* Fixed: subscription forms with list selection field are working now;
|
||||
* Fixed: newsletter editor does not require "unsubscribe" link when a third-party sending method is used;
|
||||
|
||||
= 3.0.0-rc.2.0.0 - 2017-08-29 =
|
||||
* Improved: MailPoet updates on high traffic sites now use less resources;
|
||||
* Improved: newsletter is saved when "next" button is pressed in newsletter editor;
|
||||
@ -101,7 +113,7 @@ Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You c
|
||||
* Improved: we collect more informative data from those who share their data with us. You should too!
|
||||
* Fixed: subscription management form works again;
|
||||
* Fixed: MailPoet 3 no longer processes the "wysija_form" shortcode used by the old MailPoet 2 to allow both plugins to display forms. Please use the newer "mailpoet_form" shortcode instead. Thx Lynn!
|
||||
* Fixed: reactivated post notifications will be sent on next scheduled time. Thx Luc!
|
||||
* Fixed: reactivated post notifications will be sent on next scheduled time. Thx Luc!
|
||||
* Fixed: updating subscription information of WP users no longer erases their first/last name;
|
||||
* Fixed: automated latest content in welcome emails always displays the latest posts. Kudos Ehi!
|
||||
|
||||
|
@ -91,7 +91,7 @@ global.stubImage = function(defaultWidth, defaultHeight) {
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
testHelpers.loadTemplate('blocks/base/toolsGeneric.hbs', window, {id: 'newsletter_editor_template_tools_generic'});
|
||||
|
@ -292,12 +292,12 @@ define([
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
onStub = sinon.stub()
|
||||
global.stubChannel(EditorApplication, {on: onStub})
|
||||
onStub = sinon.stub();
|
||||
global.stubChannel(EditorApplication, {on: onStub});
|
||||
global.stubConfig(EditorApplication);
|
||||
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model);
|
||||
EditorApplication.getBlockTypeView = sinon.stub().returns(Backbone.View);
|
||||
model = {set: sinon.stub()}
|
||||
model = {set: sinon.stub()};
|
||||
view = new (module.AutomatedLatestContentBlockView)({model: model});
|
||||
});
|
||||
|
||||
|
@ -265,9 +265,9 @@ define([
|
||||
|
||||
|
||||
beforeEach(function () {
|
||||
onStub = sinon.stub()
|
||||
global.stubChannel(EditorApplication, {on: onStub})
|
||||
model = {set: sinon.stub(), toJSON: sinon.stub()}
|
||||
onStub = sinon.stub();
|
||||
global.stubChannel(EditorApplication, {on: onStub});
|
||||
model = {set: sinon.stub(), toJSON: sinon.stub()};
|
||||
view = new (ButtonBlock.ButtonBlockView)({model: model});
|
||||
view.render();
|
||||
});
|
||||
|
@ -93,7 +93,11 @@ define([
|
||||
|
||||
expect(model.get('blocks')).to.have.length(1);
|
||||
expect(model.get('blocks').at(0).get('blocks')).to.have.length(2);
|
||||
expect(model.get('blocks').at(0).get('blocks').at(1).get('someField')).to.equal('some text 2');
|
||||
expect(
|
||||
model.get('blocks').at(0)
|
||||
.get('blocks').at(1)
|
||||
.get('someField')
|
||||
).to.equal('some text 2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,223 +1,223 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/blocks/divider'
|
||||
], function(App, DividerBlock) {
|
||||
var EditorApplication = App;
|
||||
|
||||
describe('Divider', function () {
|
||||
describe('model', function () {
|
||||
var model;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {}
|
||||
});
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
delete EditorApplication.getChannel;
|
||||
});
|
||||
|
||||
it('has a divider type', function () {
|
||||
expect(model.get('type')).to.equal('divider');
|
||||
});
|
||||
|
||||
it('has a background color', function () {
|
||||
expect(model.get('styles.block.backgroundColor')).to.match(/^(#[abcdef0-9]{6})|transparent$/);
|
||||
});
|
||||
|
||||
it('has padding', function () {
|
||||
expect(model.get('styles.block.padding')).to.match(/^\d+px$/);
|
||||
});
|
||||
|
||||
it('has border style', function () {
|
||||
expect(model.get('styles.block.borderStyle')).to.match(/^(none|dotted|dashed|solid|double|groove|ridge|inset|outset)$/);
|
||||
});
|
||||
|
||||
it('has border width', function () {
|
||||
expect(model.get('styles.block.borderWidth')).to.match(/^\d+px$/);
|
||||
});
|
||||
|
||||
it('has border color', function () {
|
||||
expect(model.get('styles.block.borderColor')).to.match(/^(#[abcdef0-9]{6})|transparent$/);
|
||||
});
|
||||
|
||||
it('changes attributes with set', function () {
|
||||
var newValue = 'outset';
|
||||
model.set('styles.block.borderStyle', newValue);
|
||||
expect(model.get('styles.block.borderStyle')).to.equal(newValue);
|
||||
});
|
||||
|
||||
it('triggers autosave if any attribute changes', function () {
|
||||
var mock = sinon.mock().exactly(5).withArgs('autoSave');
|
||||
EditorApplication.getChannel = sinon.stub().returns({
|
||||
trigger: mock
|
||||
});
|
||||
|
||||
model.set('styles.block.backgroundColor', '#000000');
|
||||
model.set('styles.block.padding', '19px');
|
||||
model.set('styles.block.borderStyle', 'double');
|
||||
model.set('styles.block.borderWidth', '17px');
|
||||
model.set('styles.block.borderColor', '#123456');
|
||||
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
divider: {
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: '#123456',
|
||||
padding: '37px',
|
||||
borderStyle: 'inset',
|
||||
borderWidth: '7px',
|
||||
borderColor: '#345678'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)();
|
||||
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
expect(model.get('styles.block.padding')).to.equal('37px');
|
||||
expect(model.get('styles.block.borderStyle')).to.equal('inset');
|
||||
expect(model.get('styles.block.borderWidth')).to.equal('7px');
|
||||
expect(model.get('styles.block.borderColor')).to.equal('#345678');
|
||||
});
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockView)({model: model});
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
expect(view.$('.mailpoet_divider')).to.have.length(1);
|
||||
});
|
||||
|
||||
it('rerenders if model attributes change', function () {
|
||||
view.render();
|
||||
|
||||
model.set('styles.block.borderStyle', 'inset');
|
||||
|
||||
expect(view.$('.mailpoet_divider').css('border-top-style')).to.equal('inset');
|
||||
});
|
||||
|
||||
it('opens settings if clicked', function () {
|
||||
var mock = sinon.mock().once();
|
||||
model.on('startEditing', mock);
|
||||
view.render();
|
||||
view.$('.mailpoet_divider').click();
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('does not open settings if clicked on the resize handle', function () {
|
||||
var mock = sinon.mock().never();
|
||||
model.on('startEditing', mock);
|
||||
view.render();
|
||||
view.$('.mailpoet_resize_handle').click();
|
||||
mock.verify();
|
||||
});
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)(),
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
expect(view.$('.mailpoet_divider_selector')).to.have.length(1);
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
|
||||
before(function() {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
view.render();
|
||||
});
|
||||
|
||||
it('updates the model when divider style changes', function () {
|
||||
view.$('.mailpoet_field_divider_style').last().click();
|
||||
expect(model.get('styles.block.borderStyle')).to.equal('inset');
|
||||
});
|
||||
|
||||
it('updates the model when divider width slider changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width').val('17').change();
|
||||
expect(model.get('styles.block.borderWidth')).to.equal('17px');
|
||||
});
|
||||
|
||||
it('updates the range slider when divider width input changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width_input').val('19').trigger('input');
|
||||
expect(view.$('.mailpoet_field_divider_border_width').val()).to.equal('19');
|
||||
});
|
||||
|
||||
it('updates the input when divider width range slider changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width').val('19').change();
|
||||
expect(view.$('.mailpoet_field_divider_border_width_input').val()).to.equal('19');
|
||||
});
|
||||
|
||||
it('updates the model when divider color changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_color').val('#123457').change();
|
||||
expect(model.get('styles.block.borderColor')).to.equal('#123457');
|
||||
});
|
||||
|
||||
it('updates the model when divider background color changes', function () {
|
||||
view.$('.mailpoet_field_divider_background_color').val('#cccccc').change();
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#cccccc');
|
||||
});
|
||||
|
||||
it ('changes color of available divider styles when actual divider color changes', function() {
|
||||
var newColor = '#889912';
|
||||
view.$('.mailpoet_field_divider_border_color').val(newColor).change();
|
||||
expect(view.$('.mailpoet_field_divider_style div')).to.have.$css('border-top-color', newColor);
|
||||
});
|
||||
|
||||
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function() {
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({
|
||||
model: model,
|
||||
renderOptions: {
|
||||
hideApplyToAll: true
|
||||
}
|
||||
});
|
||||
view.render();
|
||||
expect(view.$('.mailpoet_button_divider_apply_to_all').length).to.equal(0);
|
||||
});
|
||||
|
||||
it.skip('closes the sidepanel after "Done" is clicked', function () {
|
||||
var mock = sinon.mock().once();
|
||||
global.MailPoet.Modal.cancel = mock;
|
||||
view.$('.mailpoet_done_editing').click();
|
||||
mock.verify();
|
||||
delete(global.MailPoet.Modal.cancel);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/blocks/divider'
|
||||
], function(App, DividerBlock) {
|
||||
var EditorApplication = App;
|
||||
|
||||
describe('Divider', function () {
|
||||
describe('model', function () {
|
||||
var model;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {}
|
||||
});
|
||||
global.stubAvailableStyles(EditorApplication);
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
delete EditorApplication.getChannel;
|
||||
});
|
||||
|
||||
it('has a divider type', function () {
|
||||
expect(model.get('type')).to.equal('divider');
|
||||
});
|
||||
|
||||
it('has a background color', function () {
|
||||
expect(model.get('styles.block.backgroundColor')).to.match(/^(#[abcdef0-9]{6})|transparent$/);
|
||||
});
|
||||
|
||||
it('has padding', function () {
|
||||
expect(model.get('styles.block.padding')).to.match(/^\d+px$/);
|
||||
});
|
||||
|
||||
it('has border style', function () {
|
||||
expect(model.get('styles.block.borderStyle')).to.match(/^(none|dotted|dashed|solid|double|groove|ridge|inset|outset)$/);
|
||||
});
|
||||
|
||||
it('has border width', function () {
|
||||
expect(model.get('styles.block.borderWidth')).to.match(/^\d+px$/);
|
||||
});
|
||||
|
||||
it('has border color', function () {
|
||||
expect(model.get('styles.block.borderColor')).to.match(/^(#[abcdef0-9]{6})|transparent$/);
|
||||
});
|
||||
|
||||
it('changes attributes with set', function () {
|
||||
var newValue = 'outset';
|
||||
model.set('styles.block.borderStyle', newValue);
|
||||
expect(model.get('styles.block.borderStyle')).to.equal(newValue);
|
||||
});
|
||||
|
||||
it('triggers autosave if any attribute changes', function () {
|
||||
var mock = sinon.mock().exactly(5).withArgs('autoSave');
|
||||
EditorApplication.getChannel = sinon.stub().returns({
|
||||
trigger: mock
|
||||
});
|
||||
|
||||
model.set('styles.block.backgroundColor', '#000000');
|
||||
model.set('styles.block.padding', '19px');
|
||||
model.set('styles.block.borderStyle', 'double');
|
||||
model.set('styles.block.borderWidth', '17px');
|
||||
model.set('styles.block.borderColor', '#123456');
|
||||
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('uses defaults from config when they are set', function () {
|
||||
global.stubConfig(EditorApplication, {
|
||||
blockDefaults: {
|
||||
divider: {
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: '#123456',
|
||||
padding: '37px',
|
||||
borderStyle: 'inset',
|
||||
borderWidth: '7px',
|
||||
borderColor: '#345678'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)();
|
||||
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#123456');
|
||||
expect(model.get('styles.block.padding')).to.equal('37px');
|
||||
expect(model.get('styles.block.borderStyle')).to.equal('inset');
|
||||
expect(model.get('styles.block.borderWidth')).to.equal('7px');
|
||||
expect(model.get('styles.block.borderColor')).to.equal('#345678');
|
||||
});
|
||||
});
|
||||
|
||||
describe('block view', function () {
|
||||
var model;
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockView)({model: model});
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
expect(view.$('.mailpoet_divider')).to.have.length(1);
|
||||
});
|
||||
|
||||
it('rerenders if model attributes change', function () {
|
||||
view.render();
|
||||
|
||||
model.set('styles.block.borderStyle', 'inset');
|
||||
|
||||
expect(view.$('.mailpoet_divider').css('border-top-style')).to.equal('inset');
|
||||
});
|
||||
|
||||
it('opens settings if clicked', function () {
|
||||
var mock = sinon.mock().once();
|
||||
model.on('startEditing', mock);
|
||||
view.render();
|
||||
view.$('.mailpoet_divider').click();
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
it('does not open settings if clicked on the resize handle', function () {
|
||||
var mock = sinon.mock().never();
|
||||
model.on('startEditing', mock);
|
||||
view.render();
|
||||
view.$('.mailpoet_resize_handle').click();
|
||||
mock.verify();
|
||||
});
|
||||
});
|
||||
|
||||
describe('settings view', function () {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubConfig(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
});
|
||||
var model = new (DividerBlock.DividerBlockModel)(),
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
|
||||
it('renders', function () {
|
||||
expect(view.render).to.not.throw();
|
||||
expect(view.$('.mailpoet_divider_selector')).to.have.length(1);
|
||||
});
|
||||
|
||||
describe('once rendered', function () {
|
||||
var model, view;
|
||||
|
||||
before(function() {
|
||||
global.stubChannel(EditorApplication);
|
||||
global.stubAvailableStyles(EditorApplication, {
|
||||
dividers: ['solid', 'inset']
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
model = new (DividerBlock.DividerBlockModel)();
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({model: model});
|
||||
view.render();
|
||||
});
|
||||
|
||||
it('updates the model when divider style changes', function () {
|
||||
view.$('.mailpoet_field_divider_style').last().click();
|
||||
expect(model.get('styles.block.borderStyle')).to.equal('inset');
|
||||
});
|
||||
|
||||
it('updates the model when divider width slider changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width').val('17').change();
|
||||
expect(model.get('styles.block.borderWidth')).to.equal('17px');
|
||||
});
|
||||
|
||||
it('updates the range slider when divider width input changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width_input').val('19').trigger('input');
|
||||
expect(view.$('.mailpoet_field_divider_border_width').val()).to.equal('19');
|
||||
});
|
||||
|
||||
it('updates the input when divider width range slider changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_width').val('19').change();
|
||||
expect(view.$('.mailpoet_field_divider_border_width_input').val()).to.equal('19');
|
||||
});
|
||||
|
||||
it('updates the model when divider color changes', function () {
|
||||
view.$('.mailpoet_field_divider_border_color').val('#123457').change();
|
||||
expect(model.get('styles.block.borderColor')).to.equal('#123457');
|
||||
});
|
||||
|
||||
it('updates the model when divider background color changes', function () {
|
||||
view.$('.mailpoet_field_divider_background_color').val('#cccccc').change();
|
||||
expect(model.get('styles.block.backgroundColor')).to.equal('#cccccc');
|
||||
});
|
||||
|
||||
it ('changes color of available divider styles when actual divider color changes', function() {
|
||||
var newColor = '#889912';
|
||||
view.$('.mailpoet_field_divider_border_color').val(newColor).change();
|
||||
expect(view.$('.mailpoet_field_divider_style div')).to.have.$css('border-top-color', newColor);
|
||||
});
|
||||
|
||||
it('does not display "Apply to all" option when `hideApplyToAll` option is active', function() {
|
||||
view = new (DividerBlock.DividerBlockSettingsView)({
|
||||
model: model,
|
||||
renderOptions: {
|
||||
hideApplyToAll: true
|
||||
}
|
||||
});
|
||||
view.render();
|
||||
expect(view.$('.mailpoet_button_divider_apply_to_all').length).to.equal(0);
|
||||
});
|
||||
|
||||
it.skip('closes the sidepanel after "Done" is clicked', function () {
|
||||
var mock = sinon.mock().once();
|
||||
global.MailPoet.Modal.cancel = mock;
|
||||
view.$('.mailpoet_done_editing').click();
|
||||
mock.verify();
|
||||
delete(global.MailPoet.Modal.cancel);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,8 @@ define([
|
||||
Backbone.Radio = {
|
||||
Requests: {
|
||||
request: function () {
|
||||
}, reply: function () {
|
||||
},
|
||||
reply: function () {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ define([
|
||||
var deferred = jQuery.Deferred();
|
||||
deferred.resolve({});
|
||||
return deferred;
|
||||
}
|
||||
};
|
||||
var module;
|
||||
spy = sinon.spy(post);
|
||||
module = CommunicationInjector({
|
||||
|
@ -54,7 +54,7 @@ define([
|
||||
expect(json.subject).to.equal('some subject');
|
||||
expect(json.preheader).to.equal('some preheader');
|
||||
expect(json).to.not.include.keys('segments', 'modified_at', 'someField');
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -221,6 +221,26 @@ class APITest extends \MailPoetTest {
|
||||
expect($api->validatePermissions('test', $permissions))->true();
|
||||
}
|
||||
|
||||
function testItThrowsExceptionWhenInvalidEndpointMethodIsCalled() {
|
||||
$this->api = API::JSON(new AccessControl());
|
||||
$namespace = array(
|
||||
'name' => 'MailPoet\API\JSON\v2',
|
||||
'version' => 'v2'
|
||||
);
|
||||
$this->api->addEndpointNamespace($namespace['name'], $namespace['version']);
|
||||
|
||||
$data = array(
|
||||
'endpoint' => 'a_p_i_test_namespaced_endpoint_stub_v2',
|
||||
'api_version' => 'v2',
|
||||
'method' => 'fakeMethod'
|
||||
);
|
||||
$this->api->setRequestData($data);
|
||||
$response = $this->api->processRoute();
|
||||
|
||||
expect($response->status)->equals(Response::STATUS_BAD_REQUEST);
|
||||
expect($response->errors[0]['message'])->equals('Invalid API endpoint method.');
|
||||
}
|
||||
|
||||
function _after() {
|
||||
WPHooksHelper::releaseAllHooks();
|
||||
wp_delete_user($this->wp_user_id);
|
||||
|
18
tests/unit/API/JSON/v1/AutomatedLatestContentTest.php
Normal file
18
tests/unit/API/JSON/v1/AutomatedLatestContentTest.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Test\API\JSON\v1;
|
||||
|
||||
use MailPoet\API\JSON\v1\AutomatedLatestContent;
|
||||
|
||||
class AutomatedLatestContentTest extends \MailPoetTest {
|
||||
function testItGetsPostTypes() {
|
||||
$router = new AutomatedLatestContent();
|
||||
$response = $router->getPostTypes();
|
||||
expect($response->data)->notEmpty();
|
||||
foreach($response->data as $post_type) {
|
||||
expect($post_type)->count(2);
|
||||
expect($post_type['name'])->notEmpty();
|
||||
expect($post_type['label'])->notEmpty();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Test\API\JSON\v1;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Codeception\Util\Fixtures;
|
||||
use Codeception\Util\Stub;
|
||||
use Helper\WordPressHooks as WPHooksHelper;
|
||||
use MailPoet\API\JSON\v1\Newsletters;
|
||||
use MailPoet\API\JSON\Response as APIResponse;
|
||||
use MailPoet\API\JSON\v1\Newsletters;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterOption;
|
||||
use MailPoet\Models\NewsletterOptionField;
|
||||
@ -747,6 +748,17 @@ class NewslettersTest extends \MailPoetTest {
|
||||
expect($response->errors[0]['message'])->equals('The email could not be sent: failed');
|
||||
}
|
||||
|
||||
function testItReturnsBrowserPreviewUrlWithoutProtocol() {
|
||||
$data = array(
|
||||
'id' => $this->newsletter->id,
|
||||
'body' => 'fake body'
|
||||
);
|
||||
$router = new Newsletters();
|
||||
$response = $router->showPreview($data);
|
||||
expect($response->meta['preview_url'])->notContains('http');
|
||||
expect($response->meta['preview_url'])->regExp('!^\/\/!');
|
||||
}
|
||||
|
||||
function testItGeneratesPreviewLinksWithNewsletterHashAndNoSubscriberData() {
|
||||
$router = new Newsletters();
|
||||
$response = $router->listing();
|
||||
@ -767,4 +779,4 @@ class NewslettersTest extends \MailPoetTest {
|
||||
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
|
||||
\ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ class SubscribersTest extends \MailPoetTest {
|
||||
function _before() {
|
||||
$obfuscator = new FieldNameObfuscator();
|
||||
$this->obfuscatedEmail = $obfuscator->obfuscate('email');
|
||||
$this->obfuscatedSegments = $obfuscator->obfuscate('segments');
|
||||
$this->segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1'));
|
||||
$this->segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2'));
|
||||
|
||||
@ -433,7 +434,7 @@ class SubscribersTest extends \MailPoetTest {
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'toto@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
'segments' => array($this->segment_1->id, $this->segment_2->id)
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id)
|
||||
));
|
||||
expect($response->status)->equals(APIResponse::STATUS_OK);
|
||||
}
|
||||
@ -470,7 +471,7 @@ class SubscribersTest extends \MailPoetTest {
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'toto@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
'segments' => array($this->segment_1->id, $this->segment_2->id)
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id)
|
||||
));
|
||||
|
||||
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
|
||||
@ -482,7 +483,7 @@ class SubscribersTest extends \MailPoetTest {
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'toto@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
'segments' => array($this->segment_1->id, $this->segment_2->id),
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id),
|
||||
// exists in table and in the form
|
||||
'first_name' => 'aaa',
|
||||
// exists in table, but not in the form
|
||||
@ -503,14 +504,14 @@ class SubscribersTest extends \MailPoetTest {
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'toto@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
'segments' => array($this->segment_1->id, $this->segment_2->id)
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id)
|
||||
));
|
||||
|
||||
try {
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'tata@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
'segments' => array($this->segment_1->id, $this->segment_2->id)
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id)
|
||||
));
|
||||
$this->fail('It should not be possible to subscribe a second time so soon');
|
||||
} catch(\Exception $e) {
|
||||
|
@ -5,6 +5,10 @@ use MailPoet\Config\Env;
|
||||
|
||||
class EnvTest extends \MailPoetTest {
|
||||
function _before() {
|
||||
// Back up original environment values
|
||||
$this->file = Env::$file;
|
||||
$this->version = Env::$version;
|
||||
|
||||
Env::init('file', '1.0.0');
|
||||
}
|
||||
|
||||
@ -80,4 +84,9 @@ class EnvTest extends \MailPoetTest {
|
||||
expect(Env::getDbTimezoneOffset('+11'))->equals("+11:00");
|
||||
expect(Env::getDbTimezoneOffset('-5.5'))->equals("-05:30");
|
||||
}
|
||||
|
||||
function _after() {
|
||||
// Restore the original environment
|
||||
Env::init($this->file, $this->version);
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ class PluginActivatedHookTest extends \MailPoetTest {
|
||||
$this
|
||||
);
|
||||
$hook = new PluginActivatedHook($deferred_admin_notices);
|
||||
$hook->action("mailpoet", true);
|
||||
$hook->action("mailpoet/mailpoet.php", true);
|
||||
}
|
||||
|
||||
public function testItDoesntAddsAMessageIfNoNetworkActivation() {
|
||||
public function testItDoesntAddAMessageIfPluginNameDiffers() {
|
||||
$deferred_admin_notices = Stub::makeEmpty(
|
||||
'MailPoet\Config\DeferredAdminNotices',
|
||||
array(
|
||||
@ -29,7 +29,19 @@ class PluginActivatedHookTest extends \MailPoetTest {
|
||||
$this
|
||||
);
|
||||
$hook = new PluginActivatedHook($deferred_admin_notices);
|
||||
$hook->action("mailpoet", false);
|
||||
$hook->action("some/plugin.php", true);
|
||||
}
|
||||
|
||||
public function testItDoesntAddAMessageIfNoNetworkActivation() {
|
||||
$deferred_admin_notices = Stub::makeEmpty(
|
||||
'MailPoet\Config\DeferredAdminNotices',
|
||||
array(
|
||||
'addNetworkAdminNotice' => Stub::never(),
|
||||
),
|
||||
$this
|
||||
);
|
||||
$hook = new PluginActivatedHook($deferred_admin_notices);
|
||||
$hook->action("mailpoet/mailpoet.php", false);
|
||||
}
|
||||
|
||||
}
|
||||
|
42
tests/unit/Models/SendingQueueTest.php
Normal file
42
tests/unit/Models/SendingQueueTest.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace MailPoet\Test\Models;
|
||||
|
||||
use AspectMock\Test as Mock;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
|
||||
class SendingQueueTest extends \MailPoetTest {
|
||||
function _before() {
|
||||
$this->queue = SendingQueue::create();
|
||||
$this->queue->save();
|
||||
|
||||
$this->rendered_body = array(
|
||||
'html' => 'some html',
|
||||
'text' => 'some text'
|
||||
);
|
||||
}
|
||||
|
||||
function testItCanEncodeEmojisInBody() {
|
||||
$mock = Mock::double('MailPoet\WP\Emoji', [
|
||||
'encodeForUTF8Column' => function($params) {
|
||||
return $params;
|
||||
}
|
||||
]);
|
||||
$this->queue->encodeEmojisInBody($this->rendered_body);
|
||||
$mock->verifyInvokedMultipleTimes('encodeForUTF8Column', 2);
|
||||
}
|
||||
|
||||
function testItCanDecodeEmojisInBody() {
|
||||
$mock = Mock::double('MailPoet\WP\Emoji', [
|
||||
'decodeEntities' => function($params) {
|
||||
return $params;
|
||||
}
|
||||
]);
|
||||
$this->queue->decodeEmojisInBody($this->rendered_body);
|
||||
$mock->verifyInvokedMultipleTimes('decodeEntities', 2);
|
||||
}
|
||||
|
||||
function _after() {
|
||||
Mock::clean();
|
||||
\ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||
}
|
||||
}
|
@ -1020,7 +1020,40 @@ class SubscriberTest extends \MailPoetTest {
|
||||
expect(Subscriber::setRequiredFieldsDefaultValues(array()))->equals(
|
||||
array(
|
||||
'first_name' => '',
|
||||
'last_name' => ''
|
||||
'last_name' => '',
|
||||
'status' => Subscriber::STATUS_UNCONFIRMED
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testItSetsDefaultStatusDependingOnSingupConfirmationOption() {
|
||||
// when signup confirmation is disabled, status should be 'subscribed'
|
||||
Setting::setValue('signup_confirmation.enabled', false);
|
||||
expect(Subscriber::setRequiredFieldsDefaultValues(array()))->equals(
|
||||
array(
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'status' => Subscriber::STATUS_SUBSCRIBED
|
||||
)
|
||||
);
|
||||
|
||||
Setting::setValue('signup_confirmation.enabled', true);
|
||||
// when signup confirmation is enabled, status should be 'unconfirmed'
|
||||
expect(Subscriber::setRequiredFieldsDefaultValues(array()))->equals(
|
||||
array(
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'status' => Subscriber::STATUS_UNCONFIRMED
|
||||
)
|
||||
);
|
||||
|
||||
// when status is specified, it should not change regardless of signup confirmation option
|
||||
Setting::setValue('signup_confirmation.enabled', true);
|
||||
expect(Subscriber::setRequiredFieldsDefaultValues(array('status' => Subscriber::STATUS_SUBSCRIBED)))->equals(
|
||||
array(
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'status' => Subscriber::STATUS_SUBSCRIBED
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -1034,6 +1067,7 @@ class SubscriberTest extends \MailPoetTest {
|
||||
expect($result->getErrors())->false();
|
||||
expect($result->first_name)->isEmpty();
|
||||
expect($result->last_name)->isEmpty();
|
||||
expect($result->status)->equals(Subscriber::STATUS_UNCONFIRMED);
|
||||
}
|
||||
|
||||
function testItDoesNotSetDefaultValuesForExistingSubscribers() {
|
||||
|
51
tests/unit/WP/EmojiTest.php
Normal file
51
tests/unit/WP/EmojiTest.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace MailPoet\Test\WP;
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\WP\Emoji;
|
||||
|
||||
class EmojiTest extends \MailPoetTest {
|
||||
function _before() {
|
||||
$this->data_encoded = "Emojis: 😃😵💪, not emojis: .Ž";
|
||||
$this->data_decoded = "Emojis: 😃😵💪, not emojis: .Ž";
|
||||
|
||||
$this->column = 'dummycol';
|
||||
}
|
||||
|
||||
function testItCanEncodeForUTF8Column() {
|
||||
$table = Env::$db_prefix . 'dummytable_utf8';
|
||||
$this->createTable($table, 'utf8');
|
||||
|
||||
$result = Emoji::encodeForUTF8Column($table, $this->column, $this->data_decoded);
|
||||
expect($result)->equals($this->data_encoded);
|
||||
|
||||
$this->dropTable($table);
|
||||
}
|
||||
|
||||
function testItDoesNotEncodeForUTF8MB4Column() {
|
||||
$table = Env::$db_prefix . 'dummytable_utf8mb4';
|
||||
$this->createTable($table, 'utf8mb4');
|
||||
|
||||
$result = Emoji::encodeForUTF8Column($table, $this->column, $this->data_decoded);
|
||||
expect($result)->equals($this->data_decoded);
|
||||
|
||||
$this->dropTable($table);
|
||||
}
|
||||
|
||||
function testItCanDecodeEntities() {
|
||||
$result = Emoji::decodeEntities($this->data_encoded);
|
||||
expect($result)->equals($this->data_decoded);
|
||||
}
|
||||
|
||||
private function createTable($table, $charset) {
|
||||
\ORM::raw_execute(
|
||||
'CREATE TABLE IF NOT EXISTS ' . $table
|
||||
. ' (' . $this->column . ' TEXT) '
|
||||
. 'DEFAULT CHARSET=' . $charset . ';'
|
||||
);
|
||||
}
|
||||
|
||||
private function dropTable($table) {
|
||||
\ORM::raw_execute('DROP TABLE IF EXISTS ' . $table);
|
||||
}
|
||||
}
|
@ -75,6 +75,9 @@ jQuery('.toplevel_page_mailpoet-newsletters.menu-top-last')
|
||||
|
||||
<%= javascript('lib/analytics.js') %>
|
||||
|
||||
<% set helpscout_form_id = (mailpoet_has_valid_premium_key()) ? '6974b88d-8d85-11e7-b5b5-0ec85169275a' : 'dd918048-8d73-11e7-b5b5-0ec85169275a' %>
|
||||
<script>!function(e,o,n){window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={},t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!0,baseUrl:"//mailpoet3.helpscoutdocs.com/"},contact:{enabled:!0,formId:"<%= helpscout_form_id %>"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r)}(document,window.HSCW||{},window.HS||{});</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
if(window['HS'] !== undefined) {
|
||||
// HelpScout Beacon: Configuration
|
||||
|
@ -1200,7 +1200,7 @@
|
||||
height: '768px'
|
||||
},
|
||||
validation: {
|
||||
validateUnsubscribeLinkPresent: true, // TODO: Add validation based on whether Mailpoet MTA is used or not
|
||||
validateUnsubscribeLinkPresent: <%= mss_active ? 'true' : 'false' %>,
|
||||
},
|
||||
urls: {
|
||||
send: '<%= admin_url('admin.php?page=mailpoet-newsletters#/send/' ~ (params('id') | intval)) %>',
|
||||
|
@ -60,8 +60,8 @@
|
||||
<div class="feature-section one-col mailpoet_centered">
|
||||
<h2><%= __('Care to Give Your Opinion?') %></h2>
|
||||
|
||||
<script type="text/javascript" charset="utf-8" src="//secure.polldaddy.com/p/9801032.js"></script>
|
||||
<noscript><a href="//polldaddy.com/poll/9801032/">To which gender identity to you identify?</a></noscript>
|
||||
<script type="text/javascript" charset="utf-8" src="//secure.polldaddy.com/p/9801036.js"></script>
|
||||
<noscript><a href="//polldaddy.com/poll/9801036/">Should MailPoet include more default templates?</a></noscript>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
@ -36,7 +36,6 @@ var baseConfig = {
|
||||
'wp-js-hooks': 'WP-JS-Hooks/src/event-manager.js',
|
||||
'blob$': 'blob-tmp/Blob.js',
|
||||
'papaparse': 'papaparse/papaparse.min.js',
|
||||
'helpscout': 'helpscout.js',
|
||||
'html2canvas': 'html2canvas/dist/html2canvas.js',
|
||||
'asyncqueue': 'vendor/jquery.asyncqueue.js'
|
||||
},
|
||||
@ -118,10 +117,6 @@ var baseConfig = {
|
||||
include: require.resolve('handlebars'),
|
||||
loader: 'expose-loader?Handlebars',
|
||||
},
|
||||
{
|
||||
include: /helpscout.js$/,
|
||||
loader: 'exports-loader?window.HS',
|
||||
},
|
||||
{
|
||||
include: /html2canvas.js$/,
|
||||
loader: 'expose-loader?html2canvas',
|
||||
@ -177,7 +172,6 @@ var adminConfig = {
|
||||
'settings/reinstall_from_scratch.js',
|
||||
'subscribers/importExport/import.js',
|
||||
'subscribers/importExport/export.js',
|
||||
'helpscout'
|
||||
],
|
||||
form_editor: [
|
||||
'form_editor/form_editor.js',
|
||||
@ -388,4 +382,4 @@ module.exports = _.map([adminConfig, publicConfig, migratorConfig, testConfig],
|
||||
);
|
||||
}
|
||||
return _.extend({}, baseConfig, config);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user