Added newsletter info to email unsubscribe url (#14693)

refs https://github.com/TryGhost/Team/issues/1495

For single newsletters, the unsubscribe link on emails auto unsubscribed member from the newsletter. In case of multiple newsletters, we were missing the newsletter information on unsubscribe URL that will allow us to auto unsubscribe member from that specific newsletter as they intended, while allowing them option to manage other newsletter preferences via Portal UI. This change -

- adds relevant newsletter UUID on the unsubscribe url in emails
- allows portal to auto unsubscribe members from desired newsletter
This commit is contained in:
Rishabh Garg 2022-05-05 11:00:24 +05:30 committed by GitHub
parent 2da52130a6
commit 420697291b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 5 deletions

View File

@ -167,6 +167,9 @@ module.exports = {
await emailBatchModel.save({status: 'submitting'}, knexOptions);
try {
// Load newsletter data on email
await emailBatchModel.relations.email.related('newsletter').fetch(Object.assign({}, {require: false}, knexOptions));
// send the email
const sendResponse = await this.send(emailBatchModel.relations.email.toJSON(), recipientRows, memberSegment);
@ -217,11 +220,12 @@ module.exports = {
// collate static and dynamic data for each recipient ready for provider
const recipientData = {};
const newsletterUuid = emailData.newsletter ? emailData.newsletter.uuid : null;
recipients.forEach((recipient) => {
// static data for every recipient
const data = {
unique_id: recipient.member_uuid,
unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(recipient.member_uuid)
unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(recipient.member_uuid, newsletterUuid)
};
// computed properties on recipients - TODO: better way of handling these

View File

@ -66,12 +66,13 @@ const htmlToPlaintext = (html) => {
/**
* createUnsubscribeUrl
*
* Takes a member uuid and returns the url that should be used to unsubscribe
* Takes a member and newsletter uuid. Returns the url that should be used to unsubscribe
* In case of no member uuid, generates the preview unsubscribe url - `?preview=1`
*
* @param {string} uuid
* @param {string} uuid post uuid
* @param {string} newsletterUuid newsletter uuid
*/
const createUnsubscribeUrl = (uuid) => {
const createUnsubscribeUrl = (uuid, newsletterUuid) => {
const siteUrl = urlUtils.getSiteUrl();
const unsubscribeUrl = new URL(siteUrl);
unsubscribeUrl.pathname = `${unsubscribeUrl.pathname}/unsubscribe/`.replace('//', '/');
@ -80,6 +81,9 @@ const createUnsubscribeUrl = (uuid) => {
} else {
unsubscribeUrl.searchParams.set('preview', '1');
}
if (newsletterUuid) {
unsubscribeUrl.searchParams.set('newsletter', newsletterUuid);
}
return unsubscribeUrl.href;
};

View File

@ -2,8 +2,9 @@ const should = require('should');
const sinon = require('sinon');
const settingsCache = require('../../../../../core/shared/settings-cache');
const models = require('../../../../../core/server/models');
const urlUtils = require('../../../../../core/shared/url-utils');
const {parseReplacements, renderEmailForSegment, _getTemplateSettings} = require('../../../../../core/server/services/mega/post-email-serializer');
const {parseReplacements, renderEmailForSegment, _getTemplateSettings, createUnsubscribeUrl} = require('../../../../../core/server/services/mega/post-email-serializer');
describe('Post Email Serializer', function () {
it('creates replacement pattern for valid format and value', function () {
@ -85,6 +86,34 @@ describe('Post Email Serializer', function () {
});
});
describe('createUnsubscribeUrl', function () {
before(function () {
models.init();
});
afterEach(function () {
sinon.restore();
});
it('generates unsubscribe url for preview', function () {
sinon.stub(urlUtils, 'getSiteUrl').returns('https://site.com/blah');
const unsubscribeUrl = createUnsubscribeUrl(null);
unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?preview=1');
});
it('generates unsubscribe url with only post uuid', function () {
sinon.stub(urlUtils, 'getSiteUrl').returns('https://site.com/blah');
const unsubscribeUrl = createUnsubscribeUrl('post-abcd');
unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?uuid=post-abcd');
});
it('generates unsubscribe url with both post and newsletter uuid', function () {
sinon.stub(urlUtils, 'getSiteUrl').returns('https://site.com/blah');
const unsubscribeUrl = createUnsubscribeUrl('post-abcd', 'newsletter-abcd');
unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?uuid=post-abcd&newsletter=newsletter-abcd');
});
});
describe('getTemplateSettings', function () {
before(function () {
models.init();