summaryrefslogtreecommitdiff
path: root/src/lib/collection/helpers.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/collection/helpers.ts')
-rw-r--r--src/lib/collection/helpers.ts107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/lib/collection/helpers.ts b/src/lib/collection/helpers.ts
new file mode 100644
index 0000000..83eb21d
--- /dev/null
+++ b/src/lib/collection/helpers.ts
@@ -0,0 +1,107 @@
+import type { CollectionEntry } from "astro:content";
+import {
+ Blog,
+ Entity,
+ type Entry,
+ type MicroEntry,
+ type OriginalEntry,
+ type TranslationEntry,
+} from "./schemas.ts";
+import { getEntries, type z } from "astro:content";
+import { defined, get, identity } from "../../utils/anonymous.ts";
+import { createKeyFromArmor } from "../pgp/create.ts";
+import { getUserIDsFromKey } from "../pgp/user.ts";
+import type { UserIDPacket } from "openpgp";
+import { getCollection } from "astro:content";
+
+export function getLastUpdate({ data }: CollectionEntry<"blog">): Date {
+ return data.dateUpdated ?? data.dateCreated;
+}
+export const sortLastCreated = (
+ { data: a }: CollectionEntry<"blog">,
+ { data: b }: CollectionEntry<"blog">,
+): number => b.dateCreated - a.dateCreated;
+export const sortFirstCreated = (
+ a: CollectionEntry<"blog">,
+ b: CollectionEntry<"blog">,
+): number => sortLastCreated(b, a);
+export const sortLastUpdated = (
+ { data: a }: CollectionEntry<"blog">,
+ { data: b }: CollectionEntry<"blog">,
+): number =>
+ (b.dateUpdated ?? b.dateCreated) - (a.dateUpdated ?? a.dateCreated);
+export const sortFirstUpdated = (
+ a: CollectionEntry<"blog">,
+ b: CollectionEntry<"blog">,
+): number => sortLastUpdated(b, a);
+
+export async function getSigners(
+ { data }: CollectionEntry<"blog">,
+): Promise<{
+ id: string;
+ entity: CollectionEntry<"entity">;
+ role: z.infer<typeof Blog>["signers"][number]["role"] | undefined;
+}[]> {
+ 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))
+ );
+}
+
+export async function getFirstAuthorEmail(
+ blog: CollectionEntry<"blog">,
+): Promise<string | undefined> {
+ const signers = await getSigners(blog);
+ const emails = await Promise.all(
+ signers.filter(({ role }) => role === "author").map(async ({ entity }) => {
+ const { publickey } = Entity.parse(entity.data);
+ const key = await createKeyFromArmor(publickey.armor);
+ const users = getUserIDsFromKey(undefined, key);
+ return users.map(get("email")).filter(Boolean)?.[0];
+ }),
+ );
+ return emails.filter(defined)?.[0];
+}
+
+export async function getFirstUserID(
+ blog: CollectionEntry<"blog">,
+): Promise<
+ (Partial<UserIDPacket> & { entity: string; website: string | undefined })
+> {
+ const signers = await getSigners(blog);
+ const userIDs = await Promise.all(
+ signers.filter(({ role }) => role === "author").map(
+ async ({ id, 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 };
+ })?.[0];
+ },
+ ),
+ );
+ return userIDs.filter(defined)?.[0];
+}
+
+export async function fromPosts<T extends Entry, U>(
+ filter: (entry: CollectionEntry<"blog">) => entry is T,
+ predicate: (entries: T[]) => U = identity as (entries: T[]) => U,
+): Promise<U> {
+ const entries = await getCollection<"blog", T>("blog", filter);
+ return predicate(entries);
+}
+export const isOriginal = (
+ entry: CollectionEntry<"blog">,
+): entry is OriginalEntry => entry.data.kind === "original";
+export const isTranslation = (
+ entry: CollectionEntry<"blog">,
+): entry is TranslationEntry => entry.data.kind === "translation";
+export const isMicro = (
+ entry: CollectionEntry<"blog">,
+): entry is MicroEntry => entry.data.kind === "micro";