Skip to content

Commit

Permalink
Lazy load default settings
Browse files Browse the repository at this point in the history
Closes #2061

- Lazy load the defaultSettings value in Settings model
- Populate individual defaults before read/edit
- Populate all defaults before first browse call
- Remove populateDefaults calls from init code
  • Loading branch information
jgable committed Jun 17, 2014
1 parent 063b2ea commit d37be6f
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 39 deletions.
119 changes: 89 additions & 30 deletions core/server/api/settings.js
Expand Up @@ -17,6 +17,8 @@ var _ = require('lodash'),
readSettingsResult,
settingsResult,
canEditAllSettings,
populateDefaultSetting,
hasPopulatedDefaults = false,

/**
* ## Cache
Expand Down Expand Up @@ -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
Expand All @@ -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);
};
Expand All @@ -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);
Expand Down Expand Up @@ -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;

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 === '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 (setting.type === 'blog') {
return when(settingsResult(result));
// 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();
});
}

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();
},

/**
Expand Down
4 changes: 1 addition & 3 deletions core/server/data/versioning/index.js
Expand Up @@ -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;
Expand Down
3 changes: 0 additions & 3 deletions core/server/index.js
Expand Up @@ -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();
Expand Down
32 changes: 29 additions & 3 deletions core/server/models/settings.js
Expand Up @@ -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
Expand All @@ -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);
});
},

Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit d37be6f

Please sign in to comment.