mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
🐛 Dynamic Routing Beta: Disallow using author
resource and author
data key name (#9790)
* 🐛 Dynamic Routing Beta: Shortform `author.foo` is not allowed refs #9601 - otherwise you get access to {{author}} in the theme, which is deprecated & causes errors - recommend not using {{author}} as data longform name in the yaml validator - (internal usage is still allowed) - also warn against using reserved data key names like filter, resource, limit etc - maybe remove this restriction later but seems like a sensible validation right now.
This commit is contained in:
parent
fd8502448a
commit
cd690efad1
4 changed files with 136 additions and 3 deletions
|
@ -54,7 +54,7 @@ class TaxonomyRouter extends ParentRouter {
|
|||
type: 'channel',
|
||||
name: this.taxonomyKey,
|
||||
permalinks: this.permalinks.getValue(),
|
||||
data: {[this.taxonomyKey]: _.omit(RESOURCE_CONFIG.QUERY[this.taxonomyKey], 'alias')},
|
||||
data: {[this.taxonomyKey]: _.omit(RESOURCE_CONFIG.QUERY[this.taxonomyKey], ['alias', 'internal'])},
|
||||
filter: RESOURCE_CONFIG.TAXONOMIES[this.taxonomyKey].filter,
|
||||
resourceType: this.getResourceType(),
|
||||
context: [this.taxonomyKey],
|
||||
|
|
|
@ -10,6 +10,16 @@ module.exports.QUERY = {
|
|||
}
|
||||
},
|
||||
author: {
|
||||
internal: true,
|
||||
alias: 'users',
|
||||
type: 'read',
|
||||
resource: 'users',
|
||||
options: {
|
||||
slug: '%s',
|
||||
visibility: 'public'
|
||||
}
|
||||
},
|
||||
user: {
|
||||
alias: 'users',
|
||||
type: 'read',
|
||||
resource: 'users',
|
||||
|
|
|
@ -48,6 +48,15 @@ _private.validateData = function validateData(object) {
|
|||
|
||||
let [resourceKey, slug] = shortForm.split('.');
|
||||
|
||||
// @NOTE: `data: author.foo` is not allowed currently, because this will make {{author}} available in the theme, which is deprecated (single author usage)
|
||||
if (!RESOURCE_CONFIG.QUERY[resourceKey] ||
|
||||
(RESOURCE_CONFIG.QUERY[resourceKey].hasOwnProperty('internal') && RESOURCE_CONFIG.QUERY[resourceKey].internal === true)) {
|
||||
throw new common.errors.ValidationError({
|
||||
message: `Resource key not supported. ${resourceKey}`,
|
||||
help: 'Please use: tag, user, post or page.'
|
||||
});
|
||||
}
|
||||
|
||||
longForm.query[options.resourceKey || resourceKey] = {};
|
||||
longForm.query[options.resourceKey || resourceKey] = _.omit(_.cloneDeep(RESOURCE_CONFIG.QUERY[resourceKey]), 'alias');
|
||||
|
||||
|
@ -81,7 +90,22 @@ _private.validateData = function validateData(object) {
|
|||
};
|
||||
|
||||
_.each(object.data, (value, key) => {
|
||||
// CASE: short form e.g. data: tag.recipes
|
||||
// CASE: a name is required to define the data longform
|
||||
if (['resource', 'type', 'limit', 'order', 'include', 'filter', 'status', 'visibility', 'slug', 'redirect'].indexOf(key) !== -1) {
|
||||
throw new common.errors.ValidationError({
|
||||
message: 'Please wrap the data definition into a custom name.',
|
||||
help: 'Example:\n data:\n my-tag:\n resource: tags\n ...\n'
|
||||
});
|
||||
}
|
||||
|
||||
// @NOTE: We disallow author, because {{author}} is deprecated.
|
||||
if (key === 'author') {
|
||||
throw new common.errors.ValidationError({
|
||||
message: 'Please choose a different name. We recommend not using author.'
|
||||
});
|
||||
}
|
||||
|
||||
// CASE: short form used with custom names, resolve to longform and return
|
||||
if (typeof object.data[key] === 'string') {
|
||||
const longForm = shortToLongForm(object.data[key], {resourceKey: key});
|
||||
data.query = _.merge(data.query, longForm.query);
|
||||
|
|
|
@ -326,6 +326,9 @@ describe('UNIT: services/settings/validate', function () {
|
|||
'/music/': {
|
||||
data: 'tag.music'
|
||||
},
|
||||
'/ghost/': {
|
||||
data: 'user.ghost'
|
||||
},
|
||||
'/sleep/': {
|
||||
data: {
|
||||
bed: 'tag.bed',
|
||||
|
@ -374,6 +377,24 @@ describe('UNIT: services/settings/validate', function () {
|
|||
},
|
||||
templates: []
|
||||
},
|
||||
'/ghost/': {
|
||||
data: {
|
||||
query: {
|
||||
user: {
|
||||
resource: 'users',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'ghost',
|
||||
visibility: 'public'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
users: [{redirect: true, slug: 'ghost'}]
|
||||
}
|
||||
},
|
||||
templates: []
|
||||
},
|
||||
'/music/': {
|
||||
data: {
|
||||
query: {
|
||||
|
@ -609,7 +630,7 @@ describe('UNIT: services/settings/validate', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('errors', function () {
|
||||
it('errors: data shortform incorrect', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
|
@ -619,7 +640,16 @@ describe('UNIT: services/settings/validate', function () {
|
|||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
(err instanceof common.errors.ValidationError).should.be.true();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
|
||||
it('errors: data longform resource is missing', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
'/magic/': {
|
||||
|
@ -630,7 +660,16 @@ describe('UNIT: services/settings/validate', function () {
|
|||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
(err instanceof common.errors.ValidationError).should.be.true();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
|
||||
it('errors: data longform type is missing', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
'/magic/': {
|
||||
|
@ -648,5 +687,65 @@ describe('UNIT: services/settings/validate', function () {
|
|||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
|
||||
it('errors: data shortform author is not allowed', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
'/magic/': {
|
||||
permalink: '/{slug}/',
|
||||
data: 'author.food'
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
(err instanceof common.errors.ValidationError).should.be.true();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
|
||||
it('errors: data longform name is author', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
'/magic/': {
|
||||
permalink: '/{slug}/',
|
||||
data: {
|
||||
author: {
|
||||
resource: 'users'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
(err instanceof common.errors.ValidationError).should.be.true();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
|
||||
it('errors: data longform does not use a custom name at all', function () {
|
||||
try {
|
||||
validate({
|
||||
collections: {
|
||||
'/magic/': {
|
||||
permalink: '/{slug}/',
|
||||
data: {
|
||||
resource: 'users'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
(err instanceof common.errors.ValidationError).should.be.true();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('should fail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue