0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00
-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQTqYa7kNs8D7Oo9dgLSEYbwtHKVrQUCYP6iagAKCRDSEYbwtHKV
 rR/dAPsGjY89fheicUdZfWbVUGunIQAKCYWj4sNMR5ZJbFQ8IAD8Dbx5XLR1IYmX
 7uzjx7ayuHt+o9jJkaRFGpETIRln4w0=
 =JY+u
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQTqYa7kNs8D7Oo9dgLSEYbwtHKVrQUCYP6kDQAKCRDSEYbwtHKV
 rVJ1AQCDiGWEJNVItQbPoAURACUtQPtg8GH1O62We+LUNdKQ5gEA2+snzZAi9fag
 60k5eyYxcB4JOwSVLIS19FcybgnhuAg=
 =1a74
 -----END PGP SIGNATURE-----

Merged v4.10.2 into main

v4.10.2
This commit is contained in:
Daniel Lockyer 2021-07-26 13:01:12 +01:00
commit 04b5a1c6c5
4 changed files with 54 additions and 54 deletions

@ -1 +1 @@
Subproject commit 46973d2473c1a61a96953dc136f70975d21b041d
Subproject commit e1b0886ad21457d7751115fa69b28550be60d4b0

View file

@ -24,10 +24,8 @@ const events = require('../../lib/common/events');
const messages = {
invalidSegment: 'Invalid segment value. Use one of the valid:"status:free" or "status:-free" values.',
unexpectedEmailRecipientFilterError: 'Unexpected email_recipient_filter value "{emailRecipientFilter}", expected an NQL equivalent',
noneEmailRecipientFilterError: 'Cannot sent email to "none" email_recipient_filter',
unexpectedRecipientFilterError: 'Unexpected recipient_filter value "{recipientFilter}", expected an NQL equivalent',
noneRecipientFileterError: 'Cannot sent email to "none" recipient_filter'
unexpectedFilterError: 'Unexpected {property} value "{value}", expected an NQL equivalent',
noneFilterError: 'Cannot send email to "none" {property}'
};
const getFromAddress = () => {
@ -108,6 +106,38 @@ const sendTestEmail = async (postModel, toEmails, apiVersion) => {
return response;
};
/**
* transformRecipientFilter
*
* Accepts a filter string, errors on unexpected legacy filter syntax and enforces subscribed:true
*
* @param {string} emailRecipientFilter NQL filter for members
* @param {object} options
*/
const transformEmailRecipientFilter = (emailRecipientFilter, {errorProperty = 'email_recipient_filter'} = {}) => {
switch (emailRecipientFilter) {
// `paid` and `free` were swapped out for NQL filters in 4.5.0, we shouldn't see them here now
case 'paid':
case 'free':
throw new errors.GhostError({
message: tpl(messages.unexpectedFilterError, {
property: errorProperty,
value: emailRecipientFilter
})
});
case 'all':
return 'subscribed:true';
case 'none':
throw new errors.GhostError({
message: tpl(messages.noneFilterError, {
property: errorProperty
})
});
default:
return `subscribed:true+(${emailRecipientFilter})`;
}
};
/**
* addEmail
*
@ -128,28 +158,7 @@ const addEmail = async (postModel, options) => {
const filterOptions = Object.assign({}, knexOptions, {limit: 1});
const emailRecipientFilter = postModel.get('email_recipient_filter');
switch (emailRecipientFilter) {
// `paid` and `free` were swapped out for NQL filters in 4.5.0, we shouldn't see them here now
case 'paid':
case 'free':
throw new errors.GhostError({
message: tpl(messages.unexpectedEmailRecipientFilterError, {
emailRecipientFilter
})
});
case 'all':
filterOptions.filter = 'subscribed:true';
break;
case 'none':
throw new errors.GhostError({
message: tpl(messages.noneEmailRecipientFilterError, {
emailRecipientFilter
})
});
default:
filterOptions.filter = `subscribed:true+${emailRecipientFilter}`;
}
filterOptions.filter = transformEmailRecipientFilter(emailRecipientFilter, {errorProperty: 'email_recipient_filter'});
const startRetrieve = Date.now();
debug('addEmail: retrieving members count');
@ -348,27 +357,8 @@ async function getEmailMemberRows({emailModel, memberSegment, options}) {
const knexOptions = _.pick(options, ['transacting', 'forUpdate']);
const filterOptions = Object.assign({}, knexOptions);
const recipientFilter = emailModel.get('recipient_filter');
switch (recipientFilter) {
// `paid` and `free` were swapped out for NQL filters in 4.5.0, we shouldn't see them here now
case 'paid':
case 'free':
throw new errors.GhostError({
message: tpl(messages.unexpectedRecipientFilterError, {
recipientFilter
})
});
case 'all':
filterOptions.filter = 'subscribed:true';
break;
case 'none':
throw new errors.GhostError({
message: tpl(messages.noneRecipientFileterError)
});
default:
filterOptions.filter = `subscribed:true+${recipientFilter}`;
}
const recipientFilter = transformEmailRecipientFilter(emailModel.get('recipient_filter'), {errorProperty: 'recipient_filter'});
filterOptions.filter = recipientFilter;
if (memberSegment) {
filterOptions.filter = `${filterOptions.filter}+${memberSegment}`;
@ -542,6 +532,7 @@ module.exports = {
sendTestEmail,
handleUnsubscribeRequest,
// NOTE: below are only exposed for testing purposes
_transformEmailRecipientFilter: transformEmailRecipientFilter,
_partitionMembersBySegment: partitionMembersBySegment,
_getEmailMemberRows: getEmailMemberRows
};

View file

@ -1,6 +1,6 @@
{
"name": "ghost",
"version": "4.10.1",
"version": "4.10.2",
"description": "The professional publishing platform",
"author": "Ghost Foundation",
"homepage": "https://ghost.org",

View file

@ -2,11 +2,12 @@ const should = require('should');
const sinon = require('sinon');
const errors = require('@tryghost/errors');
const {addEmail, _partitionMembersBySegment, _getEmailMemberRows} = require('../../../../core/server/services/mega/mega');
const {addEmail, _partitionMembersBySegment, _getEmailMemberRows, _transformEmailRecipientFilter} = require('../../../../core/server/services/mega/mega');
describe('MEGA', function () {
describe('addEmail', function () {
it('addEmail throws when "free" or "paid" strings are used as a email_recipient_filter', async function () {
// via transformEmailRecipientFilter
it('throws when "free" or "paid" strings are used as a email_recipient_filter', async function () {
const postModel = {
get: sinon.stub().returns('free')
};
@ -20,7 +21,8 @@ describe('MEGA', function () {
}
});
it('addEmail throws when "none" is used as a email_recipient_filter', async function () {
// via transformEmailRecipientFilter
it('throws when "none" is used as a email_recipient_filter', async function () {
const postModel = {
get: sinon.stub().returns('none')
};
@ -30,11 +32,18 @@ describe('MEGA', function () {
should.fail('addEmail did not throw');
} catch (err) {
should.equal(err instanceof errors.GhostError, true);
err.message.should.equal('Cannot sent email to "none" email_recipient_filter');
err.message.should.equal('Cannot send email to "none" email_recipient_filter');
}
});
});
describe('transformEmailRecipientFilter', function () {
it('enforces subscribed:true with correct operator precedence', function () {
const transformedFilter = _transformEmailRecipientFilter('status:free,status:-free');
transformedFilter.should.equal('subscribed:true+(status:free,status:-free)');
});
});
describe('getEmailMemberRows', function () {
it('addEmail throws when "free" or "paid" strings are used as a recipient_filter', async function () {
const emailModel = {
@ -60,7 +69,7 @@ describe('MEGA', function () {
should.fail('getEmailMemberRows did not throw');
} catch (err) {
should.equal(err instanceof errors.GhostError, true);
err.message.should.equal('Cannot sent email to "none" recipient_filter');
err.message.should.equal('Cannot send email to "none" recipient_filter');
}
});
});