diff --git a/core/server/controllers/admin.js b/core/server/controllers/admin.js index 879c6ba3ed..3d17bd787e 100644 --- a/core/server/controllers/admin.js +++ b/core/server/controllers/admin.js @@ -273,15 +273,7 @@ adminControllers = { }); }, 'export': function (req, res) { - // Get current version from settings - api.settings.read({ key: "databaseVersion" }) - .then(function (setting) { - // Export the current versions data - return dataExport(setting.value); - }, function () { - // If no setting, assume 001 - return dataExport("001"); - }) + return dataExport() .then(function (exportedData) { // Save the exported data to the file system for download var fileName = path.resolve(__dirname + '/../../server/data/export/exported-' + (new Date().getTime()) + '.json'); diff --git a/core/server/data/export/001.js b/core/server/data/export/001.js deleted file mode 100644 index 6f6da2a715..0000000000 --- a/core/server/data/export/001.js +++ /dev/null @@ -1,45 +0,0 @@ -var _ = require("underscore"), - when = require("when"), - knex = require('../../models/base').Knex, - Exporter001; - -Exporter001 = function () { - this.version = "001"; -}; - -Exporter001.prototype.exportData = function () { - var self = this, - tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'settings'], - selectOps = _.map(tables, function (name) { - return knex(name).select(); - }); - - return when.all(selectOps).then(function (tableData) { - var exportData = { - meta: { - exported_on: new Date().getTime(), - version: self.version - }, - data: { - // Filled below - } - }; - - _.each(tables, function (name, i) { - exportData.data[name] = tableData[i]; - }); - - return when.resolve(exportData); - }, function (err) { - console.log("Error exporting data: " + err); - }); -}; - -module.exports = { - // Make available for unit tests - Exporter001: Exporter001, - - exportData: function () { - return new Exporter001().exportData(); - } -}; \ No newline at end of file diff --git a/core/server/data/export/002.js b/core/server/data/export/002.js deleted file mode 100644 index e54a08cc79..0000000000 --- a/core/server/data/export/002.js +++ /dev/null @@ -1,49 +0,0 @@ -var _ = require("underscore"), - when = require("when"), - knex = require('../../models/base').Knex, - Exporter002; - -Exporter002 = function () { - this.version = "002"; -}; - -Exporter002.prototype.exportData = function () { - var self = this, - tables = [ - 'posts', 'users', 'roles', 'roles_users', 'permissions', - 'permissions_roles', 'settings', 'tags', 'posts_tags', - 'custom_data', 'posts_custom_data' - ], - selectOps = _.map(tables, function (name) { - return knex(name).select(); - }); - - return when.all(selectOps).then(function (tableData) { - var exportData = { - meta: { - exported_on: new Date().getTime(), - version: self.version - }, - data: { - // Filled below - } - }; - - _.each(tables, function (name, i) { - exportData.data[name] = tableData[i]; - }); - - return when.resolve(exportData); - }, function (err) { - console.log("Error exporting data: " + err); - }); -}; - -module.exports = { - // Make available for unit tests - Exporter002: Exporter002, - - exportData: function () { - return new Exporter002().exportData(); - } -}; \ No newline at end of file diff --git a/core/server/data/export/index.js b/core/server/data/export/index.js index f327175ca3..ed33f11135 100644 --- a/core/server/data/export/index.js +++ b/core/server/data/export/index.js @@ -1,22 +1,65 @@ var when = require('when'), - migration = require('../migration'); + _ = require('underscore'), + migration = require('../migration'), + client = require('../../models/base').client, + knex = require('../../models/base').Knex, -module.exports = function (version) { - var exporter; + exporter; - if (version > migration.databaseVersion) { - return when.reject("Your data version is ahead of the current Ghost version. Please upgrade in order to export."); +function getTablesFromSqlite3() { + return knex.Raw("select * from sqlite_master where type = 'table'").then(function (response) { + return _.reject(_.pluck(response, 'tbl_name'), function (name) { + return name === 'sqlite_sequence'; + }); + }); +} + +function getTablesFromMySQL() { + knex.Raw("show tables").then(function (response) { + return _.flatten(_.map(response, function (entry) { + return _.values(entry); + })); + }); +} + +exporter = function () { + var tablesToExport; + + if (client === 'sqlite3') { + tablesToExport = getTablesFromSqlite3(); + } else if (client === 'mysql') { + tablesToExport = getTablesFromMySQL(); + } else { + return when.reject("No exporter for database client " + client); } - try { - exporter = require("./" + version); - } catch (ignore) { - // Zero effs given - } + return when.join(migration.getDatabaseVersion(), tablesToExport).then(function (results) { + var version = results[0], + tables = results[1], + selectOps = _.map(tables, function (name) { + return knex(name).select(); + }); - if (!exporter) { - return when.reject("No exporter found for data version " + version); - } + return when.all(selectOps).then(function (tableData) { + var exportData = { + meta: { + exported_on: new Date().getTime(), + version: version + }, + data: { + // Filled below + } + }; - return exporter.exportData(); + _.each(tables, function (name, i) { + exportData.data[name] = tableData[i]; + }); + + return when.resolve(exportData); + }, function (err) { + console.log("Error exporting data: " + err); + }); + }); }; + +module.exports = exporter; \ No newline at end of file diff --git a/core/server/data/migration/index.js b/core/server/data/migration/index.js index 7603bd39ae..fad4a9f86c 100644 --- a/core/server/data/migration/index.js +++ b/core/server/data/migration/index.js @@ -67,6 +67,7 @@ function setDatabaseVersion() { module.exports = { + getDatabaseVersion: getDatabaseVersion, // Check for whether data is needed to be bootstrapped or not init: function () { var self = this; diff --git a/core/server/models/base.js b/core/server/models/base.js index ad073be4f4..016e9384b7 100644 --- a/core/server/models/base.js +++ b/core/server/models/base.js @@ -10,6 +10,7 @@ var GhostBookshelf, // Initializes Bookshelf as its own instance, so we can modify the Models and not mess up // others' if they're using the library outside of ghost. GhostBookshelf = Bookshelf.Initialize('ghost', config[process.env.NODE_ENV || 'development'].database); +GhostBookshelf.client = config[process.env.NODE_ENV].database.client; GhostBookshelf.validator = new Validator(); diff --git a/core/test/unit/export_spec.js b/core/test/unit/export_spec.js index 01982036f9..0a5460e48d 100644 --- a/core/test/unit/export_spec.js +++ b/core/test/unit/export_spec.js @@ -1,122 +1,65 @@ -///*globals describe, beforeEach, it*/ -//var testUtils = require('./testUtils'), -// should = require('should'), -// sinon = require('sinon'), -// when = require('when'), -// _ = require("underscore"), -// errors = require('../../server/errorHandling'), -// -// // Stuff we are testing -// migration = require('../../server/data/migration'), -// exporter = require('../../server/data/export'), -// Exporter001 = require('../../server/data/export/001'), -// Exporter002 = require('../../server/data/export/002'), -// Settings = require('../../server/models/settings').Settings; -// -//describe("Export", function () { -// -// should.exist(exporter); -// -// beforeEach(function (done) { -// // clear database... we need to initialise it manually for each test -// testUtils.clearData().then(function () { -// done(); -// }, done); -// }); -// -// it("resolves 001", function (done) { -// var exportStub = sinon.stub(Exporter001, "exportData", function () { -// return when.resolve(); -// }); -// -// exporter("001").then(function () { -// exportStub.called.should.equal(true); -// -// exportStub.restore(); -// -// done(); -// }).then(null, done); -// }); -// -// describe("001", function () { -// -// should.exist(Exporter001); -// -// it("exports data", function (done) { -// // initialise database to version 001 - confusingly we have to set the max version to be one higher -// // than the migration version we want -// migration.migrateUpFromVersion('001', '002').then(function () { -// return Settings.populateDefaults(); -// }).then(function () { -// return exporter("001"); -// }).then(function (exportData) { -// var tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'settings']; -// -// should.exist(exportData); -// -// should.exist(exportData.meta); -// should.exist(exportData.data); -// -// exportData.meta.version.should.equal("001"); -// _.findWhere(exportData.data.settings, {key: "databaseVersion"}).value.should.equal("001"); -// -// _.each(tables, function (name) { -// should.exist(exportData.data[name]); -// }); -// // 002 data should not be present -// should.not.exist(exportData.data.tags); -// -// done(); -// }).then(null, done); -// }); -// }); -// -// it("resolves 002", function (done) { -// var exportStub = sinon.stub(Exporter002, "exportData", function () { -// return when.resolve(); -// }); -// -// exporter("002").then(function () { -// exportStub.called.should.equal(true); -// -// exportStub.restore(); -// -// done(); -// }).then(null, done); -// }); -// -// describe("002", function () { -// this.timeout(5000); -// -// should.exist(Exporter001); -// -// it("exports data", function (done) { -// // initialise database to version 001 - confusingly we have to set the max version to be one higher -// // than the migration version we want -// migration.migrateUpFromVersion('001', '003').then(function () { -// return Settings.populateDefaults(); -// }).then(function () { -// return exporter("002"); -// }).then(function (exportData) { -// var tables = [ -// 'posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', -// 'settings', 'tags', 'posts_tags', 'custom_data', 'posts_custom_data' -// ]; -// -// should.exist(exportData); -// -// should.exist(exportData.meta); -// should.exist(exportData.data); -// -// exportData.meta.version.should.equal("002"); -// _.findWhere(exportData.data.settings, {key: "databaseVersion"}).value.should.equal("002"); -// -// _.each(tables, function (name) { -// should.exist(exportData.data[name]); -// }); -// -// done(); -// }).then(null, done); -// }); -// }); -//}); +/*globals describe, before, beforeEach, afterEach, it*/ +var testUtils = require('./testUtils'), + should = require('should'), + sinon = require('sinon'), + when = require('when'), + _ = require("underscore"), + errors = require('../../server/errorHandling'), + + // Stuff we are testing + migration = require('../../server/data/migration'), + exporter = require('../../server/data/export'), + Settings = require('../../server/models/settings').Settings; + +describe("Exporter", function () { + + should.exist(exporter); + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + this.timeout(5000); + testUtils.initData().then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it("exports data", function (done) { + // Stub migrations to return 000 as the current database version + var migrationStub = sinon.stub(migration, "getDatabaseVersion", function () { + return when.resolve("000"); + }); + + exporter().then(function (exportData) { + var tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'permissions_users', + 'settings', 'tags', 'posts_tags']; + + should.exist(exportData); + + should.exist(exportData.meta); + should.exist(exportData.data); + + exportData.meta.version.should.equal("000"); + _.findWhere(exportData.data.settings, {key: "databaseVersion"}).value.should.equal("000"); + + _.each(tables, function (name) { + should.exist(exportData.data[name]); + }); + // should not export sqlite data + should.not.exist(exportData.data.sqlite_sequence); + + migrationStub.restore(); + done(); + }).then(null, done); + }); +});