diff options
Diffstat (limited to 'src/lib/collection/helpers.ts')
-rw-r--r-- | src/lib/collection/helpers.ts | 115 |
1 files changed, 103 insertions, 12 deletions
diff --git a/src/lib/collection/helpers.ts b/src/lib/collection/helpers.ts index f65e7c0..4dfafff 100644 --- a/src/lib/collection/helpers.ts +++ b/src/lib/collection/helpers.ts @@ -2,18 +2,26 @@ import type { CollectionEntry } from "astro:content"; import { Blog, Entity, + ENTITY_TYPES, + type EntityTypesEnum, type Entry, + type LICENSES, type MicroEntry, + Original, type OriginalEntry, + Translation, type TranslationEntry, } from "./schemas.ts"; -import { getEntries, type z } from "astro:content"; -import { defined, get, identity } from "../../utils/anonymous.ts"; +import type { z } from "astro:content"; +import { defined, get, identity, transform } from "../../utils/anonymous.ts"; import { createKeyFromArmor } from "../pgp/create.ts"; import { getUserIDsFromKey } from "../pgp/user.ts"; import type { UserIDPacket } from "openpgp"; +import readingTime from "reading-time"; import { getCollection } from "astro:content"; import { getEntry } from "astro:content"; +import { getEntries } from "astro:content"; +import { listYearsWithRanges } from "../../utils/datetime.ts"; export function getLastUpdate({ data }: CollectionEntry<"blog">): Date { return data.dateUpdated ?? data.dateCreated; @@ -36,20 +44,28 @@ export const sortFirstUpdated = ( b: CollectionEntry<"blog">, ): number => sortLastUpdated(b, a); +export function getSignersIDs( + { data }: CollectionEntry<"blog">, +): Record<z.infer<typeof EntityTypesEnum>, string[]> { + const { signers } = Blog.parse(data); + const id = ({ entity }: typeof signers[number]) => entity.id; + return Object.fromEntries( + ENTITY_TYPES.map((x) => [x, signers.filter((s) => s.role === x).map(id)]), + ) as ReturnType<typeof getSignersIDs>; +} + export async function getSigners( { data }: CollectionEntry<"blog">, ): Promise<{ - id: string; entity: CollectionEntry<"entity">; - role: z.infer<typeof Blog>["signers"][number]["role"] | undefined; + role?: z.infer<typeof Blog>["signers"][number]["role"]; }[]> { const post = Blog.parse(data); - return await getEntries(post.signers.map(get("entity"))).then((x) => - x.map((x) => ({ - id: x.id, - entity: x, - role: post.signers?.find((y) => y.entity.id === x.id)?.role, - })).filter(({ role }) => defined(role)) + return await Promise.all( + post.signers.map(async ({ entity, role }) => ({ + entity: await getEntry(entity), + role, + })), ); } @@ -76,13 +92,13 @@ export async function getFirstUserID( const signers = await getSigners(blog); const userIDs = await Promise.all( signers.filter(({ role }) => role === "author").map( - async ({ id, entity }) => { + async ({ entity }) => { const { publickey, websites } = Entity.parse(entity.data); const website = websites?.[0]; const key = await createKeyFromArmor(publickey.armor); const users = getUserIDsFromKey(undefined, key); return users.map((user) => { - return { ...user, entity: id, website }; + return { ...user, entity: entity.id, website }; })?.[0]; }, ), @@ -118,3 +134,78 @@ export async function getTranslationOriginal( } return await getEntry(translation.data.translationOf); } + +export function licenseNotice( + license: typeof LICENSES[number], + { title, holders, years }: { + title: string; + holders: { name: string; email?: string }[]; + years: number[]; + }, + locale?: Intl.LocalesArgument, +): string | undefined { + const list = new Intl.ListFormat(locale, { + style: "narrow", + type: "unit", + }); + switch (license) { + case "CC0": + return `${title} by ${ + list.format(holders.map(get("name"))) + } is marked CC0 1.0 Universal. To view a copy of this mark, visit https://creativecommons.org/publicdomain/zero/1.0/`; + case "CC-BY": + case "CC-BY-SA": + case "CC-BY-ND": + case "CC-BY-NC": + case "CC-BY-NC-SA": + case "CC-BY-NC-ND": + return `${title} © ${ + listYearsWithRanges(years, { + locale, + list: { type: "unit", style: "narrow" }, + }) + } by ${ + list.format(holders.map(get("name"))) + } is licensed under Creative Commons ${ + license.slice(3).replace("BY", "Attribution").replace( + "SA", + "ShareAlike", + ).replace("ND", "NoDerivatives").replace("NC", "NonCommercial") + } 4.0 International. To view a copy of this license, visit https://creativecommons.org/licenses/${ + license.slice(3).toLowerCase() + }/4.0/`; + case "WTFPL": + return `Copyright (C) ${ + listYearsWithRanges(years, { + locale, + list: { type: "unit", style: "narrow" }, + }) + } ${ + list.format(holders.map(({ name, email }) => + name + (email !== undefined ? ` ${email}` : "") + )) + }`; + case "public domain": + undefined; + } +} +export function licenseURL(license: typeof LICENSES[number]): URL | undefined { + switch (license) { + case "CC0": + case "CC-BY": + case "CC-BY-SA": + case "CC-BY-ND": + case "CC-BY-NC": + case "CC-BY-NC-SA": + case "CC-BY-NC-ND": + return new URL( + `https://creativecommons.org/licenses/${ + license.slice(3).toLowerCase() + }/4.0/`, + ); + case "WTFPL": + return new URL("http://www.wtfpl.net/"); + case "public domain": + return undefined; + } +} |