2020-04-29 18:44:27 +03:00
|
|
|
const should = require('should');
|
|
|
|
const sinon = require('sinon');
|
|
|
|
const _ = require('lodash');
|
|
|
|
const testUtils = require('../../../utils');
|
|
|
|
const urlUtils = require('../../../utils/urlUtils');
|
|
|
|
const urlService = require('../../../../core/frontend/services/url');
|
|
|
|
const generateFeed = require('../../../../core/frontend/services/rss/generate-feed');
|
2017-11-07 23:00:03 +03:00
|
|
|
|
|
|
|
describe('RSS: Generate Feed', function () {
|
2020-04-29 18:44:27 +03:00
|
|
|
const data = {};
|
|
|
|
let baseUrl;
|
|
|
|
|
|
|
|
// Static set of posts
|
|
|
|
let posts;
|
2017-11-07 23:00:03 +03:00
|
|
|
|
|
|
|
before(function () {
|
|
|
|
posts = _.cloneDeep(testUtils.DataGenerator.forKnex.posts);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2017-11-07 23:00:03 +03:00
|
|
|
posts = _.filter(posts, function filter(post) {
|
2019-09-16 13:51:54 +03:00
|
|
|
return post.status === 'published' && post.type === 'post';
|
2017-11-07 23:00:03 +03:00
|
|
|
});
|
|
|
|
|
2020-09-17 11:46:45 +03:00
|
|
|
posts[2].meta_description = 'test stuffs';
|
|
|
|
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
_.each(posts, function (post) {
|
2017-11-07 23:00:03 +03:00
|
|
|
post.url = '/' + post.slug + '/';
|
2018-03-27 17:16:15 +03:00
|
|
|
post.primary_author = {name: 'Joe Bloggs'};
|
2021-03-18 20:16:37 +03:00
|
|
|
|
|
|
|
// data is from fixtures that are inserted directly into the database via knex
|
|
|
|
// that means it has raw __GHOST_URL__ values that would typically be modified by the model layer
|
|
|
|
// we're not using the model layer here so we need to transform manually
|
|
|
|
Object.entries(post).forEach(([key, value]) => {
|
|
|
|
if (value && typeof value === 'string') {
|
|
|
|
post[key] = value.replace(/__GHOST_URL__/g, 'http://my-ghost-blog.com');
|
|
|
|
}
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(function () {
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.restore();
|
2017-11-07 23:00:03 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function () {
|
2019-01-21 19:53:44 +03:00
|
|
|
sinon.stub(urlService, 'getUrlByResourceId');
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
|
2017-11-10 10:36:39 +03:00
|
|
|
baseUrl = '/rss/';
|
|
|
|
|
|
|
|
data.safeVersion = '0.6';
|
2017-11-07 23:00:03 +03:00
|
|
|
data.title = 'Test Title';
|
|
|
|
data.description = 'Testing Desc';
|
2017-11-10 10:36:39 +03:00
|
|
|
data.meta = {pagination: {pages: 1}};
|
2017-11-07 23:00:03 +03:00
|
|
|
});
|
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
describe('without subdirectory', function () {
|
|
|
|
let sandbox;
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
beforeEach(function () {
|
|
|
|
sandbox = sinon.createSandbox();
|
|
|
|
urlUtils.stubUrlUtils({url: 'http://my-ghost-blog.com'}, sandbox);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
});
|
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
afterEach(function () {
|
|
|
|
sandbox.restore();
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
it('should get the RSS tags correct', function (done) {
|
|
|
|
data.posts = [];
|
|
|
|
|
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
|
|
|
|
|
|
|
// xml & rss tags
|
|
|
|
xmlData.should.match(/^<\?xml version="1.0" encoding="UTF-8"\?>/);
|
|
|
|
xmlData.should.match(/<rss/);
|
|
|
|
xmlData.should.match(/xmlns:dc="http:\/\/purl.org\/dc\/elements\/1.1\/"/);
|
|
|
|
xmlData.should.match(/xmlns:content="http:\/\/purl.org\/rss\/1.0\/modules\/content\/"/);
|
|
|
|
xmlData.should.match(/xmlns:atom="http:\/\/www.w3.org\/2005\/Atom"/);
|
|
|
|
xmlData.should.match(/version="2.0"/);
|
|
|
|
xmlData.should.match(/xmlns:media="http:\/\/search.yahoo.com\/mrss\/"/);
|
|
|
|
|
|
|
|
// channel tags
|
|
|
|
xmlData.should.match(/<channel><title><!\[CDATA\[Test Title\]\]><\/title>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[Testing Desc\]\]><\/description>/);
|
|
|
|
xmlData.should.match(/<link>http:\/\/my-ghost-blog.com\/<\/link>/);
|
|
|
|
xmlData.should.match(/<image><url>http:\/\/my-ghost-blog.com\/favicon.png<\/url><title>Test Title<\/title><link>http:\/\/my-ghost-blog.com\/<\/link><\/image>/);
|
|
|
|
xmlData.should.match(/<generator>Ghost 0.6<\/generator>/);
|
|
|
|
xmlData.should.match(/<lastBuildDate>.*?<\/lastBuildDate>/);
|
|
|
|
xmlData.should.match(/<atom:link href="http:\/\/my-ghost-blog.com\/rss\/" rel="self"/);
|
|
|
|
xmlData.should.match(/type="application\/rss\+xml"\/><ttl>60<\/ttl>/);
|
|
|
|
xmlData.should.match(/<\/channel><\/rss>$/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
it('should get the item tags correct', function (done) {
|
|
|
|
data.posts = posts;
|
|
|
|
|
|
|
|
_.each(data.posts, function (post) {
|
|
|
|
urlService.getUrlByResourceId.withArgs(post.id, {secure: undefined, absolute: true}).returns('http://my-ghost-blog.com/' + post.slug + '/');
|
|
|
|
});
|
|
|
|
|
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
|
|
|
|
|
|
|
// item tags
|
|
|
|
xmlData.should.match(/<item><title><!\[CDATA\[HTML Ipsum\]\]><\/title>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[<h1>HTML Ipsum Presents<\/h1>/);
|
|
|
|
xmlData.should.match(/<link>http:\/\/my-ghost-blog.com\/html-ipsum\/<\/link>/);
|
|
|
|
xmlData.should.match(/<image><url>http:\/\/my-ghost-blog.com\/favicon.png<\/url><title>Test Title<\/title><link>http:\/\/my-ghost-blog.com\/<\/link><\/image>/);
|
|
|
|
xmlData.should.match(/<guid isPermaLink="false">/);
|
|
|
|
xmlData.should.match(/<\/guid><dc:creator><!\[CDATA\[Joe Bloggs\]\]><\/dc:creator>/);
|
|
|
|
xmlData.should.match(/<pubDate>Thu, 01 Jan 2015/);
|
|
|
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<h1>HTML Ipsum Presents<\/h1>/);
|
|
|
|
xmlData.should.match(/<\/code><\/pre>\]\]><\/content:encoded><\/item>/);
|
|
|
|
xmlData.should.not.match(/<author>/);
|
|
|
|
|
|
|
|
// basic structure check
|
2020-04-29 18:44:27 +03:00
|
|
|
const postEnd = '<\/code><\/pre>\]\]><\/content:encoded>';
|
|
|
|
const firstIndex = xmlData.indexOf(postEnd);
|
2019-06-18 16:13:55 +03:00
|
|
|
|
|
|
|
// The first title should be before the first content
|
|
|
|
xmlData.indexOf('HTML Ipsum').should.be.below(firstIndex);
|
|
|
|
// The second title should be after the first content
|
|
|
|
xmlData.indexOf('Ghostly Kitchen Sink').should.be.above(firstIndex);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2017-11-10 10:36:39 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
it('should only return visible tags', function (done) {
|
2020-04-29 18:44:27 +03:00
|
|
|
const postWithTags = posts[2];
|
2019-06-18 16:13:55 +03:00
|
|
|
postWithTags.tags = [
|
|
|
|
{name: 'public', visibility: 'public'},
|
|
|
|
{name: 'internal', visibility: 'internal'},
|
|
|
|
{name: 'visibility'}
|
|
|
|
];
|
|
|
|
|
|
|
|
data.posts = [postWithTags];
|
|
|
|
|
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
|
|
|
// item tags
|
|
|
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
|
|
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<!--kg-card-begin: markdown--><h2 id="testing">testing<\/h2>\n/);
|
|
|
|
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
|
|
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
|
|
|
xmlData.should.match(/<category><!\[CDATA\[public\]\]/);
|
|
|
|
xmlData.should.match(/<category><!\[CDATA\[visibility\]\]/);
|
|
|
|
xmlData.should.not.match(/<category><!\[CDATA\[internal\]\]/);
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2017-11-10 10:36:39 +03:00
|
|
|
|
2019-10-30 20:46:17 +03:00
|
|
|
it('should not error if author is somehow not present', function (done) {
|
2019-06-18 16:13:55 +03:00
|
|
|
data.posts = [_.omit(posts[2], 'primary_author')];
|
2017-11-10 10:36:39 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
2017-11-10 10:36:39 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// special/optional tags
|
|
|
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
|
|
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<!--kg-card-begin: markdown--><h2 id="testing">testing<\/h2>\n/);
|
|
|
|
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
|
|
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
|
|
|
xmlData.should.not.match(/<dc:creator>/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-10-30 20:46:17 +03:00
|
|
|
it('should not error if post content is null', function (done) {
|
|
|
|
data.posts = [Object.assign({}, posts[2], {html: null})];
|
|
|
|
|
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
|
|
|
|
|
|
|
// special/optional tags
|
|
|
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
|
|
|
xmlData.should.match(/<content:encoded\/>/);
|
|
|
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
|
|
|
xmlData.should.match(/<dc:creator>/);
|
|
|
|
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
it('should use meta_description and image where available', function (done) {
|
|
|
|
data.posts = [posts[2]];
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// special/optional tags
|
|
|
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
|
|
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<!--kg-card-begin: markdown--><h2 id="testing">testing<\/h2>\n/);
|
|
|
|
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
|
|
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
|
|
|
});
|
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
it('should use excerpt when no meta_description is set', function (done) {
|
|
|
|
data.posts = [posts[0]];
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
_.each(data.posts, function (post) {
|
|
|
|
urlService.getUrlByResourceId.withArgs(post.id, {secure: undefined, absolute: true}).returns('http://my-ghost-blog.com/' + post.slug + '/');
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
|
|
|
|
|
|
|
// special/optional tags
|
|
|
|
xmlData.should.match(/<title><!\[CDATA\[HTML Ipsum\]\]>/);
|
|
|
|
xmlData.should.match(/<description><!\[CDATA\[This is my custom excerpt!/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should process urls correctly', function (done) {
|
|
|
|
data.posts = [posts[3]];
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
generateFeed(baseUrl, data).then(function (xmlData) {
|
|
|
|
should.exist(xmlData);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// anchor URL - <a href="#nowhere" title="Anchor URL">
|
|
|
|
xmlData.should.match(/<a href="#nowhere" title="Anchor URL">/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// relative URL - <a href="/about#nowhere" title="Relative URL">
|
|
|
|
xmlData.should.match(/<a href="http:\/\/my-ghost-blog.com\/about#nowhere" title="Relative URL">/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// protocol relative URL - <a href="//somewhere.com/link#nowhere" title="Protocol Relative URL">
|
|
|
|
xmlData.should.match(/<a href="\/\/somewhere.com\/link#nowhere" title="Protocol Relative URL">/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
// absolute URL - <a href="http://somewhere.com/link#nowhere" title="Absolute URL">
|
|
|
|
xmlData.should.match(/<a href="http:\/\/somewhere.com\/link#nowhere" title="Absolute URL">/);
|
2017-11-07 23:00:03 +03:00
|
|
|
|
2019-06-18 16:13:55 +03:00
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
2017-11-07 23:00:03 +03:00
|
|
|
});
|
|
|
|
});
|