aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2022-01-14 17:26:35 +0000
committers-ol <s+removethis@s-ol.nu>2022-01-24 11:12:05 +0000
commit09395afa8d9bd98324230d6fdc7f13f24aaa769d (patch)
treea8211e47ab6fb219fe5a20a1ac683b4b50d77cbe
parentserver: support replying (diff)
downloadfedidag-09395afa8d9bd98324230d6fdc7f13f24aaa769d.tar.gz
fedidag-09395afa8d9bd98324230d6fdc7f13f24aaa769d.zip
server: ActivityStreams reply/link/unlink API
-rw-r--r--server/main.ts111
1 files changed, 83 insertions, 28 deletions
diff --git a/server/main.ts b/server/main.ts
index 02d5933..7cb21a0 100644
--- a/server/main.ts
+++ b/server/main.ts
@@ -23,19 +23,47 @@ if (DEBUG) {
app.use(express.json());
app.use(cookieParser());
+type LinkOr<T> = string | T;
+
+type Person = {
+ id: string;
+ type: 'Person',
+ name: string;
+};
+
type Note = {
type: 'Note';
published: string;
- attributedTo: string | {
- id: string;
- type: 'Person',
- name: string;
- };
+ attributedTo: LinkOr<Person>;
inReplyTo: string[];
replies: string[];
content: string;
};
+type Relationship<S, O> = {
+ type: 'Relationship';
+ relationship: string;
+ subject: S;
+ object: O;
+};
+
+type Create<O> = {
+ type: 'Create';
+ actor: LinkOr<Person>;
+ object: O;
+};
+
+type Delete<O> = {
+ type: 'Create';
+ actor: LinkOr<Person>;
+ object: O;
+};
+
+const iri2id = (iri: string) => {
+ const parts = iri.split('/');
+ return parts[parts.length - 1];
+};
+
const discdag = express()
.post('/login', wrap(async ($req, $res) => {
const { username, password } = $req.body;
@@ -189,7 +217,6 @@ const discdag = express()
{
items: {
'@id': 'as:items',
- '@type': '@id',
'@container': '@id'
},
},
@@ -202,30 +229,51 @@ const discdag = express()
});
}))
- .put('/disc/:discussion', wrap(async ($req, $res) => {
- const { inReplyTo, content } = $req.body as { inReplyTo: string[], content: string };
+ .post('/disc/:discussion', wrap(async ($req, $res) => {
const { discussion } = $req.params;
const { digest } = $req.cookies;
if (!digest || !digest.length)
return $res.status(401).end();
- if (!inReplyTo.length || !content.length)
- return $res.status(400).end();
+ type Activity =
+ | Create<Note>
+ | Create<Relationship<string, string>>
+ | Delete<Relationship<string, string>>
+ ;
+ const activity = $req.body as Activity;
+
+ let selection: string[];
+ let body: string;
+ let method = 'GET';
+ if (activity.type === 'Create' && activity.object?.type === 'Note') {
+ method = 'POST';
+ selection = activity.object.inReplyTo.map(iri2id);
+ body = new URLSearchParams({ Action: 'SendReply', ReplyText: activity.object.content }).toString();
+ } else if (activity.object?.type === 'Relationship' && activity.object.relationship === 'as:inReplyTo') {
+ const frm = iri2id(activity.object.object);
+ const to = iri2id(activity.object.subject);
+ selection = [frm, to];
+ body = new URLSearchParams({
+ Action: activity.type === 'Create' ? 'CreateLink' : 'RemoveLink',
+ N0: frm,
+ N1: to,
+ }).toString();
+ } else {
+ return $res.status(501).end();
+ }
- const parents = inReplyTo.map(id => {
- const parts = id.split('/');
- return parts[parts.length - 1];
- }).join(',');
+ const headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Cookie': `DiscussionID=${discussion}; digest=${digest}; SelectedNodes=${selection.join(',')}`,
+ };
- const res = await fetch(DISCDAG_URL, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Cookie': `DiscussionID=${discussion}; digest=${digest}; SelectedNodes=${parents}`,
- },
- body: new URLSearchParams({ Action: 'SendReply', ReplyText: content }).toString(),
- });
+ let res;
+ if (method === 'POST') {
+ res = await fetch(DISCDAG_URL, { method, headers, body });
+ } else {
+ res = await fetch(DISCDAG_URL + `?${body}`, { method, headers });
+ }
if (res.status !== 200)
throw new Error("bad response");
@@ -271,11 +319,18 @@ const discdag = express()
items[to]?.inReplyTo.push(frm);
}
- return $res
- .json({
- '@context': 'https://www.w3.org/ns/activitystreams',
- items,
- });
+ return $res.json({
+ '@context': [
+ 'https://www.w3.org/ns/activitystreams',
+ {
+ items: {
+ '@id': 'as:items',
+ '@container': '@id'
+ },
+ },
+ ],
+ items,
+ });
}))
;
@@ -318,7 +373,7 @@ app.get(/\/remote\/.*/, wrap(async ($req, $res) => {
try {
app.listen(PORT, (): void => {
- console.log(`Connected successfully on port ${PORT}`);
+ console.log(`Connected successfully on port ${PORT}`);
});
} catch (error) {
console.error(`Error occured: ${error}`);