From f9a77c5c27aede4e5978eb55d9b7af781b680a1d Mon Sep 17 00:00:00 2001 From: João Augusto Costa Branco Marado Torres Date: Tue, 24 Jun 2025 12:08:41 -0300 Subject: feat!: initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Augusto Costa Branco Marado Torres --- src/pages/blog/read/[...slug].astro | 333 ++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/pages/blog/read/[...slug].astro (limited to 'src/pages/blog/read') diff --git a/src/pages/blog/read/[...slug].astro b/src/pages/blog/read/[...slug].astro new file mode 100644 index 0000000..05d68e8 --- /dev/null +++ b/src/pages/blog/read/[...slug].astro @@ -0,0 +1,333 @@ +--- +import { type CollectionEntry, getCollection } from "astro:content"; +import { render } from "astro:content"; +import BaseHead from "@components/BaseHead.astro"; +import Translations from "@components/Translations.astro"; +import { toIso8601Full } from "@utils/datetime"; +import ReadingTime from "@components/ReadingTime.astro"; +import Keywords from "@components/Keywords.astro"; +import Citations from "@components/Citations.astro"; +import Signature from "@components/signature/Signature.astro"; +import CopyrightNotice from "@components/CopyrightNotice.astro"; +import { getEntries } from "astro:content"; +import { verifier as verifierPrototype } from "@lib/pgp/verify"; +import { defined, get } from "@utils/anonymous"; +import Authors from "@components/signature/Authors.astro"; +import { getEntry } from "astro:content"; + +export async function getStaticPaths() { + const posts = await getCollection("blog"); + return posts.map((post) => ({ + params: { slug: post.id }, + props: post, + })); +} + +type Props = CollectionEntry<"blog">; + +const post = Astro.props; + +if (defined(post.data.translationOf)) { + const original = await getEntry( + post.data.translationOf as CollectionEntry<"blog">, + ); + + if (!original) { + throw new Error(`Original post not found for ${post.id}`); + } + + const originalAuthor = (original.data.signers ?? []).filter( + (s) => s.role === "author", + ).map((s) => s.entity.id)?.[0]; + const originalCoAuthors = new Set( + (original.data.signer ?? []).filter( + (s) => s.role === "co-author", + ).map((s) => s.entity.id), + ); + const translationAuthor = (post.data.signer ?? []).filter( + (s) => s.role === "author", + ).map((s) => s.entity.id)?.[0]; + const translationCoAuthors = new Set( + (post.data.signer ?? []).filter( + (s) => s.role === "co-author", + ).map((s) => s.entity.id), + ); + + if ( + (translationAuthor !== undefined && + translationAuthor !== originalAuthor) || + !translationCoAuthors.isSubsetOf(originalCoAuthors) + ) { + throw new Error( + `Post ${post.id} has mismatched (co-)authors from original post ${original.id}`, + ); + } + + const translators = (post.data.signer ?? []).filter( + (s) => s.role === "translator", + ).map((s) => s.entity.id); + + for (const translator of translators) { + if ( + originalAuthor === translator || originalCoAuthors.has(translator) + ) { + throw new Error( + `Translator ${translator} in ${post.id} is already a (co-)author in original post`, + ); + } + } +} else { + if (post.data.signer?.some((x) => x.role === "translator")) { + throw new Error( + `Post ${post.id} is not a translation but has translators defined`, + ); + } +} + +// Add own post as a translation +const translationsSet = new Set( + (await getCollection( + "blog", + (x) => + x.data.translationOf?.id === + (post.data.translationOf !== undefined + ? post.data.translationOf.id + : post.id), + ) ?? []).map(({ id }) => id), +); + +translationsSet.add(post.id); +const translations = [...translationsSet.values()].map((id) => ({ + collection: post.collection, + id, +})); + +const signers = await getEntries( + post.data.signer?.map(get("entity")) ?? [], +).then((x) => x.filter(defined)) + .then((x) => + x.map((x) => ({ + entity: x, + role: post.data.signer?.find((y) => y.entity.id === x.id)?.role, + })) + ) + .then((x) => x.filter((x) => x.role !== undefined)); + +const verifier = await verifierPrototype.then((x) => x.clone()); + +// Add signers public keys to keyring +for (const { data } of signers.map(get("entity"))) { + if (data.publickey.armor !== undefined) { + verifier.addKeyFromArmor(data.publickey.armor); + } +} + +const verification = post.filePath !== undefined + ? await verifier.verify([ + new URL(`file://${Deno.cwd()}/${post.filePath}`), + ]) + : undefined; + +const { Content } = await render(post); + +const { lang } = post.data; + +const commit = await verification?.commit; +--- + + + + + + + +
+
+ +
+

{post.data.title}

+ { + post.data.subtitle && ( +

+ {post.data.subtitle} +

+ ) + } +
+ { + post.data.description && ( +
+

Resumo

+ { + post.data.description.split(new RegExp("\\s{2,}")) + .map(( + x, + ) => ( +

{x}

+ )) + } +
+ ) + } + {verification && } +
+ { + verification?.verifications && + ( + + ) + } +
+
Data de criação
+
+ +
+ { + post.data.dateUpdated && ( +
Última atualização
+ +
+ ) + } + { + post.data.locationCreated && ( +
+ Local de criação +
+ {post.data.locationCreated} +
+ ) + } +
+ +
+
+
+
+ + + +
+
+ + + + + + + + -- cgit v1.2.3