mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Merge pull request #6548 from ErisDS/config-api
Restructure Configuration API endpoint
This commit is contained in:
commit
5de57f892d
7 changed files with 82 additions and 103 deletions
|
@ -31,13 +31,13 @@
|
|||
<meta name="msapplication-square150x150logo" content="{{asset "img/medium.png" ghost="true"}}" />
|
||||
<meta name="msapplication-square310x310logo" content="{{asset "img/large.png" ghost="true"}}" />
|
||||
|
||||
{{#each configuration}}
|
||||
<meta name="env-{{this.key}}" content="{{this.value}}" data-type="{{this.type}}" />
|
||||
{{#each configuration as |config key|}}
|
||||
<meta name="env-{{key}}" content="{{config.value}}" data-type="{{config.type}}" />
|
||||
{{/each}}
|
||||
|
||||
{{#unless skip_google_fonts}}
|
||||
{{#if configuration.useGoogleFonts.value}}
|
||||
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans:400,300,700" />
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<link rel="stylesheet" href="{{asset "vendor.css" ghost="true" minifyInProduction="true"}}" />
|
||||
<link rel="stylesheet" href="{{asset "ghost.css" ghost="true" minifyInProduction="true"}}" />
|
||||
|
|
|
@ -18,7 +18,7 @@ export default AuthenticatedRoute.extend(styleBody, {
|
|||
|
||||
model() {
|
||||
let cachedConfig = this.get('cachedConfig');
|
||||
let configUrl = this.get('ghostPaths.url').api('configuration');
|
||||
let configUrl = this.get('ghostPaths.url').api('configuration', 'about');
|
||||
|
||||
if (cachedConfig) {
|
||||
return cachedConfig;
|
||||
|
@ -26,12 +26,8 @@ export default AuthenticatedRoute.extend(styleBody, {
|
|||
|
||||
return this.get('ajax').request(configUrl)
|
||||
.then((configurationResponse) => {
|
||||
let configKeyValues = configurationResponse.configuration;
|
||||
let [cachedConfig] = configurationResponse.configuration;
|
||||
|
||||
cachedConfig = {};
|
||||
configKeyValues.forEach((configKeyValue) => {
|
||||
cachedConfig[configKeyValue.key] = configKeyValue.value;
|
||||
});
|
||||
this.set('cachedConfig', cachedConfig);
|
||||
|
||||
return cachedConfig;
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
// RESTful API for browsing the configuration
|
||||
var _ = require('lodash'),
|
||||
config = require('../config'),
|
||||
errors = require('../errors'),
|
||||
Promise = require('bluebird'),
|
||||
i18n = require('../i18n'),
|
||||
|
||||
configuration;
|
||||
|
||||
|
@ -15,28 +13,24 @@ function labsFlag(key) {
|
|||
};
|
||||
}
|
||||
|
||||
function getValidKeys() {
|
||||
var validKeys = {
|
||||
fileStorage: {value: (config.fileStorage !== false), type: 'bool'},
|
||||
publicAPI: labsFlag('publicAPI'),
|
||||
apps: {value: (config.apps === true), type: 'bool'},
|
||||
version: {value: config.ghostVersion, type: 'string'},
|
||||
environment: process.env.NODE_ENV,
|
||||
database: config.database.client,
|
||||
mail: _.isObject(config.mail) ? config.mail.transport : '',
|
||||
blogUrl: {value: config.url.replace(/\/$/, ''), type: 'string'},
|
||||
blogTitle: {value: config.theme.title, type: 'string'},
|
||||
routeKeywords: {value: JSON.stringify(config.routeKeywords), type: 'json'}
|
||||
};
|
||||
|
||||
return validKeys;
|
||||
function getAboutConfig() {
|
||||
return {
|
||||
version: config.ghostVersion,
|
||||
environment: process.env.NODE_ENV,
|
||||
database: config.database.client,
|
||||
mail: _.isObject(config.mail) ? config.mail.transport : ''
|
||||
};
|
||||
}
|
||||
|
||||
function formatConfigurationObject(val, key) {
|
||||
function getBaseConfig() {
|
||||
return {
|
||||
key: key,
|
||||
value: (_.isObject(val) && _.has(val, 'value')) ? val.value : val,
|
||||
type: _.isObject(val) ? (val.type || null) : null
|
||||
fileStorage: {value: (config.fileStorage !== false), type: 'bool'},
|
||||
useGoogleFonts: {value: !config.isPrivacyDisabled('useGoogleFonts'), type: 'bool'},
|
||||
useGravatar: {value: !config.isPrivacyDisabled('useGravatar'), type: 'bool'},
|
||||
publicAPI: labsFlag('publicAPI'),
|
||||
blogUrl: {value: config.url.replace(/\/$/, ''), type: 'string'},
|
||||
blogTitle: {value: config.theme.title, type: 'string'},
|
||||
routeKeywords: {value: JSON.stringify(config.routeKeywords), type: 'json'}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -48,26 +42,23 @@ function formatConfigurationObject(val, key) {
|
|||
configuration = {
|
||||
|
||||
/**
|
||||
* ### Browse
|
||||
* Fetch all configuration keys
|
||||
* @returns {Promise(Configurations)}
|
||||
*/
|
||||
browse: function browse() {
|
||||
return Promise.resolve({configuration: _.map(getValidKeys(), formatConfigurationObject)});
|
||||
},
|
||||
|
||||
/**
|
||||
* ### Read
|
||||
*
|
||||
* Always returns {configuration: []}
|
||||
* Sometimes the array contains configuration items
|
||||
* @param {Object} options
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
read: function read(options) {
|
||||
var data = getValidKeys();
|
||||
options = options || {};
|
||||
|
||||
if (_.has(data, options.key)) {
|
||||
return Promise.resolve({configuration: [formatConfigurationObject(data[options.key], options.key)]});
|
||||
} else {
|
||||
return Promise.reject(new errors.NotFoundError(i18n.t('errors.api.configuration.invalidKey')));
|
||||
if (!options.key) {
|
||||
return Promise.resolve({configuration: [getBaseConfig()]});
|
||||
}
|
||||
|
||||
if (options.key === 'about') {
|
||||
return Promise.resolve({configuration: [getAboutConfig()]});
|
||||
}
|
||||
|
||||
return Promise.resolve({configuration: []});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
var _ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
api = require('../api'),
|
||||
errors = require('../errors'),
|
||||
updateCheck = require('../update-check'),
|
||||
config = require('../config'),
|
||||
i18n = require('../i18n'),
|
||||
adminControllers;
|
||||
|
||||
|
@ -14,22 +14,20 @@ adminControllers = {
|
|||
/*jslint unparam:true*/
|
||||
|
||||
function renderIndex() {
|
||||
var configuration;
|
||||
return api.configuration.browse().then(function then(data) {
|
||||
configuration = data.configuration;
|
||||
}).then(function getAPIClient() {
|
||||
return api.clients.read({slug: 'ghost-admin'});
|
||||
}).then(function renderIndex(adminClient) {
|
||||
configuration.push({key: 'clientId', value: adminClient.clients[0].slug, type: 'string'});
|
||||
configuration.push({key: 'clientSecret', value: adminClient.clients[0].secret, type: 'string'});
|
||||
var configuration,
|
||||
fetch = {
|
||||
configuration: api.configuration.read().then(function (res) { return res.configuration[0]; }),
|
||||
client: api.clients.read({slug: 'ghost-admin'}).then(function (res) { return res.clients[0]; })
|
||||
};
|
||||
|
||||
var apiConfig = _.omit(configuration, function omit(value) {
|
||||
return _.contains(['environment', 'database', 'mail', 'version'], value.key);
|
||||
});
|
||||
return Promise.props(fetch).then(function renderIndex(result) {
|
||||
configuration = result.configuration;
|
||||
|
||||
configuration.clientId = {value: result.client.slug, type: 'string'};
|
||||
configuration.clientSecret = {value: result.client.secret, type: 'string'};
|
||||
|
||||
res.render('default', {
|
||||
skip_google_fonts: config.isPrivacyDisabled('useGoogleFonts'),
|
||||
configuration: apiConfig
|
||||
configuration: configuration
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ apiRoutes = function apiRoutes(middleware) {
|
|||
router.del = router.delete;
|
||||
|
||||
// ## Configuration
|
||||
router.get('/configuration', authenticatePrivate, api.http(api.configuration.browse));
|
||||
router.get('/configuration', authenticatePrivate, api.http(api.configuration.read));
|
||||
router.get('/configuration/:key', authenticatePrivate, api.http(api.configuration.read));
|
||||
|
||||
// ## Posts
|
||||
|
|
|
@ -1,68 +1,63 @@
|
|||
/*globals describe, before, afterEach, it */
|
||||
var testUtils = require('../../utils'),
|
||||
should = require('should'),
|
||||
|
||||
rewire = require('rewire'),
|
||||
_ = require('lodash'),
|
||||
config = rewire('../../../server/config'),
|
||||
|
||||
// Stuff we are testing
|
||||
ConfigurationAPI = rewire('../../../server/api/configuration');
|
||||
|
||||
describe('Configuration API', function () {
|
||||
var newConfig = {
|
||||
fileStorage: true,
|
||||
apps: true,
|
||||
version: '0.5.0',
|
||||
environment: process.env.NODE_ENV,
|
||||
database: {
|
||||
client: 'mysql'
|
||||
},
|
||||
mail: {
|
||||
transport: 'SMTP'
|
||||
},
|
||||
blogUrl: 'http://local.tryghost.org'
|
||||
};
|
||||
|
||||
// Keep the DB clean
|
||||
before(testUtils.teardown);
|
||||
afterEach(testUtils.teardown);
|
||||
|
||||
should.exist(ConfigurationAPI);
|
||||
|
||||
it('can browse config', function (done) {
|
||||
var updatedConfig = _.extend({}, config, newConfig);
|
||||
config.set(updatedConfig);
|
||||
ConfigurationAPI.__set__('config', updatedConfig);
|
||||
it('can read basic config and get all expected properties', function (done) {
|
||||
ConfigurationAPI.read().then(function (response) {
|
||||
var props;
|
||||
|
||||
ConfigurationAPI.browse(testUtils.context.owner).then(function (response) {
|
||||
should.exist(response);
|
||||
should.exist(response.configuration);
|
||||
testUtils.API.checkResponse(response.configuration[0], 'configuration');
|
||||
/*jshint unused:false */
|
||||
done();
|
||||
}).catch(function (error) {
|
||||
console.log(JSON.stringify(error));
|
||||
response.configuration.should.be.an.Array().with.lengthOf(1);
|
||||
props = response.configuration[0];
|
||||
|
||||
// Check the structure
|
||||
props.should.have.property('blogUrl').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('blogTitle').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('routeKeywords').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('fileStorage').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('useGoogleFonts').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('useGravatar').which.is.an.Object().with.properties('type', 'value');
|
||||
props.should.have.property('publicAPI').which.is.an.Object().with.properties('type', 'value');
|
||||
|
||||
// Check a few values
|
||||
props.blogUrl.should.have.property('value', 'http://127.0.0.1:2369');
|
||||
props.fileStorage.should.have.property('value', true);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('can read config', function (done) {
|
||||
var updatedConfig = _.extend({}, config, newConfig);
|
||||
config.set(updatedConfig);
|
||||
ConfigurationAPI.__set__('config', updatedConfig);
|
||||
it('can read about config and get all expected properties', function (done) {
|
||||
ConfigurationAPI.read({key: 'about'}).then(function (response) {
|
||||
var props;
|
||||
|
||||
ConfigurationAPI.read(_.extend({}, testUtils.context.owner, {key: 'database'})).then(function (response) {
|
||||
should.exist(response);
|
||||
should.exist(response.configuration);
|
||||
testUtils.API.checkResponse(response.configuration[0], 'configuration');
|
||||
response.configuration[0].key.should.equal('database');
|
||||
response.configuration[0].value.should.equal('mysql');
|
||||
response.configuration[0].type.should.be.null();
|
||||
/*jshint unused:false */
|
||||
done();
|
||||
}).catch(function (error) {
|
||||
console.log(JSON.stringify(error));
|
||||
response.configuration.should.be.an.Array().with.lengthOf(1);
|
||||
props = response.configuration[0];
|
||||
|
||||
// Check the structure
|
||||
props.should.have.property('version').which.is.a.String();
|
||||
props.should.have.property('environment').which.is.a.String();
|
||||
props.should.have.property('database').which.is.a.String();
|
||||
props.should.have.property('mail').which.is.a.String();
|
||||
|
||||
// Check a few values
|
||||
props.environment.should.match(/^testing/);
|
||||
props.version.should.eql(require('../../../../package.json').version);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ var _ = require('lodash'),
|
|||
protocol = 'http://',
|
||||
expectedProperties = {
|
||||
// API top level
|
||||
configuration: ['key', 'value', 'type'],
|
||||
posts: ['posts', 'meta'],
|
||||
tags: ['tags', 'meta'],
|
||||
users: ['users', 'meta'],
|
||||
|
|
Loading…
Reference in a new issue