summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
authorDiego Magdaleno <diegomagdaleno@protonmail.com>2021-05-22 15:55:45 -0500
committerDiego Magdaleno <diegomagdaleno@protonmail.com>2021-05-22 15:55:45 -0500
commite4a4759e971387675d127990b53dfd8b3a443d82 (patch)
tree8f4e8101fafc01492ace38a5fa51e32f07b85e1d /src/util
parentConfig: Refactor config to be be in separate classes (diff)
downloadserver-e4a4759e971387675d127990b53dfd8b3a443d82.tar.xz
Fix merge issues, update to reflect config changes and package.json
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Channel.ts54
-rw-r--r--src/util/Member.ts49
-rw-r--r--src/util/Message.ts54
-rw-r--r--src/util/instanceOf.ts17
4 files changed, 142 insertions, 32 deletions
diff --git a/src/util/Channel.ts b/src/util/Channel.ts
new file mode 100644
index 00000000..c8df85bc
--- /dev/null
+++ b/src/util/Channel.ts
@@ -0,0 +1,54 @@
+import {
+	ChannelCreateEvent,
+	ChannelModel,
+	ChannelType,
+	getPermission,
+	GuildModel,
+	Snowflake,
+	TextChannel,
+	VoiceChannel
+} from "@fosscord/server-util";
+import { HTTPError } from "lambert-server";
+import { emitEvent } from "./Event";
+
+// TODO: DM channel
+export async function createChannel(channel: Partial<TextChannel | VoiceChannel>, user_id: string = "0") {
+	if (!channel.permission_overwrites) channel.permission_overwrites = [];
+
+	switch (channel.type) {
+		case ChannelType.GUILD_TEXT:
+		case ChannelType.GUILD_VOICE:
+			break;
+		case ChannelType.DM:
+		case ChannelType.GROUP_DM:
+			throw new HTTPError("You can't create a dm channel in a guild");
+		// TODO: check if guild is community server
+		case ChannelType.GUILD_STORE:
+		case ChannelType.GUILD_NEWS:
+		default:
+			throw new HTTPError("Not yet supported");
+	}
+
+	const permissions = await getPermission(user_id, channel.guild_id);
+	permissions.hasThrow("MANAGE_CHANNELS");
+
+	if (channel.parent_id) {
+		const exists = await ChannelModel.findOne({ id: channel.parent_id }, { guild_id: true }).exec();
+		if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400);
+		if (exists.guild_id !== channel.guild_id) throw new HTTPError("The category channel needs to be in the guild");
+	}
+
+	// TODO: auto generate position
+
+	channel = await new ChannelModel({
+		...channel,
+		id: Snowflake.generate(),
+		created_at: new Date(),
+		// @ts-ignore
+		recipients: null
+	}).save();
+
+	await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent);
+
+	return channel;
+}
diff --git a/src/util/Member.ts b/src/util/Member.ts
index 2842298d..d03a8f12 100644
--- a/src/util/Member.ts
+++ b/src/util/Member.ts
@@ -10,7 +10,7 @@ import {
 	RoleModel,
 	toObject,
 	UserModel,
-	GuildDocument,
+	GuildDocument
 } from "@fosscord/server-util";
 
 import { HTTPError } from "lambert-server";
@@ -27,7 +27,7 @@ export const PublicMemberProjection = {
 	pending: true,
 	deaf: true,
 	mute: true,
-	premium_since: true,
+	premium_since: true
 };
 
 export async function isMember(user_id: string, guild_id: string) {
@@ -59,12 +59,13 @@ export async function addMember(user_id: string, guild_id: string, cache?: { gui
 		premium_since: undefined,
 		deaf: false,
 		mute: false,
-		pending: false,
+		pending: false
 	};
 
 	await Promise.all([
 		new MemberModel({
 			...member,
+			read_state: {},
 			settings: {
 				channel_overrides: [],
 				message_notifications: 0,
@@ -73,8 +74,8 @@ export async function addMember(user_id: string, guild_id: string, cache?: { gui
 				muted: false,
 				suppress_everyone: false,
 				suppress_roles: false,
-				version: 0,
-			},
+				version: 0
+			}
 		}).save(),
 
 		UserModel.updateOne({ id: user_id }, { $push: { guilds: guild_id } }).exec(),
@@ -85,10 +86,10 @@ export async function addMember(user_id: string, guild_id: string, cache?: { gui
 			data: {
 				...member,
 				user,
-				guild_id: guild_id,
+				guild_id: guild_id
 			},
-			guild_id: guild_id,
-		} as GuildMemberAddEvent),
+			guild_id: guild_id
+		} as GuildMemberAddEvent)
 	]);
 
 	await emitEvent({
@@ -99,7 +100,7 @@ export async function addMember(user_id: string, guild_id: string, cache?: { gui
 				.populate({ path: "joined_at", match: { id: user.id } })
 				.execPopulate()
 		),
-		user_id,
+		user_id
 	} as GuildCreateEvent);
 }
 
@@ -115,7 +116,7 @@ export async function removeMember(user_id: string, guild_id: string) {
 	return Promise.all([
 		MemberModel.deleteOne({
 			id: user_id,
-			guild_id: guild_id,
+			guild_id: guild_id
 		}).exec(),
 		UserModel.updateOne({ id: user.id }, { $pull: { guilds: guild_id } }).exec(),
 		GuildModel.updateOne({ id: guild_id }, { $inc: { member_count: -1 } }).exec(),
@@ -123,18 +124,18 @@ export async function removeMember(user_id: string, guild_id: string) {
 		emitEvent({
 			event: "GUILD_DELETE",
 			data: {
-				id: guild_id,
+				id: guild_id
 			},
-			user_id: user_id,
+			user_id: user_id
 		} as GuildDeleteEvent),
 		emitEvent({
 			event: "GUILD_MEMBER_REMOVE",
 			data: {
 				guild_id: guild_id,
-				user: user,
+				user: user
 			},
-			guild_id: guild_id,
-		} as GuildMemberRemoveEvent),
+			guild_id: guild_id
+		} as GuildMemberRemoveEvent)
 	]);
 }
 
@@ -147,7 +148,7 @@ export async function addRole(user_id: string, guild_id: string, role_id: string
 	var memberObj = await MemberModel.findOneAndUpdate(
 		{
 			id: user_id,
-			guild_id: guild_id,
+			guild_id: guild_id
 		},
 		{ $push: { roles: role_id } }
 	).exec();
@@ -159,9 +160,9 @@ export async function addRole(user_id: string, guild_id: string, role_id: string
 		data: {
 			guild_id: guild_id,
 			user: user,
-			roles: memberObj.roles,
+			roles: memberObj.roles
 		},
-		guild_id: guild_id,
+		guild_id: guild_id
 	} as GuildMemberUpdateEvent);
 }
 
@@ -174,7 +175,7 @@ export async function removeRole(user_id: string, guild_id: string, role_id: str
 	var memberObj = await MemberModel.findOneAndUpdate(
 		{
 			id: user_id,
-			guild_id: guild_id,
+			guild_id: guild_id
 		},
 		{ $pull: { roles: role_id } }
 	).exec();
@@ -186,9 +187,9 @@ export async function removeRole(user_id: string, guild_id: string, role_id: str
 		data: {
 			guild_id: guild_id,
 			user: user,
-			roles: memberObj.roles,
+			roles: memberObj.roles
 		},
-		guild_id: guild_id,
+		guild_id: guild_id
 	} as GuildMemberUpdateEvent);
 }
 
@@ -198,7 +199,7 @@ export async function changeNickname(user_id: string, guild_id: string, nickname
 	var memberObj = await MemberModel.findOneAndUpdate(
 		{
 			id: user_id,
-			guild_id: guild_id,
+			guild_id: guild_id
 		},
 		{ nick: nickname }
 	).exec();
@@ -210,8 +211,8 @@ export async function changeNickname(user_id: string, guild_id: string, nickname
 		data: {
 			guild_id: guild_id,
 			user: user,
-			nick: nickname,
+			nick: nickname
 		},
-		guild_id: guild_id,
+		guild_id: guild_id
 	} as GuildMemberUpdateEvent);
 }
diff --git a/src/util/Message.ts b/src/util/Message.ts
new file mode 100644
index 00000000..0d3cdac7
--- /dev/null
+++ b/src/util/Message.ts
@@ -0,0 +1,54 @@
+import { ChannelModel, MessageCreateEvent } from "@fosscord/server-util";
+import { Snowflake } from "@fosscord/server-util";
+import { MessageModel } from "@fosscord/server-util";
+import { PublicMemberProjection } from "@fosscord/server-util";
+import { toObject } from "@fosscord/server-util";
+import { getPermission } from "@fosscord/server-util";
+import { Message } from "@fosscord/server-util";
+import { HTTPError } from "lambert-server";
+import { emitEvent } from "./Event";
+// TODO: check webhook, application, system author
+
+export async function handleMessage(opts: Partial<Message>) {
+	const channel = await ChannelModel.findOne({ id: opts.channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec();
+	if (!channel || !opts.channel_id) throw new HTTPError("Channel not found", 404);
+	// TODO: are tts messages allowed in dm channels? should permission be checked?
+
+	const permissions = await getPermission(opts.author_id, channel.guild_id, opts.channel_id, { channel });
+	permissions.hasThrow("SEND_MESSAGES");
+	if (opts.tts) permissions.hasThrow("SEND_TTS_MESSAGES");
+	if (opts.message_reference) {
+		permissions.hasThrow("READ_MESSAGE_HISTORY");
+		if (opts.message_reference.guild_id !== channel.guild_id) throw new HTTPError("You can only reference messages from this guild");
+	}
+
+	if (opts.message_reference) {
+		if (opts.message_reference.channel_id !== opts.channel_id) throw new HTTPError("You can only reference messages from this channel");
+		// TODO: should be checked if the referenced message exists?
+	}
+
+	// TODO: check and put it all in the body
+	return {
+		...opts,
+		guild_id: channel.guild_id,
+		channel_id: opts.channel_id,
+		// TODO: generate mentions and check permissions
+		mention_channels_ids: [],
+		mention_role_ids: [],
+		mention_user_ids: [],
+		attachments: [], // TODO: message attachments
+		embeds: opts.embeds || [],
+		reactions: opts.reactions || [],
+		type: opts.type ?? 0
+	};
+}
+
+export async function sendMessage(opts: Partial<Message>) {
+	const message = await handleMessage({ ...opts, id: Snowflake.generate(), timestamp: new Date() });
+
+	const data = toObject(await new MessageModel(message).populate({ path: "member", select: PublicMemberProjection }).save());
+
+	await emitEvent({ event: "MESSAGE_CREATE", channel_id: opts.channel_id, data, guild_id: message.guild_id } as MessageCreateEvent);
+
+	return data;
+}
diff --git a/src/util/instanceOf.ts b/src/util/instanceOf.ts
index e4e58092..b67bde27 100644
--- a/src/util/instanceOf.ts
+++ b/src/util/instanceOf.ts
@@ -5,7 +5,8 @@ import { Tuple } from "lambert-server";
 import "missing-native-js-functions";
 
 export const OPTIONAL_PREFIX = "$";
-export const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+export const EMAIL_REGEX =
+	/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
 
 export function check(schema: any) {
 	return (req: Request, res: Response, next: NextFunction) => {
@@ -27,9 +28,9 @@ export function FieldErrors(fields: Record<string, { code?: string; message: str
 			_errors: [
 				{
 					message,
-					code: code || "BASE_TYPE_INVALID",
-				},
-			],
+					code: code || "BASE_TYPE_INVALID"
+				}
+			]
 		}))
 	);
 }
@@ -68,7 +69,7 @@ export function instanceOf(
 		optional = false,
 		errors = {},
 		req,
-		ref,
+		ref
 	}: { path?: string; optional?: boolean; errors?: any; req: Request; ref?: { key: string | number; obj: any } }
 ): Boolean {
 	if (!ref) ref = { obj: null, key: "" };
@@ -131,7 +132,7 @@ export function instanceOf(
 								optional,
 								errors: errors[i],
 								req,
-								ref: { key: i, obj: value },
+								ref: { key: i, obj: value }
 							}) === true
 						) {
 							delete errors[i];
@@ -153,7 +154,7 @@ export function instanceOf(
 					throw new FieldError(
 						"BASE_TYPE_BAD_LENGTH",
 						req.t("common:field.BASE_TYPE_BAD_LENGTH", {
-							length: `${type.min} - ${type.max}`,
+							length: `${type.min} - ${type.max}`
 						})
 					);
 				}
@@ -185,7 +186,7 @@ export function instanceOf(
 							optional: OPTIONAL,
 							errors: errors[newKey],
 							req,
-							ref: { key: newKey, obj: value },
+							ref: { key: newKey, obj: value }
 						}) === true
 					) {
 						delete errors[newKey];