git.s-ol.nu fedidag / 6754ad0
server: support replying s-ol 1 year, 8 months ago
1 changed file(s) with 91 addition(s) and 14 deletion(s). Raw diff Collapse all Expand all
2121 }
2222 app.use(express.json());
2323 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 };
2437
2538 const discdag = express()
2639 .post('/login', wrap(async ($req, $res) => {
135148 if (doc.text().indexOf("Invalid discussion ID:") > -1)
136149 return $res.status(404).end();
137150
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
151151 let first = null;
152152 const items: Record<string, Note> = {};
153153 for (const node of doc('g.node', 'svg')) {
199199 first,
200200 items,
201201 });
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 ;
203280
204281 app.use('/discdag', discdag);
205282