Ghost/core/server/api/canary/db.js
Sam Lord 2887e416da
Switch to @tryghost/errors from ignition errors package (#13807)
refs: TryGhost/Toolbox#147

* Replaces all references to isIgnitionError with isGhostError
* Switches use of GhostError to InternalServerError - as GhostError is no longer public
There are places where InternalServerError is not the valid error, and new errors should be added to the @tryghost/errors package to ensure that we can use semantically correct errors in those cases.
2021-12-01 10:22:01 +00:00

138 lines
4.3 KiB
JavaScript

const Promise = require('bluebird');
const dbBackup = require('../../data/db/backup');
const exporter = require('../../data/exporter');
const importer = require('../../data/importer');
const errors = require('@tryghost/errors');
const models = require('../../models');
module.exports = {
docName: 'db',
backupContent: {
permissions: true,
options: [
'include',
'filename'
],
validation: {
options: {
include: {
values: exporter.BACKUP_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 dbBackup.backup(frame.options);
}
},
exportContent: {
options: [
'include',
'filename'
],
validation: {
options: {
include: {
values: exporter.BACKUP_TABLES
}
}
},
headers: {
disposition: {
type: 'file',
value: () => (exporter.fileName())
}
},
permissions: true,
async query(frame) {
if (frame.options.filename) {
let backup = await dbBackup.readBackup(frame.options.filename);
if (!backup) {
throw new errors.NotFoundError();
}
return backup;
}
return Promise.resolve()
.then(() => exporter.doExport({include: frame.options.withRelated}))
.catch((err) => {
return Promise.reject(new errors.InternalServerError({err: err}));
});
}
},
importContent: {
headers: {
cacheInvalidate: true
},
options: [
'include'
],
validation: {
options: {
include: {
values: exporter.BACKUP_TABLES
}
}
},
permissions: true,
query(frame) {
return importer.importFromFile(frame.file, {include: frame.options.withRelated});
}
},
deleteAllContent: {
headers: {
cacheInvalidate: true
},
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 errors.InternalServerError({
err: err
});
});
});
}
return dbBackup.backup().then(deleteContent);
}
}
};