Merge pull request #2980 from jgable/lazyLoadDefaultSettings

Lazy load default settings
This commit is contained in:
Sebastian Gierlinger 2014-06-17 21:52:34 +02:00
commit a3665cd917
4 changed files with 122 additions and 42 deletions

View File

@ -17,6 +17,8 @@ var _ = require('lodash'),
readSettingsResult,
settingsResult,
canEditAllSettings,
populateDefaultSetting,
hasPopulatedDefaults = false,
/**
* ## Cache
@ -183,6 +185,38 @@ settingsResult = function (settings, type) {
return result;
};
/**
* ### Populate Default Setting
* @private
* @param key
* @param type
* @returns Promise(Setting)
*/
populateDefaultSetting = function (key) {
// Call populateDefault and update the settings cache
return dataProvider.Settings.populateDefault(key).then(function (defaultSetting) {
// Process the default result and add to settings cache
var readResult = readSettingsResult(defaultSetting);
// Add to the settings cache
return updateSettingsCache(readResult).then(function () {
// Update theme with the new settings
return config.theme.update(settings, config().url);
}).then(function () {
// Get the result from the cache with permission checks
return defaultSetting;
});
}).otherwise(function (err) {
// Pass along NotFoundError
if (typeof err === errors.NotFoundError) {
return when.reject(err);
}
// TODO: Different kind of error?
return when.reject(new errors.NotFoundError('Problem finding setting: ' + key));
});
};
/**
* ### Can Edit All Settings
* Check that this edit request is allowed for all settings requested to be updated
@ -191,21 +225,28 @@ settingsResult = function (settings, type) {
* @returns {*}
*/
canEditAllSettings = function (settingsInfo, options) {
var checks = _.map(settingsInfo, function (settingInfo) {
var setting = settingsCache[settingInfo.key];
var checkSettingPermissions = function (setting) {
if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject(
new errors.NoPermissionError('Attempted to access core setting from external request')
);
}
if (!setting) {
return when.reject(new errors.NotFoundError('Unable to find setting: ' + settingInfo.key));
}
return canThis(options.context).edit.setting(setting.key);
},
checks = _.map(settingsInfo, function (settingInfo) {
var setting = settingsCache[settingInfo.key];
if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject(
new errors.NoPermissionError('Attempted to access core setting from external request')
);
}
if (!setting) {
// Try to populate a default setting if not in the cache
return populateDefaultSetting(settingInfo.key).then(function (defaultSetting) {
// Get the result from the cache with permission checks
return checkSettingPermissions(defaultSetting);
});
}
return canThis(options.context).edit.setting(settingInfo.key);
});
return checkSettingPermissions(setting);
});
return when.all(checks);
};
@ -223,6 +264,14 @@ settings = {
* @returns {*}
*/
browse: function browse(options) {
// First, check if we have populated the settings from default-settings yet
if (!hasPopulatedDefaults) {
return dataProvider.Settings.populateDefaults().then(function () {
hasPopulatedDefaults = true;
return settings.browse(options);
});
}
options = options || {};
var result = settingsResult(settingsCache, options.type);
@ -253,30 +302,40 @@ settings = {
options = { key: options };
}
var setting = settingsCache[options.key],
result = {};
var getSettingsResult = function () {
var setting = settingsCache[options.key],
result = {};
if (!setting) {
return when.reject(new errors.NotFoundError('Unable to find setting: ' + options.key));
result[options.key] = setting;
if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject(
new errors.NoPermissionError('Attempted to access core setting from external request')
);
}
if (setting.type === 'blog') {
return when(settingsResult(result));
}
return canThis(options.context).read.setting(options.key).then(function () {
return settingsResult(result);
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to read settings.'));
});
};
// If the setting is not already in the cache
if (!settingsCache[options.key]) {
// Try to populate the setting from default-settings file
return populateDefaultSetting(options.key).then(function () {
// Get the result from the cache with permission checks
return getSettingsResult();
});
}
result[options.key] = setting;
if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject(
new errors.NoPermissionError('Attempted to access core setting from external request')
);
}
if (setting.type === 'blog') {
return when(settingsResult(result));
}
return canThis(options.context).read.setting(options.key).then(function () {
return settingsResult(result);
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to read settings.'));
});
// Get the result from the cache with permission checks
return getSettingsResult();
},
/**

View File

@ -13,9 +13,7 @@ var _ = require('lodash'),
function getDefaultDatabaseVersion() {
if (!defaultDatabaseVersion) {
// This be the current version according to the software
defaultDatabaseVersion = _.find(defaultSettings.core, function (setting) {
return setting.key === 'databaseVersion';
}).defaultValue;
defaultDatabaseVersion = defaultSettings.core.databaseVersion.defaultValue;
}
return defaultDatabaseVersion;

View File

@ -215,9 +215,6 @@ function init(server) {
return builtFilesExist().then(function () {
// Initialise the models
return models.init();
}).then(function () {
// Populate any missing default settings
return models.Settings.populateDefaults();
}).then(function () {
// Initialize the settings cache
return api.init();

View File

@ -25,7 +25,14 @@ function parseDefaultSettings() {
return defaultSettingsFlattened;
}
defaultSettings = parseDefaultSettings();
function getDefaultSettings() {
if (!defaultSettings) {
defaultSettings = parseDefaultSettings();
}
return defaultSettings;
}
// Each setting is saved as a separate row in the database,
// but the overlying API treats them as a single key:value mapping
@ -43,7 +50,7 @@ Settings = ghostBookshelf.Model.extend({
validate: function () {
var self = this;
return when(validation.validateSchema(self.tableName, self.toJSON())).then(function () {
return validation.validateSettings(defaultSettings, self);
return validation.validateSettings(getDefaultSettings(), self);
});
},
@ -117,12 +124,31 @@ Settings = ghostBookshelf.Model.extend({
});
},
populateDefault: function (key) {
if (!getDefaultSettings()[key]) {
return when.reject(new errors.NotFoundError('Unable to find default setting: ' + key));
}
// TOOD: databaseVersion and currentVersion special cases?
this.findOne({ key: key }).then(function (foundSetting) {
if (foundSetting) {
return foundSetting;
}
var defaultSetting = _.clone(getDefaultSettings()[key]);
defaultSetting.value = defaultSetting.defaultValue;
return Settings.forge(defaultSetting).save(null, {user: 1});
});
},
populateDefaults: function () {
return this.findAll().then(function (allSettings) {
var usedKeys = allSettings.models.map(function (setting) { return setting.get('key'); }),
insertOperations = [];
_.each(defaultSettings, function (defaultSetting, defaultSettingKey) {
_.each(getDefaultSettings(), function (defaultSetting, defaultSettingKey) {
var isMissingFromDB = usedKeys.indexOf(defaultSettingKey) === -1;
// Temporary code to deal with old databases with currentVersion settings
if (defaultSettingKey === 'databaseVersion' && usedKeys.indexOf('currentVersion') !== -1) {