add user_id field to Member

This commit is contained in:
Flam3rboy 2021-09-02 19:50:05 +02:00
parent c410fbcc0d
commit 562a53d6bb
17 changed files with 68 additions and 80 deletions

View File

@ -136,7 +136,7 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => {
await Message.update({ id: message_id, channel_id }, message); 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({ await emitEvent({
event: "MESSAGE_REACTION_ADD", event: "MESSAGE_REACTION_ADD",

View File

@ -20,7 +20,7 @@ router.put("/:overwrite_id", check({ allow: String, deny: String, type: Number,
if (body.type === 0) { if (body.type === 0) {
if (!(await Role.count({ id: overwrite_id }))) throw new HTTPError("role not found", 404); if (!(await Role.count({ id: overwrite_id }))) throw new HTTPError("role not found", 404);
} else if (body.type === 1) { } 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); } else throw new HTTPError("type not supported", 501);
// @ts-ignore // @ts-ignore

View File

@ -10,7 +10,7 @@ router.post("/", async (req: Request, res: Response) => {
const user_id = req.user_id; const user_id = req.user_id;
const timestamp = Date.now(); const timestamp = Date.now();
const channel = await Channel.findOneOrFail({ id: channel_id }); 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({ await emitEvent({
event: "TYPING_START", event: "TYPING_START",

View File

@ -14,8 +14,8 @@ router.get("/", async (req: Request, res: Response) => {
const [guild, member_count, member] = await Promise.all([ const [guild, member_count, member] = await Promise.all([
Guild.findOneOrFail({ id: guild_id }), Guild.findOneOrFail({ id: guild_id }),
Member.count({ guild: { id: guild_id }, id: req.user_id }), Member.count({ guild_id: guild_id, user_id: req.user_id }),
Member.findOneOrFail({ 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); if (!member_count) throw new HTTPError("You are not a member of the guild you are trying to access", 401);

View File

@ -21,7 +21,7 @@ router.get("/", async (req: Request, res: Response) => {
const { guild_id, member_id } = req.params; const { guild_id, member_id } = req.params;
await Member.IsInGuildOrFail(req.user_id, guild_id); 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); return res.json(member);
}); });
@ -29,13 +29,17 @@ router.get("/", async (req: Request, res: Response) => {
router.patch("/", check(MemberChangeSchema), async (req: Request, res: Response) => { router.patch("/", check(MemberChangeSchema), async (req: Request, res: Response) => {
const { guild_id, member_id } = req.params; const { guild_id, member_id } = req.params;
const body = req.body as MemberChangeSchema; const body = req.body as MemberChangeSchema;
const permission = await getPermission(req.user_id, guild_id);
if (body.roles) { if (body.roles) {
const roles = await Role.find({ id: In(body.roles) }); const roles = await Role.find({ id: In(body.roles) });
if (body.roles.length !== roles.length) throw new HTTPError("Roles not found", 404); 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); member.assign(req.body);
Promise.all([ Promise.all([

View File

@ -63,7 +63,7 @@ router.get("/", async (req: Request, res: Response) => {
// Fetch members // Fetch members
// TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file) // 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 // Construct object to respond with
const data = { const data = {

View File

@ -13,7 +13,7 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) =
const body = req.body as GuildCreateSchema; const body = req.body as GuildCreateSchema;
const { maxGuilds } = Config.get().limits.user; 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) { if (guild_count >= maxGuilds) {
throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
} }

View File

@ -20,7 +20,7 @@ router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res
const { maxGuilds } = Config.get().limits.user; 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) { if (guild_count >= maxGuilds) {
throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
} }

View File

@ -1,9 +1,10 @@
import { Router, Request, Response } from "express"; import { Router, Request, Response } from "express";
import { User } from "../../../../../util/dist"; import { PublicConnectedAccount, PublicUser, User, UserPublic } from "../../../../../util/dist";
const router: Router = Router(); const router: Router = Router();
router.get("/", async (req: Request, res: Response) => { 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"] }); const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] });
res.json({ 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; export default router;

View File

@ -1,6 +1,7 @@
import { Router, Request, Response } from "express"; import { Router, Request, Response } from "express";
import { Guild, Member, User } from "@fosscord/util"; import { Guild, Member, User } from "@fosscord/util";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { HTTPError } from "lambert-server";
const router = Router(); const router = Router();
router.post("/", async (req: Request, res: Response) => { router.post("/", async (req: Request, res: Response) => {
@ -9,16 +10,16 @@ router.post("/", async (req: Request, res: Response) => {
if (user.data.hash) { if (user.data.hash) {
// guest accounts can delete accounts without password // 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 // TODO: decrement guild member count
if (correctpass) { if (correctpass) {
await Promise.all([ await Promise.all([User.delete({ id: req.user_id }), Member.delete({ user_id: req.user_id })]);
User.delete({ id: req.user_id }), //Yeetus user deletus
Member.delete({ id: req.user_id })
]);
res.sendStatus(204); res.sendStatus(204);
} else { } else {

View File

@ -6,7 +6,7 @@ import { In } from "typeorm";
const router: Router = Router(); const router: Router = Router();
router.get("/", async (req: Request, res: Response) => { 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)); 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); if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
await Promise.all([ 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({ emitEvent({
event: "GUILD_DELETE", event: "GUILD_DELETE",
data: { data: {

View File

@ -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;

View File

@ -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 // TODO: use already queried guilds/channels of Identify and don't fetch them again
export async function setupListener(this: WebSocket) { 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 guild_ids = members.map((x) => x.guild_id);
const user = await User.findOneOrFail({ id: this.user_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: { id: this.user_id }, relations: ["channel"] });

View File

@ -56,7 +56,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
} }
const members = await Member.find({ 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"], relations: ["guild", "guild.channels", "guild.emojis", "guild.roles", "guild.stickers", "user", "roles"],
}); });
const merged_members = members.map((x: any) => { const merged_members = members.map((x: any) => {

View File

@ -8,6 +8,7 @@ import { check } from "./instanceOf";
// TODO: check permission and only show roles/members that have access to this channel // 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: 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) { export async function onLazyRequest(this: WebSocket, { d }: Payload) {
// TODO: check data // TODO: check data

View File

@ -1,6 +1,6 @@
import { PublicUser, User } from "./User"; import { PublicUser, User } from "./User";
import { BaseClass } from "./BaseClass"; 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 { Guild } from "./Guild";
import { Config, emitEvent } from "../util"; import { Config, emitEvent } from "../util";
import { import {
@ -12,15 +12,19 @@ import {
} from "../interfaces"; } from "../interfaces";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { Role } from "./Role"; import { Role } from "./Role";
import { ReadState } from "./ReadState";
@Entity("members") @Entity("members")
@Index(["user_id", "guild_id"], { unique: true })
export class Member extends BaseClass { export class Member extends BaseClass {
@JoinColumn({ name: "id" }) @Column()
@RelationId((member: Member) => member.user)
user_id: string;
@JoinColumn({ name: "user_id" })
@ManyToOne(() => User) @ManyToOne(() => User)
user: User; user: User;
@Column({ nullable: true }) @Column()
@RelationId((member: Member) => member.guild) @RelationId((member: Member) => member.guild)
guild_id: string; guild_id: string;
@ -58,20 +62,20 @@ export class Member extends BaseClass {
// read_state: ReadState; // read_state: ReadState;
static async IsInGuildOrFail(user_id: string, guild_id: string) { 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); throw new HTTPError("You are not member of this guild", 403);
} }
static async removeFromGuild(user_id: string, guild_id: string) { static async removeFromGuild(user_id: string, guild_id: string) {
const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } }); 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"); 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 // use promise all to execute all promises at the same time -> save time
return Promise.all([ return Promise.all([
Member.delete({ Member.delete({
id: user_id, user_id,
guild_id: guild_id, guild_id,
}), }),
Guild.decrement({ id: guild_id }, "member_count", -1), Guild.decrement({ id: guild_id }, "member_count", -1),
@ -84,11 +88,8 @@ export class Member extends BaseClass {
} as GuildDeleteEvent), } as GuildDeleteEvent),
emitEvent({ emitEvent({
event: "GUILD_MEMBER_REMOVE", event: "GUILD_MEMBER_REMOVE",
data: { data: { guild_id, user: member.user },
guild_id: guild_id, guild_id,
user: member.user,
},
guild_id: guild_id,
} as GuildMemberRemoveEvent), } as GuildMemberRemoveEvent),
]); ]);
} }
@ -97,11 +98,11 @@ export class Member extends BaseClass {
const [member] = await Promise.all([ const [member] = await Promise.all([
// @ts-ignore // @ts-ignore
Member.findOneOrFail({ 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 relations: ["user", "roles"], // we don't want to load the role objects just the ids
select: ["roles.id"], 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 })); member.roles.push(new Role({ id: role_id }));
@ -110,11 +111,11 @@ export class Member extends BaseClass {
emitEvent({ emitEvent({
event: "GUILD_MEMBER_UPDATE", event: "GUILD_MEMBER_UPDATE",
data: { data: {
guild_id: guild_id, guild_id,
user: member.user, user: member.user,
roles: member.roles.map((x) => x.id), roles: member.roles.map((x) => x.id),
}, },
guild_id: guild_id, guild_id,
} as GuildMemberUpdateEvent), } as GuildMemberUpdateEvent),
]); ]);
} }
@ -123,11 +124,11 @@ export class Member extends BaseClass {
const [member] = await Promise.all([ const [member] = await Promise.all([
// @ts-ignore // @ts-ignore
Member.findOneOrFail({ 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 relations: ["user", "roles"], // we don't want to load the role objects just the ids
select: ["roles.id"], 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); member.roles = member.roles.filter((x) => x.id == role_id);
@ -136,11 +137,11 @@ export class Member extends BaseClass {
emitEvent({ emitEvent({
event: "GUILD_MEMBER_UPDATE", event: "GUILD_MEMBER_UPDATE",
data: { data: {
guild_id: guild_id, guild_id,
user: member.user, user: member.user,
roles: member.roles.map((x) => x.id), roles: member.roles.map((x) => x.id),
}, },
guild_id: guild_id, guild_id,
} as GuildMemberUpdateEvent), } as GuildMemberUpdateEvent),
]); ]);
} }
@ -148,8 +149,8 @@ export class Member extends BaseClass {
static async changeNickname(user_id: string, guild_id: string, nickname: string) { static async changeNickname(user_id: string, guild_id: string, nickname: string) {
const member = await Member.findOneOrFail({ const member = await Member.findOneOrFail({
where: { where: {
id: user_id, user_id: user_id,
guild_id: guild_id, guild_id,
}, },
relations: ["user"], relations: ["user"],
}); });
@ -161,11 +162,11 @@ export class Member extends BaseClass {
emitEvent({ emitEvent({
event: "GUILD_MEMBER_UPDATE", event: "GUILD_MEMBER_UPDATE",
data: { data: {
guild_id: guild_id, guild_id,
user: member.user, user: member.user,
nick: nickname, nick: nickname,
}, },
guild_id: guild_id, guild_id,
} as GuildMemberUpdateEvent), } as GuildMemberUpdateEvent),
]); ]);
} }
@ -174,7 +175,7 @@ export class Member extends BaseClass {
const user = await User.getPublicUser(user_id); const user = await User.getPublicUser(user_id);
const { maxGuilds } = Config.get().limits.user; 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) { if (guild_count >= maxGuilds) {
throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403); 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"], 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); throw new HTTPError("You are already a member of this guild", 400);
const member = { const member = {
id: user_id, user_id,
guild_id: guild_id, guild_id,
nick: undefined, nick: undefined,
roles: [guild_id], // @everyone role roles: [guild_id], // @everyone role
joined_at: new Date(), joined_at: new Date(),
@ -224,9 +225,9 @@ export class Member extends BaseClass {
data: { data: {
...member, ...member,
user, user,
guild_id: guild_id, guild_id,
}, },
guild_id: guild_id, guild_id,
} as GuildMemberAddEvent), } as GuildMemberAddEvent),
emitEvent({ emitEvent({
event: "GUILD_CREATE", event: "GUILD_CREATE",

View File

@ -220,7 +220,7 @@ export async function getPermission(user_id?: string, guild_id?: string, channel
guild = await Guild.findOneOrFail({ id: guild_id }); guild = await Guild.findOneOrFail({ id: guild_id });
if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR); 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 // TODO: remove guild.roles and convert recipient_ids to recipients