diff options
-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/index.ts | 4 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/members/#member_id/index.ts | 10 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/widget.json.ts | 2 | ||||
-rw-r--r-- | api/src/routes/guilds/index.ts | 2 | ||||
-rw-r--r-- | api/src/routes/guilds/templates/index.ts | 2 | ||||
-rw-r--r-- | api/src/routes/users/#id/profile.ts | 10 | ||||
-rw-r--r-- | api/src/routes/users/@me/delete.ts | 11 | ||||
-rw-r--r-- | api/src/routes/users/@me/guilds.ts | 4 | ||||
-rw-r--r-- | api/src/routes/users/@me/profile.ts | 27 | ||||
-rw-r--r-- | gateway/src/listener/listener.ts | 2 | ||||
-rw-r--r-- | gateway/src/opcodes/Identify.ts | 2 | ||||
-rw-r--r-- | gateway/src/opcodes/LazyRequest.ts | 1 | ||||
-rw-r--r-- | util/src/entities/Member.ts | 63 | ||||
-rw-r--r-- | util/src/util/Permissions.ts | 2 |
17 files changed, 68 insertions, 80 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 f60484b5..37168940 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({ id: req.user_id })); + const member = channel.guild_id && (await Member.findOneOrFail({ user_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 9c49542b..97f21659 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({ id: overwrite_id }))) throw new HTTPError("user not found", 404); + if (!(await Member.count({ user_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 f1fb3c86..aef99103 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({ id: user_id }); + const member = await Member.findOneOrFail({ user_id: user_id }); await emitEvent({ event: "TYPING_START", diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index 6f55be3b..80b5c609 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 }, id: req.user_id }), - Member.findOneOrFail({ id: req.user_id }) + Member.count({ guild_id: guild_id, user_id: req.user_id }), + Member.findOneOrFail({ user_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 d9ce91c0..733a64c4 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({ id: member_id, guild_id }); + const member = await Member.findOneOrFail({ user_id: member_id, guild_id }); return res.json(member); }); @@ -29,13 +29,17 @@ router.get("/", async (req: Request, res: Response) => { router.patch("/", check(MemberChangeSchema), async (req: Request, res: Response) => { const { guild_id, member_id } = req.params; const body = req.body as MemberChangeSchema; + + const permission = await getPermission(req.user_id, guild_id); + if (body.roles) { const roles = await Role.find({ id: In(body.roles) }); if (body.roles.length !== roles.length) throw new HTTPError("Roles not found", 404); - // TODO: check if user has permission to add role + + permission.hasThrow("MANAGE_ROLES"); } - const member = await Member.findOneOrFail({ id: member_id, guild_id }); + const member = await Member.findOneOrFail({ user_id: member_id, guild_id }); member.assign(req.body); Promise.all([ diff --git a/api/src/routes/guilds/#guild_id/widget.json.ts b/api/src/routes/guilds/#guild_id/widget.json.ts index ae1f0599..193ed095 100644 --- a/api/src/routes/guilds/#guild_id/widget.json.ts +++ b/api/src/routes/guilds/#guild_id/widget.json.ts @@ -63,7 +63,7 @@ router.get("/", async (req: Request, res: Response) => { // Fetch members // TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file) - let members = await Member.find({ where: { guild_id: guild_id } }); + let members = await Member.find({ guild_id: guild_id }); // Construct object to respond with const data = { diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts index a54b83ba..92525317 100644 --- a/api/src/routes/guilds/index.ts +++ b/api/src/routes/guilds/index.ts @@ -13,7 +13,7 @@ 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({ id: req.user_id }); + const guild_count = await Member.count({ user_id: req.user_id }); if (guild_count >= maxGuilds) { throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); } diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts index 3a619278..16b65c65 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({ id: req.user_id }); + const guild_count = await Member.count({ user_id: req.user_id }); if (guild_count >= maxGuilds) { throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); } diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts index afccfed5..8be03b47 100644 --- a/api/src/routes/users/#id/profile.ts +++ b/api/src/routes/users/#id/profile.ts @@ -1,9 +1,10 @@ import { Router, Request, Response } from "express"; -import { User } from "../../../../../util/dist"; +import { PublicConnectedAccount, PublicUser, User, UserPublic } from "../../../../../util/dist"; const router: Router = Router(); router.get("/", async (req: Request, res: Response) => { + if (req.params.id === "@me") req.params.id = req.user_id; const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] }); res.json({ @@ -24,4 +25,11 @@ router.get("/", async (req: Request, res: Response) => { }); }); +export interface UserProfileResponse { + user: UserPublic; + connected_accounts: PublicConnectedAccount; + premium_guild_since?: Date; + premium_since?: Date; +} + export default router; diff --git a/api/src/routes/users/@me/delete.ts b/api/src/routes/users/@me/delete.ts index 6bfe0b93..e3b54607 100644 --- a/api/src/routes/users/@me/delete.ts +++ b/api/src/routes/users/@me/delete.ts @@ -1,6 +1,7 @@ import { Router, Request, Response } from "express"; import { Guild, Member, User } from "@fosscord/util"; import bcrypt from "bcrypt"; +import { HTTPError } from "lambert-server"; const router = Router(); router.post("/", async (req: Request, res: Response) => { @@ -9,16 +10,16 @@ router.post("/", async (req: Request, res: Response) => { if (user.data.hash) { // guest accounts can delete accounts without password - correctpass = await bcrypt.compare(req.body.password, user.data.hash); //Not sure if user typed right password :/ + correctpass = await bcrypt.compare(req.body.password, user.data.hash); + if (!correctpass) { + throw new HTTPError(req.t("auth:login.INVALID_PASSWORD")); + } } // TODO: decrement guild member count if (correctpass) { - await Promise.all([ - User.delete({ id: req.user_id }), //Yeetus user deletus - Member.delete({ id: req.user_id }) - ]); + await Promise.all([User.delete({ id: req.user_id }), Member.delete({ user_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 fb88281b..1edb0eb1 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: { id: req.user_id } }); + const members = await Member.find({ relations: ["guild"], where: { user_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({ id: req.user_id, guild_id: guild_id }), + Member.delete({ user_id: req.user_id, guild_id: guild_id }), emitEvent({ event: "GUILD_DELETE", data: { diff --git a/api/src/routes/users/@me/profile.ts b/api/src/routes/users/@me/profile.ts deleted file mode 100644 index 5ba03c68..00000000 --- a/api/src/routes/users/@me/profile.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Router, Request, Response } from "express"; -import { User } from "../../../../../util/dist"; - -const router: Router = Router(); - -router.get("/", async (req: Request, res: Response) => { - const user = await User.getPublicUser(req.user_id, { relations: ["connected_accounts"] }); - - res.json({ - connected_accounts: user.connected_accounts, - premium_guild_since: null, // TODO - premium_since: null, // TODO - user: { - username: user.username, - discriminator: user.discriminator, - id: user.id, - public_flags: user.public_flags, - avatar: user.avatar, - accent_color: user.accent_color, - banner: user.banner, - bio: user.bio, - bot: user.bot - } - }); -}); - -export default router; diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts index 75ca1680..67837e8d 100644 --- a/gateway/src/listener/listener.ts +++ b/gateway/src/listener/listener.ts @@ -26,7 +26,7 @@ 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({ where: { id: this.user_id } }); + const members = await Member.find({ user_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"] }); diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index 958f1b73..4a1b7a45 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -56,7 +56,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { } const members = await Member.find({ - where: { id: this.user_id }, + where: { user_id: this.user_id }, relations: ["guild", "guild.channels", "guild.emojis", "guild.roles", "guild.stickers", "user", "roles"], }); const merged_members = members.map((x: any) => { diff --git a/gateway/src/opcodes/LazyRequest.ts b/gateway/src/opcodes/LazyRequest.ts index 9f514f5f..146175b5 100644 --- a/gateway/src/opcodes/LazyRequest.ts +++ b/gateway/src/opcodes/LazyRequest.ts @@ -8,6 +8,7 @@ import { check } from "./instanceOf"; // 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: rewrite typeorm export async function onLazyRequest(this: WebSocket, { d }: Payload) { // TODO: check data diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index e1773730..e0dd411a 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -1,6 +1,6 @@ import { PublicUser, User } from "./User"; import { BaseClass } from "./BaseClass"; -import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm"; +import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm"; import { Guild } from "./Guild"; import { Config, emitEvent } from "../util"; import { @@ -12,15 +12,19 @@ import { } from "../interfaces"; import { HTTPError } from "lambert-server"; import { Role } from "./Role"; -import { ReadState } from "./ReadState"; @Entity("members") +@Index(["user_id", "guild_id"], { unique: true }) export class Member extends BaseClass { - @JoinColumn({ name: "id" }) + @Column() + @RelationId((member: Member) => member.user) + user_id: string; + + @JoinColumn({ name: "user_id" }) @ManyToOne(() => User) user: User; - @Column({ nullable: true }) + @Column() @RelationId((member: Member) => member.guild) guild_id: string; @@ -58,20 +62,20 @@ export class Member extends BaseClass { // read_state: ReadState; static async IsInGuildOrFail(user_id: string, guild_id: string) { - if (await Member.count({ id: user_id, guild: { id: guild_id } })) return true; + if (await Member.count({ user_id: user_id, guild: { id: guild_id } })) return true; throw new HTTPError("You are not member of this guild", 403); } static async removeFromGuild(user_id: string, guild_id: string) { const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } }); if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild"); - const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"] }); + const member = await Member.findOneOrFail({ where: { user_id, guild_id }, relations: ["user"] }); // use promise all to execute all promises at the same time -> save time return Promise.all([ Member.delete({ - id: user_id, - guild_id: guild_id, + user_id, + guild_id, }), Guild.decrement({ id: guild_id }, "member_count", -1), @@ -84,11 +88,8 @@ export class Member extends BaseClass { } as GuildDeleteEvent), emitEvent({ event: "GUILD_MEMBER_REMOVE", - data: { - guild_id: guild_id, - user: member.user, - }, - guild_id: guild_id, + data: { guild_id, user: member.user }, + guild_id, } as GuildMemberRemoveEvent), ]); } @@ -97,11 +98,11 @@ export class Member extends BaseClass { const [member] = await Promise.all([ // @ts-ignore Member.findOneOrFail({ - where: { id: user_id, guild_id: guild_id }, + where: { user_id: user_id, guild_id }, relations: ["user", "roles"], // we don't want to load the role objects just the ids select: ["roles.id"], }), - await Role.findOneOrFail({ id: role_id, guild_id: guild_id }), + await Role.findOneOrFail({ id: role_id, guild_id }), ]); member.roles.push(new Role({ id: role_id })); @@ -110,11 +111,11 @@ export class Member extends BaseClass { emitEvent({ event: "GUILD_MEMBER_UPDATE", data: { - guild_id: guild_id, + guild_id, user: member.user, roles: member.roles.map((x) => x.id), }, - guild_id: guild_id, + guild_id, } as GuildMemberUpdateEvent), ]); } @@ -123,11 +124,11 @@ export class Member extends BaseClass { const [member] = await Promise.all([ // @ts-ignore Member.findOneOrFail({ - where: { id: user_id, guild_id: guild_id }, + where: { user_id, guild_id }, relations: ["user", "roles"], // we don't want to load the role objects just the ids select: ["roles.id"], }), - await Role.findOneOrFail({ id: role_id, guild_id: guild_id }), + await Role.findOneOrFail({ id: role_id, guild_id }), ]); member.roles = member.roles.filter((x) => x.id == role_id); @@ -136,11 +137,11 @@ export class Member extends BaseClass { emitEvent({ event: "GUILD_MEMBER_UPDATE", data: { - guild_id: guild_id, + guild_id, user: member.user, roles: member.roles.map((x) => x.id), }, - guild_id: guild_id, + guild_id, } as GuildMemberUpdateEvent), ]); } @@ -148,8 +149,8 @@ export class Member extends BaseClass { static async changeNickname(user_id: string, guild_id: string, nickname: string) { const member = await Member.findOneOrFail({ where: { - id: user_id, - guild_id: guild_id, + user_id: user_id, + guild_id, }, relations: ["user"], }); @@ -161,11 +162,11 @@ export class Member extends BaseClass { emitEvent({ event: "GUILD_MEMBER_UPDATE", data: { - guild_id: guild_id, + guild_id, user: member.user, nick: nickname, }, - guild_id: guild_id, + guild_id, } as GuildMemberUpdateEvent), ]); } @@ -174,7 +175,7 @@ export class Member extends BaseClass { const user = await User.getPublicUser(user_id); const { maxGuilds } = Config.get().limits.user; - const guild_count = await Member.count({ id: user_id }); + const guild_count = await Member.count({ user_id: user_id }); if (guild_count >= maxGuilds) { throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403); } @@ -186,12 +187,12 @@ export class Member extends BaseClass { relations: ["channels", "emojis", "members", "roles", "stickers"], }); - if (await Member.count({ id: user.id, guild: { id: guild_id } })) + if (await Member.count({ user_id: user.id, guild: { id: guild_id } })) throw new HTTPError("You are already a member of this guild", 400); const member = { - id: user_id, - guild_id: guild_id, + user_id, + guild_id, nick: undefined, roles: [guild_id], // @everyone role joined_at: new Date(), @@ -224,9 +225,9 @@ export class Member extends BaseClass { data: { ...member, user, - guild_id: guild_id, + guild_id, }, - guild_id: guild_id, + guild_id, } as GuildMemberAddEvent), emitEvent({ event: "GUILD_CREATE", diff --git a/util/src/util/Permissions.ts b/util/src/util/Permissions.ts index 89b316ee..fcf1546b 100644 --- a/util/src/util/Permissions.ts +++ b/util/src/util/Permissions.ts @@ -220,7 +220,7 @@ export async function getPermission(user_id?: string, guild_id?: string, channel guild = await Guild.findOneOrFail({ id: guild_id }); if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR); - member = await Member.findOneOrFail({ where: { guild: guild_id, id: user_id }, relations: ["roles"] }); + member = await Member.findOneOrFail({ where: { guild_id, user_id }, relations: ["roles"] }); } // TODO: remove guild.roles and convert recipient_ids to recipients |