feat(backend): ✨ implement news fetching from git.cohabit
This commit is contained in:
parent
ec90d92f46
commit
5593878c66
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -37,7 +37,9 @@
|
|||
"ux",
|
||||
"route",
|
||||
"frontend",
|
||||
"components"
|
||||
"components",
|
||||
"island",
|
||||
"backend"
|
||||
],
|
||||
"[ignore]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
|
|
104
src/blog/mod.ts
Normal file
104
src/blog/mod.ts
Normal file
|
@ -0,0 +1,104 @@
|
|||
import { BlogProps } from ':components/BlogCard.tsx'
|
||||
import { NewsFrontMatter } from ':src/blog/types.ts'
|
||||
import { base64ToString } from ':src/utils.ts'
|
||||
import { extract } from '@std/front-matter/yaml'
|
||||
|
||||
export async function fetchNews(
|
||||
publisher: string,
|
||||
name: string,
|
||||
): Promise<BlogProps> {
|
||||
const apiUrl = 'https://git.cohabit.fr/api/v1/'
|
||||
const baseEndpoint = new URL(`repos/${publisher}/.news/`, apiUrl)
|
||||
const endpoint = new URL('contents/', baseEndpoint)
|
||||
|
||||
// Get readme content api url
|
||||
const readmePath = encodeURIComponent(`${name}/README.md`)
|
||||
const contentUrl = new URL(readmePath, endpoint)
|
||||
|
||||
// Fetch readme content, commit hash and raw url for relative links
|
||||
const file = await getCommitAndContent(contentUrl)
|
||||
// Get commit infos (author + date) and get readme content from base64 source
|
||||
const { raw, url, lastUpdate, author } = await getAuthorAndParseContent(
|
||||
file,
|
||||
baseEndpoint,
|
||||
)
|
||||
// Extract frontmatter
|
||||
const { attrs, body } = extract<NewsFrontMatter>(raw)
|
||||
|
||||
// Transform API responses into BlogProps for BlogCard and BlogPost components
|
||||
return {
|
||||
author,
|
||||
publisher,
|
||||
lastUpdate,
|
||||
options: attrs['x-cohabit'],
|
||||
title: attrs.title,
|
||||
hash: file.sha,
|
||||
description: attrs.description,
|
||||
body,
|
||||
name,
|
||||
url,
|
||||
tags: attrs.tags,
|
||||
}
|
||||
}
|
||||
|
||||
export async function* fetchNewsList(
|
||||
publisher: string,
|
||||
): AsyncGenerator<BlogProps, void, void> {
|
||||
const apiUrl = 'https://git.cohabit.fr/api/v1/'
|
||||
const baseEndpoint = new URL(`repos/${publisher}/.news/`, apiUrl)
|
||||
const endpoint = new URL('contents/', baseEndpoint)
|
||||
|
||||
// Fetch repo content
|
||||
const root = await fetch(endpoint).then((response) => response.json()) as {
|
||||
name: string
|
||||
type: string
|
||||
}[]
|
||||
|
||||
// Fetch `README.md` in sub directories
|
||||
const blogPropsList = root
|
||||
// Remove file and dir starting with "."
|
||||
.filter(isNewsDirectory)
|
||||
// Fetch single news and return BlogProps
|
||||
.map(({ name }) => fetchNews(publisher, name))
|
||||
|
||||
// Yield each news
|
||||
for (const blogProps of blogPropsList) {
|
||||
yield blogProps
|
||||
}
|
||||
}
|
||||
|
||||
async function getAuthorAndParseContent(
|
||||
file: { download_url: string; content: string; last_commit_sha: string },
|
||||
baseEndpoint: URL,
|
||||
) {
|
||||
const commitUrl = new URL(
|
||||
`git/commits/${file.last_commit_sha}?stat=false&verification=false&files=false`,
|
||||
baseEndpoint,
|
||||
)
|
||||
const infos = await fetch(commitUrl).then((response) =>
|
||||
response.json()
|
||||
) as {
|
||||
created: string
|
||||
author: { login: string }
|
||||
}
|
||||
|
||||
return {
|
||||
raw: base64ToString(file.content),
|
||||
url: file.download_url,
|
||||
lastUpdate: new Date(infos.created),
|
||||
author: infos.author.login,
|
||||
}
|
||||
}
|
||||
|
||||
async function getCommitAndContent(contentUrl: URL) {
|
||||
return await fetch(contentUrl).then((response) => response.json()) as {
|
||||
download_url: string
|
||||
content: string
|
||||
sha: string
|
||||
last_commit_sha: string
|
||||
}
|
||||
}
|
||||
|
||||
function isNewsDirectory(entry: { name: string; type: string }): boolean {
|
||||
return entry.type === 'dir' && entry.name.startsWith('.') === false
|
||||
}
|
12
src/blog/types.ts
Normal file
12
src/blog/types.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
export type NewsFrontMatter = {
|
||||
title: string
|
||||
description: string
|
||||
tags?: string[]
|
||||
'x-cohabit': {
|
||||
links?: Record<string, string>[]
|
||||
status: 'canceled' | 'futur' | 'current' | 'finished'
|
||||
visibility?: 'public' | 'internal'
|
||||
thumbnail: string
|
||||
dueDate: string
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue