diff options
Diffstat (limited to 'api/src/util/Member.ts')
-rw-r--r-- | api/src/util/Member.ts | 218 |
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); +} |