mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
✨ Dynamic Routing Beta: Added ability to disable+override rss (#9693)
refs #9601 - you can now use `rss:false` - ability to define a custom rss url with a target template (+ content_type) - ability to disable rss for channel or collection
This commit is contained in:
parent
13cccfa9ee
commit
fc9da07025
9 changed files with 200 additions and 14 deletions
|
@ -19,6 +19,8 @@ class CollectionRouter extends ParentRouter {
|
||||||
value: mainRoute
|
value: mainRoute
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.rss = object.rss !== false;
|
||||||
|
|
||||||
this.permalinks = {
|
this.permalinks = {
|
||||||
originalValue: object.permalink,
|
originalValue: object.permalink,
|
||||||
value: object.permalink
|
value: object.permalink
|
||||||
|
@ -72,10 +74,11 @@ class CollectionRouter extends ParentRouter {
|
||||||
this.router().param('page', middlewares.pageParam);
|
this.router().param('page', middlewares.pageParam);
|
||||||
this.mountRoute(urlService.utils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers.collection);
|
this.mountRoute(urlService.utils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers.collection);
|
||||||
|
|
||||||
this.rssRouter = new RSSRouter();
|
// REGISTER: is rss enabled?
|
||||||
|
if (this.rss) {
|
||||||
// REGISTER: enable rss by default
|
this.rssRouter = new RSSRouter();
|
||||||
this.mountRouter(this.route.value, this.rssRouter.router());
|
this.mountRouter(this.route.value, this.rssRouter.router());
|
||||||
|
}
|
||||||
|
|
||||||
// REGISTER: context middleware for entries
|
// REGISTER: context middleware for entries
|
||||||
this.router().use(this._prepareEntryContext.bind(this));
|
this.router().use(this._prepareEntryContext.bind(this));
|
||||||
|
@ -151,6 +154,10 @@ class CollectionRouter extends ParentRouter {
|
||||||
}
|
}
|
||||||
|
|
||||||
getRssUrl(options) {
|
getRssUrl(options) {
|
||||||
|
if (!this.rss) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return urlService.utils.createUrl(urlService.utils.urlJoin(this.route.value, this.rssRouter.route.value), options.absolute, options.secure);
|
return urlService.utils.createUrl(urlService.utils.urlJoin(this.route.value, this.rssRouter.route.value), options.absolute, options.secure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ class StaticRoutesRouter extends ParentRouter {
|
||||||
debug(this.route.value, this.templates);
|
debug(this.route.value, this.templates);
|
||||||
|
|
||||||
if (this.isChannel(object)) {
|
if (this.isChannel(object)) {
|
||||||
|
this.rss = object.rss !== false;
|
||||||
this.filter = object.filter;
|
this.filter = object.filter;
|
||||||
this.limit = object.limit;
|
this.limit = object.limit;
|
||||||
this.order = object.order;
|
this.order = object.order;
|
||||||
|
@ -26,6 +27,7 @@ class StaticRoutesRouter extends ParentRouter {
|
||||||
debug(this.route.value, this.templates, this.filter, this.data);
|
debug(this.route.value, this.templates, this.filter, this.data);
|
||||||
this._registerChannelRoutes();
|
this._registerChannelRoutes();
|
||||||
} else {
|
} else {
|
||||||
|
this.contentType = object.content_type;
|
||||||
debug(this.route.value, this.templates);
|
debug(this.route.value, this.templates);
|
||||||
this._registerStaticRoute();
|
this._registerStaticRoute();
|
||||||
}
|
}
|
||||||
|
@ -34,9 +36,11 @@ class StaticRoutesRouter extends ParentRouter {
|
||||||
_registerChannelRoutes() {
|
_registerChannelRoutes() {
|
||||||
this.router().use(this._prepareChannelContext.bind(this));
|
this.router().use(this._prepareChannelContext.bind(this));
|
||||||
|
|
||||||
// REGISTER: enable rss by default
|
// REGISTER: is rss enabled?
|
||||||
this.rssRouter = new RSSRouter();
|
if (this.rss) {
|
||||||
this.mountRouter(this.route.value, this.rssRouter.router());
|
this.rssRouter = new RSSRouter();
|
||||||
|
this.mountRouter(this.route.value, this.rssRouter.router());
|
||||||
|
}
|
||||||
|
|
||||||
// REGISTER: channel route
|
// REGISTER: channel route
|
||||||
this.mountRoute(this.route.value, controllers[this.controller]);
|
this.mountRoute(this.route.value, controllers[this.controller]);
|
||||||
|
@ -76,7 +80,8 @@ class StaticRoutesRouter extends ParentRouter {
|
||||||
templates: this.templates,
|
templates: this.templates,
|
||||||
defaultTemplate: 'default',
|
defaultTemplate: 'default',
|
||||||
data: this.data.query,
|
data: this.data.query,
|
||||||
context: []
|
context: [],
|
||||||
|
contentType: this.contentType
|
||||||
};
|
};
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
|
|
@ -13,5 +13,11 @@ module.exports = function renderer(req, res, data) {
|
||||||
debug('Rendering template: ' + res._template + ' for: ' + req.originalUrl);
|
debug('Rendering template: ' + res._template + ' for: ' + req.originalUrl);
|
||||||
debug('res.locals', res.locals);
|
debug('res.locals', res.locals);
|
||||||
|
|
||||||
|
if (res.routerOptions && res.routerOptions.contentType) {
|
||||||
|
if (res.routerOptions.templates.indexOf(res._template) !== -1) {
|
||||||
|
res.type(res.routerOptions.contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.render(res._template, data);
|
res.render(res._template, data);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1496,4 +1496,154 @@ describe('Integration - Web - Site', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('extended routes.yaml (5): rss override', function () {
|
||||||
|
before(function () {
|
||||||
|
sandbox.stub(settingsService, 'get').returns({
|
||||||
|
routes: {
|
||||||
|
'/about/': 'about',
|
||||||
|
'/podcast/rss/': {
|
||||||
|
templates: ['podcast/rss'],
|
||||||
|
content_type: 'xml'
|
||||||
|
},
|
||||||
|
'/cooking/': {
|
||||||
|
controller: 'channel',
|
||||||
|
rss: false
|
||||||
|
},
|
||||||
|
'/flat/': {
|
||||||
|
controller: 'channel'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
collections: {
|
||||||
|
'/podcast/': {
|
||||||
|
permalink: '/:slug/',
|
||||||
|
filter: 'featured:true',
|
||||||
|
templates: ['home'],
|
||||||
|
rss: false
|
||||||
|
},
|
||||||
|
'/music/': {
|
||||||
|
permalink: '/:slug/',
|
||||||
|
rss: false
|
||||||
|
},
|
||||||
|
'/': {
|
||||||
|
permalink: '/:slug/'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
taxonomies: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.integrationTesting.urlService.resetGenerators();
|
||||||
|
testUtils.integrationTesting.defaultMocks(sandbox, {theme: 'test-theme'});
|
||||||
|
|
||||||
|
return testUtils.integrationTesting.initGhost()
|
||||||
|
.then(function () {
|
||||||
|
app = siteApp();
|
||||||
|
|
||||||
|
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
configUtils.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /rss/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/rss/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /music/rss/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/music/rss/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(404);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /cooking/rss/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/cooking/rss/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(404);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /flat/rss/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/flat/rss/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /podcast/rss/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/podcast/rss/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(200);
|
||||||
|
response.template.should.eql('podcast/rss');
|
||||||
|
response.headers['content-type'].should.eql('text/xml; charset=utf-8');
|
||||||
|
response.body.match(/<link>/g).length.should.eql(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serve /podcast/', function () {
|
||||||
|
const req = {
|
||||||
|
secure: true,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/podcast/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
const $ = cheerio.load(response.body);
|
||||||
|
response.statusCode.should.eql(200);
|
||||||
|
$('head link')[2].attribs.href.should.eql('https://127.0.0.1:2369/rss/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -86,7 +86,8 @@ describe('UNIT - services/routing/StaticRoutesRouter', function () {
|
||||||
templates: [],
|
templates: [],
|
||||||
defaultTemplate: 'default',
|
defaultTemplate: 'default',
|
||||||
context: [],
|
context: [],
|
||||||
data: {}
|
data: {},
|
||||||
|
contentType: undefined
|
||||||
});
|
});
|
||||||
should.not.exist(res.locals.slug);
|
should.not.exist(res.locals.slug);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1 +1,8 @@
|
||||||
home.hbs
|
<html>
|
||||||
|
<head>
|
||||||
|
{{ghost_head}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
home.hbs
|
||||||
|
</body>
|
||||||
|
</html>
|
10
core/test/utils/fixtures/themes/test-theme/podcast/rss.hbs
Normal file
10
core/test/utils/fixtures/themes/test-theme/podcast/rss.hbs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<rss>
|
||||||
|
<channel>
|
||||||
|
<title>{{@blog.title}}</title>
|
||||||
|
{{#get "posts" filter="featured:true" limit="20"}}
|
||||||
|
{{#foreach posts}}
|
||||||
|
<link>{{url}}</link>
|
||||||
|
{{/foreach}}
|
||||||
|
{{/get}}
|
||||||
|
</channel>
|
||||||
|
</rss>
|
|
@ -57,7 +57,7 @@
|
||||||
"ghost-storage-base": "0.0.3",
|
"ghost-storage-base": "0.0.3",
|
||||||
"glob": "5.0.15",
|
"glob": "5.0.15",
|
||||||
"got": "7.1.0",
|
"got": "7.1.0",
|
||||||
"gscan": "1.4.3",
|
"gscan": "1.5.0",
|
||||||
"html-to-text": "3.3.0",
|
"html-to-text": "3.3.0",
|
||||||
"image-size": "0.6.3",
|
"image-size": "0.6.3",
|
||||||
"intl": "1.2.5",
|
"intl": "1.2.5",
|
||||||
|
|
|
@ -2533,9 +2533,9 @@ grunt@~0.4.0:
|
||||||
underscore.string "~2.2.1"
|
underscore.string "~2.2.1"
|
||||||
which "~1.0.5"
|
which "~1.0.5"
|
||||||
|
|
||||||
gscan@1.4.3:
|
gscan@1.5.0:
|
||||||
version "1.4.3"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/gscan/-/gscan-1.4.3.tgz#ebea3c78106f4d8562225d46754d0a41c3e0a348"
|
resolved "https://registry.yarnpkg.com/gscan/-/gscan-1.5.0.tgz#b94446ab1ebc058c36e26f086ab0c0b97634832f"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tryghost/extract-zip" "1.6.6"
|
"@tryghost/extract-zip" "1.6.6"
|
||||||
bluebird "^3.4.6"
|
bluebird "^3.4.6"
|
||||||
|
|
Loading…
Add table
Reference in a new issue