48d6e7298a
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
209 lines
6.6 KiB
JavaScript
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
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|