Skip to content

Commit

Permalink
feat(backup): Added members export to backup
Browse files Browse the repository at this point in the history
refs: TryGhost/Toolbox#334
refs: #468

- this ensures that we export a members.csv file if the endpoint exists
  • Loading branch information
ErisDS committed May 19, 2022
1 parent fbc7fdd commit fa46ccf
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 18 deletions.
8 changes: 5 additions & 3 deletions lib/tasks/backup.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ const {ProcessError} = require('../errors');
const {exportTask} = require('./import');

module.exports = async function (ui, instance) {
// First we need to export the content into a JSON file
// First we need to export the content into a JSON file & members into a CSV file
const contentExportPath = 'data/backup.json';
await exportTask(ui, instance, path.join(instance.dir, 'content/', contentExportPath));
const membersExportPath = 'data/members.csv';

await exportTask(ui, instance, path.join(instance.dir, 'content/', contentExportPath), path.join(instance.dir, 'content/', membersExportPath));

// Next we need to copy `redirects.*` files from `data/` to `settings/` because
// we're not going to backup `data/
Expand All @@ -36,7 +38,7 @@ module.exports = async function (ui, instance) {
const zipPath = path.join(process.cwd(), `backup-from-v${instance.version}-on-${datetime}.zip`);

try {
execa.shellSync(`zip -r ${zipPath} ${contentExportPath} files/ images/ media/ settings/ themes/`, {
execa.shellSync(`zip -r ${zipPath} ${contentExportPath} ${membersExportPath} files/ images/ media/ settings/ themes/`, {
cwd: path.join(instance.dir, 'content/')
});
} catch (err) {
Expand Down
18 changes: 16 additions & 2 deletions lib/tasks/import/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ async function runImport(version, url, auth, exportFile) {
await got.post('/db/', {...authOpts, body});
}

async function downloadExport(version, url, auth, outputFile) {
async function downloadContentExport(version, url, auth, outputFile) {
const authOpts = await getAuthOpts(version, url, auth);

await new Promise((resolve, reject) => {
Expand All @@ -137,10 +137,24 @@ async function downloadExport(version, url, auth, outputFile) {
});
}

async function downloadMembersExport(version, url, auth, outputFile) {
const authOpts = await getAuthOpts(version, url, auth);

await new Promise((resolve, reject) => {
const ws = fs.createWriteStream(outputFile);
got
.stream('/members/upload/', {...authOpts})
.on('finish', () => resolve())
.on('error', reject)
.pipe(ws);
});
}

module.exports = {
getBaseUrl,
isSetup,
setup,
runImport,
downloadExport
downloadContentExport,
downloadMembersExport
};
25 changes: 22 additions & 3 deletions lib/tasks/import/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const validator = require('validator');

const {SystemError} = require('../../errors');
const parseExport = require('./parse-export');
const {isSetup, setup, runImport, downloadExport} = require('./api');
const {isSetup, setup, runImport, downloadContentExport, downloadMembersExport} = require('./api');

const authPrompts = [{
type: 'string',
Expand Down Expand Up @@ -40,7 +40,18 @@ async function importTask(ui, instance, exportFile) {
}], false);
}

async function exportTask(ui, instance, exportFile) {
async function tryMembersDownload(version, url, authData, membersFile) {
try {
await downloadMembersExport(version, url, authData, membersFile);
} catch (error) {
// Members endpoint may not exist, we can ignore this
if (!error.statusCode === 404) {
throw error;
}
}
}

async function exportTask(ui, instance, contentFile, membersFile) {
const url = instance.config.get('url');

const blogIsSetup = await isSetup(instance.version, url);
Expand All @@ -49,7 +60,15 @@ async function exportTask(ui, instance, exportFile) {
}

const authData = await ui.prompt(authPrompts);
await downloadExport(instance.version, url, authData, exportFile);

return ui.listr([{
title: 'Exporting content',
task: () => downloadContentExport(instance.version, url, authData, contentFile)
}, {
title: 'Exporting members',
task: () => tryMembersDownload(instance.version, url, authData, membersFile),
enabled: () => !!membersFile
}], false);
}

module.exports = {
Expand Down
14 changes: 7 additions & 7 deletions test/unit/tasks/import/api-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const tmp = require('tmp');
const fs = require('fs-extra');

const {SystemError} = require('../../../../lib/errors');
const {getBaseUrl, isSetup, setup, runImport, downloadExport} = require('../../../../lib/tasks/import/api');
const {getBaseUrl, isSetup, setup, runImport, downloadContentExport} = require('../../../../lib/tasks/import/api');

const testUrl = 'http://localhost:2368';

Expand Down Expand Up @@ -360,7 +360,7 @@ describe('Unit > Tasks > Import > setup', function () {
});
});

describe('downloadExport', function () {
describe('downloadContentExport', function () {
it('1.x', async function () {
const clientId = 'client-id';
const clientSecret = 'client-secret';
Expand Down Expand Up @@ -409,7 +409,7 @@ describe('Unit > Tasks > Import > setup', function () {
const tmpDir = tmp.dirSync();
const outputFile = path.join(tmpDir.name, '1.x.json');

await downloadExport('1.0.0', testUrl, {
await downloadContentExport('1.0.0', testUrl, {
username: 'test@example.com',
password: 'password'
}, outputFile);
Expand Down Expand Up @@ -454,7 +454,7 @@ describe('Unit > Tasks > Import > setup', function () {
const tmpDir = tmp.dirSync();
const outputFile = path.join(tmpDir.name, '2.x.json');

await downloadExport('2.0.0', 'http://localhost:2368', {
await downloadContentExport('2.0.0', 'http://localhost:2368', {
username: 'test@example.com',
password: 'password'
}, outputFile);
Expand Down Expand Up @@ -498,7 +498,7 @@ describe('Unit > Tasks > Import > setup', function () {
const tmpDir = tmp.dirSync();
const outputFile = path.join(tmpDir.name, '3.x.json');

await downloadExport('3.0.0', 'http://localhost:2368', {
await downloadContentExport('3.0.0', 'http://localhost:2368', {
username: 'test@example.com',
password: 'password'
}, outputFile);
Expand Down Expand Up @@ -542,7 +542,7 @@ describe('Unit > Tasks > Import > setup', function () {
const tmpDir = tmp.dirSync();
const outputFile = path.join(tmpDir.name, '4.x.json');

await downloadExport('4.0.0', 'http://localhost:2368', {
await downloadContentExport('4.0.0', 'http://localhost:2368', {
username: 'test@example.com',
password: 'password'
}, outputFile);
Expand Down Expand Up @@ -587,7 +587,7 @@ describe('Unit > Tasks > Import > setup', function () {
const tmpDir = tmp.dirSync();
const outputFile = path.join(tmpDir.name, '5.x.json');

await downloadExport('5.0.0', 'http://localhost:2368', {
await downloadContentExport('5.0.0', 'http://localhost:2368', {
username: 'test@example.com',
password: 'password'
}, outputFile);
Expand Down
6 changes: 3 additions & 3 deletions test/unit/tasks/import/tasks-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,20 @@ describe('Unit: Tasks > Import > Tasks', function () {

it('exports content', async function () {
const isSetup = sinon.stub().resolves(true);
const downloadExport = sinon.stub().resolves();
const downloadContentExport = sinon.stub().resolves();
const config = createConfigStub();
const prompt = sinon.stub().resolves({username: 'username', password: 'password'});

config.get.withArgs('url').returns('http://localhost:2368');

const {exportTask} = proxyquire(modulePath, {
'./api': {isSetup, downloadExport}
'./api': {isSetup, downloadContentExport}
});

await exportTask({prompt}, {config, version: '1.0.0'}, 'test-export.json');
expect(isSetup.calledOnceWithExactly('1.0.0', 'http://localhost:2368')).to.be.true;
expect(prompt.calledOnce).to.be.true;
expect(downloadExport.calledOnceWithExactly('1.0.0', 'http://localhost:2368', {
expect(downloadContentExport.calledOnceWithExactly('1.0.0', 'http://localhost:2368', {
username: 'username', password: 'password'
}, 'test-export.json'));
});
Expand Down

0 comments on commit fa46ccf

Please sign in to comment.