mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added back compatible support for renamed settings types
refs https://github.com/TryGhost/Ghost/issues/10318
refs 1dc0405803
- Adds 1:1 mapping for filtering options to renamed settings "type" to "gorup"
- Ignores the name changes and any old types
- Detailsed type -> group mappings can be checked in the refereneced migration commit
This commit is contained in:
parent
1dc0405803
commit
8fc526ff6e
6 changed files with 154 additions and 14 deletions
|
@ -17,7 +17,7 @@ module.exports = {
|
||||||
docName: 'settings',
|
docName: 'settings',
|
||||||
|
|
||||||
browse: {
|
browse: {
|
||||||
options: ['type'],
|
options: ['type', 'group'],
|
||||||
permissions: true,
|
permissions: true,
|
||||||
query(frame) {
|
query(frame) {
|
||||||
let settings = settingsCache.getAll();
|
let settings = settingsCache.getAll();
|
||||||
|
@ -25,14 +25,14 @@ module.exports = {
|
||||||
// CASE: no context passed (functional call)
|
// CASE: no context passed (functional call)
|
||||||
if (!frame.options.context) {
|
if (!frame.options.context) {
|
||||||
return Promise.resolve(settings.filter((setting) => {
|
return Promise.resolve(settings.filter((setting) => {
|
||||||
return setting.type === 'site';
|
return setting.group === 'site';
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// CASE: omit core settings unless internal request
|
// CASE: omit core settings unless internal request
|
||||||
if (!frame.options.context.internal) {
|
if (!frame.options.context.internal) {
|
||||||
settings = _.filter(settings, (setting) => {
|
settings = _.filter(settings, (setting) => {
|
||||||
const isCore = setting.type === 'core';
|
const isCore = setting.group === 'core';
|
||||||
const isBlacklisted = SETTINGS_BLACKLIST.includes(setting.key);
|
const isBlacklisted = SETTINGS_BLACKLIST.includes(setting.key);
|
||||||
return !isBlacklisted && !isCore;
|
return !isBlacklisted && !isCore;
|
||||||
});
|
});
|
||||||
|
@ -68,7 +68,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: handle in settings model permissible fn
|
// @TODO: handle in settings model permissible fn
|
||||||
if (setting.type === 'core' && !(frame.options.context && frame.options.context.internal)) {
|
if (setting.group === 'core' && !(frame.options.context && frame.options.context.internal)) {
|
||||||
return Promise.reject(new NoPermissionError({
|
return Promise.reject(new NoPermissionError({
|
||||||
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
||||||
}));
|
}));
|
||||||
|
@ -181,7 +181,7 @@ module.exports = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstCoreSetting = frame.data.settings.find(setting => setting.type === 'core');
|
const firstCoreSetting = frame.data.settings.find(setting => setting.group === 'core');
|
||||||
if (firstCoreSetting) {
|
if (firstCoreSetting) {
|
||||||
throw new NoPermissionError({
|
throw new NoPermissionError({
|
||||||
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
||||||
|
@ -211,7 +211,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(frame.options.context && frame.options.context.internal)) {
|
if (!(frame.options.context && frame.options.context.internal)) {
|
||||||
const firstCoreSetting = settings.find(setting => getSetting(setting).type === 'core');
|
const firstCoreSetting = settings.find(setting => getSetting(setting).group === 'core');
|
||||||
if (firstCoreSetting) {
|
if (firstCoreSetting) {
|
||||||
throw new NoPermissionError({
|
throw new NoPermissionError({
|
||||||
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const url = require('./utils/url');
|
const url = require('./utils/url');
|
||||||
|
const typeGroupMapper = require('./utils/settings-type-group-mapper');
|
||||||
const settingsCache = require('../../../../../services/settings/cache');
|
const settingsCache = require('../../../../../services/settings/cache');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
browse(apiConfig, frame) {
|
||||||
|
if (frame.options.type) {
|
||||||
|
let mappedGroupOptions = typeGroupMapper(frame.options.type);
|
||||||
|
|
||||||
|
if (frame.options.group) {
|
||||||
|
frame.options.group = `${frame.options.group},${mappedGroupOptions}`;
|
||||||
|
} else {
|
||||||
|
frame.options.group = mappedGroupOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
read(apiConfig, frame) {
|
read(apiConfig, frame) {
|
||||||
if (frame.options.key === 'ghost_head') {
|
if (frame.options.key === 'ghost_head') {
|
||||||
frame.options.key = 'codeinjection_head';
|
frame.options.key = 'codeinjection_head';
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
const typeGroupMapping = {
|
||||||
|
core: [
|
||||||
|
'core'
|
||||||
|
],
|
||||||
|
blog: [
|
||||||
|
'site',
|
||||||
|
'amp',
|
||||||
|
'labs',
|
||||||
|
'slack',
|
||||||
|
'unsplash',
|
||||||
|
'views'
|
||||||
|
],
|
||||||
|
theme: [
|
||||||
|
'theme'
|
||||||
|
],
|
||||||
|
members: [
|
||||||
|
'members'
|
||||||
|
],
|
||||||
|
private: [
|
||||||
|
'private'
|
||||||
|
],
|
||||||
|
portal: [
|
||||||
|
'portal'
|
||||||
|
],
|
||||||
|
bulk_email: [
|
||||||
|
'email'
|
||||||
|
],
|
||||||
|
site: [
|
||||||
|
'site'
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapTypeToGroup = (typeOptions) => {
|
||||||
|
const types = typeOptions.split(',');
|
||||||
|
|
||||||
|
const mappedTypes = types.map((type) => {
|
||||||
|
const sanitizedType = type ? type.trim() : null;
|
||||||
|
|
||||||
|
return typeGroupMapping[sanitizedType];
|
||||||
|
}).filter(type => !!type);
|
||||||
|
|
||||||
|
return mappedTypes.join(',');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = mapTypeToGroup;
|
|
@ -12,10 +12,10 @@ const _private = {};
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
_private.settingsFilter = (settings, filter) => {
|
_private.settingsFilter = (settings, filter) => {
|
||||||
let filteredTypes = filter ? filter.split(',') : false;
|
let filteredGroups = filter ? filter.split(',') : false;
|
||||||
return _.filter(settings, (setting) => {
|
return _.filter(settings, (setting) => {
|
||||||
if (filteredTypes) {
|
if (filteredGroups) {
|
||||||
return _.includes(filteredTypes, setting.type);
|
return _.includes(filteredGroups, setting.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -30,7 +30,7 @@ module.exports = {
|
||||||
if (utils.isContentAPI(frame)) {
|
if (utils.isContentAPI(frame)) {
|
||||||
filteredSettings = models;
|
filteredSettings = models;
|
||||||
} else {
|
} else {
|
||||||
filteredSettings = _.values(_private.settingsFilter(models, frame.options.type));
|
filteredSettings = _.values(_private.settingsFilter(models, frame.options.group));
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.response = {
|
frame.response = {
|
||||||
|
@ -38,10 +38,16 @@ module.exports = {
|
||||||
meta: {}
|
meta: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (frame.options.type || frame.options.group) {
|
||||||
|
frame.response.meta.filters = {};
|
||||||
|
|
||||||
if (frame.options.type) {
|
if (frame.options.type) {
|
||||||
frame.response.meta.filters = {
|
frame.response.meta.filters.type = frame.options.type;
|
||||||
type: frame.options.type
|
}
|
||||||
};
|
|
||||||
|
if (frame.options.group) {
|
||||||
|
frame.response.meta.filters.group = frame.options.group;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,56 @@ describe('Settings API (canary)', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can request settings by group', function () {
|
||||||
|
return request.get(localUtils.API.getApiQuery(`settings/?group=theme`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => {
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.settings);
|
||||||
|
should.exist(jsonResponse.meta);
|
||||||
|
|
||||||
|
jsonResponse.settings.should.be.an.Object();
|
||||||
|
const settings = jsonResponse.settings;
|
||||||
|
|
||||||
|
Object.keys(settings).length.should.equal(1);
|
||||||
|
settings[0].key.should.equal('active_theme');
|
||||||
|
settings[0].value.should.equal('casper');
|
||||||
|
settings[0].type.should.equal('theme');
|
||||||
|
|
||||||
|
localUtils.API.checkResponse(jsonResponse, 'settings');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can request settings by group and by deprecated type', function () {
|
||||||
|
return request.get(localUtils.API.getApiQuery(`settings/?group=theme&type=private`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => {
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.settings);
|
||||||
|
should.exist(jsonResponse.meta);
|
||||||
|
|
||||||
|
jsonResponse.settings.should.be.an.Object();
|
||||||
|
const settings = jsonResponse.settings;
|
||||||
|
|
||||||
|
Object.keys(settings).length.should.equal(4);
|
||||||
|
settings[0].key.should.equal('active_theme');
|
||||||
|
settings[0].value.should.equal('casper');
|
||||||
|
settings[0].type.should.equal('theme');
|
||||||
|
|
||||||
|
localUtils.API.checkResponse(jsonResponse, 'settings');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Requesting core settings type returns no results', function () {
|
it('Requesting core settings type returns no results', function () {
|
||||||
return request.get(localUtils.API.getApiQuery(`settings/?type=core`))
|
return request.get(localUtils.API.getApiQuery(`settings/?type=core`))
|
||||||
.set('Origin', config.get('url'))
|
.set('Origin', config.get('url'))
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
const should = require('should');
|
||||||
|
const mapper = require('../../../../../../../../core//server/api/canary/utils/serializers/input/utils/settings-type-group-mapper');
|
||||||
|
|
||||||
|
describe('Unit: canary/utils/serializers/input/utils/settings-type-group-mapper', function () {
|
||||||
|
describe('browse', function () {
|
||||||
|
it('maps type to group 1:1', function () {
|
||||||
|
mapper('theme').should.eql('theme');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('maps type to multiple groups', function () {
|
||||||
|
mapper('blog').should.eql('site,amp,labs,slack,unsplash,views');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('maps multiple types to multiple groups', function () {
|
||||||
|
mapper('bulk_email,portal').should.eql('email,portal');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips unknown options for "bulk_email,unknown,portal" type to "bulk_email,portal', function () {
|
||||||
|
mapper('bulk_email,unknown,portal').should.eql('email,portal');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unexpected spacing', function () {
|
||||||
|
mapper(' bulk_email, portal ').should.eql('email,portal');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Reference in a new issue