Ghost/core/server/api/v2/db.js
Fabien O'Carroll 21427ad73f
Created DB Backup integration (#10974)
* Simplified db controller permissions options

The existing objects were confusing because they did the same thing as
setting permissions to true, but gave the impressions that something
special was happening/required.

* Added DB Backup Integration Role

This will allow us to assign certain api_keys this role, in order to
automate db backups

* Allowed admin api_keys to have configurable roles

This will allow keys for the admin api to do customised things such as db export

* Added ghost-backup integration to fixtures

* Added migrations for DB Backup Integration and role
2019-08-02 17:28:02 +08:00

121 lines
3.9 KiB
JavaScript

const Promise = require('bluebird');
const backupDatabase = require('../../data/db/backup');
const exporter = require('../../data/exporter');
const importer = require('../../data/importer');
const common = require('../../lib/common');
const models = require('../../models');
module.exports = {
docName: 'db',
backupContent: {
permissions: true,
options: [
'include',
'filename'
],
validation: {
options: {
include: {
values: exporter.EXCLUDED_TABLES
}
}
},
query(frame) {
// NOTE: we need to have `include` property available as backupDatabase uses it internally
Object.assign(frame.options, {include: frame.options.withRelated});
return backupDatabase(frame.options);
}
},
exportContent: {
options: [
'include'
],
validation: {
options: {
include: {
values: exporter.EXCLUDED_TABLES
}
}
},
headers: {
disposition: {
type: 'file',
value: () => (exporter.fileName())
}
},
permissions: true,
query(frame) {
return Promise.resolve()
.then(() => exporter.doExport({include: frame.options.withRelated}))
.catch((err) => {
return Promise.reject(new common.errors.GhostError({err: err}));
});
}
},
importContent: {
options: [
'include'
],
validation: {
options: {
include: {
values: exporter.EXCLUDED_TABLES
}
}
},
permissions: true,
query(frame) {
return importer.importFromFile(frame.file, {include: frame.options.withRelated});
}
},
deleteAllContent: {
statusCode: 204,
permissions: true,
query() {
/**
* @NOTE:
* We fetch all posts with `columns:id` to increase the speed of this endpoint.
* And if you trigger `post.destroy(..)`, this will trigger bookshelf and model events.
* But we only have to `id` available in the model. This won't work, because:
* - model layer can't trigger event e.g. `post.page` to trigger `post|page.unpublished`.
* - `onDestroyed` or `onDestroying` can contain custom logic
*/
function deleteContent() {
return models.Base.transaction((transacting) => {
const queryOpts = {
columns: 'id',
context: {internal: true},
destroyAll: true,
transacting: transacting
};
return models.Post.findAll(queryOpts)
.then((response) => {
return Promise.map(response.models, (post) => {
return models.Post.destroy(Object.assign({id: post.id}, queryOpts));
}, {concurrency: 100});
})
.then(() => models.Tag.findAll(queryOpts))
.then((response) => {
return Promise.map(response.models, (tag) => {
return models.Tag.destroy(Object.assign({id: tag.id}, queryOpts));
}, {concurrency: 100});
})
.catch((err) => {
throw new common.errors.GhostError({
err: err
});
});
});
}
return backupDatabase().then(deleteContent);
}
}
};