1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-11-22 02:12:40 +01:00
This commit is contained in:
Madeline 2023-08-14 20:28:25 +10:00
parent 9d6a3dc2a7
commit a40dfcfaef
No known key found for this signature in database
GPG Key ID: 1958E017C36F2E47
4 changed files with 111 additions and 53 deletions

View File

@ -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);
});

View File

@ -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 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"],
};
const after = min_id ? `${min_id}` : undefined;
const before = max_id ? `${max_id}` : undefined;
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 query: FindManyOptions<Message> & {
where: { id?: FindOperator<string> | FindOperator<string>[] };
} = {
order: { timestamp: "DESC" },
take: 20,
where: { channel_id: channel_id },
relations: ["author"],
};
const messages = await Message.find(query);
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,
};
return messages.map((x) => ({
...x,
toAP: () => x.toAnnounceAP(),
}));
},
);
return res.json(ret);
});

View File

@ -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,
};
};

View File

@ -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;