Add user outbox

This commit is contained in:
Jesse Wierzbinski 2023-09-12 12:50:51 -10:00
parent ed96e11301
commit 6d77c8edc7
No known key found for this signature in database
GPG key ID: F9A1E418934E40B0
3 changed files with 141 additions and 28 deletions

View file

@ -11,7 +11,6 @@ export default async (
req: Request,
matchedRoute: MatchedRoute
): Promise<Response> => {
// In the format acct:name@example.com
const username = matchedRoute.params.username;
const user = await User.findOneBy({ username });
@ -28,9 +27,17 @@ export default async (
],
id: `${getHost()}/@${user.username}/actor`,
type: "Person",
preferredUsername: user.username,
preferredUsername: user.username, // TODO: Add user display name
name: user.username,
summary: user.bio,
icon: [
// TODO: Add user avatar
],
inbox: `${getHost()}/@${user.username}/inbox`,
outbox: `${getHost()}/@${user.username}/outbox`,
followers: `${getHost()}/@${user.username}/followers`,
following: `${getHost()}/@${user.username}/following`,
liked: `${getHost()}/@${user.username}/liked`,
})
);
};

View file

@ -1,26 +0,0 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import { User } from "~database/entities/User";
import { getHost } from "@config";
import { compact } from "jsonld";
/**
* ActivityPub user actor endpoinmt
*/
export default async (
req: Request,
matchedRoute: MatchedRoute
): Promise<Response> => {
// In the format acct:name@example.com
const username = matchedRoute.params.username;
const user = await User.findOneBy({ username });
if (!user) {
return errorResponse("User not found", 404);
}
return jsonResponse({
})
};

View file

@ -0,0 +1,132 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import { User } from "~database/entities/User";
import { getHost } from "@config";
import { NodeObject, compact } from "jsonld";
import { RawObject } from "~database/entities/RawObject";
/**
* ActivityPub user inbox endpoint
*/
export default async (
req: Request,
matchedRoute: MatchedRoute
): Promise<Response> => {
// Check if POST request
if (req.method !== "POST") {
return errorResponse("Method not allowed", 405);
}
const username = matchedRoute.params.username;
const page = Boolean(matchedRoute.query.page || "false");
const min_id = matchedRoute.query.min_id || false;
const max_id = matchedRoute.query.max_id || false;
const user = await User.findOneBy({ username });
if (!user) {
return errorResponse("User not found", 404);
}
// Get the user's corresponding ActivityPub notes
const count = await RawObject.count({
where: {
data: {
attributedTo: `${getHost()}/@${user.username}`,
},
},
order: {
data: {
published: "DESC",
},
},
});
const lastPost = (await RawObject.find({
where: {
data: {
attributedTo: `${getHost()}/@${user.username}`,
},
},
order: {
data: {
published: "ASC",
},
},
take: 1,
}))[0];
if (!page)
return jsonResponse(
await compact({
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
],
id: `${getHost()}/@${user.username}/inbox`,
type: "OrderedCollection",
totalItems: count,
first: `${getHost()}/@${user.username}/outbox?page=true`,
last: `${getHost()}/@${
user.username
}/outbox?min_id=${lastPost.id}&page=true`,
})
);
else {
let posts: RawObject[] = []
if (min_id) {
posts = await RawObject.find({
where: {
data: {
attributedTo: `${getHost()}/@${user.username}`,
id: min_id,
},
},
order: {
data: {
published: "DESC",
},
},
take: 11, // Take one extra to have the ID of the next post
});
} else if (max_id) {
posts = await RawObject.find({
where: {
data: {
attributedTo: `${getHost()}/@${user.username}`,
id: max_id,
},
},
order: {
data: {
published: "ASC",
},
},
take: 10,
});
}
return jsonResponse(await compact({
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
],
id: `${getHost()}/@${user.username}/inbox`,
type: "OrderedCollectionPage",
totalItems: count,
partOf: `${getHost()}/@${user.username}/inbox`,
// Next is less recent posts chronologically, uses min_id
next: `${getHost()}/@${user.username}/outbox?min_id=${
posts[posts.length - 1].id
}&page=true`,
// Prev is more recent posts chronologically, uses max_id
prev: `${getHost()}/@${user.username}/outbox?max_id=${
posts[0].id
}&page=true`,
orderedItems: posts.slice(0, 10).map(post => post.data) as NodeObject[]
}));
}
};