summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--api/src/routes/channels/#channel_id/messages/#message_id/index.ts86
-rw-r--r--api/src/util/handlers/Message.ts3
2 files changed, 87 insertions, 2 deletions
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
index a27c71e1..6d2bf185 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -1,5 +1,18 @@
-import { Channel, emitEvent, getPermission, getRights, MessageDeleteEvent, Message, MessageUpdateEvent } from "@fosscord/util";
+import {
+	Attachment,
+	Channel,
+	Embed,
+	emitEvent,
+	getPermission,
+	getRights,
+ 	Message,
+	MessageCreateEvent,
+	MessageDeleteEvent,
+	MessageUpdateEvent,
+	uploadFile 
+} from "@fosscord/util";
 import { Router, Response, Request } from "express";
+import multer from "multer";
 import { route } from "@fosscord/api";
 import { handleMessage, postHandleMessage } from "@fosscord/api";
 import { MessageCreateSchema } from "../index";
@@ -7,6 +20,15 @@ import { MessageCreateSchema } from "../index";
 const router = Router();
 // TODO: message content/embed string length limit
 
+const messageUpload = multer({
+	limits: {
+		fileSize: 1024 * 1024 * 100,
+		fields: 10,
+		files: 1
+	},
+	storage: multer.memoryStorage()
+}); // max upload 50 mb
+
 router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
 	const { message_id, channel_id } = req.params;
 	var body = req.body as MessageCreateSchema;
@@ -51,6 +73,68 @@ router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGE
 	return res.json(message);
 });
 
+
+// Backfill message with specific timestamp
+router.put(
+	"/",
+	messageUpload.single("file"),
+	async (req, res, next) => {
+		if (req.body.payload_json) {
+			req.body = JSON.parse(req.body.payload_json);
+		}
+
+		next();
+	},
+	route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_BACKDATED_EVENTS" }),
+	async (req: Request, res: Response) => {
+		const { channel_id, message_id } = req.params;
+		var body = req.body as MessageCreateSchema;
+		const attachments: Attachment[] = [];
+
+		if (req.file) {
+			try {
+				const file = await uploadFile(`/attachments/${req.params.channel_id}`, req.file);
+				attachments.push({ ...file, proxy_url: file.url });
+			} catch (error) {
+				return res.status(400).json(error);
+			}
+		}
+		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] });
+		
+		// TODO: check the ID is not from the future, to prevent future-faking of channel histories
+
+		const embeds = body.embeds || [];
+		if (body.embed) embeds.push(body.embed);
+		let message = await handleMessage({
+			...body,
+			type: 0,
+			pinned: false,
+			author_id: req.user_id,
+			id: message_id,
+			embeds,
+			channel_id,
+			attachments,
+			edited_timestamp: undefined,
+			timestamp: undefined, // FIXME: calculate timestamp from snowflake
+		});
+
+		channel.last_message_id = message.id;
+
+		//Fix for the client bug
+		delete message.member
+		
+		await Promise.all([
+			message.save(),
+			emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
+			channel.save()
+		]);
+
+		postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
+
+		return res.json(message);
+	}
+);
+
 router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
 	const { message_id, channel_id } = req.params;
 
diff --git a/api/src/util/handlers/Message.ts b/api/src/util/handlers/Message.ts
index 5a5ac666..e9f0ac55 100644
--- a/api/src/util/handlers/Message.ts
+++ b/api/src/util/handlers/Message.ts
@@ -91,7 +91,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 				if (opts.message_reference.channel_id !== opts.channel_id) throw new HTTPError("You can only reference messages from this channel");
 			}
 		}
-		// Q: should be checked if the referenced message exists? ANSWER: NO
+		/** Q: should be checked if the referenced message exists? ANSWER: NO
+		 otherwise backfilling won't work **/
 		// @ts-ignore
 		message.type = MessageType.REPLY;
 	}