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);
});
|