Skip to content

Commit

Permalink
Add donors component
Browse files Browse the repository at this point in the history
  • Loading branch information
rakyi committed Dec 6, 2024
1 parent f08d004 commit 93a6edf
Show file tree
Hide file tree
Showing 26 changed files with 284 additions and 15 deletions.
10 changes: 8 additions & 2 deletions adminSiteServer/apiRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ import {
import { match } from "ts-pattern"
import { GdocDataInsight } from "../db/model/Gdoc/GdocDataInsight.js"
import { GdocHomepage } from "../db/model/Gdoc/GdocHomepage.js"
import { GdocAbout } from "../db/model/Gdoc/GdocAbout.js"
import { GdocAuthor } from "../db/model/Gdoc/GdocAuthor.js"
import path from "path"
import {
Expand Down Expand Up @@ -2899,8 +2900,13 @@ getRouteNonIdempotentWithRWTransaction(
async function indexAndBakeGdocIfNeccesary(
trx: db.KnexReadWriteTransaction,
user: Required<DbInsertUser>,
prevGdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor,
nextGdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor
prevGdoc:
| GdocPost
| GdocDataInsight
| GdocHomepage
| GdocAbout
| GdocAuthor,
nextGdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor
) {
const prevJson = prevGdoc.toJSON()
const nextJson = nextGdoc.toJSON()
Expand Down
15 changes: 13 additions & 2 deletions baker/SiteBaker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ import { getRedirectsFromDb } from "../db/model/Redirect.js"
import { getTombstones } from "../db/model/GdocTombstone.js"
import { bakeAllMultiDimDataPages } from "./MultiDimBaker.js"
import { getAllLinkedPublishedMultiDimDataPages } from "../db/model/MultiDimDataPage.js"
import { getPublicDonorNames } from "../db/model/Donor.js"

type PrefetchedAttachments = {
donors: string[]
linkedAuthors: LinkedAuthor[]
linkedDocuments: Record<string, OwidGdocMinimalPostInterface>
imageMetadata: Record<string, ImageMetadata>
Expand Down Expand Up @@ -170,14 +172,14 @@ function getProgressBarTotal(bakeSteps: BakeStepConfig): number {
if (bakeSteps.has("redirects")) total++
// Add a tick for the validation step that occurs when these two steps run
if (bakeSteps.has("dods") && bakeSteps.has("charts")) total++
// Add 6 ticks for prefetching attachments, which will only run if any of these steps are enabled
// Add ticks for prefetching attachments, which will only run if any of these steps are enabled
if (
bakeSteps.has("gdocPosts") ||
bakeSteps.has("gdocTombstones") ||
bakeSteps.has("dataInsights") ||
bakeSteps.has("authors")
) {
total += 7
total += 8
}
return total
}
Expand Down Expand Up @@ -350,6 +352,12 @@ export class SiteBaker {
): Promise<PrefetchedAttachments> {
if (!this._prefetchedAttachmentsCache) {
console.log("Prefetching attachments...")

const donors = await getPublicDonorNames(knex)
this.progressBar.tick({
name: `✅ Prefetched donors`,
})

const publishedGdocs = await getAllMinimalGdocBaseObjects(knex)
const publishedGdocsDictionary = keyBy(publishedGdocs, "id")
this.progressBar.tick({
Expand Down Expand Up @@ -456,6 +464,7 @@ export class SiteBaker {
})

const prefetchedAttachments = {
donors,
linkedAuthors: publishedAuthors,
linkedDocuments: publishedGdocsDictionary,
imageMetadata: imageMetadataDictionary,
Expand Down Expand Up @@ -497,6 +506,7 @@ export class SiteBaker {
)

return {
donors: this._prefetchedAttachmentsCache.donors,
linkedDocuments,
imageMetadata: pick(
this._prefetchedAttachmentsCache.imageMetadata,
Expand Down Expand Up @@ -614,6 +624,7 @@ export class SiteBaker {
publishedGdoc.linkedChartSlugs.grapher,
publishedGdoc.linkedChartSlugs.explorer,
])
publishedGdoc.donors = attachments.donors
publishedGdoc.linkedAuthors = attachments.linkedAuthors
publishedGdoc.linkedDocuments = attachments.linkedDocuments
publishedGdoc.imageMetadata = attachments.imageMetadata
Expand Down
24 changes: 24 additions & 0 deletions db/migration/1733228214376-CreateDonors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class CreateDonors1733228214376 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`-- sql
CREATE TABLE donors (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
originalName VARCHAR(255) NOT NULL,
shouldPublish BOOLEAN NOT NULL DEFAULT (false),
comment TEXT DEFAULT (''),
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY (originalName)
)
`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`-- sql
DROP TABLE donors
`)
}
}
13 changes: 13 additions & 0 deletions db/model/Donor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DbPlainDonor, DonorsTableName } from "@ourworldindata/types"
import * as db from "../db"

export async function getPublicDonorNames(
knex: db.KnexReadonlyTransaction
): Promise<string[]> {
const donors = await knex<DbPlainDonor>(DonorsTableName)
.select("name")
.where({ shouldPublish: true })
.orderBy("name")
.distinct()
return donors.map((donor) => donor.name)
}
37 changes: 37 additions & 0 deletions db/model/Gdoc/GdocAbout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
OwidGdocAboutContent,
OwidGdocAboutInterface,
OwidGdocBaseInterface,
} from "@ourworldindata/types"
import { traverseEnrichedBlock } from "@ourworldindata/utils"
import * as db from "../../db.js"
import { getPublicDonorNames } from "../Donor.js"
import { GdocBase } from "./GdocBase.js"

export class GdocAbout extends GdocBase implements OwidGdocAboutInterface {
content!: OwidGdocAboutContent

static create(obj: OwidGdocBaseInterface): GdocAbout {
const gdoc = new GdocAbout(undefined)
Object.assign(gdoc, obj)
return gdoc
}

async _loadSubclassAttachments(
knex: db.KnexReadonlyTransaction
): Promise<void> {
let hasDonors = false
for (const enrichedBlockSource of this.enrichedBlockSources) {
for (const block of enrichedBlockSource) {
traverseEnrichedBlock(block, (block) => {
if (block.type === "donors") {
hasDonors = true
}
})
}
}
if (hasDonors) {
this.donors = await getPublicDonorNames(knex)
}
}
}
2 changes: 2 additions & 0 deletions db/model/Gdoc/GdocBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class GdocBase implements OwidGdocBaseInterface {
breadcrumbs: BreadcrumbItem[] | null = null
tags: DbPlainTag[] | null = null
errors: OwidGdocErrorMessage[] = []
donors: string[] = []
imageMetadata: Record<string, ImageMetadata> = {}
linkedAuthors: LinkedAuthor[] = []
linkedCharts: Record<string, LinkedChart> = {}
Expand Down Expand Up @@ -543,6 +544,7 @@ export class GdocBase implements OwidGdocBaseInterface {
"aside",
"blockquote",
"callout",
"donors",
"expandable-paragraph",
"entry-summary",
"gray-section",
Expand Down
25 changes: 15 additions & 10 deletions db/model/Gdoc/GdocFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ import {
getPublishedGdocPostsWithTags,
} from "../../db.js"
import { enrichedBlocksToMarkdown } from "./enrichedToMarkdown.js"
import { GdocAbout } from "./GdocAbout.js"
import { GdocAuthor } from "./GdocAuthor.js"
import { extractFilenamesFromBlock } from "./gdocUtils.js"
import { fetchImagesFromDriveAndSyncToS3 } from "../Image.js"

export function gdocFromJSON(
json: Record<string, any>
): GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor {
): GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor {
if (typeof json.content === "string") {
json.content = JSON.parse(json.content)
}
Expand All @@ -72,12 +73,16 @@ export function gdocFromJSON(
OwidGdocType.Article,
OwidGdocType.LinearTopicPage,
OwidGdocType.TopicPage,
OwidGdocType.Fragment,
OwidGdocType.AboutPage
OwidGdocType.Fragment
),
// TODO: better validation here?
() => GdocPost.create({ ...(json as any) })
)
.with(
OwidGdocType.AboutPage,
// TODO: better validation here?
() => GdocAbout.create({ ...(json as any) })
)
.with(
OwidGdocType.DataInsight,
// TODO: better validation here?
Expand Down Expand Up @@ -127,7 +132,7 @@ export async function createGdocAndInsertIntoDb(
export async function updateGdocContentOnly(
knex: KnexReadonlyTransaction,
id: string,
gdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor
gdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor
): Promise<void> {
let markdown: string | null = gdoc.markdown
try {
Expand Down Expand Up @@ -276,7 +281,7 @@ export async function getPublishedGdocBaseObjectBySlug(
export async function getAndLoadGdocBySlug(
knex: KnexReadWriteTransaction,
slug: string
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor> {
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor> {
const base = await getPublishedGdocBaseObjectBySlug(knex, slug, true)
if (!base) {
throw new Error(
Expand All @@ -291,7 +296,7 @@ export async function getAndLoadGdocById(
knex: KnexReadWriteTransaction,
id: string,
contentSource?: GdocsContentSource
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor> {
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor> {
const base = await getGdocBaseObjectById(knex, id, true)
if (!base)
throw new Error(`No Google Doc with id "${id}" found in the database`)
Expand Down Expand Up @@ -320,7 +325,7 @@ export async function loadGdocFromGdocBase(
knex: KnexReadWriteTransaction,
base: OwidGdocBaseInterface,
contentSource?: GdocsContentSource
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor> {
): Promise<GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor> {
const type = get(base, "content.type") as unknown
if (!type)
throw new Error(
Expand All @@ -338,11 +343,11 @@ export async function loadGdocFromGdocBase(
OwidGdocType.Article,
OwidGdocType.LinearTopicPage,
OwidGdocType.TopicPage,
OwidGdocType.Fragment,
OwidGdocType.AboutPage
OwidGdocType.Fragment
),
() => GdocPost.create(base)
)
.with(OwidGdocType.AboutPage, () => GdocAbout.create(base))
.with(OwidGdocType.DataInsight, () => GdocDataInsight.create(base))
.with(OwidGdocType.Homepage, () => GdocHomepage.create(base))
.with(OwidGdocType.Author, () => GdocAuthor.create(base))
Expand Down Expand Up @@ -627,7 +632,7 @@ export async function getAllGdocIndexItemsOrderedByUpdatedAt(

export async function addImagesToContentGraph(
trx: KnexReadWriteTransaction,
gdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAuthor
gdoc: GdocPost | GdocDataInsight | GdocHomepage | GdocAbout | GdocAuthor
): Promise<void> {
const id = gdoc.id
// Deleting and recreating these is simpler than tracking orphans over the next code block
Expand Down
3 changes: 3 additions & 0 deletions db/model/Gdoc/enrichedToMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ ${items}
exportComponents
)
)
.with({ type: "donors" }, (_): string | undefined =>
markdownComponent("DonorList", {}, exportComponents)
)
.with({ type: "scroller" }, () => undefined) // Note: dropped
.with(
{ type: "chart-story" },
Expand Down
8 changes: 8 additions & 0 deletions db/model/Gdoc/enrichedToRaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RawBlockAside,
RawBlockChart,
RawBlockChartStory,
RawBlockDonorList,
RawBlockGraySection,
RawBlockHeading,
RawBlockHtml,
Expand Down Expand Up @@ -121,6 +122,13 @@ export function enrichedBlockToRawBlock(
},
})
)
.with(
{ type: "donors" },
(b): RawBlockDonorList => ({
type: b.type,
value: b.value,
})
)
.with(
{ type: "scroller" },
(b): RawBlockScroller => ({
Expand Down
5 changes: 5 additions & 0 deletions db/model/Gdoc/exampleEnrichedBlocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ export const enrichedBlockExamples: Record<
caption: boldLinkExampleText,
parseErrors: [],
},
donors: {
type: "donors",
value: {},
parseErrors: [],
},
scroller: {
type: "scroller",
blocks: [
Expand Down
1 change: 1 addition & 0 deletions db/model/Gdoc/gdocUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export function extractFilenamesFromBlock(
"callout",
"chart-story",
"chart",
"donors",
"entry-summary",
"expandable-paragraph",
"explorer-tiles",
Expand Down
9 changes: 9 additions & 0 deletions db/model/Gdoc/rawToArchie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
RawBlockAside,
RawBlockChart,
RawBlockChartStory,
RawBlockDonorList,
RawBlockGraySection,
RawBlockHomepageIntro,
RawBlockHorizontalRule,
Expand Down Expand Up @@ -126,6 +127,13 @@ function* rawBlockChartToArchieMLString(
yield "{}"
}

function* rawBlockDonorListToArchieMLString(
_block: RawBlockDonorList
): Generator<string, void, undefined> {
yield "{.donors}"
yield "{}"
}

function* rawBlockScrollerToArchieMLString(
block: RawBlockScroller
): Generator<string, void, undefined> {
Expand Down Expand Up @@ -811,6 +819,7 @@ export function* OwidRawGdocBlockToArchieMLStringGenerator(
.with({ type: "all-charts" }, rawBlockAllChartsToArchieMLString)
.with({ type: "aside" }, rawBlockAsideToArchieMLString)
.with({ type: "chart" }, rawBlockChartToArchieMLString)
.with({ type: "donors" }, rawBlockDonorListToArchieMLString)
.with({ type: "scroller" }, rawBlockScrollerToArchieMLString)
.with({ type: "callout" }, rawBlockCalloutToArchieMLString)
.with({ type: "chart-story" }, rawBlockChartStoryToArchieMLString)
Expand Down
11 changes: 11 additions & 0 deletions db/model/Gdoc/rawToEnriched.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
EnrichedBlockCallout,
EnrichedBlockChart,
EnrichedBlockChartStory,
EnrichedBlockDonorList,
EnrichedBlockGraySection,
EnrichedBlockHeading,
EnrichedBlockHorizontalRule,
Expand Down Expand Up @@ -43,6 +44,7 @@ import {
RawBlockCallout,
RawBlockChart,
RawBlockChartStory,
RawBlockDonorList,
RawBlockGraySection,
RawBlockHeading,
RawBlockHtml,
Expand Down Expand Up @@ -167,6 +169,7 @@ export function parseRawBlocksToEnrichedBlocks(
.with({ type: "blockquote" }, parseBlockquote)
.with({ type: "callout" }, parseCallout)
.with({ type: "chart" }, parseChart)
.with({ type: "donors" }, parseDonorList)
.with({ type: "scroller" }, parseScroller)
.with({ type: "chart-story" }, parseChartStory)
.with({ type: "image" }, parseImage)
Expand Down Expand Up @@ -489,6 +492,14 @@ const parseChart = (raw: RawBlockChart): EnrichedBlockChart => {
}
}

const parseDonorList = (raw: RawBlockDonorList): EnrichedBlockDonorList => {
return {
type: "donors",
value: raw.value,
parseErrors: [],
}
}

const parseScroller = (raw: RawBlockScroller): EnrichedBlockScroller => {
const createError = (
error: ParseError,
Expand Down
Loading

0 comments on commit 93a6edf

Please sign in to comment.