mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 18:01:36 +03:00
bd597db829
- This is part of the quest to separate the frontend and server & get rid of all the places where there are cross-requires - At the moment the settings cache is one big shared cache used by the frontend and server liberally - This change doesn't really solve the fundamental problems, as we still depend on events, and requires from inside frontend - However it allows us to control the misuse slightly better by getting rid of restricted requires and turning on that eslint ruleset
145 lines
4.3 KiB
JavaScript
145 lines
4.3 KiB
JavaScript
// 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.
|
|
const debug = require('@tryghost/debug')('settings:cache');
|
|
const _ = require('lodash');
|
|
const publicSettings = require('./public');
|
|
|
|
// Local function, only ever used for initialising
|
|
// We deliberately call "set" on each model so that set is a consistent interface
|
|
const updateSettingFromModel = function updateSettingFromModel(settingModel) {
|
|
debug('Auto updating', settingModel.get('key'));
|
|
module.exports.set(settingModel.get('key'), settingModel.toJSON());
|
|
};
|
|
|
|
/**
|
|
* ## 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) {
|
|
return settingsCache[key] || null;
|
|
}
|
|
|
|
// 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))) {
|
|
return settingsCache[key].value || null;
|
|
}
|
|
|
|
return JSON.parse(settingsCache[key].value) || null;
|
|
} catch (err) {
|
|
return settingsCache[key].value || null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
*
|
|
* IMPORTANT:
|
|
* We store settings with a type and a key in the database.
|
|
*
|
|
* {
|
|
* type: core
|
|
* key: db_hash
|
|
* value: ...
|
|
* }
|
|
*
|
|
* But the settings cache does not allow requesting a value by type, only by key.
|
|
* e.g. settingsCache.get('db_hash')
|
|
*/
|
|
module.exports = {
|
|
/**
|
|
* 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 {*}
|
|
*/
|
|
get(key, options) {
|
|
return doGet(key, options);
|
|
},
|
|
/**
|
|
* 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
|
|
*/
|
|
set(key, value) {
|
|
settingsCache[key] = _.cloneDeep(value);
|
|
},
|
|
/**
|
|
* Get the entire cache object
|
|
* Uses clone to prevent modifications from being reflected
|
|
* @return {object} cache
|
|
*/
|
|
getAll() {
|
|
return _.cloneDeep(settingsCache);
|
|
},
|
|
|
|
/**
|
|
* Get all the publically accessible cache entries with their correct names
|
|
* Uses clone to prevent modifications from being reflected
|
|
* @return {object} cache
|
|
*/
|
|
getPublic() {
|
|
let settings = {};
|
|
|
|
_.each(publicSettings, (key, newKey) => {
|
|
settings[newKey] = doGet(key) || null;
|
|
});
|
|
|
|
return settings;
|
|
},
|
|
/**
|
|
* Initialise the cache
|
|
*
|
|
* Optionally takes a collection of settings & can populate the cache with these.
|
|
*
|
|
* @param {EventEmitter} events
|
|
* @param {Bookshelf.Collection<Settings>} [settingsCollection]
|
|
* @return {object}
|
|
*/
|
|
init(events, settingsCollection) {
|
|
// First, reset the cache and listeners
|
|
this.reset(events);
|
|
|
|
// // if we have been passed a collection of settings, use this to populate the cache
|
|
if (settingsCollection && settingsCollection.models) {
|
|
_.each(settingsCollection.models, updateSettingFromModel);
|
|
}
|
|
|
|
// Bind to events to automatically keep up-to-date
|
|
events.on('settings.edited', updateSettingFromModel);
|
|
events.on('settings.added', updateSettingFromModel);
|
|
events.on('settings.deleted', updateSettingFromModel);
|
|
|
|
return settingsCache;
|
|
},
|
|
|
|
/**
|
|
* Reset both the cache and the listeners, must be called during init
|
|
* @param {EventEmitter} events
|
|
*/
|
|
reset(events) {
|
|
settingsCache = {};
|
|
|
|
events.removeListener('settings.edited', updateSettingFromModel);
|
|
events.removeListener('settings.added', updateSettingFromModel);
|
|
events.removeListener('settings.deleted', updateSettingFromModel);
|
|
}
|
|
};
|