mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 05:50:35 +03:00
Returned relative paths in html for Content API V2 by default (#10091)
refs #10083 - you can send `?absolute_urls=true` and Ghost will also transform the paths in the content (this is optional/conditional)
This commit is contained in:
parent
94b3735c6e
commit
1b9c61eed1
@ -39,7 +39,8 @@ module.exports = {
|
||||
'fields',
|
||||
'status',
|
||||
'formats',
|
||||
'debug'
|
||||
'debug',
|
||||
'absolute_urls'
|
||||
],
|
||||
data: [
|
||||
'id',
|
||||
|
@ -16,7 +16,8 @@ module.exports = {
|
||||
'limit',
|
||||
'order',
|
||||
'page',
|
||||
'debug'
|
||||
'debug',
|
||||
'absolute_urls'
|
||||
],
|
||||
validation: {
|
||||
options: {
|
||||
@ -42,7 +43,8 @@ module.exports = {
|
||||
'fields',
|
||||
'status',
|
||||
'formats',
|
||||
'debug'
|
||||
'debug',
|
||||
'absolute_urls'
|
||||
],
|
||||
data: [
|
||||
'id',
|
||||
|
@ -1,23 +1,35 @@
|
||||
const urlService = require('../../../../../../services/url');
|
||||
const {urlFor, makeAbsoluteUrls} = require('../../../../../../services/url/utils');
|
||||
|
||||
const forPost = (id, attrs, options) => {
|
||||
attrs.url = urlService.getUrlByResourceId(id, {absolute: true});
|
||||
|
||||
if (attrs.feature_image) {
|
||||
attrs.feature_image = urlFor('image', {image: attrs.feature_image}, true);
|
||||
attrs.feature_image = urlService.utils.urlFor('image', {image: attrs.feature_image}, true);
|
||||
}
|
||||
|
||||
if (attrs.og_image) {
|
||||
attrs.og_image = urlFor('image', {image: attrs.og_image}, true);
|
||||
attrs.og_image = urlService.utils.urlFor('image', {image: attrs.og_image}, true);
|
||||
}
|
||||
|
||||
if (attrs.twitter_image) {
|
||||
attrs.twitter_image = urlFor('image', {image: attrs.twitter_image}, true);
|
||||
attrs.twitter_image = urlService.utils.urlFor('image', {image: attrs.twitter_image}, true);
|
||||
}
|
||||
|
||||
if (attrs.html) {
|
||||
attrs.html = makeAbsoluteUrls(attrs.html, urlFor('home', true), attrs.url).html();
|
||||
const urlOptions = {
|
||||
assetsOnly: true
|
||||
};
|
||||
|
||||
if (options.absolute_urls) {
|
||||
urlOptions.assetsOnly = false;
|
||||
}
|
||||
|
||||
attrs.html = urlService.utils.makeAbsoluteUrls(
|
||||
attrs.html,
|
||||
urlService.utils.urlFor('home', true),
|
||||
attrs.url,
|
||||
urlOptions
|
||||
).html();
|
||||
}
|
||||
|
||||
if (options.columns && !options.columns.includes('url')) {
|
||||
@ -50,11 +62,11 @@ const forUser = (id, attrs) => {
|
||||
attrs.url = urlService.getUrlByResourceId(id, {absolute: true});
|
||||
|
||||
if (attrs.profile_image) {
|
||||
attrs.profile_image = urlFor('image', {image: attrs.profile_image}, true);
|
||||
attrs.profile_image = urlService.utils.urlFor('image', {image: attrs.profile_image}, true);
|
||||
}
|
||||
|
||||
if (attrs.cover_image) {
|
||||
attrs.cover_image = urlFor('image', {image: attrs.cover_image}, true);
|
||||
attrs.cover_image = urlService.utils.urlFor('image', {image: attrs.cover_image}, true);
|
||||
}
|
||||
|
||||
return attrs;
|
||||
@ -64,7 +76,7 @@ const forTag = (id, attrs) => {
|
||||
attrs.url = urlService.getUrlByResourceId(id, {absolute: true});
|
||||
|
||||
if (attrs.feature_image) {
|
||||
attrs.feature_image = urlFor('image', {image: attrs.feature_image}, true);
|
||||
attrs.feature_image = urlService.utils.urlFor('image', {image: attrs.feature_image}, true);
|
||||
}
|
||||
|
||||
return attrs;
|
||||
|
@ -124,7 +124,6 @@ function getAmperizeHTML(html, post) {
|
||||
amperize = amperize || new Amperize();
|
||||
|
||||
// make relative URLs abolute
|
||||
// @TODO: API v2 already makes the urls absolute. Remove if we drop v0.1.
|
||||
html = urlService.utils.makeAbsoluteUrls(html, urlService.utils.urlFor('home', true), post.url).html();
|
||||
|
||||
if (!amperizeCache[post.id] || moment(new Date(amperizeCache[post.id].updated_at)).diff(new Date(post.updated_at)) < 0) {
|
||||
|
@ -381,23 +381,20 @@ function redirectToAdmin(status, res, adminPath) {
|
||||
* absolute urls. Returns an object. The html string can be accessed by calling `html()` on
|
||||
* the variable that takes the result of this function
|
||||
*/
|
||||
function makeAbsoluteUrls(html, siteUrl, itemUrl) {
|
||||
var htmlContent = cheerio.load(html, {decodeEntities: false});
|
||||
function makeAbsoluteUrls(html, siteUrl, itemUrl, options = {assetsOnly: false}) {
|
||||
const htmlContent = cheerio.load(html, {decodeEntities: false});
|
||||
const staticImageUrlPrefixRegex = new RegExp(STATIC_IMAGE_URL_PREFIX);
|
||||
|
||||
// convert relative resource urls to absolute
|
||||
['href', 'src'].forEach(function forEach(attributeName) {
|
||||
htmlContent('[' + attributeName + ']').each(function each(ix, el) {
|
||||
var baseUrl,
|
||||
attributeValue,
|
||||
parsed;
|
||||
|
||||
el = htmlContent(el);
|
||||
|
||||
attributeValue = el.attr(attributeName);
|
||||
let attributeValue = el.attr(attributeName);
|
||||
|
||||
// if URL is absolute move on to the next element
|
||||
try {
|
||||
parsed = url.parse(attributeValue);
|
||||
const parsed = url.parse(attributeValue);
|
||||
|
||||
if (parsed.protocol) {
|
||||
return;
|
||||
@ -415,11 +412,15 @@ function makeAbsoluteUrls(html, siteUrl, itemUrl) {
|
||||
if (attributeValue[0] === '#') {
|
||||
return;
|
||||
}
|
||||
// compose an absolute URL
|
||||
|
||||
if (options.assetsOnly && !attributeValue.match(staticImageUrlPrefixRegex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compose an absolute URL
|
||||
// if the relative URL begins with a '/' use the blog URL (including sub-directory)
|
||||
// as the base URL, otherwise use the post's URL.
|
||||
baseUrl = attributeValue[0] === '/' ? siteUrl : itemUrl;
|
||||
const baseUrl = attributeValue[0] === '/' ? siteUrl : itemUrl;
|
||||
attributeValue = urlJoin(baseUrl, attributeValue);
|
||||
el.attr(attributeName, attributeValue);
|
||||
});
|
||||
|
@ -89,6 +89,11 @@ describe('Posts', function () {
|
||||
should.exist(urlParts.protocol);
|
||||
should.exist(urlParts.host);
|
||||
|
||||
res.body.posts[7].slug.should.eql('not-so-short-bit-complex');
|
||||
res.body.posts[7].html.should.match(/<a href="\/about#nowhere" title="Relative URL/);
|
||||
res.body.posts[9].slug.should.eql('ghostly-kitchen-sink');
|
||||
res.body.posts[9].html.should.match(/<img src="http:\/\/127.0.0.1:2369\/content\/images\/lol.jpg"/);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -68,8 +68,19 @@ describe('Unit: v2/utils/serializers/output/posts', function () {
|
||||
urlService.utils.urlFor.getCall(3).args.should.eql(['home', true]);
|
||||
|
||||
urlService.utils.makeAbsoluteUrls.callCount.should.eql(2);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql(['## markdown', 'urlFor', 'getUrlByResourceId']);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(1).args.should.eql(['<img href=/content/test.jpf', 'urlFor', 'getUrlByResourceId']);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql([
|
||||
'## markdown',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: true}
|
||||
]);
|
||||
|
||||
urlService.utils.makeAbsoluteUrls.getCall(1).args.should.eql([
|
||||
'<img href=/content/test.jpf',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: true}
|
||||
]);
|
||||
|
||||
urlService.getUrlByResourceId.callCount.should.eql(4);
|
||||
urlService.getUrlByResourceId.getCall(0).args.should.eql(['id1', {absolute: true}]);
|
||||
@ -77,5 +88,34 @@ describe('Unit: v2/utils/serializers/output/posts', function () {
|
||||
urlService.getUrlByResourceId.getCall(2).args.should.eql(['id4', {absolute: true}]);
|
||||
urlService.getUrlByResourceId.getCall(3).args.should.eql(['id2', {absolute: true}]);
|
||||
});
|
||||
|
||||
it('absolute_urls = true', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors'],
|
||||
absolute_urls: true
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = {
|
||||
data: [
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id2',
|
||||
html: '<img href=/content/test.jpf'
|
||||
}))
|
||||
],
|
||||
meta: {}
|
||||
};
|
||||
|
||||
serializers.output.posts.all(ctrlResponse, apiConfig, frame);
|
||||
urlService.utils.makeAbsoluteUrls.callCount.should.eql(1);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql([
|
||||
'<img href=/content/test.jpf',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: false}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -813,5 +813,33 @@ describe('Url', function () {
|
||||
|
||||
result.should.match(/<a href="http:\/\/my-ghost-blog.com\/blog\/about#nowhere" title="Relative URL">/);
|
||||
});
|
||||
|
||||
it('asset urls only', function () {
|
||||
let html = '<a href="/about" title="Relative URL"><img src="/content/images/1.jpg">';
|
||||
let result = urlService.utils.makeAbsoluteUrls(html, siteUrl, itemUrl, {assetsOnly: true}).html();
|
||||
|
||||
result.should.match(/<img src="http:\/\/my-ghost-blog.com\/content\/images\/1.jpg">/);
|
||||
result.should.match(/<a href="\/about\" title="Relative URL">/);
|
||||
|
||||
html = '<a href="/content/images/09/01/image.jpg">';
|
||||
result = urlService.utils.makeAbsoluteUrls(html, siteUrl, itemUrl, {assetsOnly: true}).html();
|
||||
|
||||
result.should.match(/<a href="http:\/\/my-ghost-blog.com\/content\/images\/09\/01\/image.jpg">/);
|
||||
|
||||
html = '<a href="/blog/content/images/09/01/image.jpg">';
|
||||
result = urlService.utils.makeAbsoluteUrls(html, siteUrl, itemUrl, {assetsOnly: true}).html();
|
||||
|
||||
result.should.match(/<a href="http:\/\/my-ghost-blog.com\/blog\/content\/images\/09\/01\/image.jpg">/);
|
||||
|
||||
html = '<img src="http://my-ghost-blog.de/content/images/09/01/image.jpg">';
|
||||
result = urlService.utils.makeAbsoluteUrls(html, siteUrl, itemUrl, {assetsOnly: true}).html();
|
||||
|
||||
result.should.match(/<img src="http:\/\/my-ghost-blog.de\/content\/images\/09\/01\/image.jpg">/);
|
||||
|
||||
html = '<img src="http://external.com/image.jpg">';
|
||||
result = urlService.utils.makeAbsoluteUrls(html, siteUrl, itemUrl, {assetsOnly: true}).html();
|
||||
|
||||
result.should.match(/<img src="http:\/\/external.com\/image.jpg">/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user