Added option to export extra tables

refs #9742, refs #8719

- you can now use `include` to export extra tables e.g. `include=clients`
- admin client won't make use of this option yet, maybe later and optional
- we won't announce this new ability for now (stays hidden)
This commit is contained in:
kirrg001 2018-07-30 17:21:52 +02:00
parent 3efee1ae54
commit 40c8eacd44
5 changed files with 82 additions and 11 deletions

View File

@ -55,8 +55,8 @@ db = {
options = options || {};
// Export data, otherwise send error 500
function exportContent() {
return exporter.doExport().then((exportedData) => {
function exportContent(options) {
return exporter.doExport({include: options.include}).then((exportedData) => {
return {
db: [exportedData]
};
@ -67,6 +67,7 @@ db = {
tasks = [
localUtils.handlePermissions(docName, 'exportContent'),
localUtils.convertOptions(exporter.EXCLUDED_TABLES, null, {forModel: false}),
exportContent
];

View File

@ -273,16 +273,20 @@ utils = {
* @param {Array} allowedIncludes
* @returns {Function} doConversion
*/
convertOptions: function convertOptions(allowedIncludes, allowedFormats) {
convertOptions: function convertOptions(allowedIncludes, allowedFormats, convertOptions = {forModel: true}) {
/**
* Convert our options from API-style to Model-style
* Convert our options from API-style to Model-style (default)
* @param {Object} options
* @returns {Object} options
*/
return function doConversion(options) {
if (options.include) {
options.withRelated = utils.prepareInclude(options.include, allowedIncludes);
delete options.include;
if (!convertOptions.forModel) {
options.include = utils.prepareInclude(options.include, allowedIncludes);
} else {
options.withRelated = utils.prepareInclude(options.include, allowedIncludes);
delete options.include;
}
}
if (options.fields) {

View File

@ -6,7 +6,7 @@ var _ = require('lodash'),
common = require('../../lib/common'),
security = require('../../lib/security'),
models = require('../../models'),
excludedTables = ['accesstokens', 'refreshtokens', 'clients', 'client_trusted_domains'],
EXCLUDED_TABLES = ['accesstokens', 'refreshtokens', 'clients', 'client_trusted_domains'],
modelOptions = {context: {internal: true}},
// private
@ -50,13 +50,14 @@ getVersionAndTables = function getVersionAndTables(options) {
};
exportTable = function exportTable(tableName, options) {
if (excludedTables.indexOf(tableName) < 0) {
if (EXCLUDED_TABLES.indexOf(tableName) < 0 ||
(options.include && _.isArray(options.include) && options.include.indexOf(tableName) !== -1)) {
return (options.transacting || db.knex)(tableName).select();
}
};
doExport = function doExport(options) {
options = options || {};
options = options || {include: []};
var tables, version;
@ -93,5 +94,6 @@ doExport = function doExport(options) {
module.exports = {
doExport: doExport,
fileName: exportFileName
fileName: exportFileName,
EXCLUDED_TABLES: EXCLUDED_TABLES
};

View File

@ -72,6 +72,25 @@ describe('DB API', function () {
var jsonResponse = res.body;
should.exist(jsonResponse.db);
jsonResponse.db.should.have.length(1);
Object.keys(jsonResponse.db[0].data).length.should.eql(21);
done();
});
});
it('include more tables', function (done) {
request.get(testUtils.API.getApiQuery('db/?include=clients,client_trusted_domains'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
const jsonResponse = res.body;
should.exist(jsonResponse.db);
jsonResponse.db.should.have.length(1);
Object.keys(jsonResponse.db[0].data).length.should.eql(23);
done();
});
});

View File

@ -41,7 +41,7 @@ describe('Exporter', function () {
});
});
it('should try to export all the correct tables', function (done) {
it('should try to export all the correct tables (without excluded)', function (done) {
// Setup for success
queryMock.select.returns(new Promise.resolve({}));
@ -86,6 +86,51 @@ describe('Exporter', function () {
}).catch(done);
});
it('should try to export all the correct tables with extra tables', function (done) {
// Setup for success
queryMock.select.returns(new Promise.resolve({}));
// Execute
exporter.doExport({include: ['clients', 'client_trusted_domains']}).then(function (exportData) {
// all tables, except of the tokens
const expectedCallCount = schemaTables.length - 2;
should.exist(exportData);
exportData.meta.version.should.eql('1.0.0');
tablesStub.calledOnce.should.be.true();
db.knex.called.should.be.true();
queryMock.select.called.should.be.true();
knexMock.callCount.should.eql(expectedCallCount);
queryMock.select.callCount.should.have.eql(expectedCallCount);
knexMock.getCall(0).args[0].should.eql('posts');
knexMock.getCall(1).args[0].should.eql('users');
knexMock.getCall(2).args[0].should.eql('posts_authors');
knexMock.getCall(3).args[0].should.eql('roles');
knexMock.getCall(4).args[0].should.eql('roles_users');
knexMock.getCall(5).args[0].should.eql('permissions');
knexMock.getCall(6).args[0].should.eql('permissions_users');
knexMock.getCall(7).args[0].should.eql('permissions_roles');
knexMock.getCall(8).args[0].should.eql('permissions_apps');
knexMock.getCall(9).args[0].should.eql('settings');
knexMock.getCall(10).args[0].should.eql('tags');
knexMock.getCall(11).args[0].should.eql('posts_tags');
knexMock.getCall(12).args[0].should.eql('apps');
knexMock.getCall(13).args[0].should.eql('app_settings');
knexMock.getCall(14).args[0].should.eql('app_fields');
knexMock.getCall(15).args[0].should.eql('clients');
knexMock.getCall(16).args[0].should.eql('client_trusted_domains');
knexMock.calledWith('refreshtokens').should.be.false();
knexMock.calledWith('accesstokens').should.be.false();
done();
}).catch(done);
});
it('should catch and log any errors', function (done) {
// Setup for failure
queryMock.select.returns(Promise.reject({}));