mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-27 18:52:14 +03:00
Add setting filter
closes #172 - added type to ghost.settings() - added /api/settings?type=<filter> - added availableThemes to settingsCache - removed cachedSettingsRequestHandler - removed /api/themes (including front end) - changed activePlugins to type "plugin" in default-settings.json
This commit is contained in:
parent
596c1dccd2
commit
bd8db968ea
@ -3,7 +3,7 @@
|
||||
"use strict";
|
||||
//id:0 is used to issue PUT requests
|
||||
Ghost.Models.Settings = Backbone.Model.extend({
|
||||
url: Ghost.settings.apiRoot + '/settings',
|
||||
url: Ghost.settings.apiRoot + '/settings?type=blog,theme',
|
||||
id: "0"
|
||||
});
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
/*global window, document, Ghost, $, _, Backbone */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
Ghost.Models.Themes = Backbone.Model.extend({
|
||||
url: Ghost.settings.apiRoot + '/themes'
|
||||
});
|
||||
|
||||
}());
|
@ -57,8 +57,7 @@
|
||||
|
||||
showContent: function (id) {
|
||||
var self = this,
|
||||
model,
|
||||
themes;
|
||||
model;
|
||||
|
||||
Ghost.router.navigate('/settings/' + id);
|
||||
Ghost.trigger('urlchange');
|
||||
@ -70,13 +69,9 @@
|
||||
this.pane = new Settings[id]({ el: '.settings-content'});
|
||||
|
||||
if (!this.models.hasOwnProperty(this.pane.options.modelType)) {
|
||||
themes = this.models.Themes = new Ghost.Models.Themes();
|
||||
model = this.models[this.pane.options.modelType] = new Ghost.Models[this.pane.options.modelType]();
|
||||
themes.fetch().then(function () {
|
||||
model.fetch().then(function () {
|
||||
model.set({availableThemes: themes.toJSON()});
|
||||
self.renderPane(model);
|
||||
});
|
||||
model.fetch().then(function () {
|
||||
self.renderPane(model);
|
||||
});
|
||||
} else {
|
||||
model = this.models[this.pane.options.modelType];
|
||||
@ -157,8 +152,7 @@
|
||||
},
|
||||
|
||||
saveSettings: function () {
|
||||
var themes = this.model.get('availableThemes'),
|
||||
title = this.$('#blog-title').val(),
|
||||
var title = this.$('#blog-title').val(),
|
||||
description = this.$('#blog-description').val(),
|
||||
email = this.$('#email-address').val(),
|
||||
postsPerPage = this.$('#postsPerPage').val();
|
||||
@ -180,8 +174,6 @@
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
|
||||
this.model.unset('availableThemes');
|
||||
this.model.save({
|
||||
title: title,
|
||||
description: description,
|
||||
@ -194,7 +186,6 @@
|
||||
success: this.saveSuccess,
|
||||
error: this.saveError
|
||||
});
|
||||
this.model.set({availableThemes: themes});
|
||||
}
|
||||
},
|
||||
showLogo: function () {
|
||||
@ -208,16 +199,12 @@
|
||||
showUpload: function (id, key, src) {
|
||||
var self = this, upload = new Ghost.Models.uploadModal({'id': id, 'key': key, 'src': src, 'accept': {
|
||||
func: function () { // The function called on acceptance
|
||||
var data = {},
|
||||
themes;
|
||||
var data = {};
|
||||
data[key] = this.$('.js-upload-target').attr('src');
|
||||
themes = self.model.get('availableThemes');
|
||||
self.model.unset('availableThemes');
|
||||
self.model.save(data, {
|
||||
success: self.saveSuccess,
|
||||
error: self.saveError
|
||||
});
|
||||
self.model.set({availableThemes: themes});
|
||||
self.render();
|
||||
return true;
|
||||
},
|
||||
|
@ -100,10 +100,10 @@ Ghost = function () {
|
||||
* this data is what becomes globally available to themes */
|
||||
return {
|
||||
url: instance.config().url,
|
||||
title: instance.settings().title,
|
||||
description: instance.settings().description,
|
||||
logo: instance.settings().logo,
|
||||
cover: instance.settings().cover
|
||||
title: instance.settings().title.value,
|
||||
description: instance.settings().description.value,
|
||||
logo: instance.settings().logo.value,
|
||||
cover: instance.settings().cover.value
|
||||
};
|
||||
},
|
||||
statuses: function () { return statuses; },
|
||||
@ -121,7 +121,7 @@ Ghost = function () {
|
||||
'appRoot': appRoot,
|
||||
'themePath': themePath,
|
||||
'pluginPath': pluginPath,
|
||||
'activeTheme': path.join(themePath, !instance.settingsCache ? "" : instance.settingsCache.activeTheme),
|
||||
'activeTheme': path.join(themePath, !instance.settingsCache ? "" : instance.settingsCache.activeTheme.value),
|
||||
'adminViews': path.join(appRoot, '/core/server/views/'),
|
||||
'helperTemplates': path.join(appRoot, '/core/server/helpers/tpl/'),
|
||||
'lang': path.join(appRoot, '/core/shared/lang/'),
|
||||
@ -142,15 +142,14 @@ Ghost.prototype.init = function () {
|
||||
instance.dataProvider.init(),
|
||||
instance.getPaths(),
|
||||
instance.mail.init(self)
|
||||
|
||||
).then(function () {
|
||||
return models.Settings.populateDefaults();
|
||||
}).then(function () {
|
||||
// Initialize plugins
|
||||
return self.initPlugins();
|
||||
}).then(function () {
|
||||
// Initialize the settings cache
|
||||
return self.updateSettingsCache();
|
||||
}).then(function () {
|
||||
// Initialize plugins
|
||||
return self.initPlugins();
|
||||
}).then(function () {
|
||||
// Initialize the permissions actions and objects
|
||||
@ -164,7 +163,7 @@ Ghost.prototype.init = function () {
|
||||
}).otherwise(function (error) {
|
||||
// this is where all the "first run" functionality should go
|
||||
var dbhash = uuid.v4();
|
||||
return when(models.Settings.add({key: 'dbHash', value: dbhash})).then(function (returned) {
|
||||
return when(models.Settings.add({key: 'dbHash', value: dbhash, type: 'core'})).then(function (returned) {
|
||||
self.dbHash = dbhash;
|
||||
return dbhash;
|
||||
});
|
||||
@ -179,33 +178,62 @@ Ghost.prototype.updateSettingsCache = function (settings) {
|
||||
settings = settings || {};
|
||||
|
||||
if (!_.isEmpty(settings)) {
|
||||
self.settingsCache = settings;
|
||||
_.map(settings, function (setting, key) {
|
||||
self.settingsCache[key].value = setting.value;
|
||||
});
|
||||
} else {
|
||||
// TODO: this should use api.browse
|
||||
return models.Settings.findAll().then(function (result) {
|
||||
var settings = {};
|
||||
_.map(result.models, function (member) {
|
||||
if (!settings.hasOwnProperty(member.attributes.key)) {
|
||||
if (member.attributes.key === 'activeTheme') {
|
||||
member.attributes.value = member.attributes.value.substring(member.attributes.value.lastIndexOf('/') + 1);
|
||||
var settingsThemePath = path.join(themePath, member.attributes.value);
|
||||
fs.exists(settingsThemePath, function (exists) {
|
||||
if (!exists) {
|
||||
member.attributes.value = "casper";
|
||||
}
|
||||
settings[member.attributes.key] = member.attributes.value;
|
||||
});
|
||||
return;
|
||||
}
|
||||
settings[member.attributes.key] = member.attributes.value;
|
||||
}
|
||||
return when(models.Settings.findAll()).then(function (result) {
|
||||
return when(self.readSettingsResult(result)).then(function (s) {
|
||||
self.settingsCache = s;
|
||||
});
|
||||
|
||||
self.settingsCache = settings;
|
||||
}, errors.logAndThrowError);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Ghost.prototype.readSettingsResult = function (result) {
|
||||
var settings = {};
|
||||
return when(_.map(result.models, function (member) {
|
||||
if (!settings.hasOwnProperty(member.attributes.key)) {
|
||||
var val = {};
|
||||
if (member.attributes.key === 'activeTheme') {
|
||||
member.attributes.value = member.attributes.value.substring(member.attributes.value.lastIndexOf('/') + 1);
|
||||
val.value = member.attributes.value;
|
||||
val.type = member.attributes.type;
|
||||
settings[member.attributes.key] = val;
|
||||
} else {
|
||||
val.value = member.attributes.value;
|
||||
val.type = member.attributes.type;
|
||||
settings[member.attributes.key] = val;
|
||||
}
|
||||
}
|
||||
})).then(function () {
|
||||
return when(instance.paths().availableThemes).then(function (themes) {
|
||||
var themeKeys = Object.keys(themes),
|
||||
res = [],
|
||||
i,
|
||||
item;
|
||||
for (i = 0; i < themeKeys.length; i += 1) {
|
||||
//do not include hidden files
|
||||
if (themeKeys[i].indexOf('.') !== 0) {
|
||||
item = {};
|
||||
item.name = themeKeys[i];
|
||||
//data about files currently not used
|
||||
//item.details = themes[themeKeys[i]];
|
||||
if (themeKeys[i] === settings.activeTheme.value) {
|
||||
item.active = true;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
settings.availableThemes = {};
|
||||
settings.availableThemes.value = res;
|
||||
settings.availableThemes.type = 'theme';
|
||||
return settings;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// ## Template utils
|
||||
|
||||
// Compile a template for a handlebars helper
|
||||
@ -303,7 +331,6 @@ Ghost.prototype.doFilter = function (name, args, callback) {
|
||||
// Initialise plugins. Will load from config.activePlugins by default
|
||||
Ghost.prototype.initPlugins = function (pluginsToLoad) {
|
||||
pluginsToLoad = pluginsToLoad || models.Settings.activePlugins;
|
||||
|
||||
var self = this;
|
||||
|
||||
return plugins.init(this, pluginsToLoad).then(function (loadedPlugins) {
|
||||
@ -326,11 +353,11 @@ Ghost.prototype.initTheme = function (app) {
|
||||
// self.globals is a hack til we have a better way of getting combined settings & config
|
||||
hbsOptions = {templateOptions: {data: {blog: self.blogGlobals()}}};
|
||||
|
||||
if (!self.themeDirectories.hasOwnProperty(self.settings().activeTheme)) {
|
||||
if (!self.themeDirectories.hasOwnProperty(self.settings().activeTheme.value)) {
|
||||
// Throw an error if the theme is not available...
|
||||
// TODO: move this to happen on app start
|
||||
errors.logAndThrowError('The currently active theme ' + self.settings().activeTheme + ' is missing.');
|
||||
} else if (self.themeDirectories[self.settings().activeTheme].hasOwnProperty('partials')) {
|
||||
errors.logAndThrowError('The currently active theme ' + self.settings().activeTheme.value + ' is missing.');
|
||||
} else if (self.themeDirectories[self.settings().activeTheme.value].hasOwnProperty('partials')) {
|
||||
// Check that the theme has a partials directory before trying to use it
|
||||
hbsOptions.partialsDir = path.join(self.paths().activeTheme, 'partials');
|
||||
}
|
||||
|
@ -192,11 +192,9 @@ when.all([ghost.init(), helpers.loadCoreHelpers(ghost)]).then(function () {
|
||||
server.put('/api/v0.1/posts/:id', authAPI, disableCachedResult, api.requestHandler(api.posts.edit));
|
||||
server.del('/api/v0.1/posts/:id', authAPI, disableCachedResult, api.requestHandler(api.posts.destroy));
|
||||
// #### Settings
|
||||
server.get('/api/v0.1/settings', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.browse));
|
||||
server.get('/api/v0.1/settings/:key', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.read));
|
||||
server.put('/api/v0.1/settings', authAPI, disableCachedResult, api.cachedSettingsRequestHandler(api.settings.edit));
|
||||
// #### Themes
|
||||
server.get('/api/v0.1/themes', authAPI, disableCachedResult, api.requestHandler(api.themes.browse));
|
||||
server.get('/api/v0.1/settings', authAPI, disableCachedResult, api.requestHandler(api.settings.browse));
|
||||
server.get('/api/v0.1/settings/:key', authAPI, disableCachedResult, api.requestHandler(api.settings.read));
|
||||
server.put('/api/v0.1/settings', authAPI, disableCachedResult, api.requestHandler(api.settings.edit));
|
||||
// #### Users
|
||||
server.get('/api/v0.1/users', authAPI, disableCachedResult, api.requestHandler(api.users.browse));
|
||||
server.get('/api/v0.1/users/:id', authAPI, disableCachedResult, api.requestHandler(api.users.read));
|
||||
|
@ -17,9 +17,9 @@ var Ghost = require('../ghost'),
|
||||
settings,
|
||||
themes,
|
||||
requestHandler,
|
||||
cachedSettingsRequestHandler,
|
||||
settingsObject,
|
||||
settingsCollection;
|
||||
settingsCollection,
|
||||
settingsFilter;
|
||||
|
||||
// ## Posts
|
||||
posts = {
|
||||
@ -195,6 +195,16 @@ notifications = {
|
||||
// ### Helpers
|
||||
// Turn a settings collection into a single object/hashmap
|
||||
settingsObject = function (settings) {
|
||||
if (_.isObject(settings)) {
|
||||
return _.reduce(settings, function (res, item, key) {
|
||||
if (_.isArray(item)) {
|
||||
res[key] = item;
|
||||
} else {
|
||||
res[key] = item.value;
|
||||
}
|
||||
return res;
|
||||
}, {});
|
||||
}
|
||||
return (settings.toJSON ? settings.toJSON() : settings).reduce(function (res, item) {
|
||||
if (item.toJSON) { item = item.toJSON(); }
|
||||
if (item.key) { res[item.key] = item.value; }
|
||||
@ -208,13 +218,28 @@ settingsCollection = function (settings) {
|
||||
});
|
||||
};
|
||||
|
||||
settingsFilter = function (settings, filter) {
|
||||
return _.object(_.filter(_.pairs(settings), function (setting) {
|
||||
if (filter) {
|
||||
return _.some(filter.split(","), function (f) {
|
||||
return setting[1].type === f;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
};
|
||||
|
||||
settings = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse(options) {
|
||||
// **returns:** a promise for a settings json object
|
||||
return dataProvider.Settings.browse(options).then(settingsObject, errors.logAndThrowError);
|
||||
// **returns:** a promise for a settings json object
|
||||
if (ghost.settings()) {
|
||||
return when(ghost.settings()).then(function (settings) {
|
||||
return settingsObject(settingsFilter(settings, options.type));
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Read
|
||||
@ -225,14 +250,17 @@ settings = {
|
||||
options = { key: options };
|
||||
}
|
||||
|
||||
// **returns:** a promise for a single key-value pair
|
||||
return dataProvider.Settings.read(options.key).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject("Unable to find setting: " + options.key);
|
||||
}
|
||||
|
||||
return _.pick(setting.toJSON(), 'key', 'value');
|
||||
}, errors.logAndThrowError);
|
||||
if (ghost.settings()) {
|
||||
return when(ghost.settings()[options.key]).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject("Unable to find setting: " + options.key);
|
||||
}
|
||||
var res = {};
|
||||
res.key = options.key;
|
||||
res.value = setting.value;
|
||||
return res;
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Edit
|
||||
@ -241,61 +269,36 @@ settings = {
|
||||
edit: function edit(key, value) {
|
||||
// Check for passing a collection of settings first
|
||||
if (_.isObject(key)) {
|
||||
//clean data
|
||||
var type = key.type;
|
||||
delete key.type;
|
||||
delete key.availableThemes;
|
||||
|
||||
key = settingsCollection(key);
|
||||
|
||||
return dataProvider.Settings.edit(key).then(settingsObject, errors.logAndThrowError);
|
||||
return dataProvider.Settings.edit(key).then(function (result) {
|
||||
result.models = result;
|
||||
return when(ghost.readSettingsResult(result)).then(function (settings) {
|
||||
ghost.updateSettingsCache(settings);
|
||||
return settingsObject(settingsFilter(ghost.settings(), type));
|
||||
});
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
|
||||
// **returns:** a promise for a settings json object
|
||||
return dataProvider.Settings.read(key).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject("Unable to find setting: " + key);
|
||||
}
|
||||
|
||||
if (!_.isString(value)) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
setting.set('value', value);
|
||||
|
||||
return dataProvider.Settings.edit(setting);
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
};
|
||||
|
||||
// ## Themes
|
||||
|
||||
themes = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse() {
|
||||
// **returns:** a promise for a themes json object
|
||||
return when(ghost.paths().availableThemes).then(function (themes) {
|
||||
var themeKeys = Object.keys(themes),
|
||||
res = [],
|
||||
i,
|
||||
activeTheme = ghost.paths().activeTheme.substring(ghost.paths().activeTheme.lastIndexOf('/') + 1),
|
||||
item;
|
||||
|
||||
for (i = 0; i < themeKeys.length; i += 1) {
|
||||
//do not include hidden files
|
||||
if (themeKeys[i].indexOf('.') !== 0) {
|
||||
item = {};
|
||||
item.name = themeKeys[i];
|
||||
item.details = themes[themeKeys[i]];
|
||||
if (themeKeys[i] === activeTheme) {
|
||||
item.active = true;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return dataProvider.Settings.edit(setting).then(function (result) {
|
||||
ghost.settings()[_.first(result).attributes.key].value = _.first(result).attributes.value;
|
||||
return settingsObject(ghost.settings());
|
||||
}, errors.logAndThrowError);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ## Request Handlers
|
||||
|
||||
// ### requestHandler
|
||||
@ -317,41 +320,6 @@ requestHandler = function (apiMethod) {
|
||||
};
|
||||
};
|
||||
|
||||
// ### cachedSettingsRequestHandler
|
||||
// Special request handler for settings to access the internal cache version of the settings object
|
||||
cachedSettingsRequestHandler = function (apiMethod) {
|
||||
if (!ghost.settings()) {
|
||||
return requestHandler(apiMethod);
|
||||
}
|
||||
|
||||
return function (req, res) {
|
||||
var options = _.extend(req.body, req.query, req.params),
|
||||
promise;
|
||||
|
||||
switch (apiMethod.name) {
|
||||
case 'browse':
|
||||
promise = when(ghost.settings());
|
||||
break;
|
||||
case 'read':
|
||||
promise = when(ghost.settings()[options.key]);
|
||||
break;
|
||||
case 'edit':
|
||||
promise = apiMethod(options).then(function (result) {
|
||||
ghost.updateSettingsCache(result);
|
||||
return result;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
errors.logAndThrowError(new Error('Unknown method name for settings API: ' + apiMethod.name));
|
||||
}
|
||||
return promise.then(function (result) {
|
||||
res.json(result || {});
|
||||
}, function (error) {
|
||||
res.json(400, {error: error});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// Public API
|
||||
module.exports.posts = posts;
|
||||
module.exports.users = users;
|
||||
@ -360,4 +328,3 @@ module.exports.notifications = notifications;
|
||||
module.exports.settings = settings;
|
||||
module.exports.themes = themes;
|
||||
module.exports.requestHandler = requestHandler;
|
||||
module.exports.cachedSettingsRequestHandler = cachedSettingsRequestHandler;
|
||||
|
@ -15,7 +15,7 @@ frontendControllers = {
|
||||
'homepage': function (req, res) {
|
||||
// Parse the page number
|
||||
var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
postsPerPage = parseInt(ghost.settings().postsPerPage, 10),
|
||||
postsPerPage = parseInt(ghost.settings().postsPerPage.value, 10),
|
||||
options = {};
|
||||
|
||||
// No negative pages
|
||||
@ -67,10 +67,10 @@ frontendControllers = {
|
||||
// Initialize RSS
|
||||
var siteUrl = ghost.config().url,
|
||||
feed = new RSS({
|
||||
title: ghost.settings().title,
|
||||
description: ghost.settings().description,
|
||||
title: ghost.settings().title.value,
|
||||
description: ghost.settings().description.value,
|
||||
generator: 'Ghost v' + res.locals.version,
|
||||
author: ghost.settings().author,
|
||||
author: ghost.settings().author.value,
|
||||
feed_url: siteUrl + '/rss/',
|
||||
site_url: siteUrl,
|
||||
ttl: '60'
|
||||
|
@ -46,14 +46,14 @@
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"activePlugins": {
|
||||
"defaultValue": ""
|
||||
},
|
||||
"activeTheme": {
|
||||
"defaultValue": "casper"
|
||||
}
|
||||
},
|
||||
"plugin": {
|
||||
"activePlugins": {
|
||||
"defaultValue": "[]"
|
||||
},
|
||||
"installedPlugins": {
|
||||
"defaultValue": "[]"
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ coreHelpers = function (ghost) {
|
||||
ghost.registerThemeHelper('e', function (key, defaultString, options) {
|
||||
var output;
|
||||
|
||||
if (ghost.settings().defaultLang === 'en' && _.isEmpty(options.hash) && !ghost.settings().forceI18n) {
|
||||
if (ghost.settings().defaultLang.value === 'en' && _.isEmpty(options.hash) && !ghost.settings().forceI18n.value) {
|
||||
output = defaultString;
|
||||
} else {
|
||||
output = ghost.polyglot().t(key, options.hash);
|
||||
|
@ -96,7 +96,7 @@ GhostMailer.prototype.send = function (message) {
|
||||
}
|
||||
|
||||
var from = 'ghost-mailer@' + url.parse(this.ghost.config().url).hostname,
|
||||
to = message.to || this.ghost.settings().email,
|
||||
to = message.to || this.ghost.settings().email.value,
|
||||
sendMail = nodefn.lift(this.transport.sendMail.bind(this.transport));
|
||||
|
||||
message = _.extend(message, {
|
||||
|
@ -80,7 +80,6 @@
|
||||
<script src="/public/models/tag.js"></script>
|
||||
<script src="/public/models/widget.js"></script>
|
||||
<script src="/public/models/settings.js"></script>
|
||||
<script src="/public/models/themes.js"></script>
|
||||
<script src="/public/models/uploadModal.js"></script>
|
||||
<!-- // require '/public/views/*' -->
|
||||
<script src="/public/views/base.js"></script>
|
||||
|
@ -8,7 +8,7 @@ var fs = require('fs'),
|
||||
I18n = function (ghost) {
|
||||
|
||||
// TODO: validate
|
||||
var lang = ghost.settings().defaultLang,
|
||||
var lang = ghost.settings().defaultLang.value,
|
||||
path = ghost.paths().lang,
|
||||
langFilePath = path + lang + '.json';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user