From be3d555480d1fb1a4dcfb4c5655fee3f1b47ce59 Mon Sep 17 00:00:00 2001 From: Moon Man Date: Sun, 31 Dec 2023 14:14:33 -0500 Subject: [PATCH] likes collection --- src/activity.ts | 36 ++++++++++++++++++++++++++++++++++-- src/collection.ts | 26 ++++++++++++++++++++++++++ src/router.ts | 8 +++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/activity.ts b/src/activity.ts index db9985b..5737170 100644 --- a/src/activity.ts +++ b/src/activity.ts @@ -1,14 +1,15 @@ import { readFileSync } from "node:fs"; import markdownit from "markdown-it"; -import { Article } from "./article.js"; +import { Article, getById as getArticleById } from "./article.js"; import { User, getByActor } from "./user.js"; -import { fillRoute } from "./router.js"; +import { fillRoute, reverseRoute } from "./router.js"; import { streamToString, hashDigest } from "./util.js"; import { signedFetch, SignedInit, getActor } from "./net.js"; import { getById as getUserById, getKeyId } from "./user.js"; import parser from "activitypub-http-signatures"; import type { Request, Response } from "express"; import { addFollower } from "./follower.js"; +import { addLikeOrShare } from "./collection.js"; export const CONTEXT = "https://www.w3.org/ns/activitystreams"; export const PUBLIC = CONTEXT + "#Public"; @@ -43,6 +44,37 @@ export const handleInboxPost = async (req: Request, res: Response) => { res.status(202).end(); return; } + else if (activity.type === "Like") { + const articleId = reverseRoute("object", req.url) + + if (articleId) { + const article = await getArticleById(parseInt(articleId)); + + if (article) { + const user = await getUserById(article.users_id); + + if (user) { + const init: SignedInit = { + keyId: getKeyId(user.nickname), + privateKey: user.private_key + }; + + const liker = await getActor(activity.actor, init); + + if (liker) { + await addLikeOrShare(article.id, liker, 1); + + res.status(201).end(); + console.log(`added like for article: ${article.id} actor: ${user.id}`); + return; + } + } + + } + } + + res.status(403).end(); + } else if (activity.type === "Follow") { console.log(JSON.stringify(activity, null, 4)); const actor = await getByActor(activity.object); diff --git a/src/collection.ts b/src/collection.ts index d48ce53..60376fb 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -1,4 +1,5 @@ import { CONTEXT } from "./activity.js"; +import { Actor } from "./activitypub_types.js"; import db from "./db.js"; import { z } from "zod"; @@ -53,3 +54,28 @@ export const orderedCollectionPage = (collectionId: string, orderedItems: (strin return collection; }; + +export const addLikeOrShare = async (articleId: number, person: Actor, likeOrShare: 1|2) => { + await db("remote_users") + .insert({ + actor: person.id, + nickname: person.preferredUsername, + name: person.name, + inbox: person.inbox, + shared_inbox: person.endpoints?.sharedInbox + }) + .onConflict().ignore(); + ; + + await db("collections") + .insert({ + collection_types_id: likeOrShare, + articles_id: articleId, + value: person.id, + created_at: new Date() + }) + .onConflict().ignore() + ; + + console.log("Follower added"); +}; \ No newline at end of file diff --git a/src/router.ts b/src/router.ts index 0400bee..1ca9c7f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -16,4 +16,10 @@ export const fillRoute = (route: Route, value: number | string) => + (typeof value === "number" ? Routes[route].replace(":id", value.toString()) : Routes[route].replace(":actor", value as string)) - ; \ No newline at end of file + ; + +export const reverseRoute = (route: Route, path: string) => { + const r = new RegExp("^" + Routes[route].replace(/:(id|actor)/, "(.+)") + "$"); + const match = path.match(r) + return !!match ? match[1] : null; +};