Added naive settings type options parameter support to settings API v2

refs TryGhost/Ghost#10318
refs 8fc526ff6

- This is symetric change to one done for v3 API (commited as 8fc526ff6)
- Added 'core' filtering for v2 API controller
This commit is contained in:
Nazar Gargol 2020-06-25 16:32:16 +12:00
parent 05ac53ffa1
commit e394b5ad9c
7 changed files with 141 additions and 12 deletions

View File

@ -18,14 +18,14 @@ module.exports = {
// CASE: no context passed (functional call)
if (!frame.options.context) {
return Promise.resolve(settings.filter((setting) => {
return setting.type === 'site';
return setting.group === 'site';
}));
}
// CASE: omit core settings unless internal request
if (!frame.options.context.internal) {
settings = _.filter(settings, (setting) => {
const isCore = setting.type === 'core';
const isCore = setting.group === 'core';
return !isCore;
});
}
@ -60,7 +60,7 @@ module.exports = {
}
// @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({
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
}));
@ -84,7 +84,7 @@ module.exports = {
const errors = [];
frame.data.settings.map((setting) => {
if (setting.type === 'core' && !(frame.options.context && frame.options.context.internal)) {
if (setting.group === 'core' && !(frame.options.context && frame.options.context.internal)) {
errors.push(new NoPermissionError({
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
}));
@ -120,7 +120,7 @@ module.exports = {
key: setting.key
})
}));
} else if (settingFromCache.type === 'core' && !(frame.options.context && frame.options.context.internal)) {
} else if (settingFromCache.core === 'core' && !(frame.options.context && frame.options.context.internal)) {
// @TODO: handle in settings model permissible fn
errors.push(new NoPermissionError({
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')

View File

@ -1,7 +1,16 @@
const _ = require('lodash');
const url = require('./utils/url');
const typeGroupMapper = require('./utils/settings-type-group-mapper');
module.exports = {
browse(apiConfig, frame) {
if (frame.options.type) {
let mappedGroupOptions = typeGroupMapper(frame.options.type);
frame.options.group = mappedGroupOptions;
}
},
read(apiConfig, frame) {
if (frame.options.key === 'ghost_head') {
frame.options.key = 'codeinjection_head';

View File

@ -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;

View File

@ -13,10 +13,10 @@ const deprecatedSettings = ['secondary_nav'];
* @returns {*}
*/
_private.settingsFilter = (settings, filter) => {
let filteredTypes = filter ? filter.split(',') : false;
let filteredGroups = filter ? filter.split(',') : false;
return _.filter(settings, (setting) => {
if (filteredTypes) {
return _.includes(filteredTypes, setting.type) && !_.includes(deprecatedSettings, setting.key);
if (filteredGroups) {
return _.includes(filteredGroups, setting.group) && !_.includes(deprecatedSettings, setting.key);
}
return !_.includes(deprecatedSettings, setting.key);

View File

@ -19,10 +19,16 @@ module.exports.forPost = (frame, model, attrs) => {
module.exports.forSettings = (attrs, frame) => {
const _ = require('lodash');
const mapGroupToType = require('./settings-type-group-mapper');
// @TODO: https://github.com/TryGhost/Ghost/issues/10106
// @NOTE: Admin & Content API return a different format, needs two mappers
if (_.isArray(attrs)) {
attrs.forEach((attr) => {
attr.type = mapGroupToType(attr.group);
delete attr.group;
});
// CASE: read single setting
if (frame.original.params && frame.original.params.key) {
if (frame.original.params.key === 'ghost_head') {

View File

@ -0,0 +1,20 @@
const groupTypeMapping = {
core: 'core',
amp: 'blog',
labs: 'blog',
slack: 'blog',
unsplash: 'blog',
views: 'blog',
theme: 'theme',
members: 'members',
private: 'private',
portal: 'portal',
email: 'bulk_email',
site: 'site'
};
const mapGroupToType = (group) => {
return groupTypeMapping[group];
};
module.exports = mapGroupToType;

View File

@ -113,6 +113,55 @@ describe('Settings API (v2)', function () {
});
});
it('Can not request settings by group, returns all settings instead', 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(39);
settings.map(s => s.key).should.deepEqual(defaultSettingsKeys);
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Can request settings by type and ignores group ', 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(3);
settings[0].key.should.equal('is_private');
settings[0].value.should.equal(false);
settings[0].type.should.equal('private');
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Requesting core settings type returns no results', function () {
return request.get(localUtils.API.getApiQuery(`settings/?type=core`))
.set('Origin', config.get('url'))
@ -178,7 +227,7 @@ describe('Settings API (v2)', function () {
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('default_locale');
done();
});
@ -203,7 +252,7 @@ describe('Settings API (v2)', function () {
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('active_timezone');
done();
});
@ -228,7 +277,7 @@ describe('Settings API (v2)', function () {
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('ghost_head');
done();
});
@ -253,7 +302,7 @@ describe('Settings API (v2)', function () {
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('codeinjection_foot');
done();
});