Removed code + test for old type param

refs: https://github.com/TryGhost/Team/issues/1625

- type was renamed to group, and type is used to store the actual value type
- we no longer need any backwards compatibility for the old concept of type
This commit is contained in:
Hannah Wolfe 2022-05-15 14:09:53 +01:00
parent 0c097f6532
commit 51a016ac7f
8 changed files with 1184 additions and 636 deletions

View File

@ -1,6 +1,5 @@
const _ = require('lodash');
const url = require('./utils/url');
const typeGroupMapper = require('../../../../shared/serializers/input/utils/settings-filter-type-group-mapper');
const settingsCache = require('../../../../../../shared/settings-cache');
const {WRITABLE_KEYS_ALLOWLIST} = require('../../../../../../shared/labs');
@ -9,18 +8,6 @@ const DEPRECATED_SETTINGS = [
];
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;
}
}
},
edit(apiConfig, frame) {
// CASE: allow shorthand syntax where a single key and value are passed to edit instead of object and options
if (_.isString(frame.data)) {

View File

@ -1,7 +1,3 @@
const url = require('../utils/url');
module.exports = (attrs) => {
url.forSettings(attrs);
return attrs;
};

View File

@ -38,20 +38,14 @@ function serializeSettings(models, apiConfig, frame) {
}
frame.response = {
settings: mappers.settings(filteredSettings, frame),
settings: mappers.settings(filteredSettings),
meta: {}
};
if (frame.options.type || frame.options.group) {
frame.response.meta.filters = {};
if (frame.options.type) {
frame.response.meta.filters.type = frame.options.type;
}
if (frame.options.group) {
frame.response.meta.filters.group = frame.options.group;
}
if (frame.options.group) {
frame.response.meta.filters = {
group: frame.options.group
};
}
}

View File

@ -58,10 +58,6 @@ const forTag = (id, attrs, options) => {
return attrs;
};
const forSettings = (attrs) => {
return attrs;
};
const forImage = (path) => {
return urlUtils.urlFor('image', {image: path}, true);
};
@ -69,5 +65,4 @@ const forImage = (path) => {
module.exports.forPost = forPost;
module.exports.forUser = forUser;
module.exports.forTag = forTag;
module.exports.forSettings = forSettings;
module.exports.forImage = forImage;

View File

@ -36,7 +36,8 @@ const notImplemented = function (req, res, next) {
schedules: ['PUT'],
files: ['POST'],
media: ['POST'],
db: ['POST']
db: ['POST'],
settings: ['GET']
};
const match = req.url.match(/^\/(\w+)\/?/);

File diff suppressed because it is too large Load Diff

View File

@ -47,171 +47,201 @@ describe('Settings API', function () {
mockManager.restore();
});
it('Can request all settings', async function () {
await agent
.get('settings/')
.expectStatus(200)
.matchBodySnapshot({
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
})
.matchHeaderSnapshot({
etag: anyEtag
});
});
it('Can edit a setting', async function () {
const settingsToChange = [
{
key: 'title',
value: []
},
{
key: 'codeinjection_head',
value: null
},
{
key: 'navigation',
value: JSON.stringify([{
label: 'label1'
}])
},
{
key: 'slack_username',
value: 'New Slack Username'
},
{
key: 'is_private',
value: false
},
{
key: 'meta_title',
value: 'SEO title'
},
{
key: 'meta_description',
value: 'SEO description'
},
{
key: 'og_image',
value: '/content/images/2019/07/facebook.png'
},
{
key: 'og_title',
value: 'facebook title'
},
{
key: 'og_description',
value: 'facebook description'
},
{
key: 'twitter_image',
value: '/content/images/2019/07/twitter.png'
},
{
key: 'twitter_title',
value: 'twitter title'
},
{
key: 'twitter_description',
value: 'twitter description'
},
{
key: 'locale',
value: 'ua'
},
{
key: 'labs',
value: JSON.stringify({})
},
{
key: 'timezone',
value: 'Pacific/Auckland'
},
{
key: 'unsplash',
value: false
}
];
await agent.put('settings/')
.body({
settings: settingsToChange
})
.expectStatus(200)
.matchBodySnapshot({
settings: matchSettingsArray(settingsToChange.length)
})
.matchHeaderSnapshot({
etag: anyEtag
});
});
it('can do updateMembersEmail', async function () {
await agent
.post('settings/members/email/')
.body({
email: 'test@test.com',
type: 'supportAddressUpdate'
})
.expectStatus(204)
.expectEmptyBody()
.matchHeaderSnapshot({
etag: anyEtag
});
mockManager.assert.sentEmail({to: 'test@test.com'});
});
it('can do validateMembersEmailUpdate', async function () {
const magicLink = await membersService.api.getMagicLink('test@test.com');
const magicLinkUrl = new URL(magicLink);
const token = magicLinkUrl.searchParams.get('token');
// @TODO Fixing https://github.com/TryGhost/Team/issues/584 should result in this test changing
await agent
.get(`settings/members/email/?token=${token}&action=supportAddressUpdate`)
.expectStatus(302)
.expectEmptyBody()
.matchHeaderSnapshot();
// Assert that the setting is changed as a side effect
// NOTE: cannot use read here :/
await agent.get('settings/')
.expect(({body}) => {
const fromAddress = body.settings.find((setting) => {
return setting.key === 'members_support_address';
describe('Browse', function () {
it('Can request all settings', async function () {
await agent
.get('settings/')
.expectStatus(200)
.matchBodySnapshot({
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
})
.matchHeaderSnapshot({
etag: anyEtag
});
assert.equal(fromAddress.value, 'test@test.com');
});
});
it('Can request settings by group', async function () {
await agent
.get('settings/?group=theme')
.expectStatus(200)
.matchBodySnapshot({
settings: matchSettingsArray(1)
})
.matchHeaderSnapshot({
etag: anyEtag
});
});
it('Requesting core settings by group ignores the parameter and returns no settings', async function () {
await agent
.get('settings/?group=core')
.expectStatus(200)
.matchBodySnapshot()
.matchHeaderSnapshot({
etag: anyEtag
});
});
});
it('can do disconnectStripeConnectIntegration', async function () {
await agent
.delete('/settings/stripe/connect/')
.expectStatus(204)
.expectEmptyBody()
.matchHeaderSnapshot({
etag: anyEtag
});
describe('Edit', function () {
it('Can edit a setting', async function () {
const settingsToChange = [
{
key: 'title',
value: []
},
{
key: 'codeinjection_head',
value: null
},
{
key: 'navigation',
value: JSON.stringify([{
label: 'label1'
}])
},
{
key: 'slack_username',
value: 'New Slack Username'
},
{
key: 'is_private',
value: false
},
{
key: 'meta_title',
value: 'SEO title'
},
{
key: 'meta_description',
value: 'SEO description'
},
{
key: 'og_image',
value: '/content/images/2019/07/facebook.png'
},
{
key: 'og_title',
value: 'facebook title'
},
{
key: 'og_description',
value: 'facebook description'
},
{
key: 'twitter_image',
value: '/content/images/2019/07/twitter.png'
},
{
key: 'twitter_title',
value: 'twitter title'
},
{
key: 'twitter_description',
value: 'twitter description'
},
{
key: 'locale',
value: 'ua'
},
{
key: 'labs',
value: JSON.stringify({})
},
{
key: 'timezone',
value: 'Pacific/Auckland'
},
{
key: 'unsplash',
value: false
}
];
const stripeSettings = [
'stripe_connect_publishable_key',
'stripe_connect_secret_key',
'stripe_connect_livemode',
'stripe_connect_display_name',
'stripe_connect_account_id',
'members_stripe_webhook_id',
'members_stripe_webhook_secret'
];
// Assert that the settings are changed as a side effect
await agent.get('settings/')
.expect(({body}) => {
body.settings.forEach((setting) => {
if (stripeSettings.includes(setting.key)) {
assert.equal(setting.value, null);
}
await agent.put('settings/')
.body({
settings: settingsToChange
})
.expectStatus(200)
.matchBodySnapshot({
settings: matchSettingsArray(settingsToChange.length)
})
.matchHeaderSnapshot({
etag: anyEtag
});
});
});
});
describe('stripe connect', function () {
it('can do disconnectStripeConnectIntegration', async function () {
await agent
.delete('/settings/stripe/connect/')
.expectStatus(204)
.expectEmptyBody()
.matchHeaderSnapshot({
etag: anyEtag
});
const stripeSettings = [
'stripe_connect_publishable_key',
'stripe_connect_secret_key',
'stripe_connect_livemode',
'stripe_connect_display_name',
'stripe_connect_account_id',
'members_stripe_webhook_id',
'members_stripe_webhook_secret'
];
// Assert that the settings are changed as a side effect
await agent.get('settings/')
.expect(({body}) => {
body.settings.forEach((setting) => {
if (stripeSettings.includes(setting.key)) {
assert.equal(setting.value, null);
}
});
});
});
});
// @TODO Fixing https://github.com/TryGhost/Team/issues/584 should result in thes tests changing
describe('deprecated', function () {
it('can do updateMembersEmail', async function () {
await agent
.post('settings/members/email/')
.body({
email: 'test@test.com',
type: 'supportAddressUpdate'
})
.expectStatus(204)
.expectEmptyBody()
.matchHeaderSnapshot({
etag: anyEtag
});
mockManager.assert.sentEmail({to: 'test@test.com'});
});
it('can do validateMembersEmailUpdate', async function () {
const magicLink = await membersService.api.getMagicLink('test@test.com');
const magicLinkUrl = new URL(magicLink);
const token = magicLinkUrl.searchParams.get('token');
await agent
.get(`settings/members/email/?token=${token}&action=supportAddressUpdate`)
.expectStatus(302)
.expectEmptyBody()
.matchHeaderSnapshot();
// Assert that the setting is changed as a side effect
// NOTE: cannot use read here :/
await agent.get('settings/')
.expect(({body}) => {
const fromAddress = body.settings.find((setting) => {
return setting.key === 'members_support_address';
});
assert.equal(fromAddress.value, 'test@test.com');
});
});
});
});

View File

@ -6,338 +6,6 @@ const testUtils = require('../../../utils');
const localUtils = require('./utils');
const db = require('../../../../core/server/data/db');
// NOTE: in future iterations these fields should be fetched from a central module.
// Have put a list as is here for the lack of better place for it.
const defaultSettingsKeyTypes = [
{
key: 'title',
type: 'string',
group: 'site'
},
{
key: 'description',
type: 'string',
group: 'site'
},
{
key: 'logo',
type: 'string',
group: 'site'
},
{
key: 'cover_image',
type: 'string',
group: 'site'
},
{
key: 'icon',
type: 'string',
group: 'site'
},
{
key: 'locale',
type: 'string',
group: 'site'
},
{
key: 'timezone',
type: 'string',
group: 'site'
},
{
key: 'codeinjection_head',
type: 'string',
group: 'site'
},
{
key: 'codeinjection_foot',
type: 'string',
group: 'site'
},
{
key: 'facebook',
type: 'string',
group: 'site'
},
{
key: 'twitter',
type: 'string',
group: 'site'
},
{
key: 'navigation',
type: 'array',
group: 'site'
},
{
key: 'secondary_navigation',
type: 'array',
group: 'site'
},
{
key: 'meta_title',
type: 'string',
group: 'site'
},
{
key: 'meta_description',
type: 'string',
group: 'site'
},
{
key: 'og_image',
type: 'string',
group: 'site'
},
{
key: 'og_title',
type: 'string',
group: 'site'
},
{
key: 'og_description',
type: 'string',
group: 'site'
},
{
key: 'twitter_image',
type: 'string',
group: 'site'
},
{
key: 'twitter_title',
type: 'string',
group: 'site'
},
{
key: 'twitter_description',
type: 'string',
group: 'site'
},
{
key: 'active_theme',
type: 'string',
group: 'theme'
},
{
key: 'is_private',
type: 'boolean',
group: 'private'
},
{
key: 'password',
type: 'string',
group: 'private'
},
{
key: 'public_hash',
type: 'string',
group: 'private'
},
{
key: 'default_content_visibility',
type: 'string',
group: 'members'
},
{
key: 'default_content_visibility_tiers',
type: 'array',
group: 'members'
},
{
key: 'members_signup_access',
type: 'string',
group: 'members'
},
{
key: 'members_support_address',
type: 'string',
group: 'members'
},
{
key: 'members_monthly_price_id',
type: 'string',
group: 'members'
},
{
key: 'members_yearly_price_id',
type: 'string',
group: 'members'
},
{
key: 'stripe_plans',
type: 'array',
group: 'members'
},
{
key: 'stripe_secret_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_publishable_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_secret_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_publishable_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_account_id',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_display_name',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_livemode',
type: 'boolean',
group: 'members'
},
{
key: 'portal_name',
type: 'boolean',
group: 'portal'
},
{
key: 'portal_button',
type: 'boolean',
group: 'portal'
},
{
key: 'portal_plans',
type: 'array',
group: 'portal'
},
{
key: 'portal_products',
type: 'array',
group: 'portal'
},
{
key: 'portal_button_style',
type: 'string',
group: 'portal'
},
{
key: 'firstpromoter',
type: 'boolean',
group: 'firstpromoter'
},
{
key: 'firstpromoter_id',
type: 'string',
group: 'firstpromoter'
},
{
key: 'portal_button_icon',
type: 'string',
group: 'portal'
},
{
key: 'portal_button_signup_text',
type: 'string',
group: 'portal'
},
{
key: 'mailgun_api_key',
type: 'string',
group: 'email'
},
{
key: 'mailgun_domain',
type: 'string',
group: 'email'
},
{
key: 'mailgun_base_url',
type: 'string',
group: 'email'
},
{
key: 'email_track_opens',
type: 'boolean',
group: 'email'
},
{
key: 'email_verification_required',
type: 'boolean',
group: 'email'
},
{
key: 'amp',
type: 'boolean',
group: 'amp'
},
{
key: 'amp_gtag_id',
type: 'string',
group: 'amp'
},
{
key: 'slack_url',
type: 'string',
group: 'slack'
},
{
key: 'slack_username',
type: 'string',
group: 'slack'
},
{
key: 'unsplash',
type: 'boolean',
group: 'unsplash'
},
{
key: 'shared_views',
type: 'array',
group: 'views'
},
{
key: 'accent_color',
type: 'string',
group: 'site'
},
{
key: 'oauth_client_id',
type: 'string',
group: 'oauth'
},
{
key: 'oauth_client_secret',
type: 'string',
group: 'oauth'
},
{
key: 'editor_default_email_recipients',
type: 'string',
group: 'editor'
},
{
key: 'editor_default_email_recipients_filter',
type: 'string',
group: 'editor'
},
{
key: 'labs',
type: 'object',
group: 'labs'
}
];
const calculatedSettingsTypes = ['members_enabled', 'members_invite_only', 'paid_members_enabled', 'firstpromoter_account'];
describe('Settings API (canary)', function () {
let request;
@ -348,115 +16,6 @@ describe('Settings API (canary)', function () {
await localUtils.doAuth(request);
});
it('Can request all settings', function () {
return request.get(localUtils.API.getApiQuery(`settings/`))
.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;
for (const defaultSetting of defaultSettingsKeyTypes) {
should.exist(settings.find((setting) => {
return (setting.key === defaultSetting.key)
&& (setting.type === defaultSetting.type)
&& (setting.group === defaultSetting.group);
}), `Expected to find a setting with key ${defaultSetting.key}, type ${defaultSetting.type}, and group ${defaultSetting.group}`);
}
should.equal(settings.length, (defaultSettingsKeyTypes.length + calculatedSettingsTypes.length));
const unsplash = settings.find(s => s.key === 'unsplash');
should.exist(unsplash);
unsplash.value.should.equal(true);
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Ignores the deprecated type filter', function () {
return request.get(localUtils.API.getApiQuery(`settings/?type=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;
// Returns all settings
should.equal(settings.length, (defaultSettingsKeyTypes.length + calculatedSettingsTypes.length));
for (const defaultSetting of defaultSettingsKeyTypes) {
should.exist(settings.find((setting) => {
return setting.key === defaultSetting.key && setting.type === defaultSetting.type;
}), `Expected to find a setting with key ${defaultSetting.key} and type ${defaultSetting.type}`);
}
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
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('string');
settings[0].group.should.equal('theme');
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Requesting core settings type ignores the parameter and returns all settings', function () {
return request.get(localUtils.API.getApiQuery(`settings/?type=core`))
.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((defaultSettingsKeyTypes.length + calculatedSettingsTypes.length));
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Can edit newly introduced locale setting', function () {
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))