summary refs log tree commit diff
path: root/src/routes/channels/#channel_id/messages/index.ts
blob: 7fdff809df62c57147728ad3e0b6619fb9092778 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { Router } from "express";
import {
	ChannelModel,
	ChannelType,
	getPermission,
	Message,
	MessageCreateEvent,
	MessageDocument,
	MessageModel,
	Snowflake,
	toObject
} from "@fosscord/server-util";
import { HTTPError } from "lambert-server";
import { MessageCreateSchema } from "../../../../schema/Message";
import { check, instanceOf, Length } from "../../../../util/instanceOf";
import { PublicUserProjection } from "../../../../util/User";
import multer from "multer";
import { emitEvent } from "../../../../util/Event";
import { Query } from "mongoose";
import { PublicMemberProjection } from "../../../../util/Member";
import { sendMessage } from "../../../../util/Message";
const router: Router = Router();

export default router;

export function isTextChannel(type: ChannelType): boolean {
	switch (type) {
		case ChannelType.GUILD_VOICE:
		case ChannelType.GUILD_CATEGORY:
			throw new HTTPError("not a text channel", 400);
		case ChannelType.DM:
		case ChannelType.GROUP_DM:
		case ChannelType.GUILD_NEWS:
		case ChannelType.GUILD_STORE:
		case ChannelType.GUILD_TEXT:
			return true;
	}
}

// https://discord.com/developers/docs/resources/channel#create-message
// get messages
router.get("/", async (req, res) => {
	const channel_id = req.params.channel_id;
	const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec();
	if (!channel) throw new HTTPError("Channel not found", 404);

	isTextChannel(channel.type);

	try {
		instanceOf({ $around: String, $after: String, $before: String, $limit: new Length(Number, 1, 100) }, req.query, {
			path: "query",
			req
		});
	} catch (error) {
		return res.status(400).json({ code: 50035, message: "Invalid Query", success: false, errors: error });
	}
	var { around, after, before, limit }: { around?: string; after?: string; before?: string; limit?: number } = req.query;
	if (!limit) limit = 50;
	var halfLimit = Math.floor(limit / 2);

	const permissions = await getPermission(req.user_id, channel.guild_id, channel_id, { channel });
	permissions.hasThrow("VIEW_CHANNEL");
	if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);

	var query: Query<MessageDocument[], MessageDocument>;
	if (after) query = MessageModel.find({ channel_id, id: { $gt: after } });
	else if (before) query = MessageModel.find({ channel_id, id: { $lt: before } });
	else if (around)
		query = MessageModel.find({
			channel_id,
			id: { $gt: (BigInt(around) - BigInt(halfLimit)).toString(), $lt: (BigInt(around) + BigInt(halfLimit)).toString() }
		});
	else {
		query = MessageModel.find({ channel_id }).sort({ id: -1 });
	}

	const messages = await query.limit(limit).exec();

	return res.json(
		toObject(messages).map((x) => {
			(x.reactions || []).forEach((x) => {
				// @ts-ignore
				if ((x.user_ids || []).includes(req.user_id)) x.me = true;
				// @ts-ignore
				delete x.user_ids;
			});

			return x;
		})
	);
});

// TODO: config max upload size
const messageUpload = multer({ limits: { fieldSize: 1024 * 1024 * 1024 * 50 } }); // max upload 50 mb

// TODO: dynamically change limit of MessageCreateSchema with config
// TODO: check: sum of all characters in an embed structure must not exceed 6000 characters

// https://discord.com/developers/docs/resources/channel#create-message
// TODO: text channel slowdown
// TODO: trim and replace message content and every embed field
// Send message
router.post("/", check(MessageCreateSchema), async (req, res) => {
	const { channel_id } = req.params;
	const body = req.body as MessageCreateSchema;

	const embeds = [];
	if (body.embed) embeds.push(body.embed);
	const data = await sendMessage({ ...body, type: 0, pinned: false, author_id: req.user_id, embeds, channel_id });

	return res.send(data);
});