Skip to content

Commit 7c84997

Browse files
committed
feat: cache content JSON
1 parent 63a70ba commit 7c84997

File tree

4 files changed

+216
-136
lines changed

4 files changed

+216
-136
lines changed

src/build.ts

Lines changed: 58 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { trelloApi } from './trello/api'
1+
import { Card, trelloApi } from './trello/api'
22
import { config } from 'dotenv'
3-
import * as showdown from 'showdown'
4-
import { promises as fs } from 'fs'
53
import * as path from 'path'
6-
import { execSync } from 'child_process'
7-
import * as handlebars from 'handlebars'
84
import { setUpWebhooks } from './trello-netlify-bridge/setUpWebhooks'
5+
import { cacheToFile } from './cache/cache-to-file'
6+
import { render } from './website/render'
97

108
config()
119

@@ -16,65 +14,59 @@ const netlifyWebhook = process.env.NETLIFY_WEBHOOK!
1614

1715
const srcDir = path.join(__dirname, '..', 'src')
1816
const webDir = path.join(__dirname, '..', 'web')
17+
const cacheLocation = path.join(webDir, 'cards.json')
18+
const cacheCards = cacheToFile<Card[]>(cacheLocation)
19+
const t = trelloApi({ apiKey, apiToken })
1920

20-
trelloApi({ apiKey, apiToken })
21-
.lists.cards({
22-
list: websiteContentList,
23-
})
24-
.then(cards =>
25-
Promise.all([
26-
// Render the website
27-
(async cards => {
28-
const contentFromCards = cards.reduce(
29-
(content, { desc }) => `${content}\n\n${desc}`,
30-
'',
31-
)
32-
const contentAsMarkdown = new showdown.Converter().makeHtml(
33-
contentFromCards,
34-
)
35-
try {
36-
await fs.stat(webDir)
37-
} catch {
38-
await fs.mkdir(webDir)
39-
}
40-
41-
const tpl = await fs.readFile(path.join(srcDir, 'index.html'), 'utf-8')
42-
const targetFile = path.join(webDir, 'index.html')
43-
44-
const content = {
45-
content: contentAsMarkdown,
46-
gitRev: execSync('git rev-parse HEAD')
47-
.toString()
48-
.trim(),
49-
timestamp: new Date().toISOString(),
50-
} as const
51-
52-
await fs.writeFile(
53-
targetFile,
54-
handlebars.compile(tpl)(content),
55-
'utf-8',
56-
)
57-
console.log(`${targetFile} written`)
58-
console.log('website generated successfully')
59-
})(cards),
60-
// Update webhooks
61-
setUpWebhooks({
62-
cards,
63-
websiteContentList,
64-
netlifyWebhook,
65-
apiToken,
66-
apiKey,
67-
}).then(webhooks => {
68-
console.log('Active webhooks:')
69-
webhooks.forEach(({ id, description, active }) => {
70-
console.log(
71-
`${id} (${active ? 'active' : 'inactive'}): ${description} `,
72-
)
73-
})
74-
}),
75-
]),
76-
)
77-
.catch(error => {
78-
console.error(error)
79-
process.exit(1)
80-
})
21+
t.lists
22+
.cards({
23+
list: websiteContentList,
24+
})
25+
.then(cards =>
26+
Promise.all(
27+
cards.map(card =>
28+
card.badges.attachments > 0
29+
? t
30+
.card({ id: card.id })
31+
.attachments()
32+
.then(attachments => ({
33+
...card,
34+
attachments,
35+
}))
36+
: Promise.resolve(card),
37+
),
38+
),
39+
)
40+
.then(cards =>
41+
Promise.all([
42+
// Cache cards
43+
cacheCards(cards),
44+
// Render the website
45+
render({
46+
cards,
47+
webDir,
48+
srcDir,
49+
}).then(() => {
50+
console.log('website generated successfully')
51+
}),
52+
// Update webhooks
53+
setUpWebhooks({
54+
cards,
55+
websiteContentList,
56+
netlifyWebhook,
57+
apiToken,
58+
apiKey,
59+
}).then(webhooks => {
60+
console.log('Active webhooks:')
61+
webhooks.forEach(({ id, description, active }) => {
62+
console.log(
63+
`${id} (${active ? 'active' : 'inactive'}): ${description} `,
64+
)
65+
})
66+
}),
67+
]),
68+
)
69+
.catch(error => {
70+
console.error(error)
71+
process.exit(1)
72+
})

src/cache/cache-to-file.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { promises as fs } from 'fs'
2+
3+
export const cacheToFile = <T>(cacheLocation: string) => async (data: T) => {
4+
await fs.writeFile(cacheLocation, JSON.stringify(data), 'utf-8')
5+
return data
6+
}
7+
8+
export const readFromFileCache = <T>(
9+
cacheLocation: string,
10+
) => async (): Promise<T> => {
11+
return JSON.parse(await fs.readFile(cacheLocation, 'utf-8')) as T
12+
}

src/trello/api.ts

Lines changed: 103 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,114 @@
11
import fetch, { RequestInit } from 'node-fetch'
22
import * as querystring from 'querystring'
33

4+
export type Card = {
5+
id: string
6+
name: string
7+
desc: string
8+
badges: {
9+
attachments: number
10+
}
11+
attachments?: Attachment[]
12+
}
13+
14+
export type Attachment = {
15+
id: string
16+
bytes: number
17+
date: string
18+
edgeColor: string
19+
idMember: string
20+
isUpload: boolean
21+
mimeType: string
22+
name: string
23+
previews: {
24+
bytes: number
25+
url: string
26+
height: number
27+
width: number
28+
_id: number
29+
scaled: boolean
30+
}[]
31+
url: string
32+
pos: number
33+
}
34+
435
export const trelloApi = ({
5-
apiKey,
6-
apiToken,
36+
apiKey,
37+
apiToken,
738
}: {
8-
apiKey: string
9-
apiToken: string,
39+
apiKey: string
40+
apiToken: string
1041
}) => {
11-
const apiEndpoint = 'https://api.trello.com/1'
42+
const apiEndpoint = 'https://api.trello.com/1'
1243

13-
const f = ({
14-
res,
15-
query,
16-
options,
17-
}: {
18-
res: string
19-
query?: { [key: string]: any }
20-
options?: RequestInit,
21-
}) =>
22-
fetch(
23-
`${apiEndpoint}/${res}?${querystring.stringify({
24-
...query,
25-
key: apiKey,
26-
token: apiToken,
27-
})}`,
28-
options,
29-
)
44+
const f = ({
45+
res,
46+
query,
47+
options,
48+
}: {
49+
res: string
50+
query?: { [key: string]: any }
51+
options?: RequestInit
52+
}) =>
53+
fetch(
54+
`${apiEndpoint}/${res}?${querystring.stringify({
55+
...query,
56+
key: apiKey,
57+
token: apiToken,
58+
})}`,
59+
options,
60+
)
3061

31-
const query = (args: { res: string }) => f(args).then(res => res.json())
62+
const query = (args: { res: string }) => f(args).then(res => res.json())
3263

33-
const del = (args: { res: string }) =>
34-
f({
35-
...args,
36-
options: { method: 'DELETE' },
37-
})
38-
const post = (args: { res: string; query?: { [key: string]: any } }) =>
39-
f({
40-
...args,
41-
options: { method: 'POST' },
42-
})
64+
const del = (args: { res: string }) =>
65+
f({
66+
...args,
67+
options: { method: 'DELETE' },
68+
})
69+
const post = (args: { res: string; query?: { [key: string]: any } }) =>
70+
f({
71+
...args,
72+
options: { method: 'POST' },
73+
})
4374

44-
return {
45-
lists: {
46-
cards: ({ list }: { list: string }) =>
47-
query({ res: `lists/${list}/cards` }) as Promise<
48-
{ id: string; name: string; desc: string }[]
49-
>,
50-
},
51-
tokens: {
52-
token: ({ token }: { token: string }) => ({
53-
webhooks: () =>
54-
query({ res: `tokens/${token}/webhooks` }) as Promise<
55-
{
56-
id: string
57-
description: string
58-
idModel: string
59-
callbackURL: string
60-
active: boolean,
61-
}[]
62-
>,
63-
}),
64-
},
65-
webhook: ({ id }: { id: string }) => ({
66-
delete: () => del({ res: `webhook/${id}` }),
67-
}),
68-
webhooks: {
69-
create: (query: {
70-
description?: string
71-
callbackURL: string
72-
idModel: string
73-
active: boolean,
74-
}) =>
75-
post({
76-
res: 'webhooks',
77-
query,
78-
}),
79-
},
80-
}
75+
return {
76+
lists: {
77+
cards: ({ list }: { list: string }) =>
78+
query({ res: `lists/${list}/cards` }) as Promise<Card[]>,
79+
},
80+
tokens: {
81+
token: ({ token }: { token: string }) => ({
82+
webhooks: () =>
83+
query({ res: `tokens/${token}/webhooks` }) as Promise<
84+
{
85+
id: string
86+
description: string
87+
idModel: string
88+
callbackURL: string
89+
active: boolean
90+
}[]
91+
>,
92+
}),
93+
},
94+
webhook: ({ id }: { id: string }) => ({
95+
delete: () => del({ res: `webhook/${id}` }),
96+
}),
97+
webhooks: {
98+
create: (query: {
99+
description?: string
100+
callbackURL: string
101+
idModel: string
102+
active: boolean
103+
}) =>
104+
post({
105+
res: 'webhooks',
106+
query,
107+
}),
108+
},
109+
card: ({ id }: { id: string }) => ({
110+
attachments: () =>
111+
query({ res: `cards/${id}/attachments` }) as Promise<Attachment[]>,
112+
}),
113+
}
81114
}

src/website/render.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as showdown from 'showdown'
2+
import * as handlebars from 'handlebars'
3+
import { Card } from '../trello/api'
4+
import { promises as fs } from 'fs'
5+
import * as path from 'path'
6+
import { exec } from 'child_process'
7+
8+
/**
9+
* Render the website
10+
*/
11+
export const render = async ({
12+
webDir,
13+
srcDir,
14+
cards,
15+
}: {
16+
cards: Card[]
17+
webDir: string
18+
srcDir: string
19+
}) => {
20+
const contentFromCards = cards.reduce(
21+
(content, { desc }) => `${content}\n\n${desc}`,
22+
'',
23+
)
24+
const contentAsMarkdown = new showdown.Converter().makeHtml(contentFromCards)
25+
try {
26+
await fs.stat(webDir)
27+
} catch {
28+
await fs.mkdir(webDir)
29+
}
30+
31+
const tpl = await fs.readFile(path.join(srcDir, 'index.html'), 'utf-8')
32+
const targetFile = path.join(webDir, 'index.html')
33+
34+
const content = {
35+
content: contentAsMarkdown,
36+
gitRev: await exec('git rev-parse HEAD')
37+
.toString()
38+
.trim(),
39+
timestamp: new Date().toISOString(),
40+
} as const
41+
42+
await fs.writeFile(targetFile, handlebars.compile(tpl)(content), 'utf-8')
43+
}

0 commit comments

Comments
 (0)