3c5cf21274
refs: https://github.com/TryGhost/Toolbox/issues/166 New package handles the email verification workflow to prevent spammers. It currently handles MembersSubscribeEvent to detect potential abuse of the API to add members, and exposes methods for checking the threshold / starting the verification process for use by other areas of the code (at the moment - just member imports). The import package no longer needs to handle anything related to verification since it can be handled in the wrapper function in Ghost, and the API package doesn't need to do anything other than dispatch the new event.
146 lines
4.5 KiB
JavaScript
146 lines
4.5 KiB
JavaScript
// Switch these lines once there are useful utils
|
|
// const testUtils = require('./utils');
|
|
require('./utils');
|
|
|
|
const fs = require('fs-extra');
|
|
const path = require('path');
|
|
const sinon = require('sinon');
|
|
const MembersCSVImporter = require('..');
|
|
|
|
const csvPath = path.join(__dirname, '/fixtures/');
|
|
|
|
describe('Importer', function () {
|
|
let fsWriteSpy;
|
|
|
|
beforeEach(function () {
|
|
fsWriteSpy = sinon.spy(fs, 'writeFile');
|
|
});
|
|
|
|
afterEach(function () {
|
|
const writtenFile = fsWriteSpy.args[0][0];
|
|
|
|
if (writtenFile) {
|
|
fs.removeSync(writtenFile);
|
|
}
|
|
|
|
sinon.restore();
|
|
});
|
|
|
|
describe('process', function () {
|
|
it('should import a CSV file', async function () {
|
|
const defaultProduct = {
|
|
id: 'default_product_id'
|
|
};
|
|
|
|
const membersApi = {
|
|
productRepository: {
|
|
list: async () => {
|
|
return {
|
|
data: [defaultProduct]
|
|
};
|
|
}
|
|
},
|
|
members: {
|
|
get: async () => {
|
|
return null;
|
|
},
|
|
create: async (row) => {
|
|
return row;
|
|
}
|
|
}
|
|
};
|
|
|
|
const knexStub = {
|
|
transaction: sinon.stub().resolves({
|
|
rollback: () => {},
|
|
commit: () => {}
|
|
})
|
|
};
|
|
|
|
const LabelModelStub = {
|
|
findOne: sinon.stub().resolves(null)
|
|
};
|
|
|
|
const importer = new MembersCSVImporter({
|
|
storagePath: csvPath,
|
|
getTimezone: sinon.stub().returns('UTC'),
|
|
getMembersApi: () => membersApi,
|
|
sendEmail: sinon.stub(),
|
|
isSet: sinon.stub(),
|
|
addJob: sinon.stub(),
|
|
knex: knexStub,
|
|
urlFor: sinon.stub()
|
|
});
|
|
|
|
const result = await importer.process({
|
|
pathToCSV: `${csvPath}/single-column-with-header.csv`,
|
|
headerMapping: {},
|
|
importLabel: {
|
|
name: 'test import'
|
|
},
|
|
user: {
|
|
email: 'test@example.com'
|
|
},
|
|
LabelModel: LabelModelStub
|
|
});
|
|
|
|
should.exist(result.meta);
|
|
should.exist(result.meta.stats);
|
|
should.exist(result.meta.stats.imported);
|
|
result.meta.stats.imported.should.equal(2);
|
|
|
|
should.exist(result.meta.stats.invalid);
|
|
should.equal(result.meta.import_label, null);
|
|
|
|
should.exist(result.meta.originalImportSize);
|
|
result.meta.originalImportSize.should.equal(2);
|
|
|
|
fsWriteSpy.calledOnce.should.be.true();
|
|
});
|
|
});
|
|
|
|
describe('prepare', function () {
|
|
it('processes a basic valid import file for members', async function () {
|
|
const membersImporter = new MembersCSVImporter({
|
|
storagePath: csvPath,
|
|
getTimezone: sinon.stub().returns('UTC'),
|
|
getMembersApi: sinon.stub(),
|
|
sendEmail: sinon.stub(),
|
|
isSet: sinon.stub(),
|
|
addJob: sinon.stub(),
|
|
knex: sinon.stub(),
|
|
urlFor: sinon.stub()
|
|
});
|
|
|
|
const result = await membersImporter.prepare(`${csvPath}/single-column-with-header.csv`);
|
|
|
|
should.exist(result.id);
|
|
result.id.should.match(/\/members-importer\/test\/fixtures\/Members Import/);
|
|
|
|
result.batches.should.equal(2);
|
|
should.exist(result.metadata);
|
|
|
|
fsWriteSpy.calledOnce.should.be.true();
|
|
});
|
|
|
|
it('Does not include columns not in the original CSV or mapped', async function () {
|
|
const membersImporter = new MembersCSVImporter({
|
|
storagePath: csvPath,
|
|
getTimezone: sinon.stub().returns('UTC'),
|
|
getMembersApi: sinon.stub(),
|
|
sendEmail: sinon.stub(),
|
|
isSet: sinon.stub(),
|
|
addJob: sinon.stub(),
|
|
knex: sinon.stub(),
|
|
urlFor: sinon.stub()
|
|
});
|
|
|
|
await membersImporter.prepare(`${csvPath}/single-column-with-header.csv`);
|
|
|
|
const fileContents = fsWriteSpy.firstCall.args[1];
|
|
|
|
fileContents.should.match(/^email,labels\r\n/);
|
|
});
|
|
});
|
|
});
|