diff options
| author | s-ol <s+removethis@s-ol.nu> | 2022-01-14 17:26:35 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2022-01-24 11:12:05 +0000 |
| commit | 09395afa8d9bd98324230d6fdc7f13f24aaa769d (patch) | |
| tree | a8211e47ab6fb219fe5a20a1ac683b4b50d77cbe | |
| parent | server: support replying (diff) | |
| download | fedidag-09395afa8d9bd98324230d6fdc7f13f24aaa769d.tar.gz fedidag-09395afa8d9bd98324230d6fdc7f13f24aaa769d.zip | |
server: ActivityStreams reply/link/unlink API
| -rw-r--r-- | server/main.ts | 111 |
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}`); |
