add nsfp tag manager
This commit is contained in:
@@ -10,7 +10,7 @@ import audit from '../../audit.mjs';
|
||||
import { parseMultipart, collectBody } from '../../multipart.mjs';
|
||||
|
||||
const allowedMimes = ["audio", "image", "video", "%"];
|
||||
const globalfilter = cfg.nsfp?.length ? cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ') : null;
|
||||
const getGlobalfilter = () => cfg.nsfp?.length ? cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ') : null;
|
||||
const metaCache = new Map();
|
||||
const MAX_META_CACHE = 2000;
|
||||
|
||||
|
||||
126
src/inc/routes/nsfp.mjs
Normal file
126
src/inc/routes/nsfp.mjs
Normal file
@@ -0,0 +1,126 @@
|
||||
import db from "../sql.mjs";
|
||||
import lib from "../lib.mjs";
|
||||
import audit from "../audit.mjs";
|
||||
import { getNsfpIds, setNsfpIds } from "../settings.mjs";
|
||||
|
||||
export default (router, tpl) => {
|
||||
|
||||
// Admin page
|
||||
router.get(/^\/admin\/nsfp\/?$/, lib.auth, async (req, res) => {
|
||||
try {
|
||||
res.reply({
|
||||
body: tpl.render("admin/nsfp", {
|
||||
session: req.session,
|
||||
totals: await lib.countf0cks(),
|
||||
csrf_token: req.session?.csrf_token || ''
|
||||
}, req)
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[NSFP] Page render failed:', err);
|
||||
res.reply({ code: 500, body: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// API: list current NSFP tag IDs with names
|
||||
router.get('/api/v2/admin/nsfp', lib.auth, async (req, res) => {
|
||||
try {
|
||||
const ids = getNsfpIds();
|
||||
const tagRows = ids.length > 0
|
||||
? await db`SELECT id, tag, normalized FROM tags WHERE id IN ${db(ids)} ORDER BY id`
|
||||
: [];
|
||||
const tagMap = Object.fromEntries(tagRows.map(r => [r.id, r]));
|
||||
const enriched = ids.map(id => tagMap[id] || { id, tag: '(unknown)', normalized: null });
|
||||
return res.json({ success: true, nsfp: enriched, raw_ids: ids });
|
||||
} catch (err) {
|
||||
return res.json({ success: false, msg: err.message }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// API: search tags for the add-tag autocomplete
|
||||
router.get('/api/v2/admin/nsfp/search', lib.auth, async (req, res) => {
|
||||
try {
|
||||
const q = (req.url.qs?.q || '').trim();
|
||||
if (!q) return res.json({ success: true, tags: [] });
|
||||
const pattern = '%' + q + '%';
|
||||
const tags = await db`
|
||||
SELECT id, tag, normalized
|
||||
FROM tags
|
||||
WHERE tag ILIKE ${pattern} OR normalized ILIKE ${pattern}
|
||||
ORDER BY tag
|
||||
LIMIT 20
|
||||
`;
|
||||
return res.json({ success: true, tags });
|
||||
} catch (err) {
|
||||
return res.json({ success: false, msg: err.message }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// API: add a tag ID to the NSFP list
|
||||
router.post('/api/v2/admin/nsfp/add', lib.auth, async (req, res) => {
|
||||
try {
|
||||
const tagId = parseInt(req.post?.tag_id);
|
||||
if (!tagId || isNaN(tagId) || tagId <= 0) {
|
||||
return res.json({ success: false, msg: 'A valid tag_id is required' }, 400);
|
||||
}
|
||||
|
||||
const tag = await db`SELECT id, tag FROM tags WHERE id = ${tagId} LIMIT 1`;
|
||||
if (tag.length === 0) {
|
||||
return res.json({ success: false, msg: 'Tag with id ' + tagId + ' does not exist' }, 404);
|
||||
}
|
||||
|
||||
const current = getNsfpIds();
|
||||
if (current.includes(tagId)) {
|
||||
return res.json({ success: false, msg: 'Tag #' + tagId + ' (' + tag[0].tag + ') is already in the NSFP list' }, 409);
|
||||
}
|
||||
|
||||
const updated = [...current, tagId];
|
||||
setNsfpIds(updated);
|
||||
|
||||
await db`
|
||||
INSERT INTO site_settings (key, value)
|
||||
VALUES ('nsfp', ${JSON.stringify(updated)})
|
||||
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
|
||||
`;
|
||||
|
||||
await audit.log(req.session.id, 'nsfp_add', 'tag', tagId, { tag: tag[0].tag, nsfp: updated });
|
||||
|
||||
return res.json({ success: true, nsfp_ids: getNsfpIds(), added: tag[0] });
|
||||
} catch (err) {
|
||||
console.error('[NSFP] Add failed:', err);
|
||||
return res.json({ success: false, msg: err.message }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// API: remove a tag ID from the NSFP list
|
||||
router.post('/api/v2/admin/nsfp/remove', lib.auth, async (req, res) => {
|
||||
try {
|
||||
const tagId = parseInt(req.post?.tag_id);
|
||||
if (!tagId || isNaN(tagId)) {
|
||||
return res.json({ success: false, msg: 'tag_id is required' }, 400);
|
||||
}
|
||||
|
||||
const current = getNsfpIds();
|
||||
if (!current.includes(tagId)) {
|
||||
return res.json({ success: false, msg: 'Tag #' + tagId + ' is not in the NSFP list' }, 404);
|
||||
}
|
||||
|
||||
const updated = current.filter(id => id !== tagId);
|
||||
setNsfpIds(updated);
|
||||
|
||||
await db`
|
||||
INSERT INTO site_settings (key, value)
|
||||
VALUES ('nsfp', ${JSON.stringify(updated)})
|
||||
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
|
||||
`;
|
||||
|
||||
await audit.log(req.session.id, 'nsfp_remove', 'tag', tagId, { nsfp: updated });
|
||||
|
||||
return res.json({ success: true, nsfp_ids: getNsfpIds() });
|
||||
} catch (err) {
|
||||
console.error('[NSFP] Remove failed:', err);
|
||||
return res.json({ success: false, msg: err.message }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
Reference in New Issue
Block a user