diff --git a/ghost/members-importer/lib/MembersCSVImporter.js b/ghost/members-importer/lib/MembersCSVImporter.js index 66fc4e353c..2e65c7f618 100644 --- a/ghost/members-importer/lib/MembersCSVImporter.js +++ b/ghost/members-importer/lib/MembersCSVImporter.js @@ -138,11 +138,24 @@ module.exports = class MembersCSVImporter { }; const existingMember = await membersRepository.get({email: memberValues.email}, { ...options, - withRelated: ['labels'] + withRelated: ['labels', 'newsletters'] }); let member; if (existingMember) { const existingLabels = existingMember.related('labels') ? existingMember.related('labels').toJSON() : []; + const existingNewsletters = existingMember.related('newsletters'); + + // Preserve member's existing newsletter subscription preferences + if (existingNewsletters.length > 0 && memberValues.subscribed) { + memberValues.newsletters = existingNewsletters.toJSON(); + } + + // If member does not have any subscriptions, assume they have previously unsubscribed + // and do not re-subscribe them + if (!existingNewsletters.length && memberValues.subscribed) { + memberValues.subscribed = false; + } + member = await membersRepository.update({ ...memberValues, labels: existingLabels.concat(memberValues.labels) diff --git a/ghost/members-importer/test/importer.test.js b/ghost/members-importer/test/importer.test.js index 01bb45cf6e..093d3b927a 100644 --- a/ghost/members-importer/test/importer.test.js +++ b/ghost/members-importer/test/importer.test.js @@ -343,5 +343,89 @@ describe('Importer', function () { assert.equal(result.imported, 1); assert.equal(result.errors.length, 0); }); + + it ('respects existing member newsletter subscription preferences', async function () { + const importer = buildMockImporterInstance(); + + const newsletters = [ + {id: 'newsletter_1'}, + {id: 'newsletter_2'} + ]; + + const newslettersCollection = { + length: newsletters.length, + toJSON: sinon.stub().returns(newsletters) + }; + + const member = { + related: sinon.stub() + }; + + member.related.withArgs('labels').returns(null); + member.related.withArgs('newsletters').returns(newslettersCollection); + + membersRepositoryStub.get = sinon.stub(); + + membersRepositoryStub.get + .withArgs({email: 'jbloggs@example.com'}) + .resolves(member); + + await importer.perform(`${csvPath}/subscribed-to-emails-header.csv`, defaultAllowedFields); + + assert.deepEqual(membersRepositoryStub.update.args[0][0].newsletters, newsletters); + }); + + it ('does not add subscriptions for existing member when they do not have any subscriptions', async function () { + const importer = buildMockImporterInstance(); + + const member = { + related: sinon.stub() + }; + + member.related.withArgs('labels').returns(null); + member.related.withArgs('newsletters').returns({length: 0}); + + membersRepositoryStub.get = sinon.stub(); + + membersRepositoryStub.get + .withArgs({email: 'jbloggs@example.com'}) + .resolves(member); + + await importer.perform(`${csvPath}/subscribed-to-emails-header.csv`, defaultAllowedFields); + + assert.deepEqual(membersRepositoryStub.update.args[0][0].subscribed, false); + }); + + it ('removes existing member newsletter subscriptions when set to not be subscribed', async function () { + const importer = buildMockImporterInstance(); + + const newsletters = [ + {id: 'newsletter_1'}, + {id: 'newsletter_2'} + ]; + + const newslettersCollection = { + length: newsletters.length, + toJSON: sinon.stub().returns(newsletters) + }; + + const member = { + related: sinon.stub() + }; + + member.related.withArgs('labels').returns(null); + member.related.withArgs('newsletters').returns(newslettersCollection); + + membersRepositoryStub.get = sinon.stub(); + + membersRepositoryStub.get + .withArgs({email: 'test@example.com'}) + .resolves(member); + + await importer.perform(`${csvPath}/subscribed-to-emails-header.csv`, defaultAllowedFields); + + assert.equal(membersRepositoryStub.update.args[0][0].subscribed, false); + assert.equal(membersRepositoryStub.update.args[0][0].newsletters, undefined); + }); }); });