Ghost/ghost/members-csv/lib/parse.js
Naz 840deaf8d7
Restricted members importer to ignore "products" column
refs https://github.com/TryGhost/Team/issues/1076
refs 70229e4fd3 (diff-b67ecda91b5bd79c598e5c5a9ec2ccf28dbfab6a924b21352273865e07cd7ceaR57)

- The "products" column has not been doing any logic anything since at least 5.20.0 (see refed commit). The concept of columns in the export file was mostly there for analytical/data filtering reasons - so the user could analyze their exports. CSV was never a good suite for relational data that "products" (or now tiers) represent
- The "tiers" column will still be present in the exported CSV file, but there is not going to be any logic attached to it.
- The only columns that can effect the "tiers" state of the member are: "complimentary_plan" (assign default tier to the member) and "stripe_customer_id" (pulls in subscription/tier data from Stripe)
2022-10-24 18:06:02 +08:00

91 lines
2.8 KiB
JavaScript

const Promise = require('bluebird');
const pump = require('pump');
const papaparse = require('papaparse');
const fs = require('fs-extra');
/**
*
* @param {string} path - The path to the CSV to prepare
* @param {Object.<string, string>} headerMapping - An object whose keys are headers in the input CSV and values are the header to replace it with
* @param {Array<string>} [defaultLabels] - A list of labels to apply to every parsed member row
* @returns
*/
module.exports = (path, headerMapping, defaultLabels = []) => {
return new Promise(function (resolve, reject) {
const csvFileStream = fs.createReadStream(path);
const csvParserStream = papaparse.parse(papaparse.NODE_STREAM_INPUT, {
header: true,
transformHeader(_header) {
if (!headerMapping || !Reflect.has(headerMapping, _header)) {
return undefined;
}
return headerMapping[_header];
},
transform(value, header) {
if (header === 'labels') {
if (value && typeof value === 'string') {
return value.split(',').map(name => ({name}));
}
}
if (header === 'subscribed') {
return value.toLowerCase() !== 'false';
}
if (header === 'complimentary_plan') {
return value.toLowerCase() === 'true';
}
if (value === '') {
return null;
}
if (value === 'undefined') {
return null;
}
if (value.toLowerCase() === 'false') {
return false;
}
if (value.toLowerCase() === 'true') {
return true;
}
return value;
}
});
const rows = [];
const parsedCSVStream = pump(csvFileStream, csvParserStream, (err) => {
if (err) {
return reject(err);
}
resolve(rows);
});
parsedCSVStream.on('data', (row) => {
// unmapped columns end up being assigned to 'undefined' property
// in the transformHeader stage, those should be removed completely
if (Reflect.has(row, 'undefined')) {
delete row.undefined;
}
// skip a rows with no data
if (!Object.keys(row).length){
return;
}
if (row.labels) {
row.labels = row.labels.concat(defaultLabels);
} else {
row.labels = defaultLabels;
}
rows.push(row);
});
});
};