diff --git a/ghost/core/core/frontend/services/routing/controllers/unsubscribe.js b/ghost/core/core/frontend/services/routing/controllers/unsubscribe.js index a13e5a846b..41d4396d82 100644 --- a/ghost/core/core/frontend/services/routing/controllers/unsubscribe.js +++ b/ghost/core/core/frontend/services/routing/controllers/unsubscribe.js @@ -18,6 +18,9 @@ module.exports = async function unsubscribeController(req, res) { if (query.newsletter) { redirectUrl.searchParams.append('newsletter', query.newsletter); } + if (query.comments) { + redirectUrl.searchParams.append('comments', query.comments); + } redirectUrl.searchParams.append('action', 'unsubscribe'); return res.redirect(302, redirectUrl.href); diff --git a/ghost/core/core/server/services/bulk-email/bulk-email-processor.js b/ghost/core/core/server/services/bulk-email/bulk-email-processor.js index d27a9fd352..37a8f3d753 100644 --- a/ghost/core/core/server/services/bulk-email/bulk-email-processor.js +++ b/ghost/core/core/server/services/bulk-email/bulk-email-processor.js @@ -234,7 +234,7 @@ module.exports = { // static data for every recipient const data = { unique_id: recipient.member_uuid, - unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(recipient.member_uuid, newsletterUuid) + unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(recipient.member_uuid, {newsletterUuid}) }; // computed properties on recipients - TODO: better way of handling these diff --git a/ghost/core/core/server/services/comments/email-templates/new-comment-reply.hbs b/ghost/core/core/server/services/comments/email-templates/new-comment-reply.hbs index c29d3c37d9..a06eee5ac5 100644 --- a/ghost/core/core/server/services/comments/email-templates/new-comment-reply.hbs +++ b/ghost/core/core/server/services/comments/email-templates/new-comment-reply.hbs @@ -174,7 +174,7 @@ -

Manage your email preferences

+

Unsubscribe from comment reply notifications

diff --git a/ghost/core/core/server/services/comments/email-templates/new-comment-reply.txt.js b/ghost/core/core/server/services/comments/email-templates/new-comment-reply.txt.js index c215d4c219..d31a6e81df 100644 --- a/ghost/core/core/server/services/comments/email-templates/new-comment-reply.txt.js +++ b/ghost/core/core/server/services/comments/email-templates/new-comment-reply.txt.js @@ -9,5 +9,5 @@ ${data.postUrl}#ghost-comments --- Sent to ${data.toEmail} from ${data.siteDomain}. -You can manage your notification preferences at ${data.profileUrl}.`; +You can unsubscribe from these notifications at ${data.profileUrl}.`; }; diff --git a/ghost/core/core/server/services/comments/emails.js b/ghost/core/core/server/services/comments/emails.js index 98decd507e..ca739dbafa 100644 --- a/ghost/core/core/server/services/comments/emails.js +++ b/ghost/core/core/server/services/comments/emails.js @@ -2,6 +2,7 @@ const {promises: fs} = require('fs'); const path = require('path'); const moment = require('moment'); const htmlToPlaintext = require('@tryghost/html-to-plaintext'); +const postEmailSerializer = require('../mega/post-email-serializer'); class CommentsServiceEmails { constructor({config, logging, models, mailer, settingsCache, urlService, urlUtils}) { @@ -93,7 +94,7 @@ class CommentsServiceEmails { accentColor: this.settingsCache.get('accent_color'), fromEmail: this.notificationFromAddress, toEmail: to, - profileUrl: `${this.urlUtils.getSiteUrl()}#/portal/account/profile` + profileUrl: postEmailSerializer.createUnsubscribeUrl(member.get('uuid'), {comments: true}) }; const {html, text} = await this.renderEmailTemplate('new-comment-reply', templateData); diff --git a/ghost/core/core/server/services/mega/post-email-serializer.js b/ghost/core/core/server/services/mega/post-email-serializer.js index dad330e4b8..a96d5281e4 100644 --- a/ghost/core/core/server/services/mega/post-email-serializer.js +++ b/ghost/core/core/server/services/mega/post-email-serializer.js @@ -59,9 +59,11 @@ const getSite = () => { * In case of no member uuid, generates the preview unsubscribe url - `?preview=1` * * @param {string} uuid post uuid - * @param {string} newsletterUuid newsletter uuid + * @param {Object} [options] + * @param {string} [options.newsletterUuid] newsletter uuid + * @param {boolean} [options.comments] Unsubscribe from comment emails */ -const createUnsubscribeUrl = (uuid, newsletterUuid) => { +const createUnsubscribeUrl = (uuid, options = {}) => { const siteUrl = urlUtils.getSiteUrl(); const unsubscribeUrl = new URL(siteUrl); unsubscribeUrl.pathname = `${unsubscribeUrl.pathname}/unsubscribe/`.replace('//', '/'); @@ -70,8 +72,11 @@ const createUnsubscribeUrl = (uuid, newsletterUuid) => { } else { unsubscribeUrl.searchParams.set('preview', '1'); } - if (newsletterUuid) { - unsubscribeUrl.searchParams.set('newsletter', newsletterUuid); + if (options.newsletterUuid) { + unsubscribeUrl.searchParams.set('newsletter', options.newsletterUuid); + } + if (options.comments) { + unsubscribeUrl.searchParams.set('comments', '1'); } return unsubscribeUrl.href; diff --git a/ghost/core/core/shared/config/defaults.json b/ghost/core/core/shared/config/defaults.json index a1b40629f5..7b11e98591 100644 --- a/ghost/core/core/shared/config/defaults.json +++ b/ghost/core/core/shared/config/defaults.json @@ -137,7 +137,7 @@ }, "portal": { "url": "https://cdn.jsdelivr.net/npm/@tryghost/portal@~{version}/umd/portal.min.js", - "version": "2.7" + "version": "2.8" }, "sodoSearch": { "url": "https://cdn.jsdelivr.net/npm/@tryghost/sodo-search@~{version}/umd/sodo-search.min.js", diff --git a/ghost/core/test/unit/server/services/mega/post-email-serializer.test.js b/ghost/core/test/unit/server/services/mega/post-email-serializer.test.js index b30e27049f..edb56214ed 100644 --- a/ghost/core/test/unit/server/services/mega/post-email-serializer.test.js +++ b/ghost/core/test/unit/server/services/mega/post-email-serializer.test.js @@ -236,16 +236,22 @@ describe('Post Email Serializer', function () { unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?preview=1'); }); - it('generates unsubscribe url with only post uuid', function () { + it('generates unsubscribe url with only member 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'); + const unsubscribeUrl = createUnsubscribeUrl('member-abcd'); + unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?uuid=member-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'); + const unsubscribeUrl = createUnsubscribeUrl('member-abcd', {newsletterUuid: 'newsletter-abcd'}); + unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?uuid=member-abcd&newsletter=newsletter-abcd'); + }); + + it('generates unsubscribe url with comments', function () { + sinon.stub(urlUtils, 'getSiteUrl').returns('https://site.com/blah'); + const unsubscribeUrl = createUnsubscribeUrl('member-abcd', {comments: true}); + unsubscribeUrl.should.eql('https://site.com/blah/unsubscribe/?uuid=member-abcd&comments=1'); }); });