summary refs log tree commit diff
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2023-08-14 20:28:25 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2023-08-14 20:28:25 +1000
commita40dfcfaefb353039700a64cfc374fe8dca588a9 (patch)
treee8f20fec41df947ce7ada3afd344143ea05d832e
parentaaaaaaaa (diff)
downloadserver-a40dfcfaefb353039700a64cfc374fe8dca588a9.tar.xz
test
-rw-r--r--src/activitypub/routes/channel/#channel_id/followers.ts28
-rw-r--r--src/activitypub/routes/channel/#channel_id/outbox.ts86
-rw-r--r--src/activitypub/util/OrderedCollection.ts41
-rw-r--r--src/util/entities/Message.ts15
4 files changed, 114 insertions, 56 deletions
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<Message> & { - where: { id?: FindOperator<string> | FindOperator<string>[] }; - } = { - 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<Message> & { + where: { id?: FindOperator<string> | FindOperator<string>[] }; + } = { + 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 <T extends ActivityPubable>( + req: Request, + id: string, + getTotalElements: () => Promise<number>, + getElements: (before?: string, after?: string) => Promise<T[]>, +): Promise<APOrderedCollection> => { + 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 <https://www.gnu.org/licenses/>. */ -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;