Skip to content

Commit 0683c5f

Browse files
committed
Added paid member welcome email sending
1 parent 259fee3 commit 0683c5f

File tree

3 files changed

+473
-1
lines changed

3 files changed

+473
-1
lines changed

ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,10 +972,35 @@ module.exports = class MemberRepository {
972972
options.batch_id = ObjectId().toHexString();
973973
}
974974

975+
const context = options?.context || {};
976+
const source = this._resolveContextSource(context);
977+
const shouldSendPaidWelcomeEmail = config.get('memberWelcomeEmailTestInbox') && WELCOME_EMAIL_SOURCES.includes(source);
978+
let isPaidWelcomeEmailActive = false;
979+
if (shouldSendPaidWelcomeEmail && this._AutomatedEmail) {
980+
const paidWelcomeEmail = await this._AutomatedEmail.findOne({slug: MEMBER_WELCOME_EMAIL_SLUGS.paid}, options);
981+
isPaidWelcomeEmailActive = paidWelcomeEmail && paidWelcomeEmail.get('lexical') && paidWelcomeEmail.get('status') === 'active';
982+
}
983+
975984
const memberModel = await this._Member.findOne({
976985
id: data.id
977986
}, {...options, forUpdate: true});
978987

988+
const queuePaidWelcomeEmail = async (subscriptionModel) => {
989+
await this._Outbox.add({
990+
id: ObjectId().toHexString(),
991+
event_type: MemberCreatedEvent.name,
992+
payload: JSON.stringify({
993+
memberId: memberModel.id,
994+
email: memberModel.get('email'),
995+
name: memberModel.get('name'),
996+
source,
997+
timestamp: subscriptionModel.get('created_at'),
998+
memberStatus: 'paid'
999+
})
1000+
}, options);
1001+
this.dispatchEvent(StartOutboxProcessingEvent.create({memberId: memberModel.id}), options);
1002+
};
1003+
9791004
const memberStripeCustomerModel = await memberModel.related('stripeCustomers').query({
9801005
where: {
9811006
customer_id: data.subscription.customer
@@ -1190,6 +1215,9 @@ module.exports = class MemberRepository {
11901215
batchId: options.batch_id
11911216
});
11921217
this.dispatchEvent(subscriptionActivatedEvent, options);
1218+
if (isPaidWelcomeEmailActive) {
1219+
await queuePaidWelcomeEmail(updatedStripeCustomerSubscriptionModel);
1220+
}
11931221
}
11941222

11951223
// Dispatch cancellation event, i.e. send paid cancellation staff notification, if:
@@ -1278,6 +1306,9 @@ module.exports = class MemberRepository {
12781306
batchId: options.batch_id
12791307
});
12801308
this.dispatchEvent(subscriptionActivatedEvent, options);
1309+
if (isPaidWelcomeEmailActive) {
1310+
await queuePaidWelcomeEmail(newStripeCustomerSubscriptionModel);
1311+
}
12811312
}
12821313
}
12831314

ghost/core/test/integration/services/member-welcome-emails.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ describe('Member Welcome Emails Integration', function () {
4646
lexical,
4747
created_at: new Date()
4848
});
49+
50+
await db.knex('automated_emails').insert({
51+
id: ObjectId().toHexString(),
52+
status: 'active',
53+
name: 'Paid Member Welcome Email',
54+
slug: MEMBER_WELCOME_EMAIL_SLUGS.paid,
55+
subject: 'Welcome paid member to {{site.title}}',
56+
lexical,
57+
created_at: new Date()
58+
});
4959
});
5060

5161
afterEach(async function () {
@@ -235,6 +245,54 @@ describe('Member Welcome Emails Integration', function () {
235245
assert.equal(entriesAfterJob.length, 1);
236246
assert.ok(entriesAfterJob.models[0].get('message'));
237247
});
248+
249+
it('does not send email when paid template is inactive but entry has memberStatus paid', async function () {
250+
await db.knex('automated_emails')
251+
.where('slug', MEMBER_WELCOME_EMAIL_SLUGS.paid)
252+
.update({status: 'inactive'});
253+
254+
await models.Outbox.add({
255+
event_type: 'MemberCreatedEvent',
256+
payload: JSON.stringify({
257+
memberId: 'paid_member_1',
258+
email: 'paid-inactive@example.com',
259+
name: 'Paid Inactive Template Member',
260+
memberStatus: 'paid'
261+
}),
262+
status: OUTBOX_STATUSES.PENDING
263+
});
264+
265+
await scheduleInlineJob();
266+
267+
assert.equal(mailService.GhostMailer.prototype.send.callCount, 0);
268+
269+
const entriesAfterJob = await models.Outbox.findAll();
270+
assert.equal(entriesAfterJob.length, 1);
271+
assert.ok(entriesAfterJob.models[0].get('message').includes('inactive'));
272+
});
273+
274+
it('does not send email when no paid template exists but entry has memberStatus paid', async function () {
275+
await db.knex('automated_emails').where('slug', MEMBER_WELCOME_EMAIL_SLUGS.paid).del();
276+
277+
await models.Outbox.add({
278+
event_type: 'MemberCreatedEvent',
279+
payload: JSON.stringify({
280+
memberId: 'paid_member_2',
281+
email: 'paid-notemplate@example.com',
282+
name: 'Paid No Template Member',
283+
memberStatus: 'paid'
284+
}),
285+
status: OUTBOX_STATUSES.PENDING
286+
});
287+
288+
await scheduleInlineJob();
289+
290+
assert.equal(mailService.GhostMailer.prototype.send.callCount, 0);
291+
292+
const entriesAfterJob = await models.Outbox.findAll();
293+
assert.equal(entriesAfterJob.length, 1);
294+
assert.ok(entriesAfterJob.models[0].get('message'));
295+
});
238296
});
239297
});
240298

0 commit comments

Comments
 (0)