mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-08 02:52:39 -05:00
Added ability to override settings via config (#22089)
ref https://linear.app/ghost/issue/ENG-1974/create-config-option-to-forcibly-disable-email-track-clicks - We want to have the ability to turn off click tracking for sites that are adversely impacted by massive bursts of traffic from email link checkers, but we don't currently have a pattern for this. - This commit introduces a new configuration parameters `hostSettings:settingsOverrides`, which accepts key/value pairs of settings keys -> values. The value passed in here will override whatever value is set for the associated setting key in the database - It also adds an `is_read_only: true` property to any setting that is overridden, which is included in the /api/admin/settings endpoint. This value can be used by the frontend to disable the control to prevent a user from trying to change the value. - The value in the database is preserved, as the override is implemented in the settings cache `get()` and `getAll()` methods. - This commit only includes the backend changes — another commit will follow to allow disabling the 'Newsletter clicks' toggle in Admin's settings.
This commit is contained in:
parent
1d0091506b
commit
3ee9f43f6c
7 changed files with 869 additions and 10 deletions
|
@ -3,7 +3,7 @@ const _ = require('lodash');
|
|||
module.exports = (attrs) => {
|
||||
if (Array.isArray(attrs)) {
|
||||
return attrs.map((setting) => {
|
||||
return _.pick(setting, ['key', 'value']);
|
||||
return _.pick(setting, ['key', 'value', 'is_read_only']);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
const events = require('../../lib/common/events');
|
||||
const models = require('../../models');
|
||||
const labs = require('../../../shared/labs');
|
||||
const config = require('../../../shared/config');
|
||||
const adapterManager = require('../adapter-manager');
|
||||
const SettingsCache = require('../../../shared/settings-cache');
|
||||
const SettingsBREADService = require('./SettingsBREADService');
|
||||
|
@ -71,7 +72,8 @@ module.exports = {
|
|||
async init() {
|
||||
const cacheStore = adapterManager.getAdapter('cache:settings');
|
||||
const settingsCollection = await models.Settings.populateDefaults();
|
||||
SettingsCache.init(events, settingsCollection, this.getCalculatedFields(), cacheStore);
|
||||
const settingsOverrides = config.get('hostSettings:settingsOverrides') || {};
|
||||
SettingsCache.init(events, settingsCollection, this.getCalculatedFields(), cacheStore, settingsOverrides);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,7 @@ class CacheManager {
|
|||
constructor({publicSettings}) {
|
||||
// settingsCache holds cached settings, keyed by setting.key, contains the JSON version of the model
|
||||
this.settingsCache;
|
||||
this.settingsOverrides = {};
|
||||
this.publicSettings = publicSettings;
|
||||
this.calculatedFields = [];
|
||||
|
||||
|
@ -53,8 +54,20 @@ class CacheManager {
|
|||
if (!this.settingsCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
let override;
|
||||
if (this.settingsOverrides && Object.keys(this.settingsOverrides).includes(key)) {
|
||||
// Wrap the override value in an object in case it's a boolean
|
||||
override = {value: this.settingsOverrides[key]};
|
||||
}
|
||||
|
||||
const cacheEntry = this.settingsCache.get(key);
|
||||
|
||||
if (override) {
|
||||
cacheEntry.value = override.value;
|
||||
cacheEntry.is_read_only = true;
|
||||
}
|
||||
|
||||
if (!cacheEntry) {
|
||||
return;
|
||||
}
|
||||
|
@ -142,7 +155,7 @@ class CacheManager {
|
|||
const all = {};
|
||||
|
||||
keys.forEach((key) => {
|
||||
all[key] = _.cloneDeep(this.settingsCache.get(key));
|
||||
all[key] = _.cloneDeep(this.get(key, {resolve: false}));
|
||||
});
|
||||
|
||||
return all;
|
||||
|
@ -172,10 +185,12 @@ class CacheManager {
|
|||
* @param {Bookshelf.Collection<Settings>} settingsCollection
|
||||
* @param {Array} calculatedFields
|
||||
* @param {Object} cacheStore - cache storage instance base on Cache Base Adapter
|
||||
* @param {Object} settingsOverrides - key/value pairs of settings which are overridden (i.e. via config)
|
||||
* @return {Object} - filled out instance for Cache Base Adapter
|
||||
*/
|
||||
init(events, settingsCollection, calculatedFields, cacheStore) {
|
||||
init(events, settingsCollection, calculatedFields, cacheStore, settingsOverrides) {
|
||||
this.settingsCache = cacheStore;
|
||||
this.settingsOverrides = settingsOverrides;
|
||||
// First, reset the cache and
|
||||
this.reset(events);
|
||||
|
||||
|
|
|
@ -5749,6 +5749,755 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Settings API Settings overrides prevents modification of overridden settings via API 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {},
|
||||
"settings": Array [
|
||||
Object {
|
||||
"key": "members_track_sources",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "title",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "description",
|
||||
"value": "Thoughts, stories and ideas",
|
||||
},
|
||||
Object {
|
||||
"key": "logo",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "cover_image",
|
||||
"value": "https://static.ghost.org/v5.0.0/images/publication-cover.jpg",
|
||||
},
|
||||
Object {
|
||||
"key": "icon",
|
||||
"value": "http://127.0.0.1:2369/content/images/size/w256h256/2019/07/icon.png",
|
||||
},
|
||||
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": "source",
|
||||
},
|
||||
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": "default@email.com",
|
||||
},
|
||||
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": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_secret_key",
|
||||
"value": null,
|
||||
},
|
||||
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_default_plan",
|
||||
"value": "yearly",
|
||||
},
|
||||
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": "portal_signup_terms_html",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_signup_checkbox_required",
|
||||
"value": false,
|
||||
},
|
||||
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 {
|
||||
"is_read_only": true,
|
||||
"key": "email_track_clicks",
|
||||
"value": false,
|
||||
},
|
||||
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": StringMatching /\\\\\\{\\[\\^\\\\s\\]\\+\\\\\\}/,
|
||||
},
|
||||
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": "announcement_content",
|
||||
"value": "<p>Great news coming soon!</p>",
|
||||
},
|
||||
Object {
|
||||
"key": "announcement_visibility",
|
||||
"value": "[\\"visitors\\",\\"free_members\\"]",
|
||||
},
|
||||
Object {
|
||||
"key": "announcement_background",
|
||||
"value": "dark",
|
||||
},
|
||||
Object {
|
||||
"key": "comments_enabled",
|
||||
"value": "off",
|
||||
},
|
||||
Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "donations_currency",
|
||||
"value": "USD",
|
||||
},
|
||||
Object {
|
||||
"key": "donations_suggested_amount",
|
||||
"value": "500",
|
||||
},
|
||||
Object {
|
||||
"key": "recommendations_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "members_invite_only",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "allow_self_signup",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "paid_members_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_account",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "donations_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "default_email_address",
|
||||
"value": "noreply@127.0.0.1",
|
||||
},
|
||||
Object {
|
||||
"key": "support_email_address",
|
||||
"value": "default@email.com",
|
||||
},
|
||||
Object {
|
||||
"key": "all_blocked_email_domains",
|
||||
"value": Array [],
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings API Settings overrides prevents modification of overridden settings via API 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": StringMatching /\\\\d\\+/,
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": "/*",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings API Settings overrides respects settings overrides defined in hostSettings:settingsOverrides 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {},
|
||||
"settings": Array [
|
||||
Object {
|
||||
"key": "members_track_sources",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "title",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "description",
|
||||
"value": "Thoughts, stories and ideas",
|
||||
},
|
||||
Object {
|
||||
"key": "logo",
|
||||
"value": "",
|
||||
},
|
||||
Object {
|
||||
"key": "cover_image",
|
||||
"value": "https://static.ghost.org/v5.0.0/images/publication-cover.jpg",
|
||||
},
|
||||
Object {
|
||||
"key": "icon",
|
||||
"value": "http://127.0.0.1:2369/content/images/size/w256h256/2019/07/icon.png",
|
||||
},
|
||||
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": "source",
|
||||
},
|
||||
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": "default@email.com",
|
||||
},
|
||||
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": null,
|
||||
},
|
||||
Object {
|
||||
"key": "stripe_connect_secret_key",
|
||||
"value": null,
|
||||
},
|
||||
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_default_plan",
|
||||
"value": "yearly",
|
||||
},
|
||||
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": "portal_signup_terms_html",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "portal_signup_checkbox_required",
|
||||
"value": false,
|
||||
},
|
||||
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 {
|
||||
"is_read_only": true,
|
||||
"key": "email_track_clicks",
|
||||
"value": false,
|
||||
},
|
||||
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": StringMatching /\\\\\\{\\[\\^\\\\s\\]\\+\\\\\\}/,
|
||||
},
|
||||
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": "announcement_content",
|
||||
"value": "<p>Great news coming soon!</p>",
|
||||
},
|
||||
Object {
|
||||
"key": "announcement_visibility",
|
||||
"value": "[\\"visitors\\",\\"free_members\\"]",
|
||||
},
|
||||
Object {
|
||||
"key": "announcement_background",
|
||||
"value": "dark",
|
||||
},
|
||||
Object {
|
||||
"key": "comments_enabled",
|
||||
"value": "off",
|
||||
},
|
||||
Object {
|
||||
"key": "outbound_link_tagging",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_js_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "pintura_css_url",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "donations_currency",
|
||||
"value": "USD",
|
||||
},
|
||||
Object {
|
||||
"key": "donations_suggested_amount",
|
||||
"value": "500",
|
||||
},
|
||||
Object {
|
||||
"key": "recommendations_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "members_enabled",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "members_invite_only",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "allow_self_signup",
|
||||
"value": true,
|
||||
},
|
||||
Object {
|
||||
"key": "paid_members_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "firstpromoter_account",
|
||||
"value": null,
|
||||
},
|
||||
Object {
|
||||
"key": "donations_enabled",
|
||||
"value": false,
|
||||
},
|
||||
Object {
|
||||
"key": "default_email_address",
|
||||
"value": "noreply@127.0.0.1",
|
||||
},
|
||||
Object {
|
||||
"key": "support_email_address",
|
||||
"value": "default@email.com",
|
||||
},
|
||||
Object {
|
||||
"key": "all_blocked_email_domains",
|
||||
"value": Array [],
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings API Settings overrides respects settings overrides defined in hostSettings:settingsOverrides 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": StringMatching /\\\\d\\+/,
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings API deprecated can do updateMembersEmail 1: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
|
|
|
@ -968,7 +968,7 @@ describe('Members API', function () {
|
|||
await agent.delete(`/members/${memberFailVerification.id}`);
|
||||
|
||||
await configUtils.restore();
|
||||
settingsCache.set('email_verification_required', false);
|
||||
settingsCache.set('email_verification_required', {value: false});
|
||||
});
|
||||
|
||||
it('Can add and send a signup confirmation email', async function () {
|
||||
|
|
|
@ -659,4 +659,47 @@ describe('Settings API', function () {
|
|||
mockManager.assert.sentEmailCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Settings overrides', function () {
|
||||
this.beforeEach(async function () {
|
||||
const settingsOverrides = {
|
||||
email_track_clicks: false
|
||||
};
|
||||
configUtils.set('hostSettings:settingsOverrides', settingsOverrides);
|
||||
await fixtureManager.init();
|
||||
});
|
||||
|
||||
it('respects settings overrides defined in hostSettings:settingsOverrides', async function () {
|
||||
await agent.get('settings/')
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
'content-length': anyContentLength,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
|
||||
it('prevents modification of overridden settings via API', async function () {
|
||||
await agent.put('settings/')
|
||||
.body({
|
||||
settings: [{
|
||||
key: 'email_track_clicks',
|
||||
value: true
|
||||
}]
|
||||
})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
settings: matchSettingsArray(CURRENT_SETTINGS_COUNT)
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
'content-length': anyContentLength,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,15 +10,20 @@ const InMemoryCache = require('../../../core/server/adapters/cache/MemoryCache')
|
|||
|
||||
should.equal(true, true);
|
||||
|
||||
function createCacheManager(settingsOverrides = {}) {
|
||||
const cacheStore = new InMemoryCache();
|
||||
const cache = new CacheManager({
|
||||
publicSettings
|
||||
});
|
||||
cache.init(events, {}, [], cacheStore, settingsOverrides);
|
||||
return cache;
|
||||
}
|
||||
|
||||
describe('UNIT: settings cache', function () {
|
||||
let cache;
|
||||
|
||||
beforeEach(function () {
|
||||
let cacheStore = new InMemoryCache();
|
||||
cache = new CacheManager({
|
||||
publicSettings
|
||||
});
|
||||
cache.init(events, {}, [], cacheStore);
|
||||
cache = createCacheManager();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
|
@ -93,12 +98,57 @@ describe('UNIT: settings cache', function () {
|
|||
should(cache.get('stringarr')).eql([]);
|
||||
});
|
||||
|
||||
it('.get() respects settingsOverrides', function () {
|
||||
cache = createCacheManager({
|
||||
email_track_clicks: false
|
||||
});
|
||||
cache.set('email_track_clicks', {value: true});
|
||||
should(cache.get('email_track_clicks')).eql(false);
|
||||
should(cache.get('email_track_clicks', {resolve: false})).eql({value: false, is_read_only: true});
|
||||
});
|
||||
|
||||
it('.get() only returns an override if the key is set to begin with', function () {
|
||||
should(cache.get('email_track_clicks', {resolve: false})).eql(undefined);
|
||||
});
|
||||
|
||||
it('.getAll() returns all values', function () {
|
||||
cache.set('key1', {value: '1'});
|
||||
cache.get('key1').should.eql('1');
|
||||
cache.getAll().should.eql({key1: {value: '1'}});
|
||||
});
|
||||
|
||||
it('.getAll() respects settingsOverrides', function () {
|
||||
cache = createCacheManager({
|
||||
email_track_clicks: false
|
||||
});
|
||||
cache.set('email_track_clicks', {
|
||||
id: '67996cef430e5905ab385357',
|
||||
group: 'email',
|
||||
key: 'email_track_clicks',
|
||||
value: true,
|
||||
type: 'boolean'
|
||||
});
|
||||
cache.getAll().should.eql({email_track_clicks: {
|
||||
id: '67996cef430e5905ab385357',
|
||||
group: 'email',
|
||||
key: 'email_track_clicks',
|
||||
value: false,
|
||||
is_read_only: true,
|
||||
type: 'boolean'
|
||||
}});
|
||||
});
|
||||
|
||||
it('handles multiple settingsOverrides correctly', function () {
|
||||
cache = createCacheManager({
|
||||
setting1: false,
|
||||
setting2: 'test'
|
||||
});
|
||||
cache.set('setting1', {value: true});
|
||||
cache.set('setting2', {value: 'original'});
|
||||
should(cache.get('setting1')).eql(false);
|
||||
should(cache.get('setting2')).eql('test');
|
||||
});
|
||||
|
||||
it('.getPublic() correctly filters and formats public values', function () {
|
||||
cache.set('key1', {value: 'something'});
|
||||
cache.set('title', {value: 'hello world'});
|
||||
|
|
Loading…
Add table
Reference in a new issue