Skip to content

Commit 9f3ce50

Browse files
committed
dev: add read and list endpoints
1 parent fdf10ef commit 9f3ce50

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

src/backend/src/services/ThreadService.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,116 @@ class ThreadService extends BaseService {
326326
res.json({});
327327
}
328328
}).attach(router);
329+
330+
Endpoint({
331+
route: '/read/:uid',
332+
methods: ['GET'],
333+
mw: [configurable_auth()],
334+
handler: async (req, res) => {
335+
const uid = req.params.uid;
336+
337+
if ( ! is_valid_uuid(uid) ) {
338+
throw APIError.create('field_invalid', null, {
339+
key: 'uid',
340+
expected: 'uuid',
341+
got: whatis(uid),
342+
});
343+
}
344+
345+
346+
const actor = Context.get('actor');
347+
348+
// Check read permission
349+
{
350+
const permission = PermissionUtil.join('thread', uid, 'read');
351+
const svc_permission = this.services.get('permission');
352+
const reading = await svc_permission.scan(actor, permission);
353+
const options = PermissionUtil.reading_to_options(reading);
354+
if ( options.length <= 0 ) {
355+
throw APIError.create('permission_denied', null, {
356+
permission,
357+
});
358+
}
359+
}
360+
361+
const thread = await this.get_thread({ uid });
362+
363+
res.json(this.client_safe_thread(thread));
364+
}
365+
}).attach(router);
366+
367+
Endpoint({
368+
route: '/list/:uid/:page',
369+
methods: ['POST'],
370+
mw: [configurable_auth()],
371+
handler: async (req, res) => {
372+
const uid = req.params.uid;
373+
374+
if ( ! is_valid_uuid(uid) ) {
375+
throw APIError.create('field_invalid', null, {
376+
key: 'uid',
377+
expected: 'uuid',
378+
got: whatis(uid),
379+
});
380+
}
381+
382+
const actor = Context.get('actor');
383+
384+
// Check list permission
385+
{
386+
const permission = PermissionUtil.join('thread', uid, 'list');
387+
const svc_permission = this.services.get('permission');
388+
const reading = await svc_permission.scan(actor, permission);
389+
const options = PermissionUtil.reading_to_options(reading);
390+
if ( options.length <= 0 ) {
391+
throw APIError.create('permission_denied', null, {
392+
permission,
393+
});
394+
}
395+
}
396+
397+
const page = Number(req.params.page);
398+
const validate_positive_integer = (key, value) => {
399+
if ( whatis(value) !== 'number' ) {
400+
throw APIError.create('field_invalid', null, {
401+
key,
402+
expected: 'number',
403+
got: whatis(value),
404+
});
405+
}
406+
if ( value < 0 || ! Number.isInteger(value) ) {
407+
throw APIError.create('field_invalid', null, {
408+
key,
409+
expected: 'positive integer',
410+
got: value,
411+
});
412+
}
413+
}
414+
validate_positive_integer('page', page);
415+
416+
if ( req.body.limit !== undefined ) {
417+
validate_positive_integer('limit', req.body.limit);
418+
}
419+
420+
const limit = Math.min(100, req.body.limit ?? 50);
421+
const offset = page * limit;
422+
423+
const threads = await this.db.read(
424+
"SELECT * FROM `thread` WHERE parent_uid=? LIMIT ?,?",
425+
[uid, offset, limit]
426+
);
427+
428+
res.json(threads.map(this.client_safe_thread));
429+
}
430+
}).attach(router);
431+
}
432+
433+
client_safe_thread (thread) {
434+
return {
435+
uid: thread.uid,
436+
parent: thread.parent_uid,
437+
text: thread.text,
438+
};
329439
}
330440

331441
async get_thread ({ uid }) {

0 commit comments

Comments
 (0)