Fixed relative canonical_url values not being stored as root-relative (#10989)

no issue

- we try to store all urls as relative paths where possible in Ghost so that the `config.url` value can be changed
- all relative paths are stored as root-relative except for the `post.canonical_url` field which was storing subdirectory-relative paths
- adds a migration to put the subdirectory prefix onto any relative canonical_url paths
- updates the canonical_url input serialiser to keep the subdirectory rather than stripping it to match all other url fields
This commit is contained in:
Kevin Ansfield 2019-08-05 13:56:28 +01:00 committed by GitHub
parent bbfea086b3
commit d96be4907e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 1 deletions

View File

@ -12,7 +12,7 @@ const handleCanonicalUrl = (canonicalUrl) => {
// Blog URL incl. the same protocol. This allows users to keep e.g. Facebook comments after
// a http -> https switch
if (absolute.startsWith(blogDomain) && isSameProtocol) {
return urlUtils.absoluteToRelative(canonicalUrl, {withoutSubdirectory: true});
return urlUtils.absoluteToRelative(canonicalUrl);
}
return canonicalUrl;

View File

@ -0,0 +1,98 @@
const models = require('../../../../models');
const common = require('../../../../lib/common');
const config = require('../../../../config');
const {URL} = require('url');
module.exports.config = {
transaction: true
};
// We've been incorrectly saving canonical_url fields without a subdirectory.
// We need this column to be consistent with all other relative URLs, so...
// if we have a configured url with a subdirectory
// find all posts that have a canonical_url starting with / but not //
// prefix the subdirectory to the canonical_url and save the post
module.exports.up = (options) => {
// normalize config url to always have a trailing-slash
let configUrl = config.get('url');
if (!configUrl.endsWith('/')) {
configUrl = `${configUrl}/`;
}
const url = new URL(configUrl);
const localOptions = Object.assign({
context: {internal: true}
}, options);
if (url.pathname === '/') {
common.logging.info('Skipping posts.canonical_url subdirectory fix: no subdirectory configured');
return Promise.resolve();
}
// perform a specific query for the type of canonical URLs we're looking for
// so we're not fetching and manually looping over a ton of post models
return models.Posts
.forge()
.query((qb) => {
qb.where('canonical_url', 'like', '/%');
qb.whereNot('canonical_url', 'like', '//%');
})
.fetch(localOptions)
.then((posts) => {
if (posts) {
return Promise.mapSeries(posts, (post) => {
const canonicalUrl = post.get('canonical_url').replace('/', url.pathname);
post.set('canonical_url', canonicalUrl);
return post.save(null, localOptions);
}).then(() => {
common.logging.info(`Added subdirectory prefix to canonical_url in ${posts.length} posts`);
});
}
common.logging.info('Skipping posts.canonical_url subdirectory fix: no canonical_urls to fix');
return Promise.resolve();
});
};
// if we have a configured url with a subdirectory
// find all posts with a canonical_url starting with the subdirectory
// remove it and save the post
module.exports.down = (options) => {
// normalize config url to always have a trailing-slash
let configUrl = config.get('url');
if (!configUrl.endsWith('/')) {
configUrl = `${configUrl}/`;
}
const url = new URL(configUrl);
const localOptions = Object.assign({
context: {internal: true}
}, options);
if (url.pathname === '/') {
common.logging.info('Skipping posts.canonical_url subdirectory fix: no subdirectory configured');
return Promise.resolve();
}
return models.Posts
.forge()
.query((qb) => {
qb.where('canonical_url', 'LIKE', `${url.pathname}%`);
})
.fetch()
.then((posts) => {
if (posts) {
return Promise.mapSeries(posts, (post) => {
const canonicalUrl = post.get('canonical_url').replace(url.pathname, '/');
post.set('canonical_url', canonicalUrl);
return post.save(null, localOptions);
}).then(() => {
common.logging.info(`Removed subdirectory prefix from canonical_url in ${posts.length} posts`);
});
}
common.logging.info('Skipping posts.canonical_url subdirectory fix: no canonical_urls to fix');
return Promise.resolve();
});
};