Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ghost/core/core/frontend/web/routers/link-redirects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const linkRedirects = require('../../../server/services/link-redirection');

module.exports = function handleRedirects(siteApp) {
siteApp.get(linkRedirects.service.relativeRedirectPrefix() + '*', linkRedirects.service.handleRequest);
};
4 changes: 2 additions & 2 deletions ghost/core/core/frontend/web/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const themeMiddleware = themeEngine.middleware;
const membersService = require('../../server/services/members');
const offersService = require('../../server/services/offers');
const customRedirects = require('../../server/services/custom-redirects');
const linkRedirects = require('../../server/services/link-redirection');
const linkRedirectsHandler = require('./routers/link-redirects');
const siteRoutes = require('./routes');
const shared = require('../../server/web/shared');
const errorHandler = require('@tryghost/mw-error-handler');
Expand Down Expand Up @@ -51,7 +51,7 @@ module.exports = function setupSiteApp(routerConfig) {

siteApp.use(offersService.middleware);

siteApp.use(linkRedirects.service.handleRequest);
linkRedirectsHandler(siteApp);

// you can extend Ghost with a custom redirects file
// see https://github.com/TryGhost/Ghost/issues/7707
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ class LinkRedirectsService {
return link;
}

/**
* Returns the relative path prefix without subdirectory (e.g., /r/)
* Used for Express route matching where subdirectory is already stripped
* @return {string}
**/
relativeRedirectPrefix() {
return '/' + this.#redirectURLPrefix;
}

/**
* @param {import('express').Request} req
* @param {import('express').Response} res
Expand All @@ -86,18 +95,6 @@ class LinkRedirectsService {
*/
async handleRequest(req, res, next) {
try {
// skip handling if original url doesn't match the prefix
const fullURLWithRedirectPrefix = `${this.#baseURL.pathname}${this.#redirectURLPrefix}`;
// @NOTE: below is equivalent to doing:
// router.get('/r/'), (req, res) ...
// To make it cleaner we should rework it to:
// linkRedirects.service.handleRequest(router);
// and mount routes on top like for example sitemapHandler does
// Cleanup issue: https://github.com/TryGhost/Toolbox/issues/516
if (!req.originalUrl.startsWith(fullURLWithRedirectPrefix)) {
return next();
}

const url = new URL(req.originalUrl, this.#baseURL);
const link = await this.#linkRedirectRepository.getByURL(url);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ describe('LinkRedirectsService', function () {
});
});

describe('relativeRedirectPrefix', function () {
it('returns relative path without subdirectory for Express routing', function () {
const instance = new LinkRedirectsService({
linkRedirectRepository: {},
config: {
baseURL: new URL('https://localhost:2368/blog/')
}
});
assert.equal(instance.relativeRedirectPrefix(), '/r/');
});

it('returns same value as redirectPrefix when no subdirectory configured', function () {
const instance = new LinkRedirectsService({
linkRedirectRepository: {},
config: {
baseURL: new URL('https://localhost:2368/')
}
});
assert.equal(instance.relativeRedirectPrefix(), '/r/');
});
});

describe('handleRequest', function () {
it('redirects if found', async function () {
const linkRedirectRepository = {
Expand Down Expand Up @@ -114,39 +136,5 @@ describe('LinkRedirectsService', function () {
await instance.handleRequest(req, res, next);
assert.equal(next.callCount, 1);
});

it('does not redirect if url does not contain a redirect prefix on site with no subdir', async function () {
const instance = new LinkRedirectsService({
config: {
baseURL: new URL('https://localhost:2368/')
}
});
const req = {
originalUrl: 'no_r/prefix'
};
const res = {};
const next = sinon.fake();

await instance.handleRequest(req, res, next);

assert.equal(next.callCount, 1);
});

it('does not redirect if url does not contain a redirect prefix on site with subdir', async function () {
const instance = new LinkRedirectsService({
config: {
baseURL: new URL('https://localhost:2368/blog')
}
});
const req = {
originalUrl: 'blog/no_r/prefix'
};
const res = {};
const next = sinon.fake();

await instance.handleRequest(req, res, next);

assert.equal(next.callCount, 1);
});
});
});