import sql from "../sql.mjs"; import lib from "../lib.mjs"; const allowedMimes = [ "audio", "image", "video", "%" ]; const auth = async (req, res, next) => { if(!req.session) { return res.reply({ code: 401, body: "401 - Unauthorized" }); } return next(); }; export default (router, tpl) => { router.group(/^\/api\/v2/, group => { group.get(/$/, (req, res) => { res.end("api lol"); }); group.get(/\/random(\/user\/.+|\/image|\/video|\/audio)?$/, async (req, res) => { const user = req.url.split[3] === "user" ? req.url.split[4] : "%"; const mime = (allowedMimes.filter(n => req.url.split[3]?.startsWith(n))[0] ? req.url.split[3] : "") + "%"; const rows = await sql("items") .orderByRaw("rand()") .limit(1) .where("mime", "ilike", mime) .andWhere("username", "ilike", user); return res.json({ success: rows.length > 0, items: rows.length > 0 ? rows[0] : [] }); }); group.get(/\/p\/([0-9]+)/, async (req, res) => { // legacy let eps = 100; let id = +req.url.split[3]; const rows = await sql("items").where("id", "<", id).orderBy("id", "desc").limit(eps); const items = { items: rows, last: rows[rows.length - 1].id }; return res.json({ success: true, items }); }); group.get(/\/item\/[0-9]+$/, async (req, res) => { const id = +req.url.split[3]; const item = await sql("items").where("id", id).limit(1); const next = await sql("items").select("id").where("id", ">", id).orderBy("id").limit(1); const prev = await sql("items").select("id").where("id", "<", id).orderBy("id", "desc").limit(1); if(item.length === 0) { return res.json({ success: false, msg: 'no items found' }); } const rows = { ...item[0], ...{ next: next[0]?.id ?? null, prev: prev[0]?.id ?? null } }; return res.json({ success: true, rows }); }); group.get(/\/user\/.*(\/\d+)?$/, async (req, res) => { const user = req.url.split[3]; const eps = +req.url.split[4] || 50; const rows = await sql("items") .select("id", "mime", "size", "src", "stamp", "userchannel", "username", "usernetwork") .where("username", user) .orderBy("stamp", "desc") .limit(eps); return res.json({ success: rows.length > 0, items: rows.length > 0 ? rows : [] }); }); // adminzeugs group.delete(/\/admin\/(?\d+)\/tags\/(?.*)/, auth, async (req, res) => { // delete tag if(!req.params.postid || !req.params.tagname) { return res.json({ success: false, msg: 'missing postid or tagname' }); } const postid = +req.params.postid; const tagname = decodeURIComponent(req.params.tagname); const tags = await lib.getTags(postid); const tagid = tags.filter(t => t.tag === tagname)[0]?.id ?? null; if(!tagid) { return res.json({ success: false, msg: 'tag is not assigned', tags: await lib.getTags(postid) }); } let q = sql("tags_assign").where("tag_id", tagid).andWhere("item_id", postid).del(); if(req.session.level < 50) q = q.andWhere("user_id", req.session.id); const reply = !!(await q); return res.json({ success: reply, tagid, tags: await lib.getTags(postid) }) }); group.post(/\/admin\/(?\d+)\/tags/, auth, async (req, res) => { // assign and/or create tag if(!req.params.postid || !req.post.tagname) { return res.json({ success: false, msg: 'missing postid or tag' }); } const postid = +req.params.postid; const tagname = req.post.tagname?.trim(); if(tagname.length >= 45) { return res.json({ success: false, msg: 'tag is too long!' }); } try { let tagid = ( await sql("tags") .select("id") .whereRaw("normalized = slugify(?)", [ tagname ]) )?.[0]?.id; if(!tagid) { // create new tag tagid = (await sql("tags").returning("id").insert({ tag: tagname }))[0]; } await sql("tags_assign").insert({ tag_id: tagid, item_id: postid, user_id: req.session.id }); } catch(err) { return res.json({ success: false, msg: err.message, tags: await lib.getTags(postid) }); } return res.json({ success: true, postid: postid, tag: tagname, tags: await lib.getTags(postid) }); }); group.get(/\/admin\/(?\d+)\/tags$/, auth, async (req, res) => { // get tags if(!req.params.postid) { return res.json({ success: false, msg: 'missing postid' }); } return res.json({ success: true, tags: await lib.getTags(+req.params.postid) }); }); group.put(/\/admin\/(?\d+)\/tags\/toggle$/, auth, async (req, res) => { // xD if(!req.params.postid) { return res.json({ success: false, msg: 'missing postid' }); } const postid = +req.params.postid; if(!(await lib.getTags(postid)).filter(tag => [1,2].includes(tag.id)).length) { // insert await sql('tags_assign').insert({ item_id: postid, tag_id: 1, user_id: req.session.id }); } else { // update await sql('tags_assign') .update({ tag_id: sql.raw('(array[2,1])[tag_id]') }) .whereRaw('tag_id = any(array[1,2])') .andWhere('item_id', postid); } return res.json({ success: true, tags: await lib.getTags(postid) }); }); group.get(/\/admin\/tags\/suggest$/, auth, async (req, res) => { const reply = { success: false, suggestions: {} }; const searchString = req.url.qs.q; if(searchString?.length <= 1) { reply.error = 'too short lol'; return res.json(reply); } try { const q = await sql('tags') .select('tag', sql.raw('count(tags_assign.tag_id) as tagged')) .leftJoin('tags_assign', 'tags_assign.tag_id', 'tags.id') .whereRaw("normalized like '%' || slugify(?) || '%'", [ searchString ]) .groupBy('tags.id') .orderBy('tagged', 'desc') .limit(15); reply.success = true; reply.suggestions = q; } catch(err) { reply.error = err.msg; } return res.json(reply); }); group.post(/\/admin\/deletepost$/, auth, async (req, res) => { if(!req.post.postid) { return res.json({ success: false, msg: 'no postid' }); } const postid = +req.post.postid; await sql("items").where("id", postid).del(); res.json({ success: true }); }); group.post(/\/admin\/togglefav$/, auth, async (req, res) => { const postid = +req.post.postid; let favs = await sql('favorites').select('user_id').where('item_id', postid); if(Object.values(favs).filter(u => u.user_id === req.session.id)[0]) { // del fav await sql('favorites').where('user_id', req.session.id).andWhere('item_id', postid).del(); } else { // add fav await sql('favorites').insert({ item_id: postid, user_id: req.session.id }); } favs = await sql('favorites') .select('user.user', 'user_options.avatar') .leftJoin('user', 'user.id', 'favorites.user_id') .leftJoin('user_options', 'user_options.user_id', 'favorites.user_id') .where('favorites.item_id', postid); return res.json({ success: true, itemid: postid, favs }); }); }); return router; };