🔥 Removed permalink setting

refs #9742

- removed usage of single permalink setting
  - with dynamic routing this configuration does no longer makes sense
  - because you can configure your permalinks in the routes.yaml
  - furthermore you can have multiple collections with multiple permalinks
- removed @blog.permalinks
- do not export permalink setting
- do not import permalink setting
- permalink setting UI will be removed soon
- get rid of {globals.permalink} completely
- remove yaml in-built migration
- do not expose settings.permalinks via the private API
- do not allow to edit this setting
- keep phyiscal value in case a blog needs to rollback from v2 to v1
- sorted out when the routers should be created
  - ensure routes.yaml file doesn't get validated before Ghost is fully ready to start
This commit is contained in:
kirrg001 2018-08-06 17:18:59 +02:00 committed by Katharina Irrgang
parent f574507214
commit 8bb7088ba0
35 changed files with 235 additions and 447 deletions

View File

@ -11,7 +11,7 @@ routes:
collections:
/:
permalink: '{globals.permalinks}'
permalink: '/{slug}/'
template:
- index

View File

@ -148,7 +148,7 @@ settings = {
// Omit core settings unless internal request
if (!options.context.internal) {
result.settings = _.filter(result.settings, function (setting) {
return setting.type !== 'core';
return setting.type !== 'core' && setting.key !== 'permalinks';
});
}
@ -183,6 +183,12 @@ settings = {
);
}
if (setting.key === 'permalinks') {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.errors.resourceNotFound')
}));
}
if (setting.type === 'blog') {
return Promise.resolve(settingsResult(result));
}
@ -221,6 +227,7 @@ settings = {
type = _.find(object.settings, function (setting) {
return setting.key === 'type';
});
if (_.isObject(type)) {
type = type.value;
}
@ -229,6 +236,12 @@ settings = {
return setting.key === 'type';
});
if (object.settings[0].key === 'permalinks') {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.errors.resourceNotFound')
}));
}
return canEditAllSettings(object.settings, options).then(function () {
return localUtils.checkObject(object, docName).then(function (checkedData) {
options.user = self.user;

View File

@ -7,6 +7,13 @@ var _ = require('lodash'),
security = require('../../lib/security'),
models = require('../../models'),
EXCLUDED_TABLES = ['accesstokens', 'refreshtokens', 'clients', 'client_trusted_domains'],
EXCLUDED_FIELDS_CONDITIONS = {
settings: [{
operator: 'whereNot',
key: 'key',
value: 'permalinks'
}]
},
modelOptions = {context: {internal: true}},
// private
@ -52,7 +59,15 @@ getVersionAndTables = function getVersionAndTables(options) {
exportTable = function exportTable(tableName, options) {
if (EXCLUDED_TABLES.indexOf(tableName) < 0 ||
(options.include && _.isArray(options.include) && options.include.indexOf(tableName) !== -1)) {
return (options.transacting || db.knex)(tableName).select();
const query = (options.transacting || db.knex)(tableName);
if (EXCLUDED_FIELDS_CONDITIONS[tableName]) {
EXCLUDED_FIELDS_CONDITIONS[tableName].forEach((condition) => {
query[condition.operator](condition.key, condition.value);
});
}
return query.select();
}
};

View File

@ -27,7 +27,7 @@ class SettingsImporter extends BaseImporter {
beforeImport() {
debug('beforeImport');
let activeTheme = _.find(this.dataToImport, {key: 'active_theme'});
const activeTheme = _.find(this.dataToImport, {key: 'active_theme'});
// We don't import themes. You have to upload the theme first.
if (activeTheme) {
@ -38,6 +38,20 @@ class SettingsImporter extends BaseImporter {
});
}
const permalinks = _.find(this.dataToImport, {key: 'permalinks'});
if (permalinks) {
this.problems.push({
message: 'Permalink Setting was removed. Please configure permalinks in your routes.yaml.',
help: this.modelName,
context: JSON.stringify(permalinks)
});
this.dataToImport = _.filter(this.dataToImport, (data) => {
return data.key !== 'permalinks';
});
}
// Remove core and theme data types
this.dataToImport = _.filter(this.dataToImport, (data) => {
return ['core', 'theme'].indexOf(data.type) === -1;

View File

@ -0,0 +1,72 @@
const path = require('path'),
fs = require('fs-extra'),
config = require('../../../../config'),
common = require('../../../../lib/common'),
models = require('../../../../models'),
message1 = 'Removing `globals.permalinks` from routes.yaml.',
message2 = 'Removed `globals.permalinks` from routes.yaml.',
message3 = 'Skip: Removing `globals.permalinks` from routes.yaml.',
message4 = 'Rollback: Removing `globals.permalink` from routes.yaml. Nothing todo.',
message5 = 'Skip Rollback: Removing `globals.permalinks` from routes.yaml. Nothing todo.';
module.exports.up = () => {
let localOptions = {
context: {internal: true}
};
const fileName = 'routes.yaml';
const contentPath = config.getContentPath('settings');
const filePath = path.join(contentPath, fileName);
let settingsModel;
common.logging.info(message1);
return fs.readFile(filePath, 'utf8')
.then((content) => {
if (content.match(/globals\.permalinks/)) {
return models.Settings.findOne({key: 'permalinks'}, localOptions)
.then((model) => {
settingsModel = model;
// CASE: create a backup
return fs.copy(
path.join(filePath),
path.join(contentPath, 'routes-1.0-backup.yaml')
);
})
.then(() => {
const permalinkValue = settingsModel.get('value');
const modifiedContent = content.replace(/\/?'?{globals.permalinks}'?\/?/g, permalinkValue.replace(/:(\w+)/g, '{$1}'));
return fs.writeFile(filePath, modifiedContent, 'utf8');
})
.then(() => {
common.logging.info(message2);
});
} else {
common.logging.warn(message3);
}
});
};
module.exports.down = () => {
const fileName = 'routes-1.0-backup.yaml';
const contentPath = config.getContentPath('settings');
const filePath = path.join(contentPath, fileName);
common.logging.info(message4);
return fs.readFile(filePath, 'utf8')
.then(() => {
return fs.copy(
path.join(filePath),
path.join(contentPath, 'routes.yaml')
);
})
.then(() => {
return fs.remove(filePath);
})
.catch(() => {
common.logging.warn(message5);
});
};

View File

@ -18,6 +18,12 @@ const urlService = require('./services/url');
let parentApp;
function initialiseServices() {
// CASE: When Ghost is ready with bootstrapping (db migrations etc.), we can trigger the router creation.
// Reason is that the routers access the routes.yaml, which shouldn't and doesn't have to be validated to
// start Ghost in maintenance mode.
const routing = require('./services/routing');
routing.bootstrap.start();
const permissions = require('./services/permissions'),
auth = require('./services/auth'),
apps = require('./services/apps'),

View File

@ -1,6 +1,5 @@
const debug = require('ghost-ignition').debug('services:routing:collection-router');
const common = require('../../lib/common');
const settingsCache = require('../settings/cache');
const urlService = require('../url');
const ParentRouter = require('./ParentRouter');
@ -34,15 +33,6 @@ class CollectionRouter extends ParentRouter {
this.order = object.order;
this.limit = object.limit;
/**
* @deprecated Remove in Ghost 3.0 (in discussion)
*/
if (this.permalinks.originalValue.match(/globals\.permalinks/)) {
this.permalinks.originalValue = this.permalinks.originalValue.replace('{globals.permalinks}', '{settings.permalinks}');
this.permalinks.value = this.permalinks.originalValue.replace('{settings.permalinks}', settingsCache.get('permalinks'));
this.permalinks.value = urlService.utils.deduplicateDoubleSlashes(this.permalinks.value);
}
this.permalinks.getValue = (options) => {
options = options || {};
@ -121,14 +111,6 @@ class CollectionRouter extends ParentRouter {
}
_listeners() {
/**
* @deprecated Remove in Ghost 3.0
*/
if (this.getPermalinks() && this.getPermalinks().originalValue.match(/settings\.permalinks/)) {
this._onPermalinksEditedListener = this._onPermalinksEdited.bind(this);
common.events.on('settings.permalinks.edited', this._onPermalinksEditedListener);
}
/**
* CASE: timezone changes
*
@ -140,19 +122,6 @@ class CollectionRouter extends ParentRouter {
common.events.on('settings.active_timezone.edited', this._onTimezoneEditedListener);
}
/**
* We unmount and mount the permalink url. This enables the ability to change urls on runtime.
*/
_onPermalinksEdited() {
this.unmountRoute(this.permalinks.getValue({withUrlOptions: true}));
this.permalinks.value = this.permalinks.originalValue.replace('{settings.permalinks}', settingsCache.get('permalinks'));
this.permalinks.value = urlService.utils.deduplicateDoubleSlashes(this.permalinks.value);
this.mountRoute(this.permalinks.getValue({withUrlOptions: true}), controllers.entry);
this.emit('updated');
}
_onTimezoneEdited(settingModel) {
const newTimezone = settingModel.attributes.value,
previousTimezone = settingModel._updatedAttributes.value;
@ -186,10 +155,6 @@ class CollectionRouter extends ParentRouter {
}
reset() {
if (this._onPermalinksEditedListener) {
common.events.removeListener('settings.permalinks.edited', this._onPermalinksEditedListener);
}
if (this._onTimezoneEditedListener) {
common.events.removeListener('settings.active_timezone.edited', this._onTimezoneEditedListener);
}

View File

@ -11,24 +11,32 @@ const ParentRouter = require('./ParentRouter');
const registry = require('./registry');
let siteRouter;
/**
* Create a set of default and dynamic routers defined in the routing yaml.
*
* @TODO:
* - is the PreviewRouter an app?
*/
module.exports = function bootstrap() {
module.exports.init = (options = {start: false}) => {
debug('bootstrap');
registry.resetAllRouters();
registry.resetAllRoutes();
siteRouter = new ParentRouter('SiteRouter');
registry.setRouter('siteRouter', siteRouter);
if (options.start) {
this.start();
}
return siteRouter.router();
};
/**
* Create a set of default and dynamic routers defined in the routing yaml.
*
* @TODO:
* - is the PreviewRouter an app?
*/
module.exports.start = () => {
const previewRouter = new PreviewRouter();
siteRouter.mountRouter(previewRouter.router());
registry.setRouter('siteRouter', siteRouter);
registry.setRouter('previewRouter', previewRouter);
const dynamicRoutes = settingsService.get('routes');
@ -64,5 +72,4 @@ module.exports = function bootstrap() {
registry.setRouter('appRouter', appRouter);
debug('Routes:', registry.getAllRoutes());
return siteRouter.router();
};

View File

@ -2,7 +2,7 @@ routes:
collections:
/:
permalink: '{globals.permalinks}' # special 1.0 compatibility setting. See the docs for details.
permalink: /{slug}/
template:
- index

View File

@ -3,11 +3,7 @@ const fs = require('fs-extra'),
path = require('path'),
debug = require('ghost-ignition').debug('services:settings:ensure-settings'),
common = require('../../lib/common'),
security = require('../../lib/security'),
config = require('../../config'),
yamlMigrations = {
homeTemplate: 'cm91dGVzOmNvbGxlY3Rpb25zOi86cGVybWFsaW5rOid7Z2xvYmFscy5wZXJtYWxpbmtzfScjc3BlY2lhbDEuMGNvbXBhdGliaWxpdHlzZXR0aW5nLlNlZXRoZWRvY3Nmb3JkZXRhaWxzLnRlbXBsYXRlOi1ob21lLWluZGV4dGF4b25vbWllczp0YWc6L3RhZy97c2x1Z30vYXV0aG9yOi9hdXRob3Ive3NsdWd9L3wwUUg4SHRFQWZvbHBBSmVTYWkyOEwwSGFNMGFIOU5SczhZWGhMcExmZ2c0PQ=='
};
config = require('../../config');
/**
* Makes sure that all supported settings files are in the
@ -29,21 +25,6 @@ module.exports = function ensureSettingsFiles(knownSettings) {
filePath = path.join(contentPath, fileName);
return fs.readFile(filePath, 'utf8')
.then((content) => {
content = content.replace(/\s/g, '');
/**
* routes.yaml migrations:
*
* 1. We have removed the "home.hbs" template from the default collection, because
* this is a hardcoded behaviour in Ghost. If we don't remove the home.hbs every page of the
* index collection get's rendered with the home template, but this is not the correct behaviour
* < 1.24. The index collection is `/`.
*/
if (security.tokens.generateFromContent({content: content}) === yamlMigrations.homeTemplate) {
throw new common.errors.ValidationError({code: 'ENOENT'});
}
})
.catch({code: 'ENOENT'}, () => {
// CASE: file doesn't exist, copy it from our defaults
return fs.copy(

View File

@ -243,7 +243,7 @@ _private.validateCollections = function validateCollections(collections) {
}
// CASE: we hard-require trailing slashes for the value/permalink route
if (!routingTypeObject.permalink.match(/\/$/) && !routingTypeObject.permalink.match(/globals\.permalinks/)) {
if (!routingTypeObject.permalink.match(/\/$/)) {
throw new common.errors.ValidationError({
message: common.i18n.t('errors.services.settings.yaml.validate', {
at: routingTypeObject.permalink,
@ -253,7 +253,7 @@ _private.validateCollections = function validateCollections(collections) {
}
// CASE: we hard-require leading slashes for the value/permalink route
if (!routingTypeObject.permalink.match(/^\//) && !routingTypeObject.permalink.match(/globals\.permalinks/)) {
if (!routingTypeObject.permalink.match(/^\//)) {
throw new common.errors.ValidationError({
message: common.i18n.t('errors.services.settings.yaml.validate', {
at: routingTypeObject.permalink,

View File

@ -52,7 +52,6 @@ themeMiddleware.updateTemplateData = function updateTemplateData(req, res, next)
twitter: settingsCache.get('twitter'),
timezone: settingsCache.get('active_timezone'),
navigation: settingsCache.get('navigation'),
permalinks: settingsCache.get('permalinks'),
icon: settingsCache.get('icon'),
cover_image: settingsCache.get('cover_image'),
logo: settingsCache.get('logo'),

View File

@ -12,7 +12,7 @@ var debug = require('ghost-ignition').debug('app'),
ghostLocals = require('./middleware/ghost-locals'),
logRequest = require('./middleware/log-request');
module.exports = function setupParentApp() {
module.exports = function setupParentApp(options = {}) {
debug('ParentApp setup start');
var parentApp = express();
@ -51,7 +51,7 @@ module.exports = function setupParentApp() {
parentApp.use('/ghost', require('./admin')());
// BLOG
parentApp.use(require('./site')());
parentApp.use(require('./site')(options));
debug('ParentApp setup end');

View File

@ -36,7 +36,7 @@ var debug = require('ghost-ignition').debug('blog'),
let router;
module.exports = function setupSiteApp() {
module.exports = function setupSiteApp(options = {}) {
debug('Site setup start');
var siteApp = express();
@ -127,7 +127,7 @@ module.exports = function setupSiteApp() {
debug('General middleware done');
router = siteRoutes();
router = siteRoutes(options);
function SiteRouter(req, res, next) {
router(req, res, next);
@ -149,7 +149,7 @@ module.exports = function setupSiteApp() {
module.exports.reload = () => {
// https://github.com/expressjs/express/issues/2596
router = siteRoutes();
router = siteRoutes({start: true});
// re-initialse apps (register app routers, because we have re-initialised the site routers)
apps.init();

View File

@ -1,5 +1,5 @@
const routing = require('../../services/routing');
module.exports = function siteRoutes() {
return routing.bootstrap();
module.exports = function siteRoutes(options = {}) {
return routing.bootstrap.init(options);
};

View File

@ -45,6 +45,7 @@ describe('Settings API', function () {
JSON.parse(_.find(jsonResponse.settings, {key: 'unsplash'}).value).isActive.should.eql(true);
JSON.parse(_.find(jsonResponse.settings, {key: 'amp'}).value).should.eql(true);
should.not.exist(_.find(jsonResponse.settings, {key: 'permalinks'}));
done();
});
@ -74,6 +75,21 @@ describe('Settings API', function () {
});
});
it('can\'t retrieve permalinks', function (done) {
request.get(testUtils.API.getApiQuery('settings/permalinks/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
return done(err);
}
done();
});
});
it('can\'t retrieve non existent setting', function (done) {
request.get(testUtils.API.getApiQuery('settings/testsetting/'))
.set('Authorization', 'Bearer ' + accesstoken)
@ -137,6 +153,26 @@ describe('Settings API', function () {
});
});
it('can\'t edit permalinks', function (done) {
const settingToChange = {
settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}]
};
request.put(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
return done(err);
}
done();
});
});
it('can\'t edit settings with invalid accesstoken', function (done) {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
@ -212,7 +248,7 @@ describe('Settings API', function () {
.then((res)=> {
res.headers['content-disposition'].should.eql('Attachment; filename="routes.yaml"');
res.headers['content-type'].should.eql('application/yaml; charset=utf-8');
res.headers['content-length'].should.eql('152');
res.headers['content-length'].should.eql('138');
});
});

View File

@ -55,79 +55,6 @@ describe('Frontend Routing', function () {
});
});
describe('Date permalinks', function () {
before(function (done) {
// Only way to swap permalinks setting is to login and visit the URL because
// poking the database doesn't work as settings are cached
testUtils.togglePermalinks(request, 'date')
.then(function () {
done();
})
.catch(done);
});
after(function (done) {
testUtils.togglePermalinks(request)
.then(function () {
done();
})
.catch(done);
});
it('should load a post with date permalink', function (done) {
var date = moment().format('YYYY/MM/DD');
request.get('/' + date + '/welcome/')
.expect(200)
.expect('Content-Type', /html/)
.end(doEnd(done));
});
it('expect redirect because of wrong/old permalink prefix', function (done) {
var date = moment().format('YYYY/MM/DD');
request.get('/2016/04/01/welcome/')
.expect(301)
.end(function (err) {
if (err) {
return done(err);
}
request.get('/' + date + '/welcome/')
.expect(200)
.expect('Content-Type', /html/)
.end(doEnd(done));
});
});
it('should serve RSS with date permalink', function (done) {
request.get('/rss/')
.expect('Content-Type', 'text/xml; charset=utf-8')
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
should.not.exist(res.headers['x-cache-invalidate']);
should.not.exist(res.headers['X-CSRF-Token']);
should.not.exist(res.headers['set-cookie']);
should.exist(res.headers.date);
var content = res.text,
todayMoment = moment(),
dd = todayMoment.format('DD'),
mm = todayMoment.format('MM'),
yyyy = todayMoment.format('YYYY'),
postLink = '/' + yyyy + '/' + mm + '/' + dd + '/welcome/';
content.indexOf(postLink).should.be.above(0);
done();
});
});
});
describe('Test with Initial Fixtures', function () {
describe('Error', function () {
it('should 404 for unknown post', function (done) {

View File

@ -839,7 +839,7 @@ describe('Integration: Importer', function () {
});
});
it('does not import slack hook', function () {
it('does not import settings: slack hook, permalinks', function () {
const exportData = exportedLatestBody().db[0];
exportData.data.settings[0] = testUtils.DataGenerator.forKnex.createSetting({
@ -847,12 +847,22 @@ describe('Integration: Importer', function () {
value: '[{\\"url\\":\\"https://hook.slack.com\\"}]'
});
exportData.data.settings[1] = testUtils.DataGenerator.forKnex.createSetting({
key: 'permalinks',
value: '/:primary_author/:slug/'
});
return dataImporter.doImport(exportData, importOptions)
.then(function (imported) {
imported.problems.length.should.eql(0);
imported.problems.length.should.eql(1);
return models.Settings.findOne(_.merge({key: 'slack'}, testUtils.context.internal));
}).then(function (result) {
})
.then(function (result) {
result.attributes.value.should.eql('[{"url":""}]');
return models.Settings.findOne(_.merge({key: 'permalinks'}, testUtils.context.internal));
})
.then((result) => {
result.attributes.value.should.eql('/:slug/');
});
});

View File

@ -35,6 +35,8 @@ describe('Exporter', function () {
should.exist(exportData.data[name]);
});
should.not.exist(_.find(exportData.data.settings, {key: 'permalinks'}));
// should not export sqlite data
should.not.exist(exportData.data.sqlite_sequence);
done();

View File

@ -5,7 +5,6 @@ var should = require('should'),
_ = require('lodash'),
Promise = require('bluebird'),
sequence = require('../../../server/lib/promise/sequence'),
settingsCache = require('../../../server/services/settings/cache'),
urlService = require('../../../server/services/url'),
ghostBookshelf = require('../../../server/models/base'),
models = require('../../../server/models'),
@ -102,14 +101,6 @@ describe('Post Model', function () {
});
describe('findAll', function () {
beforeEach(function () {
sandbox.stub(settingsCache, 'get').callsFake(function (key) {
return {
permalinks: '/:slug/'
}[key];
});
});
it('can findAll', function (done) {
models.Post.findAll().then(function (results) {
should.exist(results);
@ -159,14 +150,6 @@ describe('Post Model', function () {
});
describe('findPage', function () {
beforeEach(function () {
sandbox.stub(settingsCache, 'get').callsFake(function (key) {
return {
permalinks: '/:slug/'
}[key];
});
});
it('can findPage (default)', function (done) {
models.Post.findPage().then(function (results) {
should.exist(results);
@ -364,14 +347,6 @@ describe('Post Model', function () {
});
describe('findOne', function () {
beforeEach(function () {
sandbox.stub(settingsCache, 'get').callsFake(function (key) {
return {
permalinks: '/:slug/'
}[key];
});
});
it('can findOne', function (done) {
var firstPost;
@ -416,14 +391,6 @@ describe('Post Model', function () {
});
it('can findOne, returning a dated permalink', function (done) {
settingsCache.get.restore();
sandbox.stub(settingsCache, 'get').callsFake(function (key) {
return {
permalinks: '/:year/:month/:day/:slug/'
}[key];
});
urlService.getUrlByResourceId.withArgs(testUtils.DataGenerator.Content.posts[0].id).returns('/2015/01/01/html-ipsum/');
models.Post.findOne({id: testUtils.DataGenerator.Content.posts[0].id})

View File

@ -1,4 +1,5 @@
var should = require('should'),
_ = require('lodash'),
sinon = require('sinon'),
testUtils = require('../../utils'),
@ -35,6 +36,7 @@ describe('Settings Model', function () {
should.exist(results);
results.length.should.be.above(0);
should.exist(_.find(results.models, {attributes: {key : 'permalinks'}}));
done();
}).catch(done);

View File

@ -6,7 +6,6 @@ const should = require('should'),
configUtils = require('../../utils/configUtils'),
api = require('../../../server/api'),
settingsService = require('../../../server/services/settings'),
RESOURCE_CONFIG = require('../../../server/services/routing/assets/resource-config'),
themeConfig = require('../../../server/services/themes/config'),
siteApp = require('../../../server/web/parent-app'),
sandbox = sinon.sandbox.create();
@ -29,8 +28,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -457,8 +455,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -573,8 +570,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -631,8 +627,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -730,8 +725,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -813,8 +807,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -947,8 +940,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -1047,8 +1039,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -1114,8 +1105,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -1170,8 +1160,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -1324,8 +1313,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});
@ -1539,8 +1527,7 @@ describe('Integration - Web - Site', function () {
return testUtils.integrationTesting.initGhost()
.then(function () {
app = siteApp();
app = siteApp({start: true});
return testUtils.integrationTesting.urlService.waitTillFinished();
});
});

View File

@ -31,6 +31,7 @@ describe('Exporter', function () {
tablesStub = sandbox.stub(schema.commands, 'getTables').returns(schemaTables);
queryMock = {
whereNot: sandbox.stub(),
select: sandbox.stub()
};
@ -57,6 +58,7 @@ describe('Exporter', function () {
tablesStub.calledOnce.should.be.true();
db.knex.called.should.be.true();
queryMock.select.called.should.be.true();
queryMock.whereNot.calledOnce.should.be.true();
knexMock.callCount.should.eql(expectedCallCount);
queryMock.select.callCount.should.have.eql(expectedCallCount);

View File

@ -10,8 +10,6 @@ describe('UNIT - services/routing/CollectionRouter', function () {
let req, res, next;
beforeEach(function () {
sandbox.stub(settingsCache, 'get').withArgs('permalinks').returns('/:slug/');
sandbox.stub(common.events, 'emit');
sandbox.stub(common.events, 'on');
@ -119,19 +117,6 @@ describe('UNIT - services/routing/CollectionRouter', function () {
collectionRouter.getFilter().should.eql('featured:true');
});
it('permalink placeholder', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/magic/{globals.permalinks}/'});
collectionRouter.getPermalinks().getValue().should.eql('/magic/:slug/');
common.events.on.calledTwice.should.be.true();
});
it('permalink placeholder', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
collectionRouter.getPermalinks().getValue().should.eql('/:slug/');
});
it('with templates', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:slug/', templates: ['home', 'index']});
@ -189,11 +174,11 @@ describe('UNIT - services/routing/CollectionRouter', function () {
describe('timezone changes', function () {
describe('no dated permalink', function () {
it('default', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:slug/'});
sandbox.stub(collectionRouter, 'emit');
common.events.on.args[1][1]({
common.events.on.args[0][1]({
attributes: {value: 'America/Los_Angeles'},
_updatedAttributes: {value: 'Europe/London'}
});
@ -202,11 +187,11 @@ describe('UNIT - services/routing/CollectionRouter', function () {
});
it('tz has not changed', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:slug/'});
sandbox.stub(collectionRouter, 'emit');
common.events.on.args[1][1]({
common.events.on.args[0][1]({
attributes: {value: 'America/Los_Angeles'},
_updatedAttributes: {value: 'America/Los_Angeles'}
});
@ -216,16 +201,12 @@ describe('UNIT - services/routing/CollectionRouter', function () {
});
describe('with dated permalink', function () {
beforeEach(function () {
settingsCache.get.withArgs('permalinks').returns('/:year/:slug/');
});
it('default', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:year/:slug/'});
sandbox.stub(collectionRouter, 'emit');
common.events.on.args[1][1]({
common.events.on.args[0][1]({
attributes: {value: 'America/Los_Angeles'},
_updatedAttributes: {value: 'Europe/London'}
});
@ -234,11 +215,11 @@ describe('UNIT - services/routing/CollectionRouter', function () {
});
it('tz has not changed', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
const collectionRouter = new CollectionRouter('/magic/', {permalink: '/:year/:slug/'});
sandbox.stub(collectionRouter, 'emit');
common.events.on.args[1][1]({
common.events.on.args[0][1]({
attributes: {value: 'America/Los_Angeles'},
_updatedAttributes: {value: 'America/Los_Angeles'}
});
@ -247,35 +228,4 @@ describe('UNIT - services/routing/CollectionRouter', function () {
});
});
});
describe('permalink in database changes', function () {
it('permalink placeholder: flat', function () {
const collectionRouter = new CollectionRouter('/magic/', {permalink: '{globals.permalinks}'});
collectionRouter.mountRoute.callCount.should.eql(3);
collectionRouter.unmountRoute.callCount.should.eql(0);
collectionRouter.getPermalinks().getValue().should.eql('/:slug/');
settingsCache.get.withArgs('permalinks').returns('/:primary_author/:slug/');
common.events.on.args[0][1]();
collectionRouter.mountRoute.callCount.should.eql(4);
collectionRouter.unmountRoute.callCount.should.eql(1);
collectionRouter.getPermalinks().getValue().should.eql('/:primary_author/:slug/');
});
it('permalink placeholder: complex', function () {
const collectionRouter = new CollectionRouter('/animals/', {permalink: '/animals/{globals.permalinks}/'});
collectionRouter.getPermalinks().getValue().should.eql('/animals/:slug/');
settingsCache.get.withArgs('permalinks').returns('/:primary_author/:slug/');
common.events.on.args[0][1]();
collectionRouter.getPermalinks().getValue().should.eql('/animals/:primary_author/:slug/');
});
});
});

View File

@ -1,7 +1,6 @@
const should = require('should'),
sinon = require('sinon'),
configUtils = require('../../../utils/configUtils'),
settingsCache = require('../../../../server/services/settings/cache'),
common = require('../../../../server/lib/common'),
urlService = require('../../../../server/services/url'),
ParentRouter = require('../../../../server/services/routing/ParentRouter'),
@ -11,8 +10,6 @@ describe('UNIT - services/routing/ParentRouter', function () {
let req, res, next;
beforeEach(function () {
sandbox.stub(settingsCache, 'get').withArgs('permalinks').returns('/:slug/');
sandbox.stub(common.events, 'emit');
sandbox.stub(common.events, 'on');

View File

@ -1,6 +1,5 @@
const should = require('should'),
sinon = require('sinon'),
settingsCache = require('../../../../server/services/settings/cache'),
common = require('../../../../server/lib/common'),
controllers = require('../../../../server/services/routing/controllers'),
StaticRoutesRouter = require('../../../../server/services/routing/StaticRoutesRouter'),
@ -15,8 +14,6 @@ describe('UNIT - services/routing/StaticRoutesRouter', function () {
});
beforeEach(function () {
sandbox.stub(settingsCache, 'get').withArgs('permalinks').returns('/:slug/');
sandbox.stub(common.events, 'emit');
sandbox.stub(common.events, 'on');

View File

@ -84,106 +84,4 @@ describe('UNIT > Settings Service:', function () {
});
});
});
describe('Migrations: home.hbs', function () {
it('routes.yaml has modifications', function () {
fs.readFile.withArgs(path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml'), 'utf8').resolves('' +
'routes:\n' +
'\n' +
'collections:\n' +
' /:\n' +
' permalink: \'{globals.permalinks}\' # special 1.0 compatibility setting. See the docs for details.\n' +
' template:\n' +
' - index\n' +
'\n' +
'taxonomies:\n' +
' tag: /tag/{slug}/\n' +
' author: /author/{slug}/' + '' +
'\n'
);
return ensureSettings(['routes']).then(() => {
fs.readFile.callCount.should.be.eql(1);
fs.copy.called.should.be.false();
});
});
it('routes.yaml is old routes.yaml', function () {
const expectedDefaultSettingsPath = path.join(__dirname, '../../../../server/services/settings/default-routes.yaml');
const expectedContentPath = path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml');
fs.readFile.withArgs(path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml'), 'utf8').resolves('' +
'routes:\n' +
'\n' +
'collections:\n' +
' /:\n' +
' permalink: \'{globals.permalinks}\' # special 1.0 compatibility setting. See the docs for details.\n' +
' template:\n' +
' - home\n' +
' - index\n' +
'\n' +
'taxonomies:\n' +
' tag: /tag/{slug}/\n' +
' author: /author/{slug}/' +
'\n'
);
fs.copy.withArgs(expectedDefaultSettingsPath, expectedContentPath).resolves();
return ensureSettings(['routes']).then(() => {
fs.readFile.callCount.should.be.eql(1);
fs.copy.called.should.be.true();
});
});
it('routes.yaml is old routes.yaml', function () {
const expectedDefaultSettingsPath = path.join(__dirname, '../../../../server/services/settings/default-routes.yaml');
const expectedContentPath = path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml');
fs.readFile.withArgs(path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml'), 'utf8').resolves('' +
'routes:\n' +
'\n\n' +
'collections:\n' +
' /:\n' +
' permalink: \'{globals.permalinks}\' # special 1.0 compatibility setting. See the docs for details.\n' +
' template:\n' +
' - home\n' +
' - index\n' +
'\n\r' +
'taxonomies: \n' +
' tag: /tag/{slug}/\n' +
' author: /author/{slug}/' +
'\t' +
'\n'
);
fs.copy.withArgs(expectedDefaultSettingsPath, expectedContentPath).resolves();
return ensureSettings(['routes']).then(() => {
fs.readFile.callCount.should.be.eql(1);
fs.copy.called.should.be.true();
});
});
it('routes.yaml has modifications, do not replace', function () {
fs.readFile.withArgs(path.join(__dirname, '../../../utils/fixtures/settings/routes.yaml'), 'utf8').resolves('' +
'routes:\n' +
' /about/: about' +
'\n' +
'collections:\n' +
' /:\n' +
' permalink: \'{globals.permalinks}\' # special 1.0 compatibility setting. See the docs for details.\n' +
'\n' +
'taxonomies:\n' +
' tag: /categories/{slug}/\n' +
' author: /author/{slug}/' + '' +
'\n'
);
return ensureSettings(['routes']).then(() => {
fs.readFile.callCount.should.be.eql(1);
fs.copy.called.should.be.false();
});
});
});
});

View File

@ -23,7 +23,7 @@ describe('UNIT > Settings Service:', function () {
routes: null,
collections: {
'/': {
permalink: '{globals.permalinks}',
permalink: '/{slug}/',
template: ['home', 'index']
}
},

View File

@ -26,7 +26,7 @@ describe('UNIT > Settings Service:', function () {
routes: null,
collections: {
'/': {
permalink: '{globals.permalinks}',
permalink: '/{slug}/',
template: [ 'home', 'index' ]
}
},
@ -86,7 +86,7 @@ describe('UNIT > Settings Service:', function () {
routes: null,
collections: {
'/': {
permalink: '{globals.permalinks}',
permalink: '/{slug}/',
template: [ 'home', 'index' ]
}
},

View File

@ -191,27 +191,6 @@ describe('UNIT: services/settings/validate', function () {
throw new Error('should fail');
});
it('no validation error for {globals.permalinks}', function () {
const object = validate({
collections: {
'/magic/': {
permalink: '{globals.permalinks}'
}
}
});
object.should.eql({
taxonomies: {},
routes: {},
collections: {
'/magic/': {
permalink: '{globals.permalinks}',
templates: []
}
}
});
});
it('no validation error for routes', function () {
validate({
routes: {

View File

@ -98,7 +98,7 @@ describe('Themes', function () {
themeDataExpectedProps = ['posts_per_page'],
blogDataExpectedProps = [
'url', 'title', 'description', 'logo', 'cover_image', 'icon', 'twitter', 'facebook', 'navigation',
'permalinks', 'timezone', 'amp'
'timezone', 'amp'
],
updateOptionsStub;

View File

@ -2,7 +2,7 @@ routes:
collections:
/
permalink: '{globals.permalinks}'
permalink: /{slug}/
template:
- index

View File

@ -2,7 +2,7 @@ routes:
collections:
/:
permalink: '{globals.permalinks}'
permalink: /{slug}/
template:
- index

View File

@ -2,7 +2,7 @@ routes:
collections:
/:
permalink: '{globals.permalinks}'
permalink: /{slug}/
template:
- index

View File

@ -48,7 +48,6 @@ var Promise = require('bluebird'),
createUser,
createPost,
login,
togglePermalinks,
startGhost,
configureGhost,
@ -792,42 +791,6 @@ login = function login(request) {
});
};
togglePermalinks = function togglePermalinks(request, toggle) {
var permalinkString = toggle === 'date' ? '/:year/:month/:day/:slug/' : '/:slug/';
return new Promise(function (resolve, reject) {
doAuth(request).then(function (token) {
request.put('/ghost/api/v0.1/settings/')
.set('Authorization', 'Bearer ' + token)
.send({
settings: [
{
uuid: '75e994ae-490e-45e6-9207-0eab409c1c04',
key: 'permalinks',
value: permalinkString,
type: 'blog',
created_at: '2014-10-16T17:39:16.005Z',
created_by: 1,
updated_at: '2014-10-20T19:44:18.077Z',
updated_by: 1
}
]
})
.end(function (err, res) {
if (err) {
return reject(err);
}
if (res.statusCode !== 200) {
return reject(res.body);
}
resolve(res.body);
});
});
});
};
/**
* Has to run in a transaction for MySQL, otherwise the foreign key check does not work.
* Sqlite3 has no truncate command.
@ -1115,7 +1078,6 @@ module.exports = {
createUser: createUser,
createPost: createPost,
login: login,
togglePermalinks: togglePermalinks,
mockNotExistingModule: mockNotExistingModule,
unmockNotExistingModule: unmockNotExistingModule,