Ghost/core/server/api/v2/settings.js
Naz Gargol 48d6e7298a
Refactored content-disposition header handling in API v2 (#10374)
closes https://github.com/TryGhost/Ghost/issues/10331

- Left only a filename part to be handled by controller configuration, the rest was extracted to more generic headers layer
2019-01-14 18:05:16 +00:00

209 lines
6.6 KiB
JavaScript

const Promise = require('bluebird');
const _ = require('lodash');
const moment = require('moment-timezone');
const fs = require('fs-extra');
const path = require('path');
const config = require('../../config');
const models = require('../../models');
const urlService = require('../../services/url');
const common = require('../../lib/common');
const settingsCache = require('../../services/settings/cache');
module.exports = {
docName: 'settings',
browse: {
options: ['type'],
permissions: true,
query(frame) {
let settings = settingsCache.getAll();
// CASE: no context passed (functional call)
if (!frame.options.context) {
return Promise.resolve(settings.filter((setting) => {
return setting.type === 'blog';
}));
}
// CASE: omit core settings unless internal request
if (!frame.options.context.internal) {
settings = _.filter(settings, (setting) => {
return setting.type !== 'core';
});
}
return settings;
}
},
read: {
options: ['key'],
validation: {
options: {
key: {
required: true
}
}
},
permissions: {
before(frame) {
let setting = settingsCache.get(frame.options.key, {resolve: false});
if (setting.type === 'core' && !(frame.options.context && frame.options.context.internal)) {
return Promise.reject(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
}));
}
},
identifier(frame) {
return frame.options.key;
}
},
query(frame) {
let setting = settingsCache.get(frame.options.key, {resolve: false});
return {
[frame.options.key]: setting
};
}
},
edit: {
headers: {
cacheInvalidate: true
},
permissions: {
before(frame) {
const errors = [];
frame.data.settings.map((setting) => {
if (setting.type === 'core' && !(frame.options.context && frame.options.context.internal)) {
errors.push(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
}));
}
});
if (errors.length) {
return Promise.reject(errors[0]);
}
}
},
query(frame) {
let type = frame.data.settings.find((setting) => {
return setting.key === 'type';
});
if (_.isObject(type)) {
type = type.value;
}
frame.data.settings = _.reject(frame.data.settings, (setting) => {
return setting.key === 'type';
});
return models.Settings.edit(frame.data.settings, frame.options);
}
},
upload: {
headers: {
cacheInvalidate: true
},
permissions: {
method: 'edit'
},
query(frame) {
const backupRoutesPath = path.join(config.getContentPath('settings'), `routes-${moment().format('YYYY-MM-DD-HH-mm-ss')}.yaml`);
return fs.copy(`${config.getContentPath('settings')}/routes.yaml`, backupRoutesPath)
.then(() => {
return fs.copy(frame.file.path, `${config.getContentPath('settings')}/routes.yaml`);
})
.then(() => {
urlService.resetGenerators({releaseResourcesOnly: true});
})
.then(() => {
const siteApp = require('../../web/site/app');
const bringBackValidRoutes = () => {
urlService.resetGenerators({releaseResourcesOnly: true});
return fs.copy(backupRoutesPath, `${config.getContentPath('settings')}/routes.yaml`)
.then(() => {
return siteApp.reload();
});
};
try {
siteApp.reload();
} catch (err) {
return bringBackValidRoutes()
.finally(() => {
throw err;
});
}
let tries = 0;
function isBlogRunning() {
return Promise.delay(1000)
.then(() => {
if (!urlService.hasFinished()) {
if (tries > 5) {
throw new common.errors.InternalServerError({
message: 'Could not load routes.yaml file.'
});
}
tries = tries + 1;
return isBlogRunning();
}
});
}
return isBlogRunning()
.catch((err) => {
return bringBackValidRoutes()
.finally(() => {
throw err;
});
});
});
}
},
download: {
headers: {
disposition: {
type: 'yaml',
value: 'routes.yaml'
}
},
response: {
format: 'plain'
},
permissions: {
method: 'browse'
},
query() {
const routesPath = path.join(config.getContentPath('settings'), 'routes.yaml');
return fs.readFile(routesPath, 'utf-8')
.catch((err) => {
if (err.code === 'ENOENT') {
return Promise.resolve([]);
}
if (common.errors.utils.isIgnitionError(err)) {
throw err;
}
throw new common.errors.NotFoundError({
err: err
});
});
}
}
};