This commit is contained in:
2026-08-09 02:22:22 +02:00
parent 3179d15b42
commit b10ddac6f3
28 changed files with 689 additions and 66 deletions

View File

@@ -2,12 +2,15 @@ import { promises as fs } from "fs";
import db from '../../sql.mjs';
import lib from '../../lib.mjs';
import cfg from '../../config.mjs';
import { getEnableItemSlugs } from '../../settings.mjs';
import queue from '../../queue.mjs';
import search from '../../routeinc/search.mjs';
import path from "path";
import f0cklib from '../../routeinc/f0cklib.mjs';
import audit from '../../audit.mjs';
import { parseMultipart, collectBody } from '../../multipart.mjs';
import { purgeExpiredUploads } from '../../lib_delete.mjs';
import { calculateExpiresAt } from './upload.mjs';
const allowedMimes = ["audio", "image", "video", "%"];
const getGlobalfilter = () => cfg.nsfp?.length ? cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ') : null;
@@ -638,7 +641,7 @@ export default router => {
items: {
...safeItem,
id: item.id,
slug: item.slug || null,
slug: (getEnableItemSlugs() && item.slug) ? item.slug : null,
dest: relativeDest,
url: directUrl,
direct_url: directUrl
@@ -1229,6 +1232,80 @@ export default router => {
});
});
group.post(/\/items\/(?<id>[0-9]+)\/rethumb$/, lib.loggedin, async (req, res) => {
const itemid = +req.params.id;
if (!itemid) return res.json({ success: false, msg: 'No itemid provided' }, 400);
const rows = await db`
SELECT id, dest, mime, username
FROM items
WHERE id = ${itemid} AND active = true AND is_deleted = false
LIMIT 1
`;
if (!rows.length) return res.json({ success: false, msg: 'Item not found' }, 404);
const item = rows[0];
const isOwner = item.username === req.session.user;
const isAdmin = !!(req.session.admin || req.session.is_moderator);
if (!isOwner && !isAdmin) return res.json({ success: false, msg: 'Unauthorized' }, 403);
const ok = await queue.genThumbnail(item.dest, item.mime, item.id, '', false);
await queue.genBlurredThumbnail(item.id, false);
if (ok) {
db.notify('rethumb', JSON.stringify({ item_id: item.id })).catch(() => {});
audit.log(req.session.id, 'rethumb_item', 'item', item.id, {}).catch(() => {});
return res.json({ success: true, itemid: item.id });
} else {
return res.json({ success: false, msg: 'Thumbnail regeneration failed' }, 500);
}
});
group.post(/\/items\/(?<id>[0-9]+)\/expiry$/, lib.loggedin, async (req, res) => {
if (cfg.enable_expiring_uploads === false || cfg.websrv?.enable_expiring_uploads === false) {
return res.json({ success: false, msg: 'Expiring uploads feature is disabled' }, 403);
}
const itemid = +req.params.id;
if (!itemid) return res.json({ success: false, msg: 'No itemid provided' }, 400);
const rows = await db`
SELECT id, username, expires_at
FROM items
WHERE id = ${itemid} AND active = true AND is_deleted = false
LIMIT 1
`;
if (!rows.length) return res.json({ success: false, msg: 'Item not found' }, 404);
const item = rows[0];
const isOwner = item.username === req.session.user;
const isAdmin = !!(req.session.admin || req.session.is_moderator);
if (!isOwner && !isAdmin) return res.json({ success: false, msg: 'Unauthorized' }, 403);
const reqExpiry = req.body?.expiry ?? req.body?.expires_at ?? req.post?.expiry ?? req.post?.expires_at;
const nowStamp = Math.floor(Date.now() / 1000);
const targetExpiresAt = calculateExpiresAt(reqExpiry, nowStamp);
await db`UPDATE items SET expires_at = ${targetExpiresAt} WHERE id = ${item.id}`;
audit.log(req.session.id, 'set_item_expiry', 'item', item.id, { expires_at: targetExpiresAt }).catch(() => {});
if (targetExpiresAt && targetExpiresAt <= nowStamp) {
await purgeExpiredUploads().catch(err => {
console.error('[API ITEM EXPIRY] Purge failed:', err);
});
}
const expires_in = targetExpiresAt ? lib.expiresIn(targetExpiresAt) : null;
return res.json({
success: true,
itemid: item.id,
expires_at: targetExpiresAt,
expires_in: expires_in,
purged: !!(targetExpiresAt && targetExpiresAt <= nowStamp)
});
});
group.post(/\/item\/(?<id>[0-9]+)\/rating$/, lib.loggedin, async (req, res) => {
const itemid = +req.params.id;
if (!itemid) return res.json({ success: false, msg: 'No itemid provided' }, 400);