diff options
author | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-08-12 20:09:35 +0200 |
---|---|---|
committer | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-08-12 20:09:35 +0200 |
commit | 524b5df7231635682053d0c028b0a24189b875ab (patch) | |
tree | 38bdb481e6149a825170cb67cb961410de92efdd /api/src/routes/users | |
parent | npm i @fosscord/server-util@1.3.52 (diff) | |
download | server-524b5df7231635682053d0c028b0a24189b875ab.tar.xz |
:sparkles: api
Diffstat (limited to 'api/src/routes/users')
-rw-r--r-- | api/src/routes/users/#id/index.ts | 13 | ||||
-rw-r--r-- | api/src/routes/users/#id/profile.ts | 27 | ||||
-rw-r--r-- | api/src/routes/users/@me/affinities/guilds.ts | 10 | ||||
-rw-r--r-- | api/src/routes/users/@me/affinities/user.ts | 10 | ||||
-rw-r--r-- | api/src/routes/users/@me/channels.ts | 53 | ||||
-rw-r--r-- | api/src/routes/users/@me/delete.ts | 22 | ||||
-rw-r--r-- | api/src/routes/users/@me/disable.ts | 20 | ||||
-rw-r--r-- | api/src/routes/users/@me/guilds.ts | 55 | ||||
-rw-r--r-- | api/src/routes/users/@me/index.ts | 48 | ||||
-rw-r--r-- | api/src/routes/users/@me/library.ts | 10 | ||||
-rw-r--r-- | api/src/routes/users/@me/profile.ts | 27 | ||||
-rw-r--r-- | api/src/routes/users/@me/relationships.ts | 176 | ||||
-rw-r--r-- | api/src/routes/users/@me/settings.ts | 10 |
13 files changed, 481 insertions, 0 deletions
diff --git a/api/src/routes/users/#id/index.ts b/api/src/routes/users/#id/index.ts new file mode 100644 index 00000000..a2ad3ae6 --- /dev/null +++ b/api/src/routes/users/#id/index.ts @@ -0,0 +1,13 @@ +import { Router, Request, Response } from "express"; +import { getPublicUser } from "../../../util/User"; +import { HTTPError } from "lambert-server"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + const { id } = req.params; + + res.json(await getPublicUser(id)); +}); + +export default router; diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts new file mode 100644 index 00000000..4b4b9439 --- /dev/null +++ b/api/src/routes/users/#id/profile.ts @@ -0,0 +1,27 @@ +import { Router, Request, Response } from "express"; +import { getPublicUser } from "../../../util/User"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + const user = await getPublicUser(req.params.id, { user_data: true }) + + res.json({ + connected_accounts: user.user_data.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: req.user_bot ? null : user.bio, + bot: user.bot, + } + }); +}); + +export default router; diff --git a/api/src/routes/users/@me/affinities/guilds.ts b/api/src/routes/users/@me/affinities/guilds.ts new file mode 100644 index 00000000..fa6be0e7 --- /dev/null +++ b/api/src/routes/users/@me/affinities/guilds.ts @@ -0,0 +1,10 @@ +import { Router, Response, Request } from "express"; + +const router = Router(); + +router.get("/", (req: Request, res: Response) => { + // TODO: + res.status(200).send({ guild_affinities: [] }); +}); + +export default router; diff --git a/api/src/routes/users/@me/affinities/user.ts b/api/src/routes/users/@me/affinities/user.ts new file mode 100644 index 00000000..0790a8a4 --- /dev/null +++ b/api/src/routes/users/@me/affinities/user.ts @@ -0,0 +1,10 @@ +import { Router, Response, Request } from "express"; + +const router = Router(); + +router.get("/", (req: Request, res: Response) => { + // TODO: + res.status(200).send({ user_affinities: [], inverse_user_affinities: [] }); +}); + +export default router; diff --git a/api/src/routes/users/@me/channels.ts b/api/src/routes/users/@me/channels.ts new file mode 100644 index 00000000..a425a25f --- /dev/null +++ b/api/src/routes/users/@me/channels.ts @@ -0,0 +1,53 @@ +import { Router, Request, Response } from "express"; +import { + ChannelModel, + ChannelCreateEvent, + toObject, + ChannelType, + Snowflake, + trimSpecial, + Channel, + DMChannel, + UserModel +} from "@fosscord/server-util"; +import { HTTPError } from "lambert-server"; +import { emitEvent } from "../../../util/Event"; +import { DmChannelCreateSchema } from "../../../schema/Channel"; +import { check } from "../../../util/instanceOf"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + var channels = await ChannelModel.find({ recipient_ids: req.user_id }).exec(); + + res.json(toObject(channels)); +}); + +router.post("/", check(DmChannelCreateSchema), async (req: Request, res: Response) => { + const body = req.body as DmChannelCreateSchema; + + body.recipients = body.recipients.filter((x) => x !== req.user_id).unique(); + + if (!(await Promise.all(body.recipients.map((x) => UserModel.exists({ id: x })))).every((x) => x)) { + throw new HTTPError("Recipient not found"); + } + + const type = body.recipients.length === 1 ? ChannelType.DM : ChannelType.GROUP_DM; + const name = trimSpecial(body.name); + + const channel = await new ChannelModel({ + name, + type, + owner_id: req.user_id, + id: Snowflake.generate(), + created_at: new Date(), + last_message_id: null, + recipient_ids: [...body.recipients, req.user_id] + }).save(); + + await emitEvent({ event: "CHANNEL_CREATE", data: toObject(channel), user_id: req.user_id } as ChannelCreateEvent); + + res.json(toObject(channel)); +}); + +export default router; diff --git a/api/src/routes/users/@me/delete.ts b/api/src/routes/users/@me/delete.ts new file mode 100644 index 00000000..edda8e2d --- /dev/null +++ b/api/src/routes/users/@me/delete.ts @@ -0,0 +1,22 @@ +import { Router, Request, Response } from "express"; +import { GuildModel, MemberModel, UserModel } from "@fosscord/server-util"; +import bcrypt from "bcrypt"; +const router = Router(); + +router.post("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }).exec(); //User object + + let correctpass = await bcrypt.compare(req.body.password, user!.user_data.hash); //Not sure if user typed right password :/ + if (correctpass) { + await Promise.all([ + UserModel.deleteOne({ id: req.user_id }).exec(), //Yeetus user deletus + MemberModel.deleteMany({ id: req.user_id }).exec() + ]); + + res.sendStatus(204); + } else { + res.sendStatus(401); + } +}); + +export default router; diff --git a/api/src/routes/users/@me/disable.ts b/api/src/routes/users/@me/disable.ts new file mode 100644 index 00000000..0e5b734e --- /dev/null +++ b/api/src/routes/users/@me/disable.ts @@ -0,0 +1,20 @@ +import { UserModel } from "@fosscord/server-util"; +import { Router, Response, Request } from "express"; +import bcrypt from "bcrypt"; + +const router = Router(); + +router.post("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }).exec(); //User object + + let correctpass = await bcrypt.compare(req.body.password, user!.user_data.hash); //Not sure if user typed right password :/ + if (correctpass) { + await UserModel.updateOne({ id: req.user_id }, { disabled: true }).exec(); + + res.sendStatus(204); + } else { + res.status(400).json({ message: "Password does not match", code: 50018 }); + } +}); + +export default router; diff --git a/api/src/routes/users/@me/guilds.ts b/api/src/routes/users/@me/guilds.ts new file mode 100644 index 00000000..6528552b --- /dev/null +++ b/api/src/routes/users/@me/guilds.ts @@ -0,0 +1,55 @@ +import { Router, Request, Response } from "express"; +import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject } from "@fosscord/server-util"; +import { HTTPError } from "lambert-server"; +import { emitEvent } from "../../../util/Event"; +import { getPublicUser } from "../../../util/User"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }, { guilds: true }).exec(); + if (!user) throw new HTTPError("User not found", 404); + + var guildIDs = user.guilds || []; + var guild = await GuildModel.find({ id: { $in: guildIDs } }) + .populate({ path: "joined_at", match: { id: req.user_id } }) + .exec(); + + res.json(toObject(guild)); +}); + +// user send to leave a certain guild +router.delete("/:id", async (req: Request, res: Response) => { + const guild_id = req.params.id; + const guild = await GuildModel.findOne({ id: guild_id }, { guild_id: true }).exec(); + + if (!guild) throw new HTTPError("Guild doesn't exist", 404); + if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400); + + await Promise.all([ + MemberModel.deleteOne({ id: req.user_id, guild_id: guild_id }).exec(), + UserModel.updateOne({ id: req.user_id }, { $pull: { guilds: guild_id } }).exec(), + emitEvent({ + event: "GUILD_DELETE", + data: { + id: guild_id, + }, + user_id: req.user_id, + } as GuildDeleteEvent), + ]); + + const user = await getPublicUser(req.user_id); + + await emitEvent({ + event: "GUILD_MEMBER_REMOVE", + data: { + guild_id: guild_id, + user: user, + }, + guild_id: guild_id, + } as GuildMemberRemoveEvent); + + return res.sendStatus(204); +}); + +export default router; diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts new file mode 100644 index 00000000..7bd4a486 --- /dev/null +++ b/api/src/routes/users/@me/index.ts @@ -0,0 +1,48 @@ +import { Router, Request, Response } from "express"; +import { UserModel, toObject, PublicUserProjection } from "@fosscord/server-util"; +import { getPublicUser } from "../../../util/User"; +import { UserModifySchema } from "../../../schema/User"; +import { check } from "../../../util/instanceOf"; +import { handleFile } from "../../../util/cdn"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + res.json(await getPublicUser(req.user_id)); +}); + +const UserUpdateProjection = { + accent_color: true, + avatar: true, + banner: true, + bio: true, + bot: true, + discriminator: true, + email: true, + flags: true, + id: true, + locale: true, + mfa_enabled: true, + nsfw_alllowed: true, + phone: true, + public_flags: true, + purchased_flags: true, + // token: true, // this isn't saved in the db and needs to be set manually + username: true, + verified: true +}; + +router.patch("/", check(UserModifySchema), async (req: Request, res: Response) => { + const body = req.body as UserModifySchema; + + if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string); + if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string); + + const user = await UserModel.findOneAndUpdate({ id: req.user_id }, body, { projection: UserUpdateProjection }).exec(); + // TODO: dispatch user update event + + res.json(toObject(user)); +}); + +export default router; +// {"message": "Invalid two-factor code", "code": 60008} diff --git a/api/src/routes/users/@me/library.ts b/api/src/routes/users/@me/library.ts new file mode 100644 index 00000000..d771cb5e --- /dev/null +++ b/api/src/routes/users/@me/library.ts @@ -0,0 +1,10 @@ +import { Router, Response, Request } from "express"; + +const router = Router(); + +router.get("/", (req: Request, res: Response) => { + // TODO: + res.status(200).send([]); +}); + +export default router; diff --git a/api/src/routes/users/@me/profile.ts b/api/src/routes/users/@me/profile.ts new file mode 100644 index 00000000..b67d1964 --- /dev/null +++ b/api/src/routes/users/@me/profile.ts @@ -0,0 +1,27 @@ +import { Router, Request, Response } from "express"; +import { getPublicUser } from "../../../util/User"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + const user = await getPublicUser(req.user_id, { user_data: true }) + + res.json({ + connected_accounts: user.user_data.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/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts new file mode 100644 index 00000000..a8f03143 --- /dev/null +++ b/api/src/routes/users/@me/relationships.ts @@ -0,0 +1,176 @@ +import { + RelationshipAddEvent, + UserModel, + PublicUserProjection, + toObject, + RelationshipType, + RelationshipRemoveEvent, + UserDocument +} from "@fosscord/server-util"; +import { Router, Response, Request } from "express"; +import { HTTPError } from "lambert-server"; +import { emitEvent } from "../../../util/Event"; +import { check, Length } from "../../../util/instanceOf"; + +const router = Router(); + +const userProjection = { "user_data.relationships": true, ...PublicUserProjection }; + +router.get("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }, { user_data: { relationships: true } }) + .populate({ path: "user_data.relationships.id", model: UserModel }) + .exec(); + + return res.json(toObject(user.user_data.relationships)); +}); + +async function addRelationship(req: Request, res: Response, friend: UserDocument, type: RelationshipType) { + const id = friend.id; + if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend"); + + const user = await UserModel.findOne({ id: req.user_id }, userProjection).exec(); + const newUserRelationships = [...user.user_data.relationships]; + const newFriendRelationships = [...friend.user_data.relationships]; + + var relationship = newUserRelationships.find((x) => x.id === id); + const friendRequest = newFriendRelationships.find((x) => x.id === req.user_id); + + if (type === RelationshipType.blocked) { + if (relationship) { + if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user"); + relationship.type = RelationshipType.blocked; + } else { + relationship = { id, type: RelationshipType.blocked }; + newUserRelationships.push(relationship); + } + + if (friendRequest && friendRequest.type !== RelationshipType.blocked) { + newFriendRelationships.remove(friendRequest); + await Promise.all([ + UserModel.updateOne({ id: friend.id }, { "user_data.relationships": newFriendRelationships }).exec(), + emitEvent({ + event: "RELATIONSHIP_REMOVE", + data: friendRequest, + user_id: id + } as RelationshipRemoveEvent) + ]); + } + + await Promise.all([ + UserModel.updateOne({ id: req.user_id }, { "user_data.relationships": newUserRelationships }).exec(), + emitEvent({ + event: "RELATIONSHIP_ADD", + data: { + ...toObject(relationship), + user: { ...toObject(friend), user_data: undefined } + }, + user_id: req.user_id + } as RelationshipAddEvent) + ]); + + return res.sendStatus(204); + } + + var incoming_relationship = { id: req.user_id, nickname: undefined, type: RelationshipType.incoming }; + var outgoing_relationship = { id, nickname: undefined, type: RelationshipType.outgoing }; + + if (friendRequest) { + if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you"); + // accept friend request + // @ts-ignore + incoming_relationship = friendRequest; + incoming_relationship.type = RelationshipType.friends; + outgoing_relationship.type = RelationshipType.friends; + } else newFriendRelationships.push(incoming_relationship); + + if (relationship) { + if (relationship.type === RelationshipType.outgoing) throw new HTTPError("You already sent a friend request"); + if (relationship.type === RelationshipType.blocked) throw new HTTPError("Unblock the user before sending a friend request"); + if (relationship.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user"); + } else newUserRelationships.push(outgoing_relationship); + + await Promise.all([ + UserModel.updateOne({ id: req.user_id }, { "user_data.relationships": newUserRelationships }).exec(), + UserModel.updateOne({ id: friend.id }, { "user_data.relationships": newFriendRelationships }).exec(), + emitEvent({ + event: "RELATIONSHIP_ADD", + data: { + ...outgoing_relationship, + user: { ...toObject(friend), user_data: undefined } + }, + user_id: req.user_id + } as RelationshipAddEvent), + emitEvent({ + event: "RELATIONSHIP_ADD", + data: { + ...toObject(incoming_relationship), + should_notify: true, + user: { ...toObject(user), user_data: undefined } + }, + user_id: id + } as RelationshipAddEvent) + ]); + + return res.sendStatus(204); +} + +router.put("/:id", check({ $type: new Length(Number, 1, 4) }), async (req: Request, res: Response) => { + return await addRelationship(req, res, await UserModel.findOne({ id: req.params.id }), req.body.type); +}); + +router.post("/", check({ discriminator: String, username: String }), async (req: Request, res: Response) => { + return await addRelationship( + req, + res, + await UserModel.findOne(req.body as { discriminator: string; username: string }).exec(), + req.body.type + ); +}); + +router.delete("/:id", async (req: Request, res: Response) => { + const { id } = req.params; + if (id === req.user_id) throw new HTTPError("You can't remove yourself as a friend"); + + const user = await UserModel.findOne({ id: req.user_id }).exec(); + if (!user) throw new HTTPError("Invalid token", 400); + + const friend = await UserModel.findOne({ id }, userProjection).exec(); + if (!friend) throw new HTTPError("User not found", 404); + + const relationship = user.user_data.relationships.find((x) => x.id === id); + const friendRequest = friend.user_data.relationships.find((x) => x.id === req.user_id); + if (relationship?.type === RelationshipType.blocked) { + // unblock user + user.user_data.relationships.remove(relationship); + + await Promise.all([ + user.save(), + emitEvent({ event: "RELATIONSHIP_REMOVE", user_id: req.user_id, data: relationship } as RelationshipRemoveEvent) + ]); + return res.sendStatus(204); + } + if (!relationship || !friendRequest) throw new HTTPError("You are not friends with the user", 404); + if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you"); + + user.user_data.relationships.remove(relationship); + friend.user_data.relationships.remove(friendRequest); + + await Promise.all([ + user.save(), + friend.save(), + emitEvent({ + event: "RELATIONSHIP_REMOVE", + data: relationship, + user_id: req.user_id + } as RelationshipRemoveEvent), + emitEvent({ + event: "RELATIONSHIP_REMOVE", + data: friendRequest, + user_id: id + } as RelationshipRemoveEvent) + ]); + + return res.sendStatus(204); +}); + +export default router; diff --git a/api/src/routes/users/@me/settings.ts b/api/src/routes/users/@me/settings.ts new file mode 100644 index 00000000..cca9b3ab --- /dev/null +++ b/api/src/routes/users/@me/settings.ts @@ -0,0 +1,10 @@ +import { Router, Response, Request } from "express"; + +const router = Router(); + +router.patch("/", (req: Request, res: Response) => { + // TODO: + res.sendStatus(204); +}); + +export default router; |