From b710f606eca6450dd9288ef763df3531d5ac5d54 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Wed, 12 Aug 2026 17:25:51 +0200 Subject: [PATCH] visbility filter and slug resolution to id --- public/s/js/f0ckm.js | 12 ++++++------ src/inc/lib.mjs | 2 +- src/inc/routeinc/f0cklib.mjs | 10 ++++++++-- src/inc/routes/apiv2/index.mjs | 23 +++++++++++++++++------ 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/public/s/js/f0ckm.js b/public/s/js/f0ckm.js index 3f40d3e..4e7930b 100644 --- a/public/s/js/f0ckm.js +++ b/public/s/js/f0ckm.js @@ -1441,9 +1441,9 @@ window.cancelAnimFrame = (function () { if (!btn || !btn.href || btn.href.endsWith('#')) return; const pathSegments = new URL(btn.href, window.location.origin).pathname.split('/'); - const numericSegments = pathSegments.filter(s => /^\d+$/.test(s)); - if (numericSegments.length === 0) return; - const itemId = numericSegments.pop(); + const keySegments = pathSegments.filter(s => /^\d+$/.test(s) || /^[a-zA-Z0-9_-]{11}$/.test(s)); + if (keySegments.length === 0) return; + const itemId = keySegments.pop(); let ajaxUrl = `/ajax/item/${itemId}`; const params = new URLSearchParams(); @@ -3246,9 +3246,9 @@ window.cancelAnimFrame = (function () { */ const updateNavForMode = async (mode) => { const pathSegments = window.location.pathname.split('/'); - const numericSegments = pathSegments.filter(s => /^\d+$/.test(s)); - if (numericSegments.length === 0) return; - const itemid = numericSegments[numericSegments.length - 1]; + const keySegments = pathSegments.filter(s => /^\d+$/.test(s) || /^[a-zA-Z0-9_-]{11}$/.test(s)); + if (keySegments.length === 0) return; + const itemid = keySegments[keySegments.length - 1]; const params = new URLSearchParams(); params.set('mode', mode); diff --git a/src/inc/lib.mjs b/src/inc/lib.mjs index 1d74d88..f2dacbc 100644 --- a/src/inc/lib.mjs +++ b/src/inc/lib.mjs @@ -109,7 +109,7 @@ export default new class { tmp = cfg.enable_nsfl ? `items.id in (select item_id from tags_assign where tag_id = ${parseInt(cfg.nsfl_tag_id, 10) || 3})` : "1 = 0"; break; default: // sfw - tmp = "items.id in (select item_id from tags_assign where tag_id = 1)"; + tmp = "(items.id in (select item_id from tags_assign where tag_id = 1) or not exists (select 1 from tags_assign where item_id = items.id))"; break; } return tmp; diff --git a/src/inc/routeinc/f0cklib.mjs b/src/inc/routeinc/f0cklib.mjs index c9b9bca..aaba987 100644 --- a/src/inc/routeinc/f0cklib.mjs +++ b/src/inc/routeinc/f0cklib.mjs @@ -651,10 +651,16 @@ export default { // Helper to construct shared filter conditions const buildConditions = () => { + const visibilityFilter = isOwnerOrAdmin + ? db`` + : (session && session.user + ? db`and (coalesce(items.visibility, 0) = 0 or lower(items.username) = ${session.user.toLowerCase()})` + : db`and coalesce(items.visibility, 0) = 0`); + return db` ${db.unsafe(modequery)} and items.active = true - and coalesce(items.visibility, 0) = 0 + ${visibilityFilter} and (items.expires_at IS NULL OR items.expires_at > ${Math.floor(Date.now() / 1000)}) ${tagFilter} @@ -773,7 +779,7 @@ export default { // Determine the effective mode for optimization check (similar to Random) const nsfl_id = cfg.nsfl_tag_id || 3; - const useTagsDriver = !!session && (effMode === 0 || effMode === 1 || effMode === 4) && !fav && !tag && !user && !hall; + const useTagsDriver = !!session && (effMode === 1 || effMode === 4) && !fav && !tag && !user && !hall; const baseQuery = (whereClause, orderBy, limit = 1) => { return db` diff --git a/src/inc/routes/apiv2/index.mjs b/src/inc/routes/apiv2/index.mjs index 082a6c0..41fc349 100644 --- a/src/inc/routes/apiv2/index.mjs +++ b/src/inc/routes/apiv2/index.mjs @@ -752,13 +752,18 @@ export default router => { }, 200); }); - group.get(/\/item\/(?[0-9]+)$/, async (req, res) => { - const id = +req.params.id; + group.get(/\/item\/(?[a-zA-Z0-9_-]{11}|\d+)$/, async (req, res) => { + const rawIdOrSlug = req.params.id; + const isNumeric = /^\d+$/.test(rawIdOrSlug); + const id = isNumeric ? +rawIdOrSlug : (await db`SELECT id FROM items WHERE slug = ${rawIdOrSlug} LIMIT 1`)[0]?.id; + if (!id) { + return res.json({ success: false, msg: 'no items found' }); + } const item = await db` select * from "items" - where id = ${+id} and active = true + where id = ${id} and active = true limit 1 `; @@ -811,7 +816,7 @@ export default router => { if (effMode === 2) { modeCondition = db`and not exists (select 1 from tags_assign where item_id = items.id)`; } else if (effMode === 0) { - modeCondition = db`and id in (select item_id from tags_assign where tag_id = 1)`; + modeCondition = db`and (id in (select item_id from tags_assign where tag_id = 1) or not exists (select 1 from tags_assign where item_id = items.id))`; } else if (effMode === 1) { modeCondition = db`and id in (select item_id from tags_assign where tag_id = 2)`; } else if (effMode === 4) { @@ -820,17 +825,23 @@ export default router => { modeCondition = db`and ${db.unsafe(lib.getMultiRatingMode(ratingsArr))}`; } + const visibilityFilter = isOwnerOrAdmin + ? db`` + : (session && session.user + ? db`and (coalesce(visibility, 0) = 0 or lower(username) = ${session.user.toLowerCase()})` + : db`and coalesce(visibility, 0) = 0`); + const next = await db` select id from "items" - where id > ${+id} and active = true and coalesce(visibility, 0) = 0 ${guestTagFilter} ${modeCondition} + where id > ${id} and active = true ${visibilityFilter} ${guestTagFilter} ${modeCondition} order by id limit 1 `; const prev = await db` select id from "items" - where id < ${+id} and active = true and coalesce(visibility, 0) = 0 ${guestTagFilter} ${modeCondition} + where id < ${id} and active = true ${visibilityFilter} ${guestTagFilter} ${modeCondition} order by id desc limit 1 `;