add item titles

This commit is contained in:
2026-05-24 23:02:49 +02:00
parent 187f35227b
commit 613f099a8b
13 changed files with 334 additions and 16 deletions

View File

@@ -65,7 +65,7 @@
"cancel_upload": "Cancel Upload",
"shitpost_success": "Successfully shitposted {n} items!",
"shitposting_status": "Uploading",
"item_comment_placeholder": "Comment (optional)...",
"item_comment_placeholder": "Write a Comment...",
"item_tags_placeholder": "Tags...",
"btn_add_urls": "Add URL(s)",
"tags_required_shitpost": "All items need tags",

View File

@@ -657,6 +657,7 @@ export default {
author_avatar: actitem.author_avatar,
author_avatar_file: actitem.author_avatar_file,
author_description: actitem.author_description,
title: actitem.title || null,
src: {
long: actitem.src,

View File

@@ -817,6 +817,33 @@ export default router => {
});
// PATCH /api/v2/items/:id/title — set or clear the title for an item
// Allowed by: item owner, moderators, admins
group.patch(/\/items\/(?<id>\d+)\/title$/, lib.loggedin, async (req, res) => {
const id = +req.params.id;
if (!id) return res.json({ success: false, msg: 'Invalid item id' }, 400);
// Fetch item to check ownership
const rows = await db`SELECT id, username FROM items WHERE id = ${id} AND active = true LIMIT 1`;
if (!rows.length) return res.json({ success: false, msg: 'Item not found' }, 404);
const item = rows[0];
const isOwner = req.session.user === item.username;
const isMod = !!(req.session.is_moderator || req.session.admin);
if (!isOwner && !isMod) return res.json({ success: false, msg: 'Forbidden' }, 403);
// Accept title from JSON or URL-encoded body
let rawTitle = req.post?.title ?? req.body?.title ?? null;
if (rawTitle !== null) rawTitle = String(rawTitle).trim();
// Empty string → null (clears the title)
const title = (rawTitle === '' || rawTitle === null) ? null : rawTitle.substring(0, 500);
await db`UPDATE items SET title = ${title} WHERE id = ${id}`;
return res.json({ success: true, title });
});
group.post(/\/admin\/deletepost$/, lib.modAuth, async (req, res) => {
if (req.post.postid === undefined || req.post.postid === null) {
return res.json({

View File

@@ -204,7 +204,8 @@ export default router => {
return res.json({ success: false, msg: 'URL uploads are disabled' }, 403);
}
const { url: inputUrl, rating, tags: tagsRaw, comment, is_oc, is_shitpost } = req.post || {};
const { url: inputUrl, rating, tags: tagsRaw, comment, is_oc, is_shitpost, title: rawTitle } = req.post || {};
const title = (rawTitle && typeof rawTitle === 'string' && rawTitle.trim()) ? rawTitle.trim().substring(0, 500) : null;
const maxLen = cfg.main.comment_max_length;
if (comment && maxLen !== null && maxLen !== undefined && comment.length > maxLen) {
@@ -280,8 +281,9 @@ export default router => {
usernetwork: 'web',
stamp: ~~(Date.now() / 1000),
active: !isApprovalRequired,
is_oc: !!is_oc
}, 'src', 'dest', 'mime', 'size', 'checksum', 'phash', 'username', 'userchannel', 'usernetwork', 'stamp', 'active', 'is_oc')}
is_oc: !!is_oc,
title: title
}, 'src', 'dest', 'mime', 'size', 'checksum', 'phash', 'username', 'userchannel', 'usernetwork', 'stamp', 'active', 'is_oc', 'title')}
RETURNING id
`;
@@ -564,8 +566,9 @@ export default router => {
usernetwork: 'web',
stamp: ~~(Date.now() / 1000),
active: !isApprovalRequired,
is_oc: !!is_oc
}, 'src', 'dest', 'mime', 'size', 'checksum', 'phash', 'username', 'userchannel', 'usernetwork', 'stamp', 'active', 'is_oc')}
is_oc: !!is_oc,
title: title
}, 'src', 'dest', 'mime', 'size', 'checksum', 'phash', 'username', 'userchannel', 'usernetwork', 'stamp', 'active', 'is_oc', 'title')}
RETURNING id
`;