Skip to content

Commit

Permalink
🔨 unify code of mockSiteRouter, adminRouter and testPageRouter to als…
Browse files Browse the repository at this point in the history
…o use helpers for transactions
  • Loading branch information
danyx23 committed Mar 18, 2024
1 parent 94be667 commit e559c80
Show file tree
Hide file tree
Showing 8 changed files with 470 additions and 294 deletions.
202 changes: 109 additions & 93 deletions adminSiteServer/adminRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import {
import { getChartConfigBySlug } from "../db/model/Chart.js"
import { getVariableMetadata } from "../db/model/Variable.js"
import { DbPlainDatasetFile, DbPlainDataset } from "@ourworldindata/types"
import { getRouteWithROTransaction } from "./functionalRouterHelpers.js"

Check warning on line 48 in adminSiteServer/adminRouter.tsx

View workflow job for this annotation

GitHub Actions / eslint

'getRouteWithROTransaction' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 48 in adminSiteServer/adminRouter.tsx

View workflow job for this annotation

GitHub Actions / eslint

'getRouteWithROTransaction' is defined but never used. Allowed unused vars must match /^_/u
import { getPlainRouteWithROTransaction } from "./plainRouterHelpers.js"

// Used for rate-limiting important endpoints (login, register) to prevent brute force attacks
const limiterMiddleware = (
Expand Down Expand Up @@ -136,13 +138,15 @@ adminRouter.post(

adminRouter.get("/logout", logOut)

adminRouter.get("/datasets/:datasetId.csv", async (req, res) => {
const datasetId = expectInt(req.params.datasetId)
getPlainRouteWithROTransaction(
adminRouter,
"/datasets/:datasetId.csv",
async (req, res, trx) => {
const datasetId = expectInt(req.params.datasetId)

await db.knexReadonlyTransaction(async (t) => {
const datasetName = (
await db.knexRawFirst<Pick<DbPlainDataset, "name">>(
t,
trx,
`SELECT name FROM datasets WHERE id=?`,
[datasetId]
)
Expand All @@ -156,70 +160,74 @@ adminRouter.get("/datasets/:datasetId.csv", async (req, res) => {
callback(null)
},
})
await writeDatasetCSV(t, datasetId, writeStream)
await writeDatasetCSV(trx, datasetId, writeStream)
res.end()
})
})
}
)

adminRouter.get("/datasets/:datasetId/downloadZip", async (req, res) => {
const datasetId = expectInt(req.params.datasetId)
getPlainRouteWithROTransaction(
adminRouter,
"/datasets/:datasetId/downloadZip",
async (req, res, trx) => {
const datasetId = expectInt(req.params.datasetId)

res.attachment("additional-material.zip")
res.attachment("additional-material.zip")

const file = await await db.knexReadonlyTransaction((knex) =>
db.knexRawFirst<Pick<DbPlainDatasetFile, "filename" | "file">>(
knex,
`SELECT filename, file FROM dataset_files WHERE datasetId=?`,
[datasetId]
)
)
res.send(file?.file)
})
const file = await db.knexRawFirst<
Pick<DbPlainDatasetFile, "filename" | "file">
>(trx, `SELECT filename, file FROM dataset_files WHERE datasetId=?`, [
datasetId,
])
res.send(file?.file)
}
)

adminRouter.get("/posts/preview/:postId", async (req, res) => {
const postId = expectInt(req.params.postId)
const preview = await db.knexReadonlyTransaction(async (knex) => {
return renderPreview(postId, knex)
})
res.send(preview)
})
getPlainRouteWithROTransaction(
adminRouter,
"/posts/preview/:postId",
async (req, res, trx) => {
const postId = expectInt(req.params.postId)
const preview = await renderPreview(postId, trx)
res.send(preview)
}
)

adminRouter.get("/posts/compare/:postId", async (req, res) => {
const postId = expectInt(req.params.postId)

const [wpPage, archieMlText] = await db.knexReadonlyTransaction(
async (t) => {
const wpPage = await renderPreview(postId, t)
const archieMlText = await Post.select(
"archieml",
"archieml_update_statistics"
).from(t(Post.postsTable).where({ id: postId }))
return [wpPage, archieMlText]
}
)

if (
archieMlText.length === 0 ||
archieMlText[0].archieml === null ||
archieMlText[0].archieml_update_statistics === null
)
throw new Error(
`Could not compare posts because archieml was not present in the database for ${postId}`
)
const archieMlJson = JSON.parse(archieMlText[0].archieml) as OwidGdocJSON
const updateStatsJson = JSON.parse(
archieMlText[0].archieml_update_statistics
) as OwidArticleBackportingStatistics
getPlainRouteWithROTransaction(
adminRouter,
"/posts/compare/:postId",
async (req, res, trx) => {
const postId = expectInt(req.params.postId)

const wpPage = await renderPreview(postId, trx)
const archieMlText = await Post.select(
"archieml",
"archieml_update_statistics"
).from(trx(Post.postsTable).where({ id: postId }))

const errorItems = updateStatsJson.errors.map(
(error) => `<li>${error.details}</li>`
)
const errorList = `<ul>${errorItems.join("")}</ul>`
if (
archieMlText.length === 0 ||
archieMlText[0].archieml === null ||
archieMlText[0].archieml_update_statistics === null
)
throw new Error(
`Could not compare posts because archieml was not present in the database for ${postId}`
)
const archieMlJson = JSON.parse(
archieMlText[0].archieml
) as OwidGdocJSON
const updateStatsJson = JSON.parse(
archieMlText[0].archieml_update_statistics
) as OwidArticleBackportingStatistics

const errorItems = updateStatsJson.errors.map(
(error) => `<li>${error.details}</li>`
)
const errorList = `<ul>${errorItems.join("")}</ul>`

const archieMl = getOwidGdocFromJSON(archieMlJson)
const archieMlPage = renderGdoc(archieMl)
const archieMl = getOwidGdocFromJSON(archieMlJson)
const archieMlPage = renderGdoc(archieMl)

res.send(`<!doctype html>
res.send(`<!doctype html>
<html>
<head>
</head>
Expand Down Expand Up @@ -252,7 +260,8 @@ adminRouter.get("/posts/compare/:postId", async (req, res) => {
</div>
</body>
</html>`)
})
}
)

adminRouter.get("/errorTest.csv", async (req, res) => {
// Add `table /admin/errorTest.csv?code=404` to test fetch download failures
Expand All @@ -273,19 +282,23 @@ adminRouter.get(`/${GetAllExplorersRoute}`, async (req, res) => {
res.send(await explorerAdminServer.getAllExplorersCommand())
})

adminRouter.get(`/${GetAllExplorersTagsRoute}`, async (_, res) => {
return res.send({
explorers: await db.knexReadonlyTransaction((trx) =>
db.getExplorerTags(trx)
),
})
})
getPlainRouteWithROTransaction(
adminRouter,
`/${GetAllExplorersTagsRoute}`,
async (_, res, trx) => {
return res.send({
explorers: await db.getExplorerTags(trx),
})
}
)

adminRouter.get(`/${EXPLORERS_PREVIEW_ROUTE}/:slug`, async (req, res) => {
const slug = slugify(req.params.slug)
const filename = slug + EXPLORER_FILE_SUFFIX
getPlainRouteWithROTransaction(
adminRouter,
`/${EXPLORERS_PREVIEW_ROUTE}/:slug`,
async (req, res, knex) => {
const slug = slugify(req.params.slug)
const filename = slug + EXPLORER_FILE_SUFFIX

const explorerPage = await db.knexReadonlyTransaction(async (knex) => {
if (slug === DefaultNewExplorerSlug)
return renderExplorerPage(
new ExplorerProgram(DefaultNewExplorerSlug, ""),
Expand All @@ -297,19 +310,21 @@ adminRouter.get(`/${EXPLORERS_PREVIEW_ROUTE}/:slug`, async (req, res) => {
)
return `File not found`
const explorer = await explorerAdminServer.getExplorerFromFile(filename)
return renderExplorerPage(explorer, knex)
})
const explorerPage = renderExplorerPage(explorer, knex)

res.send(explorerPage)
})
return res.send(explorerPage)
}
)

adminRouter.get("/datapage-preview/:id", async (req, res) => {
const variableId = expectInt(req.params.id)
const variableMetadata = await getVariableMetadata(variableId)
if (!variableMetadata) throw new JsonError("No such variable", 404)
getPlainRouteWithROTransaction(
adminRouter,
"/datapage-preview/:id",
async (req, res, trx) => {
const variableId = expectInt(req.params.id)
const variableMetadata = await getVariableMetadata(variableId)
if (!variableMetadata) throw new JsonError("No such variable", 404)

res.send(
await db.knexReadonlyTransaction((trx) =>
res.send(
renderDataPageV2(
{
variableId,
Expand All @@ -320,19 +335,20 @@ adminRouter.get("/datapage-preview/:id", async (req, res) => {
trx
)
)
)
})
}
)

adminRouter.get("/grapher/:slug", async (req, res) => {
const previewDataPageOrGrapherPage = db.knexReadonlyTransaction(
async (knex) => {
const entity = await getChartConfigBySlug(knex, req.params.slug)
if (!entity) throw new JsonError("No such chart", 404)
return renderPreviewDataPageOrGrapherPage(entity.config, knex)
}
)
res.send(previewDataPageOrGrapherPage)
})
getPlainRouteWithROTransaction(
adminRouter,
"/grapher/:slug",
async (req, res, trx) => {
const entity = await getChartConfigBySlug(trx, req.params.slug)
if (!entity) throw new JsonError("No such chart", 404)
const previewDataPageOrGrapherPage =
await renderPreviewDataPageOrGrapherPage(entity.config, trx)
res.send(previewDataPageOrGrapherPage)
}
)

const gitCmsServer = new GitCmsServer({
baseDir: GIT_CMS_DIR,
Expand Down
2 changes: 1 addition & 1 deletion adminSiteServer/apiRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ import {
postRouteWithRWTransaction,
patchRouteWithRWTransaction,
getRouteNonIdempotentWithRWTransaction,
} from "./routerHelpers.js"
} from "./functionalRouterHelpers.js"
import { getPublishedLinksTo } from "../db/model/Link.js"
import {
createGdocAndInsertIntoDb,
Expand Down
File renamed without changes.
Loading

0 comments on commit e559c80

Please sign in to comment.