diff --git a/ghost/substack-ghost-csv-converter/.eslintrc.js b/ghost/substack-ghost-csv-converter/.eslintrc.js deleted file mode 100644 index 6a5eab530d..0000000000 --- a/ghost/substack-ghost-csv-converter/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/node', - ] -}; diff --git a/ghost/substack-ghost-csv-converter/LICENSE b/ghost/substack-ghost-csv-converter/LICENSE deleted file mode 100644 index 18972a10df..0000000000 --- a/ghost/substack-ghost-csv-converter/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Ghost Foundation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/ghost/substack-ghost-csv-converter/README.md b/ghost/substack-ghost-csv-converter/README.md deleted file mode 100644 index 0458d879c5..0000000000 --- a/ghost/substack-ghost-csv-converter/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Substack Ghost Csv Converter - -Allows converting CSV export from Substack to CSV compatible with Ghost. - -## Install - -`npm install @tryghost/substack-ghost-csv-converter --save` - -or - -`yarn add @tryghost/substack-ghost-csv-converter` - - -## Usage - -To convert the CSV file provide a path to in as a first parameter and the output csv file path as second parameter: `subghost ` - -## Develop - -This is a mono repository, managed with [lerna](https://lernajs.io/). - -Follow the instructions for the top-level repo. -1. `git clone` this repo & `cd` into it as usual -2. Run `yarn` to install top-level dependencies. - - -## Run - -- `yarn dev` - - -## Test - -- `yarn lint` run just eslint -- `yarn test` run lint and tests - - - - -# Copyright & License - -Copyright (c) 2020 Ghost Foundation - Released under the [MIT license](LICENSE). diff --git a/ghost/substack-ghost-csv-converter/bin/index.js b/ghost/substack-ghost-csv-converter/bin/index.js deleted file mode 100644 index d301116188..0000000000 --- a/ghost/substack-ghost-csv-converter/bin/index.js +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env node -const prettyCLI = require('@tryghost/pretty-cli'); -const ui = require('@tryghost/pretty-cli').ui; -const chalk = require('chalk'); -const converter = require('../'); - -prettyCLI - .configure({ - name: 'subghost' - }) - .positional('', { - paramsDesc: 'Substack CSV file path', - mustExist: true - }) - .positional('', { - paramsDesc: 'Ghost CSV destination file path. Will write to source if not present', - mustExist: false - }) - .parseAndExit() - .then((argv) => { - const dest = argv.dest || argv.source; - - ui.log(`Converting Substack CSV file...`); - - return converter(argv.source, dest).then(() => { - ui.log(`Conversion finished. File written to: ${chalk.cyan(dest)}`); - - process.exit(0); - }).catch((e) => { - ui.log(e); - process.exit(1); - }); - }); diff --git a/ghost/substack-ghost-csv-converter/index.js b/ghost/substack-ghost-csv-converter/index.js deleted file mode 100644 index 87d5e453c2..0000000000 --- a/ghost/substack-ghost-csv-converter/index.js +++ /dev/null @@ -1,37 +0,0 @@ -const {converter} = require('./lib'); - -const convertCSV = async (originFilePath, destinationFilePath) => { - await converter.normalizeMembersCSV({ - path: originFilePath, - destination: destinationFilePath, - columnsToMap: [{ - from: 'email_disabled', - to: 'subscribed_to_emails', - negate: true - }, { - from: 'stripe_connected_customer_id', - to: 'stripe_customer_id' - }], - columnsToExtract: [{ - name: 'email', - lookup: /^email/i - }, { - name: 'name', - lookup: /name/i - }, { - name: 'note', - lookup: /note/i - }, { - name: 'subscribed_to_emails', - lookup: /subscribed_to_emails/i - }, { - name: 'stripe_customer_id', - lookup: /stripe_customer_id/i - }, { - name: 'complimentary_plan', - lookup: /complimentary_plan/i - }] - }); -}; - -module.exports = convertCSV; diff --git a/ghost/substack-ghost-csv-converter/lib/converter.js b/ghost/substack-ghost-csv-converter/lib/converter.js deleted file mode 100644 index ad7d9b50f0..0000000000 --- a/ghost/substack-ghost-csv-converter/lib/converter.js +++ /dev/null @@ -1,93 +0,0 @@ -const Promise = require('bluebird'); -const csvParser = require('csv-parser'); -const _ = require('lodash'); -const fs = require('fs-extra'); -const {formatCSV} = require('.'); - -const normalizeCSVFileToJSON = async (options) => { - const columnsToExtract = options.columnsToExtract || []; - const columnsToMap = options.columnsToMap || []; - let results = []; - const rows = []; - - return new Promise(function (resolve, reject) { - let readFile = fs.createReadStream(options.path); - - readFile.on('err', function (err) { - reject(err); - }) - .pipe(csvParser({ - mapHeaders: ({header}) => { - let mapping = columnsToMap.find(column => (column.from === header)); - if (mapping) { - return mapping.to; - } - - return header; - } - })) - .on('data', function (row) { - rows.push(row); - }) - .on('end', function () { - // If CSV is single column - return all values including header - var headers = _.keys(rows[0]), result = {}, columnMap = {}; - - if (columnsToExtract.length === 1 && headers.length === 1) { - results = _.map(rows, function (value) { - result = {}; - result[columnsToExtract[0].name] = value[headers[0]]; - return result; - }); - } else { - // If there are multiple columns in csv file - // try to match headers using lookup value - - _.map(columnsToExtract, function findMatches(column) { - _.each(headers, function checkheader(header) { - if (column.lookup.test(header)) { - columnMap[column.name] = header; - } - }); - }); - - results = _.map(rows, function evaluateRow(row) { - var result = {}; - _.each(columnMap, function returnMatches(value, key) { - const mapping = columnsToMap.find(column => (column.to === key)); - - if (mapping && mapping.negate) { - result[key] = !(String(row[value]).toLowerCase() === 'true'); - } else { - result[key] = row[value]; - } - }); - return result; - }); - } - - resolve(results); - }); - }); -}; - -const normalizeMembersCSV = async (options) => { - const results = await normalizeCSVFileToJSON(options); - - let fields = ['email', 'name', 'note', 'subscribed_to_emails', 'stripe_customer_id']; - - if (results && results.length) { - fields = Object.keys(results[0]); - } - - const normalizedCSV = formatCSV(results, fields); - - const resultFilePath = options.destination || options.origin; - - return fs.writeFile(resultFilePath, normalizedCSV); -}; - -module.exports = { - normalizeCSVFileToJSON: normalizeCSVFileToJSON, - normalizeMembersCSV: normalizeMembersCSV -}; diff --git a/ghost/substack-ghost-csv-converter/lib/format-csv.js b/ghost/substack-ghost-csv-converter/lib/format-csv.js deleted file mode 100644 index 85228dc893..0000000000 --- a/ghost/substack-ghost-csv-converter/lib/format-csv.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = function formatCSV(data, fields) { - let csv = `${fields.join(',')}\r\n`; - let entry; - let field; - let j; - let i; - - for (j = 0; j < data.length; j = j + 1) { - entry = data[j]; - - for (i = 0; i < fields.length; i = i + 1) { - field = fields[i]; - csv += entry[field] !== null ? entry[field] : ''; - if (i !== fields.length - 1) { - csv += ','; - } - } - csv += '\r\n'; - } - - return csv; -}; diff --git a/ghost/substack-ghost-csv-converter/lib/index.js b/ghost/substack-ghost-csv-converter/lib/index.js deleted file mode 100644 index 813e6346fb..0000000000 --- a/ghost/substack-ghost-csv-converter/lib/index.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - get formatCSV() { - return require('./format-csv'); - }, - - get converter() { - return require('./converter'); - } -}; diff --git a/ghost/substack-ghost-csv-converter/package.json b/ghost/substack-ghost-csv-converter/package.json deleted file mode 100644 index 1e4b4370e5..0000000000 --- a/ghost/substack-ghost-csv-converter/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@tryghost/substack-ghost-csv-converter", - "version": "0.1.0", - "repository": "https://github.com/TryGhost/Members/tree/master/packages/substack-ghost-csv-converter", - "author": "Ghost Foundation", - "license": "MIT", - "main": "index.js", - "scripts": { - "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing mocha './test/**/*.test.js'", - "lint": "eslint . --ext .js --cache", - "posttest": "yarn lint" - }, - "bin": { - "subghost": "./bin/index.js" - }, - "files": [ - "index.js", - "lib", - "bin" - ], - "publishConfig": { - "access": "public" - }, - "devDependencies": { - "mocha": "7.1.1", - "should": "13.2.3", - "sinon": "8.1.1" - }, - "dependencies": { - "@tryghost/pretty-cli": "1.2.4", - "bluebird": "3.7.2", - "csv-parser": "2.3.2", - "ghost-ignition": "4.0.0", - "lodash": "4.17.15" - } -} diff --git a/ghost/substack-ghost-csv-converter/test/.eslintrc.js b/ghost/substack-ghost-csv-converter/test/.eslintrc.js deleted file mode 100644 index c5e8950433..0000000000 --- a/ghost/substack-ghost-csv-converter/test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/test', - ], - "parserOptions": { - "ecmaVersion": 2017 - }, -}; diff --git a/ghost/substack-ghost-csv-converter/test/fixtures/substack-csv-format.csv b/ghost/substack-ghost-csv-converter/test/fixtures/substack-csv-format.csv deleted file mode 100644 index ad6ed5e143..0000000000 --- a/ghost/substack-ghost-csv-converter/test/fixtures/substack-csv-format.csv +++ /dev/null @@ -1,3 +0,0 @@ -email,expiry,email_disabled,stripe_connected_customer_id -member+substack_1@example.com,"Fri Dec 25 2020 14:40:02 GMT+0000 (Coordinated Universal Time)","false",cus_GbbIQRd8TnFqHq -member+substack_2@example.com,"Fri Dec 26 2020 14:40:02 GMT+0000 (Coordinated Universal Time)","true" diff --git a/ghost/substack-ghost-csv-converter/test/hello.test.js b/ghost/substack-ghost-csv-converter/test/hello.test.js deleted file mode 100644 index 85d69d1e08..0000000000 --- a/ghost/substack-ghost-csv-converter/test/hello.test.js +++ /dev/null @@ -1,10 +0,0 @@ -// Switch these lines once there are useful utils -// const testUtils = require('./utils'); -require('./utils'); - -describe('Hello world', function () { - it('Runs a test', function () { - // TODO: Write me! - 'hello'.should.eql('hello'); - }); -}); diff --git a/ghost/substack-ghost-csv-converter/test/lib/normalize-members-csv.test.js b/ghost/substack-ghost-csv-converter/test/lib/normalize-members-csv.test.js deleted file mode 100644 index dc75ca2b9e..0000000000 --- a/ghost/substack-ghost-csv-converter/test/lib/normalize-members-csv.test.js +++ /dev/null @@ -1,45 +0,0 @@ -const path = require('path'); -const {converter} = require('../../lib'); -// Switch these lines once there are useful utils -// const testUtils = require('./utils'); -require('../utils'); - -describe('Converts Substack CSV to Ghost CSV formats', function () { - it('Reads CSV and converts it to normalized JSON', async function () { - const result = await converter.normalizeCSVFileToJSON({ - path: path.resolve('./test/fixtures/substack-csv-format.csv'), - columnsToMap: [{ - from: 'email_disabled', - to: 'subscribed_to_emails', - negate: true - }, { - from: 'stripe_connected_customer_id', - to: 'stripe_customer_id' - }], - columnsToExtract: [{ - name: 'email', - lookup: /^email/i - }, { - name: 'name', - lookup: /name/i - }, { - name: 'note', - lookup: /note/i - }, { - name: 'subscribed_to_emails', - lookup: /subscribed_to_emails/i - }, { - name: 'stripe_customer_id', - lookup: /stripe_customer_id/i - }, { - name: 'complimentary_plan', - lookup: /complimentary_plan/i - }] - }); - - result.length.should.equal(2); - Object.keys(result[0]).should.deepEqual(['email', 'subscribed_to_emails', 'stripe_customer_id']); - result[0].should.deepEqual({email: 'member+substack_1@example.com', subscribed_to_emails: true, stripe_customer_id: 'cus_GbbIQRd8TnFqHq'}); - result[1].should.deepEqual({email: 'member+substack_2@example.com', subscribed_to_emails: false, stripe_customer_id: undefined}); - }); -}); diff --git a/ghost/substack-ghost-csv-converter/test/utils/assertions.js b/ghost/substack-ghost-csv-converter/test/utils/assertions.js deleted file mode 100644 index 7364ee8aa1..0000000000 --- a/ghost/substack-ghost-csv-converter/test/utils/assertions.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Custom Should Assertions - * - * Add any custom assertions to this file. - */ - -// Example Assertion -// should.Assertion.add('ExampleAssertion', function () { -// this.params = {operator: 'to be a valid Example Assertion'}; -// this.obj.should.be.an.Object; -// }); diff --git a/ghost/substack-ghost-csv-converter/test/utils/index.js b/ghost/substack-ghost-csv-converter/test/utils/index.js deleted file mode 100644 index 0d67d86ff8..0000000000 --- a/ghost/substack-ghost-csv-converter/test/utils/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Test Utilities - * - * Shared utils for writing tests - */ - -// Require overrides - these add globals for tests -require('./overrides'); - -// Require assertions - adds custom should assertions -require('./assertions'); diff --git a/ghost/substack-ghost-csv-converter/test/utils/overrides.js b/ghost/substack-ghost-csv-converter/test/utils/overrides.js deleted file mode 100644 index 90203424ee..0000000000 --- a/ghost/substack-ghost-csv-converter/test/utils/overrides.js +++ /dev/null @@ -1,10 +0,0 @@ -// This file is required before any test is run - -// Taken from the should wiki, this is how to make should global -// Should is a global in our eslint test config -global.should = require('should').noConflict(); -should.extend(); - -// Sinon is a simple case -// Sinon is a global in our eslint test config -global.sinon = require('sinon');