Add admin image replies and attachment removal
This commit is contained in:
@@ -77,6 +77,7 @@ async function adminApi(req, res, url) {
|
||||
if (url.pathname === "/api/admin/events" && req.method === "GET") return eventStream(req, res, url, "admin");
|
||||
if (url.pathname === "/api/admin/site" && req.method === "PATCH") return updateSite(req, res);
|
||||
if (url.pathname === "/api/admin/conversations" && req.method === "GET") return adminConversations(res);
|
||||
if (url.pathname.match(/^\/api\/admin\/attachments\/\d+$/) && req.method === "DELETE") return deleteAttachment(res, url);
|
||||
if (url.pathname.match(/^\/api\/admin\/conversations\/[^/]+$/) && req.method === "GET") return adminConversation(res, url);
|
||||
if (url.pathname.match(/^\/api\/admin\/conversations\/[^/]+$/) && req.method === "DELETE") return deleteConversation(res, url);
|
||||
if (url.pathname.match(/^\/api\/admin\/conversations\/[^/]+\/messages$/) && req.method === "POST") return createAdminMessage(req, res, url);
|
||||
@@ -398,17 +399,37 @@ async function createVisitorMessage(req, res, url) {
|
||||
}
|
||||
|
||||
async function createAdminMessage(req, res, url) {
|
||||
const body = await readJson(req, 2_000_000);
|
||||
if (!body.message || !String(body.message).trim()) return json(res, 400, { error: "message_required" });
|
||||
const body = await readJson(req, 8_000_000);
|
||||
if ((!body.message || !String(body.message).trim()) && !(body.attachments || []).length) return json(res, 400, { error: "message_or_image_required" });
|
||||
if (!attachmentsAreAllowed(body.attachments || [])) return json(res, 400, { error: "only_images_allowed" });
|
||||
const conversation = findConversation(publicIdFrom(url));
|
||||
if (!conversation) return json(res, 404, { error: "conversation_not_found" });
|
||||
insertMessage(conversation.id, "admin", req.adminUser.username, String(body.message).trim());
|
||||
const messageId = insertMessage(conversation.id, "admin", req.adminUser.username, String(body.message || "").trim());
|
||||
saveAttachments(conversation.id, messageId, body.attachments || []);
|
||||
bumpConversation(conversation.id, conversation.status === "new" ? "open" : conversation.status);
|
||||
const updated = findConversation(conversation.public_id);
|
||||
publishConversation(updated, { type: "message:new", payload: conversationDetails(updated) });
|
||||
return json(res, 201, conversationDetails(updated));
|
||||
}
|
||||
|
||||
function deleteAttachment(res, url) {
|
||||
const attachmentId = Number(url.pathname.split("/").pop());
|
||||
const attachment = db.prepare(`
|
||||
SELECT a.*, c.public_id
|
||||
FROM attachments a
|
||||
JOIN conversations c ON c.id = a.conversation_id
|
||||
WHERE a.id = ?
|
||||
`).get(attachmentId);
|
||||
if (!attachment) return json(res, 404, { error: "attachment_not_found" });
|
||||
db.prepare("DELETE FROM attachments WHERE id = ?").run(attachmentId);
|
||||
if (attachment.storage_path && path.resolve(attachment.storage_path).startsWith(path.resolve(UPLOAD_DIR))) {
|
||||
fs.rmSync(attachment.storage_path, { force: true });
|
||||
}
|
||||
const conversation = findConversation(attachment.public_id);
|
||||
if (conversation) publishConversation(conversation, { type: "message:new", payload: conversationDetails(conversation) });
|
||||
return json(res, 200, { ok: true });
|
||||
}
|
||||
|
||||
async function visitorTyping(req, res, url) {
|
||||
const conversation = findConversation(publicIdFrom(url));
|
||||
if (!conversation) return json(res, 404, { error: "conversation_not_found" });
|
||||
|
||||
Reference in New Issue
Block a user