|
1 | 1 | import express from 'express'
|
2 |
| -import type { Response } from 'express' |
| 2 | +import type { Response, RequestHandler } from 'express' |
3 | 3 |
|
4 | 4 | import type { ExtendedRequest } from '@/types'
|
5 | 5 | import { defaultCacheControl } from '@/frame/middleware/cache-control.js'
|
6 | 6 | import { getProductStringFromPath, getVersionStringFromPath } from '#src/frame/lib/path-utils.js'
|
7 |
| -import { latest } from '#src/versions/lib/enterprise-server-releases.js' |
| 7 | +import { getLanguageCodeFromPath } from '#src/languages/middleware/detect-language.js' |
| 8 | +import { pagelistValidationMiddleware } from './validation' |
| 9 | +import catchMiddlewareError from '#src/observability/middleware/catch-middleware-error.js' |
8 | 10 |
|
9 | 11 | const router = express.Router()
|
10 | 12 |
|
11 |
| -router.get('/v1/enterprise-server@latest', (req, res) => { |
12 |
| - res.redirect( |
13 |
| - 307, |
14 |
| - req.originalUrl.replace( |
15 |
| - '/pagelist/v1/enterprise-server@latest', |
16 |
| - `/pagelist/v1/enterprise-server@${latest}`, |
17 |
| - ), |
18 |
| - ) |
19 |
| -}) |
20 |
| - |
21 |
| -router.get('/v1/:product@:version', (req: ExtendedRequest, res: Response) => { |
22 |
| - const { product, version } = req.params |
23 |
| - |
24 |
| - if (!req.context || !req.context.pages) throw new Error('Request not contextualized.') |
25 |
| - |
26 |
| - const pages = req.context.pages |
27 |
| - |
28 |
| - // the keys of `context.pages` are permalinks |
29 |
| - const keys = Object.keys(pages) |
30 |
| - |
31 |
| - // we filter the permalinks to get only our target version |
32 |
| - const filteredPermalinks = keys.filter((key) => versionMatcher(key, `${product}@${version}`)) |
33 |
| - const expression = /^\/en/ |
34 |
| - |
35 |
| - if (!filteredPermalinks.length) { |
36 |
| - res.status(400).type('text').send('Invalid version') |
37 |
| - return |
38 |
| - } |
39 |
| - |
40 |
| - //right now we only need english permalinks perhaps we can use the language from the request in the future |
41 |
| - const englishPermalinks = filteredPermalinks.filter((permalink) => expression.test(permalink)) |
42 |
| - |
43 |
| - defaultCacheControl(res) |
44 |
| - |
45 |
| - // new line added at the end so `wc` works as expected with `-l` and `-w`. |
46 |
| - res.type('text').send(englishPermalinks.join('\n').concat('\n')) |
47 |
| -}) |
48 |
| - |
49 |
| -router.get('/:product@:version', (req, res) => { |
50 |
| - res.redirect(307, req.originalUrl.replace('/pagelist', '/pagelist/v1')) |
51 |
| -}) |
52 |
| - |
53 |
| -// If no version is provided we'll assume API v1 and Docs version FPT |
54 |
| -router.get('/', (req, res) => { |
55 |
| - res.redirect(307, req.originalUrl.replace('/pagelist', '/pagelist/v1/free-pro-team@latest')) |
56 |
| -}) |
57 |
| - |
58 |
| -function versionMatcher(key: string, targetVersion: string) { |
59 |
| - const versionFromPath = getVersionStringFromPath(key) |
60 |
| - |
61 |
| - if (!versionFromPath) { |
| 13 | +// pagelistValidationMiddleware is used for every route to normalize the lang and version from the path |
| 14 | + |
| 15 | +// If no version or lang is provided we'll assume english and fpt and redirect there |
| 16 | +router.get( |
| 17 | + '/', |
| 18 | + pagelistValidationMiddleware as RequestHandler, |
| 19 | + catchMiddlewareError(async function (req: ExtendedRequest, res: Response) { |
| 20 | + res.redirect( |
| 21 | + 308, |
| 22 | + req.originalUrl.replace( |
| 23 | + '/pagelist', |
| 24 | + `/pagelist/${req.context!.currentLanguage}/${req.context!.currentVersion}`, |
| 25 | + ), |
| 26 | + ) |
| 27 | + }), |
| 28 | +) |
| 29 | + |
| 30 | +// handles paths with fragments that could be the language or the version |
| 31 | +router.get( |
| 32 | + '/:someParam', |
| 33 | + pagelistValidationMiddleware as RequestHandler, |
| 34 | + catchMiddlewareError(async function (req: ExtendedRequest, res: Response) { |
| 35 | + const { someParam } = req.params |
| 36 | + res.redirect( |
| 37 | + 308, |
| 38 | + req.originalUrl.replace( |
| 39 | + `/pagelist/${someParam}`, |
| 40 | + `/pagelist/${req.context!.currentLanguage}/${req.context!.currentVersion}`, |
| 41 | + ), |
| 42 | + ) |
| 43 | + }), |
| 44 | +) |
| 45 | + |
| 46 | +// for a fully qualified path with language and product version, we'll serve up the pagelist |
| 47 | +router.get( |
| 48 | + '/:lang/:productVersion', |
| 49 | + pagelistValidationMiddleware as RequestHandler, |
| 50 | + catchMiddlewareError(async function (req: ExtendedRequest, res: Response) { |
| 51 | + if (!req.context || !req.context.pages) throw new Error('Request not contextualized.') |
| 52 | + |
| 53 | + const pages = req.context.pages |
| 54 | + |
| 55 | + // the keys of `context.pages` are permalinks |
| 56 | + const keys = Object.keys(pages) |
| 57 | + |
| 58 | + // we filter the permalinks to get only our target version and language |
| 59 | + const filteredPermalinks = keys.filter((key) => |
| 60 | + versionMatcher(key, req.context!.currentVersion!, req.context!.currentLanguage!), |
| 61 | + ) |
| 62 | + |
| 63 | + // if we've filtered it out of existence, there's no articles to return so we must've |
| 64 | + // gotten a bad language or version |
| 65 | + if (!filteredPermalinks.length) { |
| 66 | + const { lang, productVersion } = req.params |
| 67 | + |
| 68 | + res |
| 69 | + .status(400) |
| 70 | + .type('application/json') |
| 71 | + .send( |
| 72 | + JSON.stringify({ |
| 73 | + error: 'Invalid version or language code', |
| 74 | + language: lang, |
| 75 | + version: productVersion, |
| 76 | + }), |
| 77 | + ) |
| 78 | + return |
| 79 | + } |
| 80 | + |
| 81 | + defaultCacheControl(res) |
| 82 | + |
| 83 | + // new line added at the end so `wc` works as expected with `-l` and `-w`. |
| 84 | + res.type('text').send(filteredPermalinks.join('\n').concat('\n')) |
| 85 | + }), |
| 86 | +) |
| 87 | + |
| 88 | +function versionMatcher(key: string, targetVersion: string, targetLang: string) { |
| 89 | + const versionFromPermalink = getVersionStringFromPath(key) |
| 90 | + |
| 91 | + if (!versionFromPermalink) { |
62 | 92 | throw new Error(`Couldn't get version from the permalink ${key} when generating the pagelist.`)
|
63 | 93 | }
|
64 | 94 | if (getProductStringFromPath(key) === 'early-access') return null
|
65 |
| - if (versionFromPath === targetVersion) return key |
| 95 | + |
| 96 | + const langFromPermalink = getLanguageCodeFromPath(key) |
| 97 | + if (!langFromPermalink) { |
| 98 | + throw new Error(`Couldn't get language from the permalink ${key} when generating the pagelist.`) |
| 99 | + } |
| 100 | + |
| 101 | + if (versionFromPermalink === targetVersion && langFromPermalink === targetLang) return key |
66 | 102 | }
|
67 | 103 |
|
68 | 104 | export default router
|
0 commit comments