From a40dfcfaefb353039700a64cfc374fe8dca588a9 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 14 Aug 2023 20:28:25 +1000 Subject: test --- .../routes/channel/#channel_id/followers.ts | 28 +++++++ .../routes/channel/#channel_id/outbox.ts | 86 ++++++++-------------- src/activitypub/util/OrderedCollection.ts | 41 +++++++++++ src/util/entities/Message.ts | 15 +++- 4 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 src/activitypub/routes/channel/#channel_id/followers.ts create mode 100644 src/activitypub/util/OrderedCollection.ts (limited to 'src') diff --git a/src/activitypub/routes/channel/#channel_id/followers.ts b/src/activitypub/routes/channel/#channel_id/followers.ts new file mode 100644 index 00000000..248e2c2c --- /dev/null +++ b/src/activitypub/routes/channel/#channel_id/followers.ts @@ -0,0 +1,28 @@ +import { route } from "@spacebar/api"; +import { Config, Member } from "@spacebar/util"; +import { makeOrderedCollection } from "activitypub/util/OrderedCollection"; +import { Router } from "express"; + +const router = Router(); +export default router; + +router.get("/", route({}), async (req, res) => { + // TODO auth + const { channel_id } = req.params; + + const { webDomain } = Config.get().federation; + + const ret = makeOrderedCollection( + req, + `https://${webDomain}/fed/channels/${channel_id}/followers`, + () => + Member.count({ + where: { guild: { channels: { id: channel_id } } }, + }), + async (before, after) => { + return []; + }, + ); + + return res.json(ret); +}); diff --git a/src/activitypub/routes/channel/#channel_id/outbox.ts b/src/activitypub/routes/channel/#channel_id/outbox.ts index bb44e174..f5dbab3a 100644 --- a/src/activitypub/routes/channel/#channel_id/outbox.ts +++ b/src/activitypub/routes/channel/#channel_id/outbox.ts @@ -1,6 +1,6 @@ import { route } from "@spacebar/api"; import { Config, Message, Snowflake } from "@spacebar/util"; -import { APOrderedCollection } from "activitypub-types"; +import { makeOrderedCollection } from "activitypub/util/OrderedCollection"; import { Router } from "express"; import { FindManyOptions, FindOperator, LessThan, MoreThan } from "typeorm"; @@ -15,60 +15,36 @@ router.get("/", route({}), async (req, res) => { const { webDomain } = Config.get().federation; - if (!page) { - const ret: APOrderedCollection = { - "@context": "https://www.w3.org/ns/activitystreams", - id: `https://${webDomain}/fed/channel/${channel_id}/outbox`, - type: "OrderedCollection", - first: `https://${webDomain}/fed/channel/${channel_id}/outbox?page=true`, - last: `https://${webDomain}/fed/channel/${channel_id}/outbox?page=true&min_id=0`, - }; - return res.json(ret); - } - - const after = min_id ? `${min_id}` : undefined; - const before = max_id ? `${max_id}` : undefined; - - const query: FindManyOptions & { - where: { id?: FindOperator | FindOperator[] }; - } = { - order: { timestamp: "DESC" }, - take: 20, - where: { channel_id: channel_id }, - relations: ["author"], - }; - - if (after) { - if (BigInt(after) > BigInt(Snowflake.generate())) - return res.status(422); - query.where.id = MoreThan(after); - } else if (before) { - if (BigInt(before) > BigInt(Snowflake.generate())) - return res.status(422); - query.where.id = LessThan(before); - } - - const messages = await Message.find(query); - - // move this to like, Channel.createAPMessages or smth - const apMessages = messages.map((message) => ({ - id: `https://${webDomain}/fed/channel/${message.channel_id}/messages/${message.id}`, - type: "Announce", - actor: `https://${webDomain}/fed/user/${message.author_id}`, - published: message.timestamp, - to: `https://${webDomain}/fed/channel/${message.channel_id}`, - object: message.toAP(), - })); - - const ret: APOrderedCollection = { - "@context": "https://www.w3.org/ns/activitystreams", - id: `https://${webDomain}/fed/channel/${channel_id}/outbox?page=true`, - type: "OrderedCollection", - first: `https://${webDomain}/fed/channel/${channel_id}/outbox?page=true`, - last: `https://${webDomain}/fed/channel/${channel_id}/outbox?page=true&min_id=0`, - totalItems: await Message.count({ where: { channel_id } }), - items: apMessages, - }; + const ret = makeOrderedCollection( + req, + `https://${webDomain}/fed/channels/${channel_id}/outbox`, + () => Message.count({ where: { channel_id } }), + async (before, after) => { + const query: FindManyOptions & { + where: { id?: FindOperator | FindOperator[] }; + } = { + order: { timestamp: "DESC" }, + take: 20, + where: { channel_id: channel_id }, + relations: ["author"], + }; + + if (after) { + if (BigInt(after) > BigInt(Snowflake.generate())) return []; + query.where.id = MoreThan(after); + } else if (before) { + if (BigInt(before) > BigInt(Snowflake.generate())) return []; + query.where.id = LessThan(before); + } + + const messages = await Message.find(query); + + return messages.map((x) => ({ + ...x, + toAP: () => x.toAnnounceAP(), + })); + }, + ); return res.json(ret); }); diff --git a/src/activitypub/util/OrderedCollection.ts b/src/activitypub/util/OrderedCollection.ts new file mode 100644 index 00000000..4ad78a81 --- /dev/null +++ b/src/activitypub/util/OrderedCollection.ts @@ -0,0 +1,41 @@ +import { APObject, APOrderedCollection } from "activitypub-types"; +import { Request } from "express"; + +interface ActivityPubable { + toAP(): APObject; +} + +export const makeOrderedCollection = async ( + req: Request, + id: string, + getTotalElements: () => Promise, + getElements: (before?: string, after?: string) => Promise, +): Promise => { + const { page, min_id, max_id } = req.query; + + if (!page) + return { + "@context": "https://www.w3.org/ns/activitystreams", + id: id, + type: "OrderedCollection", + first: `${id}page=true`, + last: `${id}?page=true&min_id=0`, + }; + + const after = min_id ? `${min_id}` : undefined; + const before = max_id ? `${max_id}` : undefined; + + const elems = await getElements(before, after); + + const items = elems.map((elem) => elem.toAP()); + + return { + "@context": "https://www.w3.org/ns/activitystreams", + id: `${id}?page=true`, + type: "OrderedCollection", + first: `${id}?page=true`, + last: `${id}?page=true&min_id=0`, + totalItems: await getTotalElements(), + items: items, + }; +}; diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index 46a3758d..32bd715e 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -16,7 +16,7 @@ along with this program. If not, see . */ -import type { APNote } from "activitypub-types"; +import type { APAnnounce, APNote } from "activitypub-types"; import { Column, CreateDateColumn, @@ -243,6 +243,19 @@ export class Message extends BaseClass { }; } + toAnnounceAP(): APAnnounce { + const { webDomain } = Config.get().federation; + + return { + id: `https://${webDomain}/fed/channel/${this.channel_id}/messages/${this.id}`, + type: "Announce", + actor: `https://${webDomain}/fed/user/${this.author_id}`, + published: this.timestamp, + to: `https://${webDomain}/fed/channel/${this.channel_id}`, + object: this.toAP(), + }; + } + toAP(): APNote { const { webDomain } = Config.get().federation; -- cgit 1.5.1