mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-09-20 17:17:36 +03:00
First pass at custom-theme-settings-service
functionality
refs https://github.com/TryGhost/Team/issues/1070 - added `bread` util that acts as a wrapper for the provided model, if we have any business functionality needed when settings are added/removed then it will go here - added primary "server" service that handles syncing of custom theme data extracted from a theme with the settings that are in the database and exported as "Service". Syncing rules on theme activation: - if a new setting is seen, create it with the default value - if a setting has it's type changed, remove it and create a new setting with the default value - if a select setting's value is not a valid option, reset it to the default value - added shared "frontend/server" service that exposes an in-memory cache of key/value pairs for the currently active theme
This commit is contained in:
parent
56012f5f21
commit
cf9cee0208
@ -1 +1,4 @@
|
||||
module.exports = require('./lib/custom-theme-settings-service');
|
||||
module.exports = {
|
||||
Service: require('./lib/service'),
|
||||
Cache: require('./lib/cache')
|
||||
};
|
||||
|
29
ghost/custom-theme-settings-service/lib/bread.js
Normal file
29
ghost/custom-theme-settings-service/lib/bread.js
Normal file
@ -0,0 +1,29 @@
|
||||
module.exports = class CustomThemeSettingsBREADService {
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {Object} options.model - Bookshelf model for custom theme settings
|
||||
*/
|
||||
constructor({model}) {
|
||||
this.Model = model;
|
||||
}
|
||||
|
||||
async browse(data, options = {}) {
|
||||
return this.Model.findAll(data, options);
|
||||
}
|
||||
|
||||
async read(data, options = {}) {
|
||||
return this.Model.findOne(data, options);
|
||||
}
|
||||
|
||||
async edit(data, options = {}) {
|
||||
return this.Model.edit(data, Object.assign({}, options, {method: 'update'}));
|
||||
}
|
||||
|
||||
async add(data, options = {}) {
|
||||
return this.Model.add(data, options);
|
||||
}
|
||||
|
||||
async destroy(data, options = {}) {
|
||||
return this.Model.destroy(data, options);
|
||||
}
|
||||
};
|
43
ghost/custom-theme-settings-service/lib/cache.js
Normal file
43
ghost/custom-theme-settings-service/lib/cache.js
Normal file
@ -0,0 +1,43 @@
|
||||
const BREAD = require('./bread');
|
||||
const {GhostError} = require('@tryghost/errors');
|
||||
|
||||
module.exports = class CustomThemeSettingsCache {
|
||||
constructor() {
|
||||
this.content = new Object();
|
||||
}
|
||||
|
||||
init({model}) {
|
||||
this.repository = new BREAD({model});
|
||||
}
|
||||
|
||||
get(key) {
|
||||
this._noUsageBeforeInit();
|
||||
|
||||
return this.content[key].value;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
this._noUsageBeforeInit();
|
||||
|
||||
return this.content;
|
||||
}
|
||||
|
||||
async populateForTheme(themeName) {
|
||||
this._noUsageBeforeInit();
|
||||
|
||||
const settingsCollection = await this.repository.browse({theme: themeName});
|
||||
const settingsJson = settingsCollection.toJSON();
|
||||
|
||||
this.content = new Object();
|
||||
|
||||
settingsJson.forEach((setting) => {
|
||||
this.content[setting.key] = setting.value;
|
||||
});
|
||||
}
|
||||
|
||||
_noUsageBeforeInit() {
|
||||
if (!this.repository) {
|
||||
throw new GhostError('CustomThemeSettingsCache must have .init({model}) called before being used');
|
||||
}
|
||||
}
|
||||
};
|
70
ghost/custom-theme-settings-service/lib/service.js
Normal file
70
ghost/custom-theme-settings-service/lib/service.js
Normal file
@ -0,0 +1,70 @@
|
||||
const _ = require('lodash');
|
||||
const BREAD = require('./bread');
|
||||
const debug = require('@tryghost/debug')('custom-theme-settings-service');
|
||||
|
||||
module.exports = class CustomThemeSettingsService {
|
||||
constructor({model, cache}) {
|
||||
this.repository = new BREAD({model});
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
// add/remove/edit theme setting records to match theme settings
|
||||
async activateTheme(theme) {
|
||||
const knownSettingsCollection = await this.repository.browse({theme: theme.name});
|
||||
// convert to JSON so we can use a standard array rather than a bookshelf collection
|
||||
let knownSettings = knownSettingsCollection.toJSON();
|
||||
|
||||
const themeSettings = theme.customSettings || {};
|
||||
|
||||
// exit early if there's nothing to sync for this theme
|
||||
if (knownSettings.length === 0 && _.isEmpty(themeSettings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let removedIds = [];
|
||||
|
||||
// sync any knownSettings that have changed in the theme
|
||||
for (const knownSetting of knownSettings) {
|
||||
const themeSetting = themeSettings[knownSetting.key];
|
||||
|
||||
const hasBeenRemoved = !themeSetting;
|
||||
const hasChangedType = themeSetting && themeSetting.type !== knownSetting.type;
|
||||
|
||||
if (hasBeenRemoved || hasChangedType) {
|
||||
debug(`Removing custom theme setting '${theme.name}.${themeSetting.key}' - ${hasBeenRemoved ? 'not found in theme' : 'type changed'}`);
|
||||
await this.repository.destroy({id: knownSetting.id});
|
||||
removedIds.push(knownSetting.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// replace value with default if it's not a valid select option
|
||||
if (themeSetting.options && !themeSetting.options.includes(knownSetting.value)) {
|
||||
debug(`Resetting custom theme setting value '${theme.name}.${themeSetting.key}' - "${knownSetting.value}" is not a valid option`);
|
||||
await this.repository.edit({value: themeSetting.default}, {id: knownSetting.id});
|
||||
}
|
||||
}
|
||||
|
||||
// clean up any removed knownSettings now that we've finished looping over them
|
||||
knownSettings = knownSettings.filter(setting => !removedIds.includes(setting.id));
|
||||
|
||||
// add any new settings found in theme (or re-add settings that were removed due to type change)
|
||||
const knownSettingsKeys = knownSettings.map(setting => setting.key);
|
||||
|
||||
for (const [key, setting] of Object.entries(themeSettings)) {
|
||||
if (!knownSettingsKeys.includes(key)) {
|
||||
const newSettingValues = {
|
||||
theme: theme.name,
|
||||
key,
|
||||
type: setting.type,
|
||||
value: setting.default
|
||||
};
|
||||
|
||||
debug(`Adding custom theme setting '${theme.name}.${key}'`);
|
||||
await this.repository.add(newSettingValues);
|
||||
}
|
||||
}
|
||||
|
||||
// populate the cache with all key/value pairs for this theme
|
||||
this.cache.populateForTheme(theme.name);
|
||||
}
|
||||
};
|
@ -24,5 +24,8 @@
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2"
|
||||
},
|
||||
"dependencies": {}
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "^0.1.5",
|
||||
"@tryghost/errors": "^0.2.14"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user