summary refs log tree commit diff
path: root/api/src/util/Member.ts
diff options
context:
space:
mode:
Diffstat (limited to 'api/src/util/Member.ts')
-rw-r--r--api/src/util/Member.ts218
1 files changed, 218 insertions, 0 deletions
diff --git a/api/src/util/Member.ts b/api/src/util/Member.ts
new file mode 100644
index 00000000..7b06720b
--- /dev/null
+++ b/api/src/util/Member.ts
@@ -0,0 +1,218 @@
+import {
+	Guild,
+	GuildCreateEvent,
+	GuildDeleteEvent,
+	GuildMemberAddEvent,
+	GuildMemberRemoveEvent,
+	GuildMemberUpdateEvent,
+	GuildModel,
+	MemberModel,
+	RoleModel,
+	toObject,
+	UserModel,
+	GuildDocument,
+	Config
+} from "@fosscord/server-util";
+
+import { HTTPError } from "lambert-server";
+import { emitEvent } from "./Event";
+import { getPublicUser } from "./User";
+
+export const PublicMemberProjection = {
+	id: true,
+	guild_id: true,
+	nick: true,
+	roles: true,
+	joined_at: true,
+	pending: true,
+	deaf: true,
+	mute: true,
+	premium_since: true
+};
+
+export async function isMember(user_id: string, guild_id: string) {
+	const exists = await MemberModel.exists({ id: user_id, guild_id });
+	if (!exists) throw new HTTPError("You are not a member of this guild", 403);
+	return exists;
+}
+
+export async function addMember(user_id: string, guild_id: string, cache?: { guild?: GuildDocument }) {
+	const user = await getPublicUser(user_id, { guilds: true });
+
+	const { maxGuilds } = Config.get().limits.user;
+	if (user.guilds.length >= maxGuilds) {
+		throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403);
+	}
+
+	const guild = cache?.guild || (await GuildModel.findOne({ id: guild_id }).exec());
+
+	if (!guild) throw new HTTPError("Guild not found", 404);
+
+	if (await MemberModel.exists({ id: user.id, guild_id })) throw new HTTPError("You are already a member of this guild", 400);
+
+	const member = {
+		id: user_id,
+		guild_id: guild_id,
+		nick: undefined,
+		roles: [guild_id], // @everyone role
+		joined_at: new Date(),
+		premium_since: undefined,
+		deaf: false,
+		mute: false,
+		pending: false
+	};
+
+	await Promise.all([
+		new MemberModel({
+			...member,
+			read_state: {},
+			settings: {
+				channel_overrides: [],
+				message_notifications: 0,
+				mobile_push: true,
+				mute_config: null,
+				muted: false,
+				suppress_everyone: false,
+				suppress_roles: false,
+				version: 0
+			}
+		}).save(),
+
+		UserModel.updateOne({ id: user_id }, { $push: { guilds: guild_id } }).exec(),
+		GuildModel.updateOne({ id: guild_id }, { $inc: { member_count: 1 } }).exec(),
+
+		emitEvent({
+			event: "GUILD_MEMBER_ADD",
+			data: {
+				...member,
+				user,
+				guild_id: guild_id
+			},
+			guild_id: guild_id
+		} as GuildMemberAddEvent)
+	]);
+
+	await emitEvent({
+		event: "GUILD_CREATE",
+		data: toObject(
+			await guild
+				.populate({ path: "members", match: { guild_id } })
+				.populate({ path: "joined_at", match: { id: user.id } })
+				.execPopulate()
+		),
+		user_id
+	} as GuildCreateEvent);
+}
+
+export async function removeMember(user_id: string, guild_id: string) {
+	const user = await getPublicUser(user_id);
+
+	const guild = await GuildModel.findOne({ id: guild_id }, { owner_id: true }).exec();
+	if (!guild) throw new HTTPError("Guild not found", 404);
+	if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild");
+	if (!(await MemberModel.exists({ id: user.id, guild_id }))) throw new HTTPError("Is not member of this guild", 404);
+
+	// use promise all to execute all promises at the same time -> save time
+	return Promise.all([
+		MemberModel.deleteOne({
+			id: user_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(),
+
+		emitEvent({
+			event: "GUILD_DELETE",
+			data: {
+				id: guild_id
+			},
+			user_id: user_id
+		} as GuildDeleteEvent),
+		emitEvent({
+			event: "GUILD_MEMBER_REMOVE",
+			data: {
+				guild_id: guild_id,
+				user: user
+			},
+			guild_id: guild_id
+		} as GuildMemberRemoveEvent)
+	]);
+}
+
+export async function addRole(user_id: string, guild_id: string, role_id: string) {
+	const user = await getPublicUser(user_id);
+
+	const role = await RoleModel.findOne({ id: role_id, guild_id: guild_id }).exec();
+	if (!role) throw new HTTPError("role not found", 404);
+
+	var memberObj = await MemberModel.findOneAndUpdate(
+		{
+			id: user_id,
+			guild_id: guild_id
+		},
+		{ $push: { roles: role_id } }
+	).exec();
+
+	if (!memberObj) throw new HTTPError("Member not found", 404);
+
+	await emitEvent({
+		event: "GUILD_MEMBER_UPDATE",
+		data: {
+			guild_id: guild_id,
+			user: user,
+			roles: memberObj.roles
+		},
+		guild_id: guild_id
+	} as GuildMemberUpdateEvent);
+}
+
+export async function removeRole(user_id: string, guild_id: string, role_id: string) {
+	const user = await getPublicUser(user_id);
+
+	const role = await RoleModel.findOne({ id: role_id, guild_id: guild_id }).exec();
+	if (!role) throw new HTTPError("role not found", 404);
+
+	var memberObj = await MemberModel.findOneAndUpdate(
+		{
+			id: user_id,
+			guild_id: guild_id
+		},
+		{ $pull: { roles: role_id } }
+	).exec();
+
+	if (!memberObj) throw new HTTPError("Member not found", 404);
+
+	await emitEvent({
+		event: "GUILD_MEMBER_UPDATE",
+		data: {
+			guild_id: guild_id,
+			user: user,
+			roles: memberObj.roles
+		},
+		guild_id: guild_id
+	} as GuildMemberUpdateEvent);
+}
+
+export async function changeNickname(user_id: string, guild_id: string, nickname: string) {
+	const user = await getPublicUser(user_id);
+
+	var memberObj = await MemberModel.findOneAndUpdate(
+		{
+			id: user_id,
+			guild_id: guild_id
+		},
+		{ nick: nickname }
+	).exec();
+
+	if (!memberObj) throw new HTTPError("Member not found", 404);
+
+	await emitEvent({
+		event: "GUILD_MEMBER_UPDATE",
+		data: {
+			guild_id: guild_id,
+			user: user,
+			nick: nickname
+		},
+		guild_id: guild_id
+	} as GuildMemberUpdateEvent);
+}