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
3 changes: 3 additions & 0 deletions lib/is-archived-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ export default function isArchivedVersion(req) {
// if this is an assets path, use the referrer
// if this is a docs path, use the req.path
const pathToCheck = patterns.assetPaths.test(req.path) ? req.get('referrer') : req.path
return isArchivedVersionByPath(pathToCheck)
}

export function isArchivedVersionByPath(pathToCheck) {
// ignore paths that don't have an enterprise version number
if (
!(
Expand Down
51 changes: 37 additions & 14 deletions src/pageinfo/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,24 @@ import shortVersions from '../../middleware/contextualizers/short-versions.js'
import contextualize from '../../middleware/context.js'
import features from '../../middleware/contextualizers/features.js'
import getRedirect from '../../lib/get-redirect.js'
import { isArchivedVersionByPath } from '../../lib/is-archived-version.js'

const router = express.Router()

const validationMiddleware = (req, res, next) => {
let { pathname } = req.query
const { pathname } = req.query
if (!pathname) {
return res.status(400).json({ error: `No 'pathname' query` })
}
if (!pathname.trim()) {
return res.status(400).json({ error: `'pathname' query empty` })
}
req.pageinfo = { pathname }
return next()
}

const pageinfoMiddleware = (req, res, next) => {
let { pathname } = req.pageinfo
// We can't use the `findPage` middleware utility function because we
// need to know when the pathname is a redirect.
// This is important so that the final `pathname` value
Expand All @@ -46,35 +52,52 @@ const validationMiddleware = (req, res, next) => {
}

if (!(pathname in req.context.pages)) {
const redirect = getRedirect(pathname, redirectsContext)
if (redirect) {
pathname = redirect
// If a pathname is not a known page, it might *either* be a redirect,
// or an archived enterprise version, or both.
// That's why it's import to not bother looking at the redirects
// if the pathname is an archived enterprise version.
// This mimics how our middleware work and their order.
req.pageinfo.archived = isArchivedVersionByPath(pathname)
if (!req.pageinfo.archived.isArchived) {
const redirect = getRedirect(pathname, redirectsContext)
if (redirect) {
pathname = redirect
}
}
}
const page = req.context.pages[pathname]

if (!page) {
return res.status(400).json({ error: `No page found for '${pathname}'` })
}

req.pageinfo = {
pathname,
page,
}
// Remember this might yield undefined if the pathname is not a page
req.pageinfo.page = req.context.pages[pathname]
// The pathname might have changed if it was a redirect
req.pageinfo.pathname = pathname

return next()
}

router.get(
'/v1',
validationMiddleware,
pageinfoMiddleware,
catchMiddlewareError(async function pageInfo(req, res) {
// Remember, the `validationMiddleware` will use redirects if the
// `pathname` used is a redirect (e.g. /en/articles/foo or
// /articles or '/en/enterprise-server@latest/foo/bar)
// So by the time we get here, the pathname should be one of the
// page's valid permalinks.
const { page, pathname } = req.pageinfo
const { page, pathname, archived } = req.pageinfo

if (archived && archived.isArchived) {
const { requestedVersion } = archived
const title = `GitHub Enterprise Server ${requestedVersion} Help Documentation`
const intro = ''
const product = 'GitHub Enterprise Server'
defaultCacheControl(res)
return res.json({ info: { intro, title, product } })
}

if (!page) {
return res.status(400).json({ error: `No page found for '${pathname}'` })
}

const pagePermalinks = page.permalinks.map((p) => p.href)
if (!pagePermalinks.includes(pathname)) {
Expand Down
23 changes: 23 additions & 0 deletions src/pageinfo/tests/pageinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,27 @@ describe('pageinfo api', () => {
expect(info.title).toMatch('GitHub Enterprise Server Fixture Documentation')
}
})

test('archived enterprise versions', async () => {
// For example /en/enterprise-server@3.8 is a valid Page in the
// site tree, but /en/enterprise-server@2.6 is not. Yet we can
// 200 OK and serve content for that. This needs to be reflected in
// page info too. Even if we have to "fabricate" the title a bit.

// At the time of writing, the latest archived version
{
const res = await get(makeURL('/en/enterprise-server@3.2'))
expect(res.statusCode).toBe(200)
const { info } = JSON.parse(res.body)
expect(info.title).toMatch('GitHub Enterprise Server 3.2 Help Documentation')
}

// The oldest known archived version that we proxy
{
const res = await get(makeURL('/en/enterprise/11.10.340'))
expect(res.statusCode).toBe(200)
const { info } = JSON.parse(res.body)
expect(info.title).toMatch('GitHub Enterprise Server 11.10.340 Help Documentation')
}
})
})