mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-27 10:42:45 +03:00
🐛 Fixed maintaining archived newsletter subscriptions for members (#16375)
refs #16355 -archived newsletters will no longer be unsubscribed when saving member -fixed bug with initialMember load -fixed errors in unit tests
This commit is contained in:
parent
4184b279d2
commit
cb05fae5a3
@ -401,6 +401,199 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Archived newsletter subscriptions are maintained when updating member data 1: [body] 1`] = `
|
||||
Object {
|
||||
"members": Array [
|
||||
Object {
|
||||
"attribution": Object {
|
||||
"id": "618ba1ffbe2896088840a6e3",
|
||||
"referrer_medium": null,
|
||||
"referrer_source": "Direct",
|
||||
"referrer_url": null,
|
||||
"title": "Short and Sweet",
|
||||
"type": "post",
|
||||
"url": "http://127.0.0.1:2369/short-and-sweet/",
|
||||
},
|
||||
"avatar_image": null,
|
||||
"comped": false,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"email": "vip@test.com",
|
||||
"email_count": 0,
|
||||
"email_open_rate": null,
|
||||
"email_opened_count": 0,
|
||||
"email_suppression": Object {
|
||||
"info": null,
|
||||
"suppressed": false,
|
||||
},
|
||||
"geolocation": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"labels": Any<Array>,
|
||||
"last_seen_at": null,
|
||||
"name": "new name",
|
||||
"newsletters": Array [
|
||||
Object {
|
||||
"body_font_category": "serif",
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"feedback_enabled": false,
|
||||
"footer_content": null,
|
||||
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Weekly newsletter",
|
||||
"sender_email": "jamie@example.com",
|
||||
"sender_name": "Jamie",
|
||||
"sender_reply_to": "newsletter",
|
||||
"show_badge": true,
|
||||
"show_feature_image": true,
|
||||
"show_header_icon": true,
|
||||
"show_header_name": true,
|
||||
"show_header_title": true,
|
||||
"slug": "weekly-newsletter",
|
||||
"sort_order": 2,
|
||||
"status": "active",
|
||||
"subscribe_on_signup": true,
|
||||
"title_alignment": "center",
|
||||
"title_font_category": "serif",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
],
|
||||
"note": null,
|
||||
"status": "free",
|
||||
"subscribed": true,
|
||||
"subscriptions": Any<Array>,
|
||||
"tiers": Array [],
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Archived newsletter subscriptions are maintained when updating member data 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "1576",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Archived newsletter subscriptions are maintained when updating member data 3: [body] 1`] = `
|
||||
Object {
|
||||
"members": Array [
|
||||
Object {
|
||||
"attribution": Object {
|
||||
"id": null,
|
||||
"referrer_medium": "Ghost Admin",
|
||||
"referrer_source": "Created manually",
|
||||
"referrer_url": null,
|
||||
"title": null,
|
||||
"type": "url",
|
||||
"url": null,
|
||||
},
|
||||
"avatar_image": null,
|
||||
"comped": false,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"email": "fgfdgdfgdf@test.com",
|
||||
"email_count": 0,
|
||||
"email_open_rate": null,
|
||||
"email_opened_count": 0,
|
||||
"email_suppression": Object {
|
||||
"info": null,
|
||||
"suppressed": false,
|
||||
},
|
||||
"geolocation": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"labels": Any<Array>,
|
||||
"last_seen_at": null,
|
||||
"name": "test newsletter",
|
||||
"newsletters": Array [
|
||||
Object {
|
||||
"body_font_category": "serif",
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"feedback_enabled": false,
|
||||
"footer_content": null,
|
||||
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Daily newsletter",
|
||||
"sender_email": "jamie@example.com",
|
||||
"sender_name": "Jamie",
|
||||
"sender_reply_to": "newsletter",
|
||||
"show_badge": true,
|
||||
"show_feature_image": true,
|
||||
"show_header_icon": true,
|
||||
"show_header_name": true,
|
||||
"show_header_title": true,
|
||||
"slug": "daily-newsletter",
|
||||
"sort_order": 1,
|
||||
"status": "active",
|
||||
"subscribe_on_signup": false,
|
||||
"title_alignment": "center",
|
||||
"title_font_category": "serif",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
Object {
|
||||
"body_font_category": "serif",
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"feedback_enabled": false,
|
||||
"footer_content": null,
|
||||
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Weekly newsletter",
|
||||
"sender_email": "jamie@example.com",
|
||||
"sender_name": "Jamie",
|
||||
"sender_reply_to": "newsletter",
|
||||
"show_badge": true,
|
||||
"show_feature_image": true,
|
||||
"show_header_icon": true,
|
||||
"show_header_name": true,
|
||||
"show_header_title": true,
|
||||
"slug": "weekly-newsletter",
|
||||
"sort_order": 2,
|
||||
"status": "active",
|
||||
"subscribe_on_signup": true,
|
||||
"title_alignment": "center",
|
||||
"title_font_category": "serif",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
],
|
||||
"note": null,
|
||||
"status": "free",
|
||||
"subscribed": true,
|
||||
"subscriptions": Any<Array>,
|
||||
"tiers": Array [],
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Archived newsletter subscriptions are maintained when updating member data 4: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "2122",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Bulk operations Can bulk delete a label from members 1: [body] 1`] = `
|
||||
Object {
|
||||
"bulk": Object {
|
||||
@ -5203,7 +5396,7 @@ Object {
|
||||
"errors": Array [
|
||||
Object {
|
||||
"code": null,
|
||||
"context": "Resource could not be found.",
|
||||
"context": Any<String>,
|
||||
"details": null,
|
||||
"ghostErrorCode": null,
|
||||
"help": null,
|
||||
@ -5220,7 +5413,7 @@ exports[`Members API Cannot edit a non-existing id 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "257",
|
||||
"content-length": "275",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
@ -5992,6 +6185,144 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Updating member data without newsletters does not change newsletters 1: [body] 1`] = `
|
||||
Object {
|
||||
"members": Array [
|
||||
Object {
|
||||
"attribution": Object {
|
||||
"id": "618ba1ffbe2896088840a6e3",
|
||||
"referrer_medium": null,
|
||||
"referrer_source": "Direct",
|
||||
"referrer_url": null,
|
||||
"title": "Short and Sweet",
|
||||
"type": "post",
|
||||
"url": "http://127.0.0.1:2369/short-and-sweet/",
|
||||
},
|
||||
"avatar_image": null,
|
||||
"comped": false,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"email": "vip@test.com",
|
||||
"email_count": 0,
|
||||
"email_open_rate": null,
|
||||
"email_opened_count": 0,
|
||||
"email_suppression": Object {
|
||||
"info": null,
|
||||
"suppressed": false,
|
||||
},
|
||||
"geolocation": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"labels": Any<Array>,
|
||||
"last_seen_at": null,
|
||||
"name": "new name",
|
||||
"newsletters": Array [
|
||||
Object {
|
||||
"body_font_category": "serif",
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"feedback_enabled": false,
|
||||
"footer_content": null,
|
||||
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Weekly newsletter",
|
||||
"sender_email": "jamie@example.com",
|
||||
"sender_name": "Jamie",
|
||||
"sender_reply_to": "newsletter",
|
||||
"show_badge": true,
|
||||
"show_feature_image": true,
|
||||
"show_header_icon": true,
|
||||
"show_header_name": true,
|
||||
"show_header_title": true,
|
||||
"slug": "weekly-newsletter",
|
||||
"sort_order": 2,
|
||||
"status": "active",
|
||||
"subscribe_on_signup": true,
|
||||
"title_alignment": "center",
|
||||
"title_font_category": "serif",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
],
|
||||
"note": null,
|
||||
"status": "free",
|
||||
"subscribed": true,
|
||||
"subscriptions": Any<Array>,
|
||||
"tiers": Array [],
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Updating member data without newsletters does not change newsletters 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "1576",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Updating newsletter subscriptions does not unsubscribe member from archived newsletter 1: [body] 1`] = `
|
||||
Object {
|
||||
"members": Array [
|
||||
Object {
|
||||
"attribution": Object {
|
||||
"id": "618ba1ffbe2896088840a6e3",
|
||||
"referrer_medium": null,
|
||||
"referrer_source": "Direct",
|
||||
"referrer_url": null,
|
||||
"title": "Short and Sweet",
|
||||
"type": "post",
|
||||
"url": "http://127.0.0.1:2369/short-and-sweet/",
|
||||
},
|
||||
"avatar_image": null,
|
||||
"comped": false,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"email": "vip@test.com",
|
||||
"email_count": 0,
|
||||
"email_open_rate": null,
|
||||
"email_opened_count": 0,
|
||||
"email_suppression": Object {
|
||||
"info": null,
|
||||
"suppressed": false,
|
||||
},
|
||||
"geolocation": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"labels": Any<Array>,
|
||||
"last_seen_at": null,
|
||||
"name": "new name",
|
||||
"newsletters": Any<Array>,
|
||||
"note": null,
|
||||
"status": "free",
|
||||
"subscribed": false,
|
||||
"subscriptions": Any<Array>,
|
||||
"tiers": Array [],
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API Updating newsletter subscriptions does not unsubscribe member from archived newsletter 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "853",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Members API without Stripe Add should fail when comped flag is passed in but Stripe is not enabled 1: [body] 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
|
@ -4,7 +4,6 @@ const ObjectId = require('bson-objectid').default;
|
||||
|
||||
const assert = require('assert');
|
||||
const nock = require('nock');
|
||||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../utils');
|
||||
const configUtils = require('../../utils/configUtils');
|
||||
@ -1764,7 +1763,8 @@ describe('Members API', function () {
|
||||
.expectStatus(404)
|
||||
.matchBodySnapshot({
|
||||
errors: [{
|
||||
id: anyUuid
|
||||
id: anyUuid,
|
||||
context: anyString
|
||||
}]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
@ -2454,6 +2454,7 @@ describe('Members API', function () {
|
||||
});
|
||||
|
||||
const memberId = body.members[0].id;
|
||||
|
||||
const editedMember = {
|
||||
subscribed: true // no change
|
||||
};
|
||||
@ -2484,6 +2485,97 @@ describe('Members API', function () {
|
||||
assert.ok(changedMember.newsletters.find(n => n.id === testUtils.DataGenerator.Content.newsletters[1].id), 'The member is still subscribed for the newsletter it subscribed to');
|
||||
});
|
||||
|
||||
it('Updating member data without newsletters does not change newsletters', async function () {
|
||||
// check that this newsletter is archived, or this test would not make sense
|
||||
const archivedNewsletterId = testUtils.DataGenerator.Content.newsletters[2].id;
|
||||
const archivedNewsletter = await models.Newsletter.findOne({id: archivedNewsletterId}, {require: true});
|
||||
assert.equal(archivedNewsletter.get('status'), 'archived', 'This test expects the newsletter to be archived');
|
||||
|
||||
const member = await models.Member.findOne({id: testUtils.DataGenerator.Content.members[5].id}, {withRelated: ['newsletters']});
|
||||
const memberNewsletters = member.related('newsletters').models;
|
||||
assert.equal(memberNewsletters[1].id, archivedNewsletterId, 'This test expects the member to be subscribed to an archived newsletter');
|
||||
assert.equal(memberNewsletters.length, 2, 'This test expects the member to have two newsletter subscriptions');
|
||||
|
||||
const memberId = member.get('id');
|
||||
const editedMember = {
|
||||
id: memberId,
|
||||
name: 'new name'
|
||||
};
|
||||
|
||||
// edit member
|
||||
const {body} = await agent
|
||||
.put(`/members/${memberId}`)
|
||||
.body({members: [editedMember]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
members: [{
|
||||
id: anyObjectId,
|
||||
uuid: anyUuid,
|
||||
created_at: anyISODateTime,
|
||||
updated_at: anyISODateTime,
|
||||
subscriptions: anyArray,
|
||||
labels: anyArray,
|
||||
newsletters: Array(1).fill(newsletterSnapshot)
|
||||
}]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
|
||||
const changedMember = body.members[0];
|
||||
assert.equal(changedMember.newsletters.length, 1); // the api only returns active newsletters
|
||||
assert.ok(changedMember.newsletters.find(n => n.id === testUtils.DataGenerator.Content.newsletters[1].id), 'The member is still subscribed to an active newsletter');
|
||||
|
||||
const changedMemberFromDb = await models.Member.findOne({id: testUtils.DataGenerator.Content.members[5].id}, {withRelated: ['newsletters']});
|
||||
assert.ok(changedMemberFromDb.related('newsletters').models.find(n => n.id === testUtils.DataGenerator.Content.newsletters[2].id), 'The member is still subscribed to the archived newsletter it subscribed to');
|
||||
});
|
||||
|
||||
it('Updating newsletter subscriptions does not unsubscribe member from archived newsletter', async function () {
|
||||
// check that this newsletter is archived, or this test would not make sense
|
||||
const archivedNewsletterId = testUtils.DataGenerator.Content.newsletters[2].id;
|
||||
const archivedNewsletter = await models.Newsletter.findOne({id: archivedNewsletterId}, {require: true});
|
||||
assert.equal(archivedNewsletter.get('status'), 'archived', 'This test expects the newsletter to be archived');
|
||||
|
||||
const member = await models.Member.findOne({id: testUtils.DataGenerator.Content.members[5].id}, {withRelated: ['newsletters']});
|
||||
const memberNewsletters = member.related('newsletters').models;
|
||||
assert.equal(memberNewsletters[1].id, archivedNewsletterId, 'This test expects the member to be subscribed to an archived newsletter');
|
||||
assert.equal(memberNewsletters.length, 2, 'This test expects the member to have two newsletter subscriptions');
|
||||
|
||||
// remove active newsletter subscriptions
|
||||
const memberId = member.get('id');
|
||||
const editedMember = {
|
||||
newsletters: []
|
||||
};
|
||||
|
||||
// edit member
|
||||
const {body} = await agent
|
||||
.put(`/members/${memberId}`)
|
||||
.body({members: [editedMember]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
members: [{
|
||||
id: anyObjectId,
|
||||
uuid: anyUuid,
|
||||
created_at: anyISODateTime,
|
||||
updated_at: anyISODateTime,
|
||||
subscriptions: anyArray,
|
||||
labels: anyArray,
|
||||
newsletters: anyArray
|
||||
}]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
|
||||
const changedMember = body.members[0];
|
||||
assert.equal(changedMember.newsletters.length, 0); // the api only returns active newsletters, so this member should have none
|
||||
|
||||
const changedMemberFromDb = await models.Member.findOne({id: testUtils.DataGenerator.Content.members[5].id}, {withRelated: ['newsletters']});
|
||||
assert.ok(changedMemberFromDb.related('newsletters').models.find(n => n.id === testUtils.DataGenerator.Content.newsletters[2].id), 'The member is still subscribed to the archived newsletter it subscribed to');
|
||||
});
|
||||
|
||||
it('Can add and send a signup confirmation email (old)', async function () {
|
||||
const filteredNewsletters = newsletters.filter(n => n.get('subscribe_on_signup'));
|
||||
filteredNewsletters.length.should.be.greaterThan(0, 'For this test to work, we need at least one newsletter fixture with subscribe_on_signup = true');
|
||||
|
@ -425,28 +425,27 @@ module.exports = class MemberRepository {
|
||||
|
||||
// Determine if we need to fetch the initial member with relations
|
||||
const needsProducts = this._stripeAPIService.configured && data.products;
|
||||
|
||||
// only update newsletters if we are receiving newsletter data
|
||||
const needsNewsletters = memberData.newsletters || typeof memberData.subscribed === 'boolean';
|
||||
|
||||
// Build list for withRelated
|
||||
const requiredRelations = [];
|
||||
if (needsProducts) {
|
||||
requiredRelations.push('products');
|
||||
}
|
||||
if (needsNewsletters) {
|
||||
requiredRelations.push('newsletters');
|
||||
}
|
||||
if (needsProducts) {
|
||||
requiredRelations.push('products');
|
||||
}
|
||||
|
||||
// Fetch the member with relations if required
|
||||
let initialMember = null;
|
||||
if (requiredRelations.length > 0) {
|
||||
initialMember = await this._Member.findOne({
|
||||
id: options.id
|
||||
}, {...sharedOptions, withRelated: requiredRelations, require: false});
|
||||
// Fetch the member
|
||||
let initialMember = await this._Member.findOne({
|
||||
id: options.id
|
||||
}, {...sharedOptions, withRelated: requiredRelations, require: false});
|
||||
|
||||
// Make sure we throw the right error if it doesn't exist
|
||||
if (!initialMember) {
|
||||
throw new NotFoundError({message: tpl(messages.memberNotFound, {id: options.id})});
|
||||
}
|
||||
// Make sure we throw the right error if it doesn't exist
|
||||
if (!initialMember) {
|
||||
throw new NotFoundError({message: tpl(messages.memberNotFound, {id: options.id})});
|
||||
}
|
||||
|
||||
// Throw error if email is invalid and it's been changed
|
||||
@ -541,22 +540,33 @@ module.exports = class MemberRepository {
|
||||
const existingNewsletters = initialMember.related('newsletters').models;
|
||||
|
||||
// This maps the old subscribed property to the new newsletters field
|
||||
if (!memberData.newsletters) {
|
||||
if (memberData.subscribed === false) {
|
||||
memberData.newsletters = [];
|
||||
} else if (memberData.subscribed === true && !existingNewsletters.find(n => n.get('status') === 'active')) {
|
||||
const browseOptions = _.pick(options, 'transacting');
|
||||
memberData.newsletters = await this.getSubscribeOnSignupNewsletters(browseOptions);
|
||||
}
|
||||
if (memberData.subscribed === false) {
|
||||
memberData.newsletters = [];
|
||||
} else if (memberData.subscribed === true && !existingNewsletters.find(n => n.get('status') === 'active')) {
|
||||
const browseOptions = _.pick(options, 'transacting');
|
||||
memberData.newsletters = await this.getSubscribeOnSignupNewsletters(browseOptions);
|
||||
}
|
||||
|
||||
// only ever populated with active newsletters - never archived ones
|
||||
if (memberData.newsletters) {
|
||||
const existingNewsletterIds = existingNewsletters.map(newsletter => newsletter.id);
|
||||
const existingNewsletterIds = existingNewsletters
|
||||
.filter(newsletter => newsletter.attributes.status !== 'archived')
|
||||
.map(newsletter => newsletter.id);
|
||||
const incomingNewsletterIds = memberData.newsletters.map(newsletter => newsletter.id);
|
||||
|
||||
newslettersToAdd = _.differenceWith(incomingNewsletterIds, existingNewsletterIds);
|
||||
newslettersToRemove = _.differenceWith(existingNewsletterIds, incomingNewsletterIds);
|
||||
}
|
||||
|
||||
// need to maintain archived newsletters; these are not exposed by the members api
|
||||
const archivedNewsletters = existingNewsletters.filter(n => n.attributes.status === 'archived');
|
||||
|
||||
if (archivedNewsletters.length > 0) {
|
||||
// if (!memberData.newsletters) {
|
||||
// memberData.newsletters = [];
|
||||
// }
|
||||
archivedNewsletters.forEach(n => memberData.newsletters.push(n));
|
||||
}
|
||||
}
|
||||
|
||||
const member = await this._Member.edit({
|
||||
|
@ -1,20 +1,29 @@
|
||||
const assert = require('assert');
|
||||
const sinon = require('sinon');
|
||||
const should = require('should');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const MemberRepository = require('../../../../lib/repositories/member');
|
||||
const {SubscriptionCreatedEvent} = require('@tryghost/member-events');
|
||||
|
||||
const mockOfferRedemption = {
|
||||
add: sinon.stub()
|
||||
};
|
||||
|
||||
describe('MemberRepository', function () {
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('#isComplimentarySubscription', function () {
|
||||
it('Does not error when subscription.plan is null', function () {
|
||||
const repo = new MemberRepository({});
|
||||
const repo = new MemberRepository({OfferRedemption: mockOfferRedemption});
|
||||
repo.isComplimentarySubscription({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resolveContextSource', function (){
|
||||
it('Maps context to source', function (){
|
||||
const repo = new MemberRepository({});
|
||||
const repo = new MemberRepository({OfferRedemption: mockOfferRedemption});
|
||||
|
||||
let source = repo._resolveContextSource({
|
||||
import: true
|
||||
@ -84,7 +93,8 @@ describe('MemberRepository', function () {
|
||||
stripeAPIService: {
|
||||
configured: true
|
||||
},
|
||||
productRepository
|
||||
productRepository,
|
||||
OfferRedemption: mockOfferRedemption
|
||||
});
|
||||
|
||||
try {
|
||||
@ -114,7 +124,8 @@ describe('MemberRepository', function () {
|
||||
stripeAPIService: {
|
||||
configured: true
|
||||
},
|
||||
productRepository
|
||||
productRepository,
|
||||
OfferRedemption: mockOfferRedemption
|
||||
});
|
||||
|
||||
try {
|
||||
@ -135,7 +146,6 @@ describe('MemberRepository', function () {
|
||||
|
||||
describe('linkSubscription', function (){
|
||||
let Member;
|
||||
let notifySpy;
|
||||
let MemberPaidSubscriptionEvent;
|
||||
let StripeCustomerSubscription;
|
||||
let MemberProductEvent;
|
||||
@ -144,9 +154,15 @@ describe('MemberRepository', function () {
|
||||
let offerRepository;
|
||||
let labsService;
|
||||
let subscriptionData;
|
||||
let notifySpy;
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
notifySpy = sinon.spy();
|
||||
|
||||
subscriptionData = {
|
||||
id: 'sub_123',
|
||||
customer: 'cus_123',
|
||||
@ -238,7 +254,8 @@ describe('MemberRepository', function () {
|
||||
MemberProductEvent,
|
||||
productRepository,
|
||||
labsService,
|
||||
Member
|
||||
Member,
|
||||
OfferRedemption: mockOfferRedemption
|
||||
});
|
||||
|
||||
sinon.stub(repo, 'getSubscriptionByStripeID').resolves(null);
|
||||
@ -266,7 +283,8 @@ describe('MemberRepository', function () {
|
||||
productRepository,
|
||||
offerRepository,
|
||||
labsService,
|
||||
Member
|
||||
Member,
|
||||
OfferRedemption: mockOfferRedemption
|
||||
});
|
||||
|
||||
sinon.stub(repo, 'getSubscriptionByStripeID').resolves(null);
|
||||
@ -292,9 +310,5 @@ describe('MemberRepository', function () {
|
||||
return false;
|
||||
})).should.be.true();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user