server: support replying
s-ol
1 year, 8 months ago
21 | 21 | } |
22 | 22 | app.use(express.json()); |
23 | 23 | app.use(cookieParser()); |
24 | ||
25 | type Note = { | |
26 | type: 'Note'; | |
27 | published: string; | |
28 | attributedTo: string | { | |
29 | id: string; | |
30 | type: 'Person', | |
31 | name: string; | |
32 | }; | |
33 | inReplyTo: string[]; | |
34 | replies: string[]; | |
35 | content: string; | |
36 | }; | |
24 | 37 | |
25 | 38 | const discdag = express() |
26 | 39 | .post('/login', wrap(async ($req, $res) => { |
135 | 148 | if (doc.text().indexOf("Invalid discussion ID:") > -1) |
136 | 149 | return $res.status(404).end(); |
137 | 150 | |
138 | type Note = { | |
139 | type: 'Note'; | |
140 | published: string; | |
141 | attributedTo: string | { | |
142 | id: string; | |
143 | type: 'Person', | |
144 | name: string; | |
145 | }; | |
146 | inReplyTo: string[]; | |
147 | replies: string[]; | |
148 | content: string; | |
149 | }; | |
150 | ||
151 | 151 | let first = null; |
152 | 152 | const items: Record<string, Note> = {}; |
153 | 153 | for (const node of doc('g.node', 'svg')) { |
199 | 199 | first, |
200 | 200 | items, |
201 | 201 | }); |
202 | })); | |
202 | })) | |
203 | ||
204 | .put('/disc/:discussion', wrap(async ($req, $res) => { | |
205 | const { inReplyTo, content } = $req.body as { inReplyTo: string[], content: string }; | |
206 | const { discussion } = $req.params; | |
207 | const { digest } = $req.cookies; | |
208 | ||
209 | if (!digest || !digest.length) | |
210 | return $res.status(401).end(); | |
211 | ||
212 | if (!inReplyTo.length || !content.length) | |
213 | return $res.status(400).end(); | |
214 | ||
215 | const parents = inReplyTo.map(id => { | |
216 | const parts = id.split('/'); | |
217 | return parts[parts.length - 1]; | |
218 | }).join(','); | |
219 | ||
220 | const res = await fetch(DISCDAG_URL, { | |
221 | method: 'POST', | |
222 | headers: { | |
223 | 'Content-Type': 'application/x-www-form-urlencoded', | |
224 | 'Cookie': `DiscussionID=${discussion}; digest=${digest}; SelectedNodes=${parents}`, | |
225 | }, | |
226 | body: new URLSearchParams({ Action: 'SendReply', ReplyText: content }).toString(), | |
227 | }); | |
228 | ||
229 | if (res.status !== 200) | |
230 | throw new Error("bad response"); | |
231 | ||
232 | const doc = cheerio.load(await res.text()); | |
233 | ||
234 | if (doc.text().indexOf("Invalid discussion ID:") > -1) | |
235 | return $res.status(404).end(); | |
236 | ||
237 | if (doc.text().indexOf("Replying only available if you have write access:") > -1) | |
238 | return $res.status(403).end(); | |
239 | ||
240 | const items: Record<string, Note> = {}; | |
241 | for (const node of doc('g.node polygon[stroke-width=5]', 'svg').parent()) { | |
242 | const nodeId = doc('title', node).text(); | |
243 | const [_, time, author] = nodeId.split('_'); | |
244 | ||
245 | const id = `${PUBLIC_URL}/discdag/disc/${discussion}/${nodeId}`; | |
246 | ||
247 | const content = doc('g:first text', node) | |
248 | .slice(3) | |
249 | .map(function(this: any) { return doc(this).text(); }) | |
250 | .toArray() | |
251 | .join(' ').trim(); | |
252 | ||
253 | items[id] = { | |
254 | type: 'Note', | |
255 | published: time.replace(/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)[a-z]*/, '$1-$2-$3T$4:$5:$6Z'), | |
256 | attributedTo: `${PUBLIC_URL}/discdag/user/${author}`, | |
257 | inReplyTo: [], | |
258 | replies: [], | |
259 | content, | |
260 | }; | |
261 | } | |
262 | ||
263 | for (const node of doc('g.edge', 'svg')) { | |
264 | let [frm, to] = doc('title', node).text().split('->'); | |
265 | if (frm === 'SELECTED' || to === 'SELECTED') continue; | |
266 | frm = `${PUBLIC_URL}/discdag/disc/${discussion}/${frm}`; | |
267 | to = `${PUBLIC_URL}/discdag/disc/${discussion}/${to}`; | |
268 | ||
269 | items[frm]?.replies.push(to); | |
270 | items[to]?.inReplyTo.push(frm); | |
271 | } | |
272 | ||
273 | return $res | |
274 | .json({ | |
275 | '@context': 'https://www.w3.org/ns/activitystreams', | |
276 | items, | |
277 | }); | |
278 | })) | |
279 | ; | |
203 | 280 | |
204 | 281 | app.use('/discdag', discdag); |
205 | 282 |