import { Guild, GuildCreateEvent, GuildDeleteEvent, GuildMemberAddEvent, GuildMemberRemoveEvent, GuildMemberUpdateEvent, Guild, Member, Role, toObject, User, GuildDocument, Config, emitEvent } from "@fosscord/util"; import { HTTPError } from "lambert-server"; 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 Member.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 Guild.findOneOrFail({ id: guild_id })); if (!guild) throw new HTTPError("Guild not found", 404); if (await Member.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 Member({ ...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(), User.update({ id: user_id }, { $push: { guilds: guild_id } }), Guild.update({ id: guild_id }, { $inc: { member_count: 1 } }), emitEvent({ event: "GUILD_MEMBER_ADD", data: { ...member, user, guild_id: guild_id }, guild_id: guild_id } as GuildMemberAddEvent) ]); await emitEvent({ event: "GUILD_CREATE", data: 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 Guild.findOneOrFail({ id: guild_id }, { owner_id: true }); 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 Member.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([ Member.deleteOne({ id: user_id, guild_id: guild_id }), User.update({ id: user.id }, { $pull: { guilds: guild_id } }), Guild.update({ id: guild_id }, { $inc: { member_count: -1 } }), 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 Role.findOneOrFail({ id: role_id, guild_id: guild_id }); if (!role) throw new HTTPError("role not found", 404); var memberObj = await Member.findOneOrFailAndUpdate( { id: user_id, guild_id: guild_id }, { $push: { roles: role_id } }, { new: true } ); 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 Role.findOneOrFail({ id: role_id, guild_id: guild_id }); if (!role) throw new HTTPError("role not found", 404); var memberObj = await Member.findOneOrFailAndUpdate( { id: user_id, guild_id: guild_id }, { $pull: { roles: role_id } }, { new: true } ); 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 Member.findOneOrFailAndUpdate( { id: user_id, guild_id: guild_id }, { nick: nickname }, { new: true } ); 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); }