mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-04 17:04:59 +03:00
Updated settings API to return all settings in edit endpoint (#14889)
refs https://github.com/TryGhost/Team/issues/1650 Since we introduced calculated settings, we need to return all settings when editing a setting, because those calculated settings can change. - When editing settings, return all the settings. Previously we didn't include the calculated settings (which caused issues with admin not having up to date values for those) - Updated Stripe <head> script to be injected based on the calculated settings Required for https://github.com/TryGhost/Admin/pull/2405
This commit is contained in:
parent
c46303cb2b
commit
c052652559
@ -44,17 +44,14 @@ function finaliseStructuredData(meta) {
|
||||
}
|
||||
|
||||
function getMembersHelper(data, frontendKey) {
|
||||
if (settingsCache.get('members_signup_access') === 'none') {
|
||||
if (!settingsCache.get('members_enabled')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const stripeDirectSecretKey = settingsCache.get('stripe_secret_key');
|
||||
const stripeDirectPublishableKey = settingsCache.get('stripe_publishable_key');
|
||||
const stripeConnectAccountId = settingsCache.get('stripe_connect_account_id');
|
||||
const colorString = _.has(data, 'site._preview') && data.site.accent_color ? ` data-accent-color="${data.site.accent_color}"` : '';
|
||||
let membersHelper = `<script defer src="${config.get('portal:url')}" data-ghost="${urlUtils.getSiteUrl()}"${colorString} data-key="${frontendKey}" data-api="${urlUtils.urlFor('api', {type: 'content'}, true)}" crossorigin="anonymous"></script>`;
|
||||
membersHelper += (`<style id="gh-members-styles">${templateStyles}</style>`);
|
||||
if ((!!stripeDirectSecretKey && !!stripeDirectPublishableKey) || !!stripeConnectAccountId) {
|
||||
if (settingsCache.get('paid_members_enabled')) {
|
||||
membersHelper += '<script async src="https://js.stripe.com/v3/"></script>';
|
||||
}
|
||||
return membersHelper;
|
||||
|
@ -195,7 +195,9 @@ module.exports = {
|
||||
this.headers.cacheInvalidate = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
// We need to return all settings here, because we have calculated settings that might change
|
||||
const browse = await settingsBREADService.browse(frame.options.context);
|
||||
return browse;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -118,7 +118,7 @@ module.exports = {
|
||||
return connectKeys;
|
||||
},
|
||||
|
||||
isStripeConnected() {
|
||||
arePaidMembersEnabled() {
|
||||
return this.isMembersEnabled() && this.getActiveStripeKeys() !== null;
|
||||
},
|
||||
|
||||
@ -137,7 +137,7 @@ module.exports = {
|
||||
|
||||
fields.push(new CalculatedField({key: 'members_enabled', type: 'boolean', group: 'members', fn: this.isMembersEnabled.bind(this), dependents: ['members_signup_access']}));
|
||||
fields.push(new CalculatedField({key: 'members_invite_only', type: 'boolean', group: 'members', fn: this.isMembersInviteOnly.bind(this), dependents: ['members_signup_access']}));
|
||||
fields.push(new CalculatedField({key: 'paid_members_enabled', type: 'boolean', group: 'members', fn: this.isStripeConnected.bind(this), dependents: ['members_signup_access', 'stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
|
||||
fields.push(new CalculatedField({key: 'paid_members_enabled', type: 'boolean', group: 'members', fn: this.arePaidMembersEnabled.bind(this), dependents: ['members_signup_access', 'stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
|
||||
fields.push(new CalculatedField({key: 'firstpromoter_account', type: 'string', group: 'firstpromoter', fn: this.getFirstpromoterId.bind(this), dependents: ['firstpromoter', 'firstpromoter_id']}));
|
||||
|
||||
return fields;
|
||||
|
@ -1286,21 +1286,57 @@ Object {
|
||||
"key": "title",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "description",
|
||||
"value": "Thoughts, stories and ideas",
|
||||
},
|
||||
Object {
|
||||
"key": "logo",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "cover_image",
|
||||
"value": "https://static.ghost.org/v4.0.0/images/publication-cover.jpg",
|
||||
},
|
||||
Object {
|
||||
"key": "icon",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "accent_color",
|
||||
"value": "#FF1A75",
|
||||
},
|
||||
Object {
|
||||
"key": "locale",
|
||||
"value": "ua",
|
||||
},
|
||||
Object {
|
||||
"key": "timezone",
|
||||
"value": "Pacific/Auckland",
|
||||
},
|
||||
Object {
|
||||
"key": "codeinjection_head",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "codeinjection_foot",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "facebook",
|
||||
"value": "ghost",
|
||||
},
|
||||
Object {
|
||||
"key": "twitter",
|
||||
"value": "@ghost",
|
||||
},
|
||||
Object {
|
||||
"key": "navigation",
|
||||
"value": "[{\\"label\\":\\"label1\\"}]",
|
||||
},
|
||||
Object {
|
||||
"key": "slack_username",
|
||||
"value": "New Slack Username",
|
||||
},
|
||||
Object {
|
||||
"key": "is_private",
|
||||
"value": false,
|
||||
"key": "secondary_navigation",
|
||||
"value": "[{\\"label\\":\\"Data & privacy\\",\\"url\\":\\"/privacy/\\"},{\\"label\\":\\"Contact\\",\\"url\\":\\"/contact/\\"},{\\"label\\":\\"Contribute →\\",\\"url\\":\\"/contribute/\\"}]",
|
||||
},
|
||||
Object {
|
||||
"key": "meta_title",
|
||||
@ -1335,21 +1371,185 @@ Object {
|
||||
"value": "twitter description",
|
||||
},
|
||||
Object {
|
||||
"key": "locale",
|
||||
"value": "ua",
|
||||
"key": "active_theme",
|
||||
"value": "casper",
|
||||
},
|
||||
Object {
|
||||
"key": "is_private",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "password",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "public_hash",
|
||||
"value": StringMatching /\\[a-z0-9\\]\\{30\\}/,
|
||||
},
|
||||
Object {
|
||||
"key": "default_content_visibility",
|
||||
"value": "public",
|
||||
},
|
||||
Object {
|
||||
"key": "default_content_visibility_tiers",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "members_signup_access",
|
||||
"value": "all",
|
||||
},
|
||||
Object {
|
||||
"key": "members_support_address",
|
||||
"value": "noreply",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_secret_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_publishable_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_plans",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_publishable_key",
|
||||
"value": "pk_test_for_stripe",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_secret_key",
|
||||
"value": "••••••••",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_livemode",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_display_name",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_account_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_monthly_price_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_yearly_price_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_name",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_plans",
|
||||
"value": "[\\"free\\"]",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_products",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_style",
|
||||
"value": "icon-and-text",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_icon",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_signup_text",
|
||||
"value": "Subscribe",
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_domain",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_api_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_base_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "email_track_opens",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "email_verification_required",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "amp",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "amp_gtag_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "labs",
|
||||
"value": "{\\"multipleProducts\\":true,\\"tierWelcomePages\\":true,\\"tierName\\":true,\\"selectablePortalLinks\\":true,\\"membersTableStatus\\":true,\\"multipleNewsletters\\":true,\\"multipleNewslettersUI\\":true,\\"membersActivityFeed\\":true,\\"dashboardV5\\":true,\\"members\\":true}",
|
||||
},
|
||||
Object {
|
||||
"key": "timezone",
|
||||
"value": "Pacific/Auckland",
|
||||
"key": "slack_url",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "slack_username",
|
||||
"value": "New Slack Username",
|
||||
},
|
||||
Object {
|
||||
"key": "unsplash",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "shared_views",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "editor_default_email_recipients",
|
||||
"value": "visibility",
|
||||
},
|
||||
Object {
|
||||
"key": "editor_default_email_recipients_filter",
|
||||
"value": "all",
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "members_invite_only",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "paid_members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_account",
|
||||
"value": null,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@ -1358,7 +1558,7 @@ exports[`Settings API Edit Can edit a setting 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "1112",
|
||||
"content-length": "3536",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
@ -1370,7 +1570,276 @@ Object {
|
||||
exports[`Settings API Edit cannot edit uneditable settings 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {},
|
||||
"settings": Array [],
|
||||
"settings": Array [
|
||||
Object {
|
||||
"key": "title",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "description",
|
||||
"value": "Thoughts, stories and ideas",
|
||||
},
|
||||
Object {
|
||||
"key": "logo",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "cover_image",
|
||||
"value": "https://static.ghost.org/v4.0.0/images/publication-cover.jpg",
|
||||
},
|
||||
Object {
|
||||
"key": "icon",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "accent_color",
|
||||
"value": "#FF1A75",
|
||||
},
|
||||
Object {
|
||||
"key": "locale",
|
||||
"value": "ua",
|
||||
},
|
||||
Object {
|
||||
"key": "timezone",
|
||||
"value": "Pacific/Auckland",
|
||||
},
|
||||
Object {
|
||||
"key": "codeinjection_head",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "codeinjection_foot",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "facebook",
|
||||
"value": "ghost",
|
||||
},
|
||||
Object {
|
||||
"key": "twitter",
|
||||
"value": "@ghost",
|
||||
},
|
||||
Object {
|
||||
"key": "navigation",
|
||||
"value": "[{\\"label\\":\\"label1\\"}]",
|
||||
},
|
||||
Object {
|
||||
"key": "secondary_navigation",
|
||||
"value": "[{\\"label\\":\\"Data & privacy\\",\\"url\\":\\"/privacy/\\"},{\\"label\\":\\"Contact\\",\\"url\\":\\"/contact/\\"},{\\"label\\":\\"Contribute →\\",\\"url\\":\\"/contribute/\\"}]",
|
||||
},
|
||||
Object {
|
||||
"key": "meta_title",
|
||||
"value": "SEO title",
|
||||
},
|
||||
Object {
|
||||
"key": "meta_description",
|
||||
"value": "SEO description",
|
||||
},
|
||||
Object {
|
||||
"key": "og_image",
|
||||
"value": "http://127.0.0.1:2369/content/images/2019/07/facebook.png",
|
||||
},
|
||||
Object {
|
||||
"key": "og_title",
|
||||
"value": "facebook title",
|
||||
},
|
||||
Object {
|
||||
"key": "og_description",
|
||||
"value": "facebook description",
|
||||
},
|
||||
Object {
|
||||
"key": "twitter_image",
|
||||
"value": "http://127.0.0.1:2369/content/images/2019/07/twitter.png",
|
||||
},
|
||||
Object {
|
||||
"key": "twitter_title",
|
||||
"value": "twitter title",
|
||||
},
|
||||
Object {
|
||||
"key": "twitter_description",
|
||||
"value": "twitter description",
|
||||
},
|
||||
Object {
|
||||
"key": "active_theme",
|
||||
"value": "casper",
|
||||
},
|
||||
Object {
|
||||
"key": "is_private",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "password",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "public_hash",
|
||||
"value": StringMatching /\\[a-z0-9\\]\\{30\\}/,
|
||||
},
|
||||
Object {
|
||||
"key": "default_content_visibility",
|
||||
"value": "public",
|
||||
},
|
||||
Object {
|
||||
"key": "default_content_visibility_tiers",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "members_signup_access",
|
||||
"value": "all",
|
||||
},
|
||||
Object {
|
||||
"key": "members_support_address",
|
||||
"value": "noreply",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_secret_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_publishable_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_plans",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_publishable_key",
|
||||
"value": "pk_test_for_stripe",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_secret_key",
|
||||
"value": "••••••••",
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_livemode",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_display_name",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_account_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_monthly_price_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "members_yearly_price_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_name",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_plans",
|
||||
"value": "[\\"free\\"]",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_products",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_style",
|
||||
"value": "icon-and-text",
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_icon",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_button_signup_text",
|
||||
"value": "Subscribe",
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_domain",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_api_key",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "mailgun_base_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "email_track_opens",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "email_verification_required",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "amp",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "amp_gtag_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_id",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "labs",
|
||||
"value": "{\\"multipleProducts\\":true,\\"tierWelcomePages\\":true,\\"tierName\\":true,\\"selectablePortalLinks\\":true,\\"membersTableStatus\\":true,\\"multipleNewsletters\\":true,\\"multipleNewslettersUI\\":true,\\"membersActivityFeed\\":true,\\"dashboardV5\\":true,\\"members\\":true}",
|
||||
},
|
||||
Object {
|
||||
"key": "slack_url",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "slack_username",
|
||||
"value": "New Slack Username",
|
||||
},
|
||||
Object {
|
||||
"key": "unsplash",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "shared_views",
|
||||
"value": "[]",
|
||||
},
|
||||
Object {
|
||||
"key": "editor_default_email_recipients",
|
||||
"value": "visibility",
|
||||
},
|
||||
Object {
|
||||
"key": "editor_default_email_recipients_filter",
|
||||
"value": "all",
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "members_invite_only",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "paid_members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_account",
|
||||
"value": null,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
@ -1390,7 +1859,7 @@ exports[`Settings API Edit cannot edit uneditable settings 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "25",
|
||||
"content-length": "3536",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
|
@ -157,7 +157,7 @@ describe('Settings API', function () {
|
||||
})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
settings: matchSettingsArray(settingsToChange.length)
|
||||
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag
|
||||
@ -167,12 +167,18 @@ describe('Settings API', function () {
|
||||
it('cannot edit uneditable settings', async function () {
|
||||
await agent.put('settings/')
|
||||
.body({
|
||||
settings: [{key: 'email_verification_required', value: false}]
|
||||
settings: [{key: 'email_verification_required', value: true}]
|
||||
})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot()
|
||||
.matchBodySnapshot({
|
||||
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag
|
||||
})
|
||||
.expect(({body}) => {
|
||||
const emailVerificationRequired = body.settings.find(setting => setting.key === 'email_verification_required');
|
||||
assert.strictEqual(emailVerificationRequired.value, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -5,10 +5,63 @@ const config = require('../../../../core/shared/config');
|
||||
const testUtils = require('../../../utils');
|
||||
const localUtils = require('./utils');
|
||||
const db = require('../../../../core/server/data/db');
|
||||
const settingsCache = require('../../../../core/shared/settings-cache');
|
||||
|
||||
describe('Settings API (canary)', function () {
|
||||
let request;
|
||||
|
||||
async function checkCanEdit(key, value, expectedValue) {
|
||||
if (!expectedValue) {
|
||||
expectedValue = value;
|
||||
}
|
||||
|
||||
const settingToChange = {
|
||||
settings: [{key, value}]
|
||||
};
|
||||
|
||||
await request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.expect((response) => {
|
||||
should.exist(response.headers['x-cache-invalidate']);
|
||||
response.headers['x-cache-invalidate'].should.eql('/*');
|
||||
});
|
||||
|
||||
// Check if not changed (also check internal ones)
|
||||
const afterValue = settingsCache.get(key);
|
||||
should.deepEqual(afterValue, expectedValue);
|
||||
}
|
||||
|
||||
async function checkCantEdit(key, value) {
|
||||
// Get current value (internal)
|
||||
const currentValue = settingsCache.get(key);
|
||||
|
||||
const settingToChange = {
|
||||
settings: [{key, value}]
|
||||
};
|
||||
|
||||
if (currentValue === value) {
|
||||
throw new Error('This test requires a different value than the current one');
|
||||
}
|
||||
|
||||
await request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.expect((response) => {
|
||||
should.not.exist(response.headers['x-cache-invalidate']);
|
||||
});
|
||||
|
||||
// Check if not changed (also check internal ones)
|
||||
const afterValue = settingsCache.get(key);
|
||||
should.deepEqual(afterValue, currentValue);
|
||||
}
|
||||
|
||||
describe('As Owner', function () {
|
||||
before(async function () {
|
||||
await localUtils.startGhost();
|
||||
@ -16,152 +69,32 @@ describe('Settings API (canary)', function () {
|
||||
await localUtils.doAuth(request);
|
||||
});
|
||||
|
||||
it('Can edit newly introduced locale setting', function () {
|
||||
return request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send({
|
||||
settings: [{key: 'locale', value: 'ge'}]
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.then(function (res) {
|
||||
should.exist(res.headers['x-cache-invalidate']);
|
||||
const jsonResponse = res.body;
|
||||
|
||||
should.exist(jsonResponse);
|
||||
should.exist(jsonResponse.settings);
|
||||
|
||||
jsonResponse.settings.length.should.eql(1);
|
||||
|
||||
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['key', 'value']);
|
||||
jsonResponse.settings[0].key.should.eql('locale');
|
||||
jsonResponse.settings[0].value.should.eql('ge');
|
||||
});
|
||||
it('Can edit newly introduced locale setting', async function () {
|
||||
await checkCanEdit('locale', 'ge');
|
||||
});
|
||||
|
||||
it('Can\'t edit permalinks', async function () {
|
||||
const settingToChange = {
|
||||
settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}]
|
||||
};
|
||||
|
||||
await request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.expect(({body, headers}) => {
|
||||
// it didn't actually edit anything, but we don't error anymore
|
||||
body.should.eql({
|
||||
settings: [],
|
||||
meta: {}
|
||||
});
|
||||
|
||||
should.not.exist(headers['x-cache-invalidate']);
|
||||
});
|
||||
await checkCantEdit('permalinks', '/:primary_author/:slug/');
|
||||
});
|
||||
|
||||
it('Can edit only allowed labs keys', async function () {
|
||||
const settingToChange = {
|
||||
settings: [{
|
||||
key: 'labs',
|
||||
value: JSON.stringify({
|
||||
activitypub: true,
|
||||
gibberish: true
|
||||
})
|
||||
}]
|
||||
};
|
||||
|
||||
const res = await request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200);
|
||||
|
||||
const jsonResponse = res.body;
|
||||
|
||||
should.exist(jsonResponse);
|
||||
should.exist(jsonResponse.settings);
|
||||
|
||||
jsonResponse.settings.length.should.eql(1);
|
||||
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['key', 'value']);
|
||||
jsonResponse.settings[0].key.should.eql('labs');
|
||||
|
||||
const responseObj = JSON.parse(jsonResponse.settings[0].value);
|
||||
|
||||
should.not.exist(responseObj.gibberish);
|
||||
await checkCanEdit('labs',
|
||||
JSON.stringify({
|
||||
activitypub: true,
|
||||
gibberish: true
|
||||
}),
|
||||
{
|
||||
activitypub: true
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Can\'t edit non existent setting', function () {
|
||||
return request.get(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.set('Accept', 'application/json')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.then(function (res) {
|
||||
let jsonResponse = res.body;
|
||||
const newValue = 'new value';
|
||||
should.exist(jsonResponse);
|
||||
should.exist(jsonResponse.settings);
|
||||
jsonResponse.settings = [{key: 'testvalue', value: newValue}];
|
||||
|
||||
return request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(jsonResponse)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.expect(({body, headers}) => {
|
||||
// it didn't actually edit anything, but we don't error anymore
|
||||
body.should.eql({
|
||||
settings: [],
|
||||
meta: {}
|
||||
});
|
||||
|
||||
should.not.exist(headers['x-cache-invalidate']);
|
||||
});
|
||||
});
|
||||
it('Can\'t edit non existent setting', async function () {
|
||||
await checkCantEdit('non-existent-setting', 'value');
|
||||
});
|
||||
|
||||
it('Will transform "1"', function () {
|
||||
return request.get(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.then(function (res) {
|
||||
const jsonResponse = res.body;
|
||||
|
||||
const settingToChange = {
|
||||
settings: [
|
||||
{
|
||||
key: 'is_private',
|
||||
value: '1'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
should.exist(jsonResponse);
|
||||
should.exist(jsonResponse.settings);
|
||||
|
||||
return request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.then(function ({body, headers}) {
|
||||
const putBody = body;
|
||||
headers['x-cache-invalidate'].should.eql('/*');
|
||||
should.exist(putBody);
|
||||
|
||||
putBody.settings[0].key.should.eql('is_private');
|
||||
putBody.settings[0].value.should.eql(true);
|
||||
|
||||
localUtils.API.checkResponse(putBody, 'settings');
|
||||
});
|
||||
});
|
||||
return checkCanEdit('is_private', '1', true);
|
||||
});
|
||||
|
||||
it('Can edit multiple setting along with a deprecated one from v4', async function () {
|
||||
@ -194,13 +127,11 @@ describe('Settings API (canary)', function () {
|
||||
headers['x-cache-invalidate'].should.eql('/*');
|
||||
should.exist(putBody);
|
||||
|
||||
putBody.settings.length.should.equal(2);
|
||||
let setting = putBody.settings.find(s => s.key === 'unsplash');
|
||||
should.equal(setting.value, true);
|
||||
|
||||
putBody.settings[0].key.should.eql('unsplash');
|
||||
should.equal(putBody.settings[0].value, true);
|
||||
|
||||
putBody.settings[1].key.should.eql('title');
|
||||
should.equal(putBody.settings[1].value, 'New Value');
|
||||
setting = putBody.settings.find(s => s.key === 'title');
|
||||
should.equal(setting.value, 'New Value');
|
||||
|
||||
localUtils.API.checkResponse(putBody, 'settings');
|
||||
});
|
||||
@ -226,11 +157,9 @@ describe('Settings API (canary)', function () {
|
||||
headers['x-cache-invalidate'].should.eql('/*');
|
||||
should.exist(putBody);
|
||||
|
||||
putBody.settings.length.should.equal(1);
|
||||
|
||||
localUtils.API.checkResponse(putBody, 'settings');
|
||||
putBody.settings[0].key.should.eql('slack_username');
|
||||
putBody.settings[0].value.should.eql('can edit me');
|
||||
const setting = putBody.settings.find(s => s.key === 'slack_username');
|
||||
setting.value.should.eql('can edit me');
|
||||
});
|
||||
|
||||
it('Can edit URLs without internal storage format leaking', async function () {
|
||||
@ -297,27 +226,7 @@ describe('Settings API (canary)', function () {
|
||||
});
|
||||
|
||||
it('Cannot edit notifications key through API', async function () {
|
||||
const settingsToChange = {
|
||||
settings: [
|
||||
{key: 'notifications', value: JSON.stringify(['do not touch me'])}
|
||||
]
|
||||
};
|
||||
|
||||
await request.put(localUtils.API.getApiQuery('settings/'))
|
||||
.set('Origin', config.get('url'))
|
||||
.send(settingsToChange)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||
.expect(200)
|
||||
.expect(({body, headers}) => {
|
||||
// it didn't actually edit anything, but we don't error anymore
|
||||
body.should.eql({
|
||||
settings: [],
|
||||
meta: {}
|
||||
});
|
||||
|
||||
should.not.exist(headers['x-cache-invalidate']);
|
||||
});
|
||||
await checkCantEdit('notifications', JSON.stringify(['do not touch me']));
|
||||
});
|
||||
});
|
||||
|
||||
@ -452,14 +361,22 @@ describe('Settings API (canary)', function () {
|
||||
});
|
||||
|
||||
it('allows editing settings that cannot be edited via HTTP', async function () {
|
||||
// Get current value
|
||||
const {settings} = await api.settings.browse({}, testUtils.context.internal);
|
||||
|
||||
const currentValue = settings.find(s => s.key === 'email_verification_required');
|
||||
|
||||
if (!currentValue || currentValue.value === true) {
|
||||
throw new Error('Invalid key or unchanged value');
|
||||
}
|
||||
|
||||
let jsonResponse = await api.settings.edit({
|
||||
settings: [{key: 'email_verification_required', value: false}]
|
||||
settings: [{key: 'email_verification_required', value: true}]
|
||||
}, testUtils.context.internal);
|
||||
|
||||
jsonResponse.should.eql({
|
||||
settings: [{key: 'email_verification_required', value: false}],
|
||||
meta: {}
|
||||
});
|
||||
const setting = jsonResponse.settings.find(s => s.key === 'email_verification_required');
|
||||
should.exist(setting);
|
||||
setting.value.should.eql(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1577,6 +1577,8 @@ describe('{{ghost_head}} helper', function () {
|
||||
});
|
||||
|
||||
it('attaches style tag to existing script/style tag', function (done) {
|
||||
settingsCache.get.withArgs('members_enabled').returns(true);
|
||||
|
||||
const renderObject = {
|
||||
post: posts[1]
|
||||
};
|
||||
@ -1656,8 +1658,8 @@ describe('{{ghost_head}} helper', function () {
|
||||
});
|
||||
|
||||
describe('members scripts', function () {
|
||||
it('includes portal when signup is "all"', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('all');
|
||||
it('includes portal when members enabled', function (done) {
|
||||
settingsCache.get.withArgs('members_enabled').returns(true);
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
@ -1674,29 +1676,9 @@ describe('{{ghost_head}} helper', function () {
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('includes portal when signup is "invite"', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('invite');
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
relativeUrl: '/',
|
||||
context: ['home', 'index'],
|
||||
safeVersion: '4.3'
|
||||
}
|
||||
})).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
|
||||
rendered.string.should.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
|
||||
rendered.string.should.containEql('<style id="gh-members-styles">');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('includes stripe when set up as direct', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('all');
|
||||
settingsCache.get.withArgs('stripe_secret_key').returns('secret');
|
||||
settingsCache.get.withArgs('stripe_publishable_key').returns('publishable');
|
||||
settingsCache.get.withArgs('stripe_connect_account_id').returns(null);
|
||||
it('includes stripe when connected', function (done) {
|
||||
settingsCache.get.withArgs('members_enabled').returns(true);
|
||||
settingsCache.get.withArgs('paid_members_enabled').returns(true);
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
@ -1714,31 +1696,9 @@ describe('{{ghost_head}} helper', function () {
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('includes stripe when set up as connect', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('all');
|
||||
settingsCache.get.withArgs('stripe_secret_key').returns(null);
|
||||
settingsCache.get.withArgs('stripe_publishable_key').returns(null);
|
||||
settingsCache.get.withArgs('stripe_connect_account_id').returns('connect_account');
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
relativeUrl: '/',
|
||||
context: ['home', 'index'],
|
||||
safeVersion: '4.3'
|
||||
}
|
||||
})).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
|
||||
rendered.string.should.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
|
||||
rendered.string.should.containEql('<style id="gh-members-styles">');
|
||||
rendered.string.should.containEql('<script async src="https://js.stripe.com');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('skips portal and stripe when signup is "none"', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('none');
|
||||
settingsCache.get.withArgs('stripe_connect_account_id').returns('connect_account');
|
||||
it('skips portal and stripe when members are disabled', function (done) {
|
||||
settingsCache.get.withArgs('members_enabled').returns(false);
|
||||
settingsCache.get.withArgs('paid_members_enabled').returns(true);
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
@ -1757,10 +1717,8 @@ describe('{{ghost_head}} helper', function () {
|
||||
});
|
||||
|
||||
it('skips stripe if not set up', function (done) {
|
||||
settingsCache.get.withArgs('members_signup_access').returns('all');
|
||||
settingsCache.get.withArgs('stripe_secret_key', null);
|
||||
settingsCache.get.withArgs('stripe_publishable_key', null);
|
||||
settingsCache.get.withArgs('stripe_connect_account_id', null);
|
||||
settingsCache.get.withArgs('members_enabled').returns(true);
|
||||
settingsCache.get.withArgs('paid_members_enabled').returns(false);
|
||||
|
||||
ghost_head(testUtils.createHbsResponse({
|
||||
locals: {
|
||||
|
Loading…
Reference in New Issue
Block a user