2017-02-27 18:53:04 +03:00
|
|
|
// It's important to keep the requires absolutely minimal here,
|
|
|
|
// As this cache is used in SO many other areas, we may open ourselves to
|
|
|
|
// circular dependency bugs.
|
2021-06-15 19:01:22 +03:00
|
|
|
const debug = require('@tryghost/debug')('settings:cache');
|
2019-01-03 18:23:22 +03:00
|
|
|
const _ = require('lodash');
|
2021-04-27 16:18:04 +03:00
|
|
|
const events = require('../../lib/common/events');
|
2019-01-03 18:23:22 +03:00
|
|
|
const publicSettings = require('./public');
|
2017-12-14 18:41:30 +03:00
|
|
|
|
|
|
|
// Local function, only ever used for initialising
|
|
|
|
// We deliberately call "set" on each model so that set is a consistent interface
|
2019-01-03 18:23:22 +03:00
|
|
|
const updateSettingFromModel = function updateSettingFromModel(settingModel) {
|
2017-12-14 18:41:30 +03:00
|
|
|
debug('Auto updating', settingModel.get('key'));
|
|
|
|
module.exports.set(settingModel.get('key'), settingModel.toJSON());
|
|
|
|
};
|
2017-02-27 18:53:04 +03:00
|
|
|
|
2019-01-03 18:23:22 +03:00
|
|
|
/**
|
|
|
|
* ## Cache
|
|
|
|
* Holds cached settings
|
|
|
|
* Keyed by setting.key
|
|
|
|
* Contains the JSON version of the model
|
|
|
|
* @type {{}} - object of objects
|
|
|
|
*/
|
|
|
|
let settingsCache = {};
|
|
|
|
|
|
|
|
const doGet = (key, options) => {
|
|
|
|
if (!settingsCache[key]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't try to resolve to the value of the setting
|
|
|
|
if (options && options.resolve === false) {
|
2019-01-07 16:35:51 +03:00
|
|
|
return settingsCache[key] || null;
|
2019-01-03 18:23:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Default behaviour is to try to resolve the value and return that
|
|
|
|
try {
|
|
|
|
// CASE: if a string contains a number e.g. "1", JSON.parse will auto convert into integer
|
|
|
|
if (!isNaN(Number(settingsCache[key].value))) {
|
2019-01-07 16:35:51 +03:00
|
|
|
return settingsCache[key].value || null;
|
2019-01-03 18:23:22 +03:00
|
|
|
}
|
|
|
|
|
2019-01-07 16:35:51 +03:00
|
|
|
return JSON.parse(settingsCache[key].value) || null;
|
2019-01-03 18:23:22 +03:00
|
|
|
} catch (err) {
|
2019-01-07 16:35:51 +03:00
|
|
|
return settingsCache[key].value || null;
|
2019-01-03 18:23:22 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-27 18:53:04 +03:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* IMPORTANT:
|
|
|
|
* We store settings with a type and a key in the database.
|
|
|
|
*
|
|
|
|
* {
|
|
|
|
* type: core
|
2017-04-24 20:41:00 +03:00
|
|
|
* key: db_hash
|
2017-02-27 18:53:04 +03:00
|
|
|
* value: ...
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* But the settings cache does not allow requesting a value by type, only by key.
|
2017-04-24 20:41:00 +03:00
|
|
|
* e.g. settingsCache.get('db_hash')
|
2017-02-27 18:53:04 +03:00
|
|
|
*/
|
|
|
|
module.exports = {
|
2017-03-03 01:00:01 +03:00
|
|
|
/**
|
|
|
|
* Get a key from the settingsCache
|
|
|
|
* Will resolve to the value, including parsing JSON, unless {resolve: false} is passed in as an option
|
|
|
|
* In which case the full JSON version of the model will be resolved
|
|
|
|
*
|
|
|
|
* @param {string} key
|
|
|
|
* @param {object} options
|
|
|
|
* @return {*}
|
|
|
|
*/
|
2019-01-03 18:23:22 +03:00
|
|
|
get(key, options) {
|
|
|
|
return doGet(key, options);
|
2017-02-27 18:53:04 +03:00
|
|
|
},
|
2017-03-03 01:00:01 +03:00
|
|
|
/**
|
|
|
|
* Set a key on the cache
|
|
|
|
* The only way to get an object into the cache
|
|
|
|
* Uses clone to prevent modifications from being reflected
|
|
|
|
* @param {string} key
|
|
|
|
* @param {object} value json version of settings model
|
|
|
|
*/
|
2019-01-03 18:23:22 +03:00
|
|
|
set(key, value) {
|
2017-03-03 01:00:01 +03:00
|
|
|
settingsCache[key] = _.cloneDeep(value);
|
2017-02-27 18:53:04 +03:00
|
|
|
},
|
2017-03-03 01:00:01 +03:00
|
|
|
/**
|
|
|
|
* Get the entire cache object
|
|
|
|
* Uses clone to prevent modifications from being reflected
|
2021-06-18 17:37:42 +03:00
|
|
|
* @return {object} cache
|
2017-03-03 01:00:01 +03:00
|
|
|
*/
|
2019-01-03 18:23:22 +03:00
|
|
|
getAll() {
|
2017-03-03 01:00:01 +03:00
|
|
|
return _.cloneDeep(settingsCache);
|
2017-02-27 18:53:04 +03:00
|
|
|
},
|
2019-01-03 18:23:22 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all the publically accessible cache entries with their correct names
|
|
|
|
* Uses clone to prevent modifications from being reflected
|
2021-06-18 17:37:42 +03:00
|
|
|
* @return {object} cache
|
2019-01-03 18:23:22 +03:00
|
|
|
*/
|
|
|
|
getPublic() {
|
|
|
|
let settings = {};
|
|
|
|
|
2021-03-04 05:24:08 +03:00
|
|
|
_.each(publicSettings, (key, newKey) => {
|
2019-01-07 16:35:51 +03:00
|
|
|
settings[newKey] = doGet(key) || null;
|
2019-01-03 18:23:22 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
},
|
2017-03-03 01:00:01 +03:00
|
|
|
/**
|
|
|
|
* Initialise the cache
|
|
|
|
*
|
|
|
|
* Optionally takes a collection of settings & can populate the cache with these.
|
|
|
|
*
|
|
|
|
* @param {Bookshelf.Collection<Settings>} [settingsCollection]
|
2021-06-18 17:37:42 +03:00
|
|
|
* @return {object}
|
2017-03-03 01:00:01 +03:00
|
|
|
*/
|
2019-01-03 18:23:22 +03:00
|
|
|
init(settingsCollection) {
|
2017-02-27 18:53:04 +03:00
|
|
|
// First, reset the cache
|
|
|
|
settingsCache = {};
|
|
|
|
|
2017-03-03 01:00:01 +03:00
|
|
|
// // if we have been passed a collection of settings, use this to populate the cache
|
|
|
|
if (settingsCollection && settingsCollection.models) {
|
2019-01-03 18:23:22 +03:00
|
|
|
_.each(settingsCollection.models, updateSettingFromModel);
|
2017-03-03 01:00:01 +03:00
|
|
|
}
|
|
|
|
|
2017-02-27 18:53:04 +03:00
|
|
|
// Bind to events to automatically keep up-to-date
|
2020-04-30 22:26:12 +03:00
|
|
|
events.on('settings.edited', updateSettingFromModel);
|
|
|
|
events.on('settings.added', updateSettingFromModel);
|
|
|
|
events.on('settings.deleted', updateSettingFromModel);
|
2017-02-27 18:53:04 +03:00
|
|
|
|
|
|
|
return settingsCache;
|
2017-12-14 18:41:30 +03:00
|
|
|
},
|
|
|
|
|
2019-01-03 18:23:22 +03:00
|
|
|
shutdown() {
|
2020-04-30 22:26:12 +03:00
|
|
|
events.removeListener('settings.edited', updateSettingFromModel);
|
|
|
|
events.removeListener('settings.added', updateSettingFromModel);
|
|
|
|
events.removeListener('settings.deleted', updateSettingFromModel);
|
2018-10-06 23:13:52 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
reset() {
|
|
|
|
settingsCache = {};
|
2017-02-27 18:53:04 +03:00
|
|
|
}
|
|
|
|
};
|