From d6a1d98acad97c351a200b2671e0bda42f8714ff Mon Sep 17 00:00:00 2001 From: Rishabh Garg Date: Mon, 6 Mar 2023 15:06:47 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20=20Added=20source=20attribution?= =?UTF-8?q?=20info=20to=20email=20alerts=20(#16360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refs https://github.com/TryGhost/Team/issues/2489 - adds attribution info for new free and paid members in email alerts --- ghost/members-api/lib/repositories/member.js | 1 + .../lib/email-templates/new-free-signup.hbs | 3 ++ .../lib/email-templates/new-paid-started.hbs | 3 ++ ghost/staff-service/lib/emails.js | 8 ++- ghost/staff-service/lib/staff-service.js | 8 ++- .../staff-service/test/staff-service.test.js | 52 ++++++++++++++++++- 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/ghost/members-api/lib/repositories/member.js b/ghost/members-api/lib/repositories/member.js index d036b1a861..71771ee01a 100644 --- a/ghost/members-api/lib/repositories/member.js +++ b/ghost/members-api/lib/repositories/member.js @@ -1086,6 +1086,7 @@ module.exports = class MemberRepository { memberId: member.id, subscriptionId: subscriptionModel.get('id'), offerId: offerId, + attribution: data.attribution, batchId: options.batch_id }); this.dispatchEvent(activatedEvent, options); diff --git a/ghost/staff-service/lib/email-templates/new-free-signup.hbs b/ghost/staff-service/lib/email-templates/new-free-signup.hbs index e2bf815e48..3a54fb71b9 100644 --- a/ghost/staff-service/lib/email-templates/new-free-signup.hbs +++ b/ghost/staff-service/lib/email-templates/new-free-signup.hbs @@ -48,6 +48,9 @@ {{/if}}

Created on {{memberData.createdAt}}{{#if memberData.location}} • {{memberData.location}} {{/if}} + {{#if referrerSource}} +

+ {{/if}}

diff --git a/ghost/staff-service/lib/email-templates/new-paid-started.hbs b/ghost/staff-service/lib/email-templates/new-paid-started.hbs index 2caa2be825..c25ac916ed 100644 --- a/ghost/staff-service/lib/email-templates/new-paid-started.hbs +++ b/ghost/staff-service/lib/email-templates/new-paid-started.hbs @@ -48,6 +48,9 @@ {{/if}}

Subscription started on {{subscriptionData.startedOn}}

+ {{#if referrerSource}} + + {{/if}} diff --git a/ghost/staff-service/lib/emails.js b/ghost/staff-service/lib/emails.js index d36ca56c45..089b965a01 100644 --- a/ghost/staff-service/lib/emails.js +++ b/ghost/staff-service/lib/emails.js @@ -16,7 +16,9 @@ class StaffServiceEmails { this.registerPartials(); } - async notifyFreeMemberSignup(member, options) { + async notifyFreeMemberSignup({ + member, attribution + }, options) { const users = await this.models.User.getEmailAlertUsers('free-signup', options); for (const user of users) { @@ -27,6 +29,7 @@ class StaffServiceEmails { const templateData = { memberData, + referrerSource: attribution?.referrerSource, siteTitle: this.settingsCache.get('title'), siteUrl: this.urlUtils.getSiteUrl(), siteDomain: this.siteDomain, @@ -47,7 +50,7 @@ class StaffServiceEmails { } } - async notifyPaidSubscriptionStarted({member, subscription, offer, tier}, options = {}) { + async notifyPaidSubscriptionStarted({member, subscription, offer, tier, attribution}, options = {}) { const users = await this.models.User.getEmailAlertUsers('paid-started', options); for (const user of users) { @@ -72,6 +75,7 @@ class StaffServiceEmails { const templateData = { memberData, + referrerSource: attribution?.referrerSource, tierData, offerData, subscriptionData, diff --git a/ghost/staff-service/lib/staff-service.js b/ghost/staff-service/lib/staff-service.js index 8a41771b14..47fc642e71 100644 --- a/ghost/staff-service/lib/staff-service.js +++ b/ghost/staff-service/lib/staff-service.js @@ -98,13 +98,17 @@ class StaffService { }); if (type === MemberCreatedEvent && member.status === 'free') { - await this.emails.notifyFreeMemberSignup(member); + await this.emails.notifyFreeMemberSignup({ + member, + attribution: event?.data?.attribution + }); } else if (type === SubscriptionActivatedEvent) { await this.emails.notifyPaidSubscriptionStarted({ member, offer, tier, - subscription + subscription, + attribution: event?.data?.attribution }); } else if (type === SubscriptionCancelledEvent) { subscription.canceledAt = event.timestamp; diff --git a/ghost/staff-service/test/staff-service.test.js b/ghost/staff-service/test/staff-service.test.js index f628c12bbd..cc339ed3c9 100644 --- a/ghost/staff-service/test/staff-service.test.js +++ b/ghost/staff-service/test/staff-service.test.js @@ -377,7 +377,7 @@ describe('StaffService', function () { created_at: '2022-08-01T07:30:39.882Z' }; - await service.emails.notifyFreeMemberSignup(member, options); + await service.emails.notifyFreeMemberSignup({member}, options); mailStub.calledOnce.should.be.true(); testCommonMailData(stubs); @@ -402,7 +402,7 @@ describe('StaffService', function () { created_at: '2022-08-01T07:30:39.882Z' }; - await service.emails.notifyFreeMemberSignup(member, options); + await service.emails.notifyFreeMemberSignup({member}, options); mailStub.calledOnce.should.be.true(); testCommonMailData(stubs); @@ -418,6 +418,39 @@ describe('StaffService', function () { sinon.match.has('html', sinon.match('Created on 1 Aug 2022 • France')) ).should.be.true(); }); + + it('sends free member signup alert with attribution', async function () { + const member = { + name: 'Ghost', + email: 'member@example.com', + id: 'abc', + geolocation: '{"country": "France"}', + created_at: '2022-08-01T07:30:39.882Z' + }; + + const attribution = { + referrerSource: 'Twitter' + }; + + await service.emails.notifyFreeMemberSignup({member, attribution}, options); + + mailStub.calledOnce.should.be.true(); + testCommonMailData(stubs); + getEmailAlertUsersStub.calledWith('free-signup').should.be.true(); + + mailStub.calledWith( + sinon.match({subject: '🥳 Free member signup: Ghost'}) + ).should.be.true(); + mailStub.calledWith( + sinon.match.has('html', sinon.match('🥳 Free member signup: Ghost')) + ).should.be.true(); + mailStub.calledWith( + sinon.match.has('html', sinon.match('Created on 1 Aug 2022 • France')) + ).should.be.true(); + mailStub.calledWith( + sinon.match.has('html', sinon.match('Source: Twitter')) + ).should.be.true(); + }); }); describe('notifyPaidSubscriptionStart', function () { @@ -451,6 +484,21 @@ describe('StaffService', function () { }; }); + it('sends paid subscription start alert with attribution', async function () { + const attribution = { + referrerSource: 'Twitter' + }; + await service.emails.notifyPaidSubscriptionStarted({member, offer: null, tier, subscription, attribution}, options); + + mailStub.calledOnce.should.be.true(); + testCommonPaidSubMailData({...stubs, member}); + + // check attribution text + mailStub.calledWith( + sinon.match.has('html', sinon.match('Source: Twitter')) + ).should.be.true(); + }); + it('sends paid subscription start alert without offer', async function () { await service.emails.notifyPaidSubscriptionStarted({member, offer: null, tier, subscription}, options);