diff options
author | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-09-03 03:37:55 +0200 |
---|---|---|
committer | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-09-03 03:37:55 +0200 |
commit | 36fe0ec0c8022cbbde23eb87ca00906629255de6 (patch) | |
tree | 43dba167ea6e790ac271b05710c41a539a0fd0d3 | |
parent | fix #309 (diff) | |
download | server-36fe0ec0c8022cbbde23eb87ca00906629255de6.tar.xz |
:bug: fix member + member list
-rw-r--r-- | api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts | 2 | ||||
-rw-r--r-- | api/src/routes/channels/#channel_id/permissions.ts | 2 | ||||
-rw-r--r-- | api/src/routes/channels/#channel_id/typing.ts | 2 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/bans.ts | 1 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/index.ts | 4 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/members/#member_id/index.ts | 4 | ||||
-rw-r--r-- | api/src/routes/guilds/index.ts | 84 | ||||
-rw-r--r-- | api/src/routes/guilds/templates/index.ts | 2 | ||||
-rw-r--r-- | api/src/routes/users/@me/channels.ts | 2 | ||||
-rw-r--r-- | api/src/routes/users/@me/delete.ts | 2 | ||||
-rw-r--r-- | api/src/routes/users/@me/guilds.ts | 4 | ||||
-rw-r--r-- | api/src/schema/Message.ts | 78 | ||||
-rw-r--r-- | gateway/src/events/Close.ts | 1 | ||||
-rw-r--r-- | gateway/src/listener/listener.ts | 44 | ||||
-rw-r--r-- | gateway/src/opcodes/Identify.ts | 14 | ||||
-rw-r--r-- | gateway/src/opcodes/LazyRequest.ts | 93 |
16 files changed, 183 insertions, 156 deletions
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts index 37168940..f60484b5 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -136,7 +136,7 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => { await Message.update({ id: message_id, channel_id }, message); - const member = channel.guild_id && (await Member.findOneOrFail({ user_id: req.user_id })); + const member = channel.guild_id && (await Member.findOneOrFail({ id: req.user_id })); await emitEvent({ event: "MESSAGE_REACTION_ADD", diff --git a/api/src/routes/channels/#channel_id/permissions.ts b/api/src/routes/channels/#channel_id/permissions.ts index 97f21659..9c49542b 100644 --- a/api/src/routes/channels/#channel_id/permissions.ts +++ b/api/src/routes/channels/#channel_id/permissions.ts @@ -20,7 +20,7 @@ router.put("/:overwrite_id", check({ allow: String, deny: String, type: Number, if (body.type === 0) { if (!(await Role.count({ id: overwrite_id }))) throw new HTTPError("role not found", 404); } else if (body.type === 1) { - if (!(await Member.count({ user_id: overwrite_id }))) throw new HTTPError("user not found", 404); + if (!(await Member.count({ id: overwrite_id }))) throw new HTTPError("user not found", 404); } else throw new HTTPError("type not supported", 501); // @ts-ignore diff --git a/api/src/routes/channels/#channel_id/typing.ts b/api/src/routes/channels/#channel_id/typing.ts index aef99103..f1fb3c86 100644 --- a/api/src/routes/channels/#channel_id/typing.ts +++ b/api/src/routes/channels/#channel_id/typing.ts @@ -10,7 +10,7 @@ router.post("/", async (req: Request, res: Response) => { const user_id = req.user_id; const timestamp = Date.now(); const channel = await Channel.findOneOrFail({ id: channel_id }); - const member = await Member.findOneOrFail({ user_id: user_id }); + const member = await Member.findOneOrFail({ id: user_id }); await emitEvent({ event: "TYPING_START", diff --git a/api/src/routes/guilds/#guild_id/bans.ts b/api/src/routes/guilds/#guild_id/bans.ts index b84a68a7..31aa2385 100644 --- a/api/src/routes/guilds/#guild_id/bans.ts +++ b/api/src/routes/guilds/#guild_id/bans.ts @@ -3,7 +3,6 @@ import { emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, import { HTTPError } from "lambert-server"; import { getIpAdress } from "../../../util/ipAddress"; import { BanCreateSchema } from "../../../schema/Ban"; - import { check } from "../../../util/instanceOf"; const router: Router = Router(); diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index 80b5c609..567898dd 100644 --- a/api/src/routes/guilds/#guild_id/index.ts +++ b/api/src/routes/guilds/#guild_id/index.ts @@ -14,8 +14,8 @@ router.get("/", async (req: Request, res: Response) => { const [guild, member_count, member] = await Promise.all([ Guild.findOneOrFail({ id: guild_id }), - Member.count({ guild_id: guild_id, user_id: req.user_id }), - Member.findOneOrFail({ user_id: req.user_id }) + Member.count({ guild_id: guild_id, id: req.user_id }), + Member.findOneOrFail({ id: req.user_id }) ]); if (!member_count) throw new HTTPError("You are not a member of the guild you are trying to access", 401); diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts index 733a64c4..8b74a524 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts @@ -21,7 +21,7 @@ router.get("/", async (req: Request, res: Response) => { const { guild_id, member_id } = req.params; await Member.IsInGuildOrFail(req.user_id, guild_id); - const member = await Member.findOneOrFail({ user_id: member_id, guild_id }); + const member = await Member.findOneOrFail({ id: member_id, guild_id }); return res.json(member); }); @@ -39,7 +39,7 @@ router.patch("/", check(MemberChangeSchema), async (req: Request, res: Response) permission.hasThrow("MANAGE_ROLES"); } - const member = await Member.findOneOrFail({ user_id: member_id, guild_id }); + const member = await Member.findOneOrFail({ id: member_id, guild_id }); member.assign(req.body); Promise.all([ diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts index a87f926c..51dcf96a 100644 --- a/api/src/routes/guilds/index.ts +++ b/api/src/routes/guilds/index.ts @@ -13,54 +13,54 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) = const body = req.body as GuildCreateSchema; const { maxGuilds } = Config.get().limits.user; - const guild_count = await Member.count({ user_id: req.user_id }); + const guild_count = await Member.count({ id: req.user_id }); if (guild_count >= maxGuilds) { throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); } const guild_id = Snowflake.generate(); - const [guild, role] = await Promise.all([ - new Guild({ - name: body.name, - region: Config.get().regions.default, - owner_id: req.user_id, - afk_timeout: 300, - default_message_notifications: 0, - explicit_content_filter: 0, - features: [], - id: guild_id, - max_members: 250000, - max_presences: 250000, - max_video_channel_users: 25, - presence_count: 0, - member_count: 0, // will automatically be increased by addMember() - mfa_level: 0, - preferred_locale: "en-US", - premium_subscription_count: 0, - premium_tier: 0, - system_channel_flags: 0, - unavailable: false, - verification_level: 0, - welcome_screen: { - enabled: false, - description: "No description", - welcome_channels: [] - }, - widget_enabled: false - }).save(), - new Role({ - id: guild_id, - guild_id: guild_id, - color: 0, - hoist: false, - managed: false, - mentionable: false, - name: "@everyone", - permissions: String("2251804225"), - position: 0 - }).save() - ]); + const guild = await new Guild({ + name: body.name, + region: Config.get().regions.default, + owner_id: req.user_id, + afk_timeout: 300, + default_message_notifications: 0, + explicit_content_filter: 0, + features: [], + id: guild_id, + max_members: 250000, + max_presences: 250000, + max_video_channel_users: 25, + presence_count: 0, + member_count: 0, // will automatically be increased by addMember() + mfa_level: 0, + preferred_locale: "en-US", + premium_subscription_count: 0, + premium_tier: 0, + system_channel_flags: 0, + unavailable: false, + verification_level: 0, + welcome_screen: { + enabled: false, + description: "No description", + welcome_channels: [] + }, + widget_enabled: false + }).save(); + + // we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error + const role = await new Role({ + id: guild_id, + guild_id: guild_id, + color: 0, + hoist: false, + managed: false, + mentionable: false, + name: "@everyone", + permissions: String("2251804225"), + position: 0 + }).save(); if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general" }]; diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts index 16b65c65..3a619278 100644 --- a/api/src/routes/guilds/templates/index.ts +++ b/api/src/routes/guilds/templates/index.ts @@ -20,7 +20,7 @@ router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res const { maxGuilds } = Config.get().limits.user; - const guild_count = await Member.count({ user_id: req.user_id }); + const guild_count = await Member.count({ id: req.user_id }); if (guild_count >= maxGuilds) { throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); } diff --git a/api/src/routes/users/@me/channels.ts b/api/src/routes/users/@me/channels.ts index 880e09c1..6fd396b8 100644 --- a/api/src/routes/users/@me/channels.ts +++ b/api/src/routes/users/@me/channels.ts @@ -10,7 +10,7 @@ import { Recipient } from "../../../../../util/dist/entities/Recipient"; const router: Router = Router(); router.get("/", async (req: Request, res: Response) => { - const recipients = await Recipient.find({ where: { id: req.user_id }, relations: ["channel"] }); + const recipients = await Recipient.find({ where: { user_id: req.user_id }, relations: ["channel"] }); res.json(recipients.map((x) => x.channel)); }); diff --git a/api/src/routes/users/@me/delete.ts b/api/src/routes/users/@me/delete.ts index e3b54607..e5fda948 100644 --- a/api/src/routes/users/@me/delete.ts +++ b/api/src/routes/users/@me/delete.ts @@ -19,7 +19,7 @@ router.post("/", async (req: Request, res: Response) => { // TODO: decrement guild member count if (correctpass) { - await Promise.all([User.delete({ id: req.user_id }), Member.delete({ user_id: req.user_id })]); + await Promise.all([User.delete({ id: req.user_id }), Member.delete({ id: req.user_id })]); res.sendStatus(204); } else { diff --git a/api/src/routes/users/@me/guilds.ts b/api/src/routes/users/@me/guilds.ts index 1edb0eb1..fb88281b 100644 --- a/api/src/routes/users/@me/guilds.ts +++ b/api/src/routes/users/@me/guilds.ts @@ -6,7 +6,7 @@ import { In } from "typeorm"; const router: Router = Router(); router.get("/", async (req: Request, res: Response) => { - const members = await Member.find({ relations: ["guild"], where: { user_id: req.user_id } }); + const members = await Member.find({ relations: ["guild"], where: { id: req.user_id } }); res.json(members.map((x) => x.guild)); }); @@ -20,7 +20,7 @@ router.delete("/:id", async (req: Request, res: Response) => { if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400); await Promise.all([ - Member.delete({ user_id: req.user_id, guild_id: guild_id }), + Member.delete({ id: req.user_id, guild_id: guild_id }), emitEvent({ event: "GUILD_DELETE", data: { diff --git a/api/src/schema/Message.ts b/api/src/schema/Message.ts index 742542df..d39f685a 100644 --- a/api/src/schema/Message.ts +++ b/api/src/schema/Message.ts @@ -7,48 +7,52 @@ export const EmbedImage = { $height: Number }; +const embed = { + $title: new Length(String, 0, 256), //title of embed + $type: String, // type of embed (always "rich" for webhook embeds) + $description: new Length(String, 0, 2048), // description of embed + $url: String, // url of embed + $timestamp: String, // ISO8601 timestamp + $color: Number, // color code of the embed + $footer: { + text: new Length(String, 0, 2048), + icon_url: String, + proxy_icon_url: String + }, // footer object footer information + $image: EmbedImage, // image object image information + $thumbnail: EmbedImage, // thumbnail object thumbnail information + $video: EmbedImage, // video object video information + $provider: { + name: String, + url: String + }, // provider object provider information + $author: { + name: new Length(String, 0, 256), + url: String, + icon_url: String, + proxy_icon_url: String + }, // author object author information + $fields: new Length( + [ + { + name: new Length(String, 0, 256), + value: new Length(String, 0, 1024), + $inline: Boolean + } + ], + 0, + 25 + ) +}; + export const MessageCreateSchema = { $content: new Length(String, 0, 2000), $nonce: String, $tts: Boolean, $flags: String, - $embed: { - $title: new Length(String, 0, 256), //title of embed - $type: String, // type of embed (always "rich" for webhook embeds) - $description: new Length(String, 0, 2048), // description of embed - $url: String, // url of embed - $timestamp: String, // ISO8601 timestamp - $color: Number, // color code of the embed - $footer: { - text: new Length(String, 0, 2048), - icon_url: String, - proxy_icon_url: String - }, // footer object footer information - $image: EmbedImage, // image object image information - $thumbnail: EmbedImage, // thumbnail object thumbnail information - $video: EmbedImage, // video object video information - $provider: { - name: String, - url: String - }, // provider object provider information - $author: { - name: new Length(String, 0, 256), - url: String, - icon_url: String, - proxy_icon_url: String - }, // author object author information - $fields: new Length( - [ - { - name: new Length(String, 0, 256), - value: new Length(String, 0, 1024), - $inline: Boolean - } - ], - 0, - 25 - ) - }, + $embed: embed, + // TODO: ^ embed is deprecated in favor of embeds (https://discord.com/developers/docs/resources/channel#message-object) + // $embeds: [embed], $allowed_mentions: { $parse: [String], $roles: [String], diff --git a/gateway/src/events/Close.ts b/gateway/src/events/Close.ts index d68fc751..b4fed316 100644 --- a/gateway/src/events/Close.ts +++ b/gateway/src/events/Close.ts @@ -3,6 +3,7 @@ import { Message } from "./Message"; import { Session } from "@fosscord/util"; export async function Close(this: WebSocket, code: number, reason: string) { + console.log("[WebSocket] closed", code, reason); await Session.delete({ session_id: this.session_id }); // @ts-ignore this.off("message", Message); diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts index 67837e8d..0b6fa50c 100644 --- a/gateway/src/listener/listener.ts +++ b/gateway/src/listener/listener.ts @@ -26,15 +26,20 @@ import { Recipient } from "../../../util/dist/entities/Recipient"; // TODO: use already queried guilds/channels of Identify and don't fetch them again export async function setupListener(this: WebSocket) { - const members = await Member.find({ user_id: this.user_id }); + const members = await Member.find({ id: this.user_id }); const guild_ids = members.map((x) => x.guild_id); const user = await User.findOneOrFail({ id: this.user_id }); - const recipients = await Recipient.find({ where: { id: this.user_id }, relations: ["channel"] }); + const recipients = await Recipient.find({ + where: { user_id: this.user_id }, + relations: ["channel"], + }); const channels = await Channel.find({ guild_id: In(guild_ids) }); const dm_channels = recipients.map((x) => x.channel); const guild_channels = channels.filter((x) => x.guild_id); - const opts: { acknowledge: boolean; channel?: AMQChannel } = { acknowledge: true }; + const opts: { acknowledge: boolean; channel?: AMQChannel } = { + acknowledge: true, + }; const consumer = consume.bind(this); if (RabbitMQ.connection) { @@ -58,13 +63,25 @@ export async function setupListener(this: WebSocket) { this.listeners; this.events[guild] = await listenEvent(guild, consumer, opts); - for (const channel of guild_channels.filter((c) => c.guild_id === guild)) { - if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) { - this.events[channel.id] = await listenEvent(channel.id, consumer, opts); + for (const channel of guild_channels.filter( + (c) => c.guild_id === guild + )) { + if ( + x + .overwriteChannel(channel.permission_overwrites) + .has("VIEW_CHANNEL") + ) { + this.events[channel.id] = await listenEvent( + channel.id, + consumer, + opts + ); } } }) - .catch((e) => console.log("couldn't get permission for guild " + guild, e)); + .catch((e) => + console.log("couldn't get permission for guild " + guild, e) + ); } this.once("close", () => { @@ -91,7 +108,12 @@ async function consume(this: WebSocket, opts: EventOpts) { opts.cancel(); break; case "CHANNEL_CREATE": - if (!permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) return; + if ( + !permission + .overwriteChannel(data.permission_overwrites) + .has("VIEW_CHANNEL") + ) + return; // TODO: check if user has permission to channel case "GUILD_CREATE": this.events[id] = await listenEvent(id, consumer, listenOpts); @@ -99,7 +121,11 @@ async function consume(this: WebSocket, opts: EventOpts) { case "CHANNEL_UPDATE": const exists = this.events[id]; // @ts-ignore - if (permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) { + if ( + permission + .overwriteChannel(data.permission_overwrites) + .has("VIEW_CHANNEL") + ) { if (exists) break; this.events[id] = await listenEvent(id, consumer, listenOpts); } else { diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index 73c9a29e..2b2c31c5 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -57,8 +57,16 @@ export async function onIdentify(this: WebSocket, data: Payload) { } const members = await Member.find({ - where: { user_id: this.user_id }, - relations: ["guild", "guild.channels", "guild.emojis", "guild.roles", "guild.stickers", "user", "roles"], + where: { id: this.user_id }, + relations: [ + "guild", + "guild.channels", + "guild.emojis", + "guild.roles", + "guild.stickers", + "user", + "roles", + ], }); const merged_members = members.map((x: any) => { return [x]; @@ -67,7 +75,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { const user_guild_settings_entries = members.map((x) => x.settings); const recipients = await Recipient.find({ - where: { id: this.user_id }, + where: { user_id: this.user_id }, relations: ["channel", "channel.recipients"], }); const channels = recipients.map((x) => x.channel); diff --git a/gateway/src/opcodes/LazyRequest.ts b/gateway/src/opcodes/LazyRequest.ts index 146175b5..e035e6bb 100644 --- a/gateway/src/opcodes/LazyRequest.ts +++ b/gateway/src/opcodes/LazyRequest.ts @@ -1,13 +1,19 @@ -// @ts-nocheck WIP -import { db, getPermission, PublicUserProjection, toObject } from "@fosscord/util"; +import { + getPermission, + Member, + PublicMemberProjection, + PublicUserProjection, + Role, +} from "@fosscord/util"; import { LazyRequest } from "../schema/LazyRequest"; import { OPCODES, Payload } from "../util/Constants"; import { Send } from "../util/Send"; import WebSocket from "../util/WebSocket"; import { check } from "./instanceOf"; +import "missing-native-js-functions"; // TODO: check permission and only show roles/members that have access to this channel -// TODO: config: if want to list all members (even those who are offline) sorted by role, or just those who are online +// TODO: config: to list all members (even those who are offline) sorted by role, or just those who are online // TODO: rewrite typeorm export async function onLazyRequest(this: WebSocket, { d }: Payload) { @@ -18,60 +24,43 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) { const permissions = await getPermission(this.user_id, guild_id); permissions.hasThrow("VIEW_CHANNEL"); - // MongoDB query to retrieve all hoisted roles and join them with the members and users collection - const roles = await db - .collection("roles") - .aggregate([ - { - $match: { - guild_id, - // hoist: true // TODO: also match @everyone role - }, - }, - { $sort: { position: 1 } }, - { - $lookup: { - from: "members", - let: { id: "$id" }, - pipeline: [ - { $match: { $expr: { $in: ["$$id", "$roles"] } } }, - { $limit: 100 }, - { - $lookup: { - from: "users", - let: { user_id: "$id" }, - pipeline: [ - { $match: { $expr: { $eq: ["$id", "$$user_id"] } } }, - { $project: PublicUserProjection }, - ], - as: "user", - }, - }, - { - $unwind: "$user", - }, - ], - as: "members", - }, - }, - ]) - .toArray(); + var members = await Member.find({ + where: { guild_id: guild_id }, + relations: ["roles", "user"], + select: PublicMemberProjection, + }); + + const roles = await Role.find({ + where: { guild_id: guild_id }, + order: { + position: "ASC", + }, + }); - const groups = roles.map((x) => ({ id: x.id === guild_id ? "online" : x.id, count: x.members.length })); - const member_count = roles.reduce((a, b) => b.members.length + a, 0); + const groups = [] as any[]; + var member_count = 0; const items = []; for (const role of roles) { - items.push({ - group: { - count: role.members.length, - id: role.id === guild_id ? "online" : role.name, - }, - }); - for (const member of role.members) { - member.roles.remove(guild_id); - items.push({ member }); + const [role_members, other_members] = members.partition((m) => + m.roles.find((r) => r.id === role.id) + ); + const group = { + count: role_members.length, + id: role.id === guild_id ? "online" : role.name, + }; + + items.push({ group }); + groups.push(group); + + for (const member of role_members) { + member.roles = member.roles.filter((x) => x.id !== guild_id); + items.push({ + member: { ...member, roles: member.roles.map((x) => x.id) }, + }); } + members = other_members; + member_count += role_members.length; } return Send(this, { |