2014-06-03 08:05:25 -05:00
|
|
|
// # DB API
|
|
|
|
// API for DB operations
|
2013-12-24 19:05:20 -05:00
|
|
|
var dataExport = require('../data/export'),
|
|
|
|
dataImport = require('../data/import'),
|
|
|
|
dataProvider = require('../models'),
|
|
|
|
fs = require('fs-extra'),
|
|
|
|
when = require('when'),
|
|
|
|
nodefn = require('when/node/function'),
|
2014-02-05 03:40:30 -05:00
|
|
|
_ = require('lodash'),
|
2014-02-19 12:32:23 -05:00
|
|
|
validation = require('../data/validation'),
|
2014-05-09 05:11:29 -05:00
|
|
|
errors = require('../../server/errors'),
|
2014-04-08 08:40:33 -05:00
|
|
|
canThis = require('../permissions').canThis,
|
2013-12-29 18:52:55 -05:00
|
|
|
api = {},
|
2013-10-09 03:52:58 -05:00
|
|
|
db;
|
|
|
|
|
2013-12-29 18:52:55 -05:00
|
|
|
api.settings = require('./settings');
|
|
|
|
|
2014-06-03 08:05:25 -05:00
|
|
|
/**
|
|
|
|
* ## DB API Methods
|
|
|
|
*
|
|
|
|
* **See:** [API Methods](index.js.html#api%20methods)
|
|
|
|
*/
|
2013-10-09 03:52:58 -05:00
|
|
|
db = {
|
2014-06-03 08:05:25 -05:00
|
|
|
/**
|
|
|
|
* ### Export Content
|
|
|
|
* Generate the JSON to export
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
* @param {{context}} options
|
|
|
|
* @returns {Promise} Ghost Export JSON format
|
|
|
|
*/
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
'exportContent': function (options) {
|
|
|
|
options = options || {};
|
2014-04-08 08:40:33 -05:00
|
|
|
|
2014-02-27 10:48:38 -05:00
|
|
|
// Export data, otherwise send error 500
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
return canThis(options.context).exportContent.db().then(function () {
|
2014-05-07 00:28:51 -05:00
|
|
|
return dataExport().then(function (exportedData) {
|
|
|
|
return when.resolve({ db: [exportedData] });
|
|
|
|
}).otherwise(function (error) {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.InternalServerError(error.message || error));
|
2014-04-08 08:40:33 -05:00
|
|
|
});
|
|
|
|
}, function () {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
|
2013-10-09 03:52:58 -05:00
|
|
|
});
|
|
|
|
},
|
2014-06-03 08:05:25 -05:00
|
|
|
/**
|
|
|
|
* ### Import Content
|
|
|
|
* Import posts, tags etc from a JSON blob
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
* @param {{context}} options
|
|
|
|
* @returns {Promise} Success
|
|
|
|
*/
|
2014-01-06 09:05:31 -05:00
|
|
|
'importContent': function (options) {
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
options = options || {};
|
|
|
|
var databaseVersion;
|
2013-10-09 03:52:58 -05:00
|
|
|
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
return canThis(options.context).importContent.db().then(function () {
|
2014-04-08 08:40:33 -05:00
|
|
|
if (!options.importfile || !options.importfile.path || options.importfile.name.indexOf('json') === -1) {
|
|
|
|
/**
|
|
|
|
* Notify of an error if it occurs
|
|
|
|
*
|
|
|
|
* - If there's no file (although if you don't select anything, the input is still submitted, so
|
|
|
|
* !req.files.importfile will always be false)
|
|
|
|
* - If there is no path
|
|
|
|
* - If the name doesn't have json in it
|
|
|
|
*/
|
2014-05-24 01:05:12 -05:00
|
|
|
return when.reject(new errors.UnsupportedMediaTypeError('Please select a .json file to import.'));
|
2014-04-08 08:40:33 -05:00
|
|
|
}
|
2013-10-09 03:52:58 -05:00
|
|
|
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
return api.settings.read({key: 'databaseVersion', context: { internal: true }}).then(function (response) {
|
2014-04-27 18:28:50 -05:00
|
|
|
var setting = response.settings[0];
|
2014-05-07 00:28:51 -05:00
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
return when(setting.value);
|
|
|
|
}, function () {
|
|
|
|
return when('002');
|
|
|
|
}).then(function (version) {
|
|
|
|
databaseVersion = version;
|
|
|
|
// Read the file contents
|
|
|
|
return nodefn.call(fs.readFile, options.importfile.path);
|
|
|
|
}).then(function (fileContents) {
|
|
|
|
var importData,
|
|
|
|
error = '';
|
2013-10-09 03:52:58 -05:00
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
// Parse the json data
|
|
|
|
try {
|
|
|
|
importData = JSON.parse(fileContents);
|
2014-05-08 19:03:05 -05:00
|
|
|
|
|
|
|
// if importData follows JSON-API format `{ db: [exportedData] }`
|
|
|
|
if (_.keys(importData).length === 1 && Array.isArray(importData.db)) {
|
|
|
|
importData = importData.db[0];
|
|
|
|
}
|
2014-04-08 08:40:33 -05:00
|
|
|
} catch (e) {
|
|
|
|
errors.logError(e, "API DB import content", "check that the import file is valid JSON.");
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.BadRequest("Failed to parse the import JSON file"));
|
2014-04-08 08:40:33 -05:00
|
|
|
}
|
2013-10-09 03:52:58 -05:00
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
if (!importData.meta || !importData.meta.version) {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.ValidationError("Import data does not specify version", 'meta.version'));
|
2014-04-08 08:40:33 -05:00
|
|
|
}
|
2013-10-09 03:52:58 -05:00
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
_.each(_.keys(importData.data), function (tableName) {
|
|
|
|
_.each(importData.data[tableName], function (importValues) {
|
|
|
|
try {
|
|
|
|
validation.validateSchema(tableName, importValues);
|
|
|
|
} catch (err) {
|
|
|
|
error += error !== "" ? "<br>" : "";
|
|
|
|
error += err.message;
|
|
|
|
}
|
|
|
|
});
|
2013-12-03 21:47:39 -05:00
|
|
|
});
|
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
if (error !== "") {
|
|
|
|
return when.reject(new Error(error));
|
|
|
|
}
|
|
|
|
// Import for the current version
|
|
|
|
return dataImport(databaseVersion, importData);
|
2013-12-28 15:13:47 -05:00
|
|
|
|
2014-04-08 08:40:33 -05:00
|
|
|
}).then(function importSuccess() {
|
|
|
|
return api.settings.updateSettingsCache();
|
|
|
|
}).then(function () {
|
2014-05-07 00:28:51 -05:00
|
|
|
return when.resolve({ db: [] });
|
2014-04-08 08:40:33 -05:00
|
|
|
}).otherwise(function importFailure(error) {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.InternalServerError(error.message || error));
|
2014-04-08 08:40:33 -05:00
|
|
|
}).finally(function () {
|
|
|
|
// Unlink the file after import
|
|
|
|
return nodefn.call(fs.unlink, options.importfile.path);
|
|
|
|
});
|
|
|
|
}, function () {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
|
2013-12-03 21:47:39 -05:00
|
|
|
});
|
2013-12-24 19:05:20 -05:00
|
|
|
},
|
2014-06-03 08:05:25 -05:00
|
|
|
/**
|
|
|
|
* ### Delete All Content
|
|
|
|
* Remove all posts and tags
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
* @param {{context}} options
|
|
|
|
* @returns {Promise} Success
|
|
|
|
*/
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
'deleteAllContent': function (options) {
|
|
|
|
options = options || {};
|
2014-04-08 08:40:33 -05:00
|
|
|
|
Refactor API arguments
closes #2610, refs #2697
- cleanup API index.js, and add docs
- all API methods take consistent arguments: object & options
- browse, read, destroy take options, edit and add take object and options
- the context is passed as part of options, meaning no more .call
everywhere
- destroy expects an object, rather than an id all the way down to the model layer
- route params such as :id, :slug, and :key are passed as an option & used
to perform reads, updates and deletes where possible - settings / themes
may need work here still
- HTTP posts api can find a post by slug
- Add API utils for checkData
2014-05-08 07:41:19 -05:00
|
|
|
return canThis(options.context).deleteAllContent.db().then(function () {
|
2014-04-08 08:40:33 -05:00
|
|
|
return when(dataProvider.deleteAllContent())
|
|
|
|
.then(function () {
|
2014-05-07 00:28:51 -05:00
|
|
|
return when.resolve({ db: [] });
|
2014-04-08 08:40:33 -05:00
|
|
|
}, function (error) {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.InternalServerError(error.message || error));
|
2014-04-08 08:40:33 -05:00
|
|
|
});
|
|
|
|
}, function () {
|
2014-05-09 05:11:29 -05:00
|
|
|
return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
|
2014-04-08 08:40:33 -05:00
|
|
|
});
|
2013-11-01 07:12:01 -05:00
|
|
|
}
|
2013-10-09 03:52:58 -05:00
|
|
|
};
|
|
|
|
|
2014-01-28 23:18:00 -05:00
|
|
|
module.exports = db;
|