mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added custom label assignment to imported members
no issue - There is a need to be able to label certain import group of members with custom labels. This will allow to distinguish/filter these newly imported members. - Allowed `POST /members/csv/` endpoint to accept `labels` field parameter which assigns labels to every member from imported csv.
This commit is contained in:
parent
fdeb7daf40
commit
633ba27f0e
3 changed files with 93 additions and 8 deletions
|
@ -67,7 +67,11 @@ const sanitizeInput = (members) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function serializeMemberLabels(labels) {
|
function serializeMemberLabels(labels) {
|
||||||
if (labels) {
|
if (_.isString(labels)) {
|
||||||
|
return [{
|
||||||
|
name: labels.trim()
|
||||||
|
}];
|
||||||
|
} else if (labels) {
|
||||||
return labels.filter((label) => {
|
return labels.filter((label) => {
|
||||||
return !!label;
|
return !!label;
|
||||||
}).map((label) => {
|
}).map((label) => {
|
||||||
|
@ -96,6 +100,27 @@ const listMembers = async function (options) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createLabels = async (labels, options) => {
|
||||||
|
const api = require('./index');
|
||||||
|
|
||||||
|
return await Promise.all(labels.map((label) => {
|
||||||
|
return api.labels.add.query({
|
||||||
|
data: {
|
||||||
|
labels: [label]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
context: options.context
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.errorType === 'ValidationError') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const members = {
|
const members = {
|
||||||
docName: 'members',
|
docName: 'members',
|
||||||
browse: {
|
browse: {
|
||||||
|
@ -341,6 +366,11 @@ const members = {
|
||||||
lookup: /created_at/i
|
lookup: /created_at/i
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// NOTE: custom labels have to be created in advance otherwise there are conflicts
|
||||||
|
// when processing member creation in parallel later on in import process
|
||||||
|
const importSetLabels = serializeMemberLabels(frame.data.labels);
|
||||||
|
await createLabels(importSetLabels, frame.options);
|
||||||
|
|
||||||
return fsLib.readCSV({
|
return fsLib.readCSV({
|
||||||
path: filePath,
|
path: filePath,
|
||||||
columnsToExtract: columnsToExtract
|
columnsToExtract: columnsToExtract
|
||||||
|
@ -352,6 +382,8 @@ const members = {
|
||||||
const api = require('./index');
|
const api = require('./index');
|
||||||
entry.labels = (entry.labels && entry.labels.split(',')) || [];
|
entry.labels = (entry.labels && entry.labels.split(',')) || [];
|
||||||
const entryLabels = serializeMemberLabels(entry.labels);
|
const entryLabels = serializeMemberLabels(entry.labels);
|
||||||
|
const mergedLabels = _.unionBy(entryLabels, importSetLabels, 'name');
|
||||||
|
|
||||||
cleanupUndefined(entry);
|
cleanupUndefined(entry);
|
||||||
|
|
||||||
let subscribed;
|
let subscribed;
|
||||||
|
@ -370,7 +402,7 @@ const members = {
|
||||||
subscribed: subscribed,
|
subscribed: subscribed,
|
||||||
stripe_customer_id: entry.stripe_customer_id,
|
stripe_customer_id: entry.stripe_customer_id,
|
||||||
comped: (String(entry.complimentary_plan).toLocaleLowerCase() === 'true'),
|
comped: (String(entry.complimentary_plan).toLocaleLowerCase() === 'true'),
|
||||||
labels: entryLabels,
|
labels: mergedLabels,
|
||||||
created_at: entry.created_at === '' ? undefined : entry.created_at
|
created_at: entry.created_at === '' ? undefined : entry.created_at
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
|
|
@ -137,9 +137,59 @@ describe('Members API', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can import CSV with minimum one field', function () {
|
it('Can import CSV with minimum one field', function () {
|
||||||
|
return request
|
||||||
|
.post(localUtils.API.getApiQuery(`members/csv/`))
|
||||||
|
.field('labels', ['global-label-1', 'global-label-1'])
|
||||||
|
.attach('membersfile', path.join(__dirname, '/../../../../utils/fixtures/csv/valid-members-labels.csv'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(201)
|
||||||
|
.then((res) => {
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.meta);
|
||||||
|
should.exist(jsonResponse.meta.stats);
|
||||||
|
|
||||||
|
jsonResponse.meta.stats.imported.should.equal(2);
|
||||||
|
jsonResponse.meta.stats.duplicates.should.equal(0);
|
||||||
|
jsonResponse.meta.stats.invalid.should.equal(0);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return request
|
||||||
|
.get(localUtils.API.getApiQuery(`members/?search=${encodeURIComponent('member+labels_1@example.com')}`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200);
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.members);
|
||||||
|
should.exist(jsonResponse.members[0]);
|
||||||
|
|
||||||
|
const importedMember1 = jsonResponse.members[0];
|
||||||
|
should(importedMember1.email).equal('member+labels_1@example.com');
|
||||||
|
should(importedMember1.name).equal(null);
|
||||||
|
should(importedMember1.note).equal(null);
|
||||||
|
importedMember1.subscribed.should.equal(true);
|
||||||
|
importedMember1.comped.should.equal(false);
|
||||||
|
importedMember1.stripe.should.not.be.undefined();
|
||||||
|
importedMember1.stripe.subscriptions.length.should.equal(0);
|
||||||
|
importedMember1.labels.length.should.equal(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can import CSV with labels and provide additional labels', function () {
|
||||||
return request
|
return request
|
||||||
.post(localUtils.API.getApiQuery(`members/csv/`))
|
.post(localUtils.API.getApiQuery(`members/csv/`))
|
||||||
.attach('membersfile', path.join(__dirname, '/../../../../utils/fixtures/csv/valid-members-defaults.csv'))
|
.attach('membersfile', path.join(__dirname, '/../../../../utils/fixtures/csv/valid-members-defaults.csv'))
|
||||||
|
|
||||||
.set('Origin', config.get('url'))
|
.set('Origin', config.get('url'))
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
@ -226,8 +276,8 @@ describe('Members API', function () {
|
||||||
should.exist(jsonResponse.total_on_date);
|
should.exist(jsonResponse.total_on_date);
|
||||||
should.exist(jsonResponse.new_today);
|
should.exist(jsonResponse.new_today);
|
||||||
|
|
||||||
// 2 from fixtures and 3 imported in previous tests
|
// 2 from fixtures and 5 imported in previous tests
|
||||||
jsonResponse.total.should.equal(5);
|
jsonResponse.total.should.equal(7);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -250,8 +300,8 @@ describe('Members API', function () {
|
||||||
should.exist(jsonResponse.total_on_date);
|
should.exist(jsonResponse.total_on_date);
|
||||||
should.exist(jsonResponse.new_today);
|
should.exist(jsonResponse.new_today);
|
||||||
|
|
||||||
// 2 from fixtures and 3 imported in previous tests
|
// 2 from fixtures and 5 imported in previous tests
|
||||||
jsonResponse.total.should.equal(5);
|
jsonResponse.total.should.equal(7);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -274,8 +324,8 @@ describe('Members API', function () {
|
||||||
should.exist(jsonResponse.total_on_date);
|
should.exist(jsonResponse.total_on_date);
|
||||||
should.exist(jsonResponse.new_today);
|
should.exist(jsonResponse.new_today);
|
||||||
|
|
||||||
// 2 from fixtures and 3 imported in previous tests
|
// 2 from fixtures and 5 imported in previous tests
|
||||||
jsonResponse.total.should.equal(5);
|
jsonResponse.total.should.equal(7);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
3
test/utils/fixtures/csv/valid-members-labels.csv
Normal file
3
test/utils/fixtures/csv/valid-members-labels.csv
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
email,labels
|
||||||
|
member+labels_1@example.com,label
|
||||||
|
member+labels_2@example.com,another-label
|
|
Loading…
Add table
Reference in a new issue