Simplify config for channels (#9158)

refs #5091

- remove the use of functions
- remove unnecessary quotes from tag filter
- move channel config to be a JSOn file called config.channels.json
- accept external config
- new channelUtils for tests
- remove channelConfig.get 
- refactor so tests work as expected
- refactor away duplicate 'name' value
This commit is contained in:
Hannah Wolfe 2017-10-24 17:18:35 +01:00 committed by GitHub
parent 6812af6eed
commit 050f1751c4
9 changed files with 121 additions and 88 deletions

2
.gitignore vendored
View File

@ -63,7 +63,7 @@ CHANGELOG.md
/core/test/coverage /core/test/coverage
# ignore all custom json files for config # ignore all custom json files for config
config.*.json /config.*.json
# Built asset files # Built asset files
/core/built /core/built

View File

@ -1,56 +1,27 @@
var _ = require('lodash'), var _ = require('lodash'),
config = require('../../config'), channels = [];
utils = require('../../utils'),
channelConfig;
channelConfig = function channelConfig() { function loadConfig() {
var defaults = { var channelConfig = {};
index: {
name: 'index',
route: '/',
frontPageTemplate: 'home'
},
tag: {
name: 'tag',
route: utils.url.urlJoin('/', config.get('routeKeywords').tag, ':slug/'),
postOptions: {
filter: 'tags:\'%s\'+tags.visibility:\'public\''
},
data: {
tag: {
type: 'read',
resource: 'tags',
options: {slug: '%s', visibility: 'public'}
}
},
slugTemplate: true,
editRedirect: '#/settings/tags/:slug/'
},
author: {
name: 'author',
route: utils.url.urlJoin('/', config.get('routeKeywords').author, ':slug/'),
postOptions: {
filter: 'author:\'%s\''
},
data: {
author: {
type: 'read',
resource: 'users',
options: {slug: '%s'}
}
},
slugTemplate: true,
editRedirect: '#/team/:slug/'
}
};
return defaults; // This is a very dirty temporary hack so that we can test out channels with some Beta testers
}; // If you are reading this code, and considering using it, best reach out to us on Slack
// Definitely don't be angry at us if the structure of the JSON changes or this goes away.
try {
channelConfig = require('../../../../config.channels.json');
} catch (err) {
channelConfig = require('./config.channels.json');
}
return channelConfig;
}
module.exports.list = function list() { module.exports.list = function list() {
return channelConfig(); _.each(loadConfig(), function (channelConfig, channelName) {
}; var channel = _.cloneDeep(channelConfig);
channel.name = channelName;
channels.push(channel);
});
module.exports.get = function get(name) { return channels;
return _.cloneDeep(channelConfig()[name]);
}; };

View File

@ -96,8 +96,12 @@ channelsRouter = function router() {
var channelsRouter = express.Router({mergeParams: true}); var channelsRouter = express.Router({mergeParams: true});
_.each(channelConfig.list(), function (channel) { _.each(channelConfig.list(), function (channel) {
var channelRoute = channel.route.replace(/:rkw-([a-zA-Z]+)/, function (fullMatch, keyword) {
return config.get('routeKeywords')[keyword];
});
// Mount this channel router on the parent channels router // Mount this channel router on the parent channels router
channelsRouter.use(channel.route, buildChannelRouter(channel)); channelsRouter.use(channelRoute, buildChannelRouter(channel));
}); });
return channelsRouter; return channelsRouter;

View File

@ -0,0 +1,41 @@
{
"index": {
"route": "/",
"frontPageTemplate": "home"
},
"tag": {
"route": "/:rkw-tag/:slug/",
"postOptions": {
"filter": "tags:'%s'+tags.visibility:public"
},
"data": {
"tag": {
"type": "read",
"resource": "tags",
"options": {
"slug": "%s",
"visibility": "public"
}
}
},
"slugTemplate": true,
"editRedirect": "#/settings/tags/:slug/"
},
"author": {
"route": "/:rkw-author/:slug/",
"postOptions": {
"filter": "author:'%s'"
},
"data": {
"author": {
"type": "read",
"resource": "users",
"options": {
"slug": "%s"
}
}
},
"slugTemplate": true,
"editRedirect": "#/team/:slug/"
}
}

View File

@ -1,23 +1,26 @@
/*jshint expr:true*/ var should = require('should'), // jshint ignore:line
var should = require('should'), _ = require('lodash'),
channelConfig = require('../../../../server/controllers/frontend/channel-config'); rewire = require('rewire'),
channelUtils = require('../../../utils/channelUtils'),
channelConfig = rewire('../../../../server/controllers/frontend/channel-config');
describe('Channel Config', function () { describe('Channel Config', function () {
it('should get the index config', function () { var channelReset;
var result = channelConfig.get('index');
should.exist(result); before(function () {
result.name.should.eql('index'); channelReset = channelConfig.__set__('loadConfig', function () {
return channelUtils.getDefaultChannels();
});
}); });
it('should get the author config', function () { after(function () {
var result = channelConfig.get('author'); channelReset();
should.exist(result);
result.name.should.eql('author');
}); });
it('should get the tag config', function () { it('should build a list of channels', function () {
var result = channelConfig.get('tag'); var channels = channelConfig.list();
should.exist(result); channels.should.be.an.Object();
result.name.should.eql('tag');
_.map(channels, 'name').should.eql(['index', 'tag', 'author']);
}); });
}); });

View File

@ -3,7 +3,7 @@ var should = require('should'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
channelConfig = require('../../../../server/controllers/frontend/channel-config'), channelUtils = require('../../../utils/channelUtils'),
setResponseContext = require('../../../../server/controllers/frontend/context'), setResponseContext = require('../../../../server/controllers/frontend/context'),
labs = require('../../../../server/utils/labs'), labs = require('../../../../server/utils/labs'),
@ -38,7 +38,7 @@ describe('Contexts', function () {
res.locals.relativeUrl = url; res.locals.relativeUrl = url;
if (channel && _.isString(channel)) { if (channel && _.isString(channel)) {
res.locals.channel = channelConfig.get(channel); res.locals.channel = channelUtils.getTestChannel(channel);
} else if (channel && _.isNumber(channel)) { } else if (channel && _.isNumber(channel)) {
pageParam = channel; pageParam = channel;
} else if (channel) { } else if (channel) {

View File

@ -3,7 +3,7 @@ var should = require('should'), // jshint ignore:line
sinon = require('sinon'), sinon = require('sinon'),
rewire = require('rewire'), rewire = require('rewire'),
channelConfig = require('../../../../server/controllers/frontend/channel-config').get, channelUtils = require('../../../utils/channelUtils'),
// stuff being tested // stuff being tested
renderChannel = rewire('../../../../server/controllers/frontend/render-channel'), renderChannel = rewire('../../../../server/controllers/frontend/render-channel'),
@ -28,7 +28,7 @@ describe('Render Channel', function () {
}, },
res = { res = {
locals: { locals: {
channel: channelConfig('tag') channel: channelUtils.getTestChannel('tag')
} }
}, },
promise = { promise = {
@ -43,7 +43,7 @@ describe('Render Channel', function () {
it('should return correct tag config', function () { it('should return correct tag config', function () {
renderChannel.__set__('fetchData', function (channelOpts) { renderChannel.__set__('fetchData', function (channelOpts) {
channelOpts.name.should.eql('tag'); channelOpts.name.should.eql('tag');
channelOpts.postOptions.filter.should.eql('tags:\'%s\'+tags.visibility:\'public\''); channelOpts.postOptions.filter.should.eql('tags:\'%s\'+tags.visibility:public');
channelOpts.data.tag.options.should.eql({slug: '%s', visibility: 'public'}); channelOpts.data.tag.options.should.eql({slug: '%s', visibility: 'public'});
return promise; return promise;

View File

@ -4,7 +4,7 @@ var should = require('should'),
_ = require('lodash'), _ = require('lodash'),
Promise = require('bluebird'), Promise = require('bluebird'),
testUtils = require('../utils'), testUtils = require('../utils'),
channelConfig = require('../../server/controllers/frontend/channel-config'), channelUtils = require('../utils/channelUtils'),
api = require('../../server/api'), api = require('../../server/api'),
settingsCache = require('../../server/settings/cache'), settingsCache = require('../../server/settings/cache'),
rss = rewire('../../server/data/xml/rss'), rss = rewire('../../server/data/xml/rss'),
@ -97,7 +97,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -140,7 +140,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -176,7 +176,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -204,7 +204,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -238,7 +238,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -270,7 +270,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -327,7 +327,7 @@ describe('RSS', function () {
done(); done();
}; };
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, failTest(done)); rss(req, res, failTest(done));
}); });
@ -336,7 +336,7 @@ describe('RSS', function () {
// setup // setup
req.originalUrl = '/tag/magic/rss/'; req.originalUrl = '/tag/magic/rss/';
req.params.slug = 'magic'; req.params.slug = 'magic';
res.locals.channel = channelConfig.get('tag'); res.locals.channel = channelUtils.getTestChannel('tag');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
// test // test
@ -344,7 +344,7 @@ describe('RSS', function () {
apiBrowseStub.calledOnce.should.be.true(); apiBrowseStub.calledOnce.should.be.true();
apiBrowseStub.calledWith({ apiBrowseStub.calledWith({
page: 1, page: 1,
filter: 'tags:\'magic\'+tags.visibility:\'public\'', filter: 'tags:\'magic\'+tags.visibility:public',
include: 'author,tags' include: 'author,tags'
}).should.be.true(); }).should.be.true();
apiTagStub.calledOnce.should.be.true(); apiTagStub.calledOnce.should.be.true();
@ -361,7 +361,7 @@ describe('RSS', function () {
req.originalUrl = '/tag/magic/rss/2/'; req.originalUrl = '/tag/magic/rss/2/';
req.params.slug = 'magic'; req.params.slug = 'magic';
req.params.page = '2'; req.params.page = '2';
res.locals.channel = channelConfig.get('tag'); res.locals.channel = channelUtils.getTestChannel('tag');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
// test // test
@ -369,7 +369,7 @@ describe('RSS', function () {
apiBrowseStub.calledOnce.should.be.true(); apiBrowseStub.calledOnce.should.be.true();
apiBrowseStub.calledWith({ apiBrowseStub.calledWith({
page: '2', page: '2',
filter: 'tags:\'magic\'+tags.visibility:\'public\'', filter: 'tags:\'magic\'+tags.visibility:public',
include: 'author,tags' include: 'author,tags'
}).should.be.true(); }).should.be.true();
@ -385,7 +385,7 @@ describe('RSS', function () {
it('should process the data correctly for an author feed', function (done) { it('should process the data correctly for an author feed', function (done) {
req.originalUrl = '/author/joe/rss/'; req.originalUrl = '/author/joe/rss/';
req.params.slug = 'joe'; req.params.slug = 'joe';
res.locals.channel = channelConfig.get('author'); res.locals.channel = channelUtils.getTestChannel('author');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
// test // test
@ -405,7 +405,7 @@ describe('RSS', function () {
req.originalUrl = '/author/joe/rss/2/'; req.originalUrl = '/author/joe/rss/2/';
req.params.slug = 'joe'; req.params.slug = 'joe';
req.params.page = '2'; req.params.page = '2';
res.locals.channel = channelConfig.get('author'); res.locals.channel = channelUtils.getTestChannel('author');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
// test // test
@ -449,7 +449,7 @@ describe('RSS', function () {
results: {posts: [], meta: {pagination: {pages: 1}}} results: {posts: [], meta: {pagination: {pages: 1}}}
}); });
}); });
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
function secondCall() { function secondCall() {
@ -502,7 +502,7 @@ describe('RSS', function () {
req = {params: {page: 4}, route: {path: '/rss/:page/'}}; req = {params: {page: 4}, route: {path: '/rss/:page/'}};
req.originalUrl = req.route.path.replace(':page', req.params.page); req.originalUrl = req.route.path.replace(':page', req.params.page);
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, function (err) { rss(req, res, function (err) {
@ -519,7 +519,7 @@ describe('RSS', function () {
req = {params: {page: 4}, route: {path: '/rss/:page/'}}; req = {params: {page: 4}, route: {path: '/rss/:page/'}};
req.originalUrl = req.route.path.replace(':page', req.params.page); req.originalUrl = req.route.path.replace(':page', req.params.page);
res.locals.channel = channelConfig.get('index'); res.locals.channel = channelUtils.getTestChannel('index');
res.locals.channel.isRSS = true; res.locals.channel.isRSS = true;
rss(req, res, function (err) { rss(req, res, function (err) {

View File

@ -0,0 +1,14 @@
var defaultChannels = require('../../server/controllers/frontend/config.channels.json');
// This is a function to get a fake or test channel
// It's currently based on the default config in Ghost itself
module.exports.getTestChannel = function getTestChannel(channelName) {
var channel = defaultChannels[channelName];
channel.name = channelName;
return channel;
};
module.exports.getDefaultChannels = function getDefaultChannels() {
return defaultChannels;
};