summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json30
-rw-r--r--package.json12
-rw-r--r--src/routes/auth/login.ts25
-rw-r--r--src/routes/auth/register.ts16
-rw-r--r--src/routes/channels/#channel_id/index.ts3
-rw-r--r--src/routes/channels/#channel_id/invites.ts4
-rw-r--r--src/routes/channels/#channel_id/messages/#message_id/index.ts5
-rw-r--r--src/routes/channels/#channel_id/messages/#message_id/reactions.ts13
-rw-r--r--src/routes/channels/#channel_id/messages/bulk-delete.ts2
-rw-r--r--src/routes/channels/#channel_id/messages/index.ts1
-rw-r--r--src/routes/channels/#channel_id/permissions.ts6
-rw-r--r--src/routes/channels/#channel_id/pins.ts5
-rw-r--r--src/routes/channels/#channel_id/typing.ts40
-rw-r--r--src/routes/channels/#channel_id/webhooks.ts1
-rw-r--r--src/routes/guilds/#guild_id/bans.ts1
-rw-r--r--src/routes/guilds/#guild_id/channels.ts10
-rw-r--r--src/routes/guilds/#guild_id/delete.ts1
-rw-r--r--src/routes/guilds/#guild_id/index.ts1
-rw-r--r--src/routes/guilds/#guild_id/members/#member_id/index.ts1
-rw-r--r--src/routes/guilds/#guild_id/members/index.ts1
-rw-r--r--src/routes/guilds/#guild_id/roles.ts11
-rw-r--r--src/routes/guilds/#guild_id/templates.ts8
-rw-r--r--src/routes/guilds/#guild_id/vanity-url.ts2
-rw-r--r--src/routes/guilds/#guild_id/welcome_screen.ts13
-rw-r--r--src/routes/guilds/#guild_id/widget.json.ts97
-rw-r--r--src/routes/guilds/#guild_id/widget.png.ts1
-rw-r--r--src/routes/guilds/#guild_id/widget.ts3
-rw-r--r--src/routes/guilds/templates/index.ts2
28 files changed, 141 insertions, 174 deletions
diff --git a/package-lock.json b/package-lock.json

index 15f0c369..abc73d46 100644 --- a/package-lock.json +++ b/package-lock.json
@@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@fosscord/server-util": "^1.3.26", + "@fosscord/server-util": "^1.3.29", "@types/jest": "^26.0.22", "@types/json-schema": "^7.0.7", "ajv": "^8.4.0", @@ -39,6 +39,9 @@ "node-fetch": "^2.6.1", "require_optional": "^1.0.1" }, + "bin": { + "api": "dist/start.js" + }, "devDependencies": { "@types/bcrypt": "^3.0.0", "@types/express": "^4.17.9", @@ -51,6 +54,7 @@ "0x": "^4.10.2", "jest": "^26.6.3", "pkg": "^5.3.0", + "saslprep": "^1.0.3", "ts-node": "^9.1.1", "ts-node-dev": "^1.1.6", "typescript": "^4.1.2" @@ -551,9 +555,9 @@ } }, "node_modules/@fosscord/server-util": { - "version": "1.3.26", - "resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.26.tgz", - "integrity": "sha512-c6SDflivNVk6gVbFm7FLWVOBTyaiO7ZSiEttCCZQ8dD3kKu0oMocDoHH5S1f7xCpBjFY9igfa/P6mrPOJrUlKw==", + "version": "1.3.29", + "resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.29.tgz", + "integrity": "sha512-lxb8LGezMG1yo9kR6CVlWN8+pjsduCG1b8wkYsAjv6sqjFz7mgKUo/rvxUenJTCspDHxDF/3RuYBLdQEtVEVXg==", "dependencies": { "@types/jsonwebtoken": "^8.5.0", "@types/mongoose-autopopulate": "^0.10.1", @@ -6403,7 +6407,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "devOptional": true }, "node_modules/meow": { "version": "3.7.0", @@ -8966,7 +8970,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, + "devOptional": true, "dependencies": { "sparse-bitfield": "^3.0.3" }, @@ -9462,7 +9466,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, + "devOptional": true, "dependencies": { "memory-pager": "^1.0.2" } @@ -11470,9 +11474,9 @@ } }, "@fosscord/server-util": { - "version": "1.3.26", - "resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.26.tgz", - "integrity": "sha512-c6SDflivNVk6gVbFm7FLWVOBTyaiO7ZSiEttCCZQ8dD3kKu0oMocDoHH5S1f7xCpBjFY9igfa/P6mrPOJrUlKw==", + "version": "1.3.29", + "resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.29.tgz", + "integrity": "sha512-lxb8LGezMG1yo9kR6CVlWN8+pjsduCG1b8wkYsAjv6sqjFz7mgKUo/rvxUenJTCspDHxDF/3RuYBLdQEtVEVXg==", "requires": { "@types/jsonwebtoken": "^8.5.0", "@types/mongoose-autopopulate": "^0.10.1", @@ -16435,7 +16439,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "devOptional": true }, "meow": { "version": "3.7.0", @@ -18493,7 +18497,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, + "devOptional": true, "requires": { "sparse-bitfield": "^3.0.3" } @@ -18923,7 +18927,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, + "devOptional": true, "requires": { "memory-pager": "^1.0.2" } diff --git a/package.json b/package.json
index 3f6d8553..17be3f28 100644 --- a/package.json +++ b/package.json
@@ -11,7 +11,7 @@ "start": "npm run build && node dist/start", "build": "tsc -b .", "dev": "tsnd --respawn src/start.ts", - "bundle": "pkg package.json" + "bundle": "npm run build && pkg package.json" }, "pkg": { "scripts": [ @@ -22,8 +22,11 @@ "assets" ], "targets": [ - "latest-win-x64" - ] + "latest-linux-x64", + "latest-win-x64", + "latest-macos-x64" + ], + "outputPath": "build" }, "repository": { "type": "git", @@ -43,7 +46,7 @@ }, "homepage": "https://github.com/fosscord/fosscord-api#readme", "dependencies": { - "@fosscord/server-util": "^1.3.26", + "@fosscord/server-util": "^1.3.29", "@types/jest": "^26.0.22", "@types/json-schema": "^7.0.7", "ajv": "^8.4.0", @@ -85,6 +88,7 @@ "0x": "^4.10.2", "jest": "^26.6.3", "pkg": "^5.3.0", + "saslprep": "^1.0.3", "ts-node": "^9.1.1", "ts-node-dev": "^1.1.6", "typescript": "^4.1.2" diff --git a/src/routes/auth/login.ts b/src/routes/auth/login.ts
index 547d115b..1c288716 100644 --- a/src/routes/auth/login.ts +++ b/src/routes/auth/login.ts
@@ -9,6 +9,7 @@ import RateLimit from "../../middlewares/RateLimit"; const router: Router = Router(); export default router; +// TODO: check if user is deleted/restricted router.post( "/", RateLimit({ count: 5, window: 60, onylIp: true }), @@ -43,11 +44,25 @@ router.post( // TODO: check captcha } - const user = await UserModel.findOne({ $or: query }, `user_data.hash id user_settings.locale user_settings.theme`).exec(); - - if (!user) { - throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } }); - } + const user = await UserModel.findOne( + { $or: query }, + { + projection: { + user_data: { + hash: true + }, + id: true, + user_settings: { + locale: true, + theme: true + } + } + } + ) + .exec() + .catch((e) => { + throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } }); + }); // the salt is saved in the password refer to bcrypt docs const same_password = await bcrypt.compare(password, user.user_data.hash); diff --git a/src/routes/auth/register.ts b/src/routes/auth/register.ts
index 83f8dc8c..25c7b3dd 100644 --- a/src/routes/auth/register.ts +++ b/src/routes/auth/register.ts
@@ -93,7 +93,9 @@ router.post( if (!adjusted_email) throw FieldErrors({ email: { code: "INVALID_EMAIL", message: req.t("auth:register.INVALID_EMAIL") } }); // check if there is already an account with this email - const exists = await UserModel.findOne({ email: adjusted_email }).exec(); + const exists = await UserModel.findOne({ email: adjusted_email }) + .exec() + .catch((e) => {}); if (exists) { throw FieldErrors({ @@ -130,7 +132,9 @@ router.post( if (!register.allowMultipleAccounts) { // TODO: check if fingerprint was eligible generated - const exists = await UserModel.findOne({ fingerprints: fingerprint }).exec(); + const exists = await UserModel.findOne({ fingerprints: fingerprint }) + .exec() + .catch((e) => {}); if (exists) { throw FieldErrors({ @@ -165,8 +169,12 @@ router.post( // TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database? for (let tries = 0; tries < 5; tries++) { discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0"); - exists = await UserModel.findOne({ discriminator, username: adjusted_username }, "id").exec(); - if (!exists) break; + try { + exists = await UserModel.findOne({ discriminator, username: adjusted_username }, "id").exec(); + } catch (error) { + // doesn't exist -> break + break; + } } if (exists) { diff --git a/src/routes/channels/#channel_id/index.ts b/src/routes/channels/#channel_id/index.ts
index dcc093ae..434f61a5 100644 --- a/src/routes/channels/#channel_id/index.ts +++ b/src/routes/channels/#channel_id/index.ts
@@ -12,7 +12,6 @@ router.get("/", async (req: Request, res: Response) => { const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permission = await getPermission(req.user_id, channel.guild_id, channel_id); permission.hasThrow("VIEW_CHANNEL"); @@ -24,7 +23,6 @@ router.delete("/", async (req: Request, res: Response) => { const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permission = await getPermission(req.user_id, channel?.guild_id, channel_id, { channel }); permission.hasThrow("MANAGE_CHANNELS"); @@ -47,7 +45,6 @@ router.patch("/", check(ChannelModifySchema), async (req: Request, res: Response permission.hasThrow("MANAGE_CHANNELS"); const channel = await ChannelModel.findOneAndUpdate({ id: channel_id }, payload).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const data = toObject(channel); diff --git a/src/routes/channels/#channel_id/invites.ts b/src/routes/channels/#channel_id/invites.ts
index 457e78ca..c9db4dd2 100644 --- a/src/routes/channels/#channel_id/invites.ts +++ b/src/routes/channels/#channel_id/invites.ts
@@ -16,7 +16,7 @@ router.post("/", check(InviteCreateSchema), async (req: Request, res: Response) const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel || !channel.guild_id) { + if (!channel.guild_id) { throw new HTTPError("This channel doesn't exist", 404); } const { guild_id } = channel; @@ -50,7 +50,7 @@ router.get("/", async (req: Request, res: Response) => { const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel || !channel.guild_id) { + if (!channel.guild_id) { throw new HTTPError("This channel doesn't exist", 404); } const { guild_id } = channel; diff --git a/src/routes/channels/#channel_id/messages/#message_id/index.ts b/src/routes/channels/#channel_id/messages/#message_id/index.ts
index 90727f60..9cd63d26 100644 --- a/src/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/src/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -13,7 +13,6 @@ router.patch("/", check(MessageCreateSchema), async (req: Request, res: Response var body = req.body as MessageCreateSchema; var message = await MessageModel.findOne({ id: message_id, channel_id }, { author_id: true }).exec(); - if (!message) throw new HTTPError("Message not found", 404); const permissions = await getPermission(req.user_id, undefined, channel_id); @@ -30,8 +29,8 @@ router.patch("/", check(MessageCreateSchema), async (req: Request, res: Response edited_timestamp: new Date() }); + // @ts-ignore message = await MessageModel.findOneAndUpdate({ id: message_id }, opts).populate("author").exec(); - if (!message) throw new HTTPError("Message not found", 404); await emitEvent({ event: "MESSAGE_UPDATE", @@ -51,9 +50,7 @@ router.delete("/", async (req: Request, res: Response) => { const { message_id, channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true }); - if (!channel) throw new HTTPError("Channel not found", 404); const message = await MessageModel.findOne({ id: message_id }, { author_id: true }).exec(); - if (!message) throw new HTTPError("Message not found", 404); const permission = await getPermission(req.user_id, channel.guild_id, channel_id); if (message.author_id !== req.user_id) permission.hasThrow("MANAGE_MESSAGES"); diff --git a/src/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/routes/channels/#channel_id/messages/#message_id/reactions.ts
index c31be435..9f68b5cd 100644 --- a/src/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/routes/channels/#channel_id/messages/#message_id/reactions.ts
@@ -39,13 +39,11 @@ router.delete("/", async (req: Request, res: Response) => { const { message_id, channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permissions = await getPermission(req.user_id, undefined, channel_id); permissions.hasThrow("MANAGE_MESSAGES"); - const message = await MessageModel.findOneAndUpdate({ id: message_id, channel_id }, { reactions: [] }).exec(); - if (!message) throw new HTTPError("Message not found", 404); + await MessageModel.findOneAndUpdate({ id: message_id, channel_id }, { reactions: [] }).exec(); await emitEvent({ event: "MESSAGE_REACTION_REMOVE_ALL", @@ -66,13 +64,11 @@ router.delete("/:emoji", async (req: Request, res: Response) => { const emoji = getEmoji(req.params.emoji); const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permissions = await getPermission(req.user_id, undefined, channel_id); permissions.hasThrow("MANAGE_MESSAGES"); const message = await MessageModel.findOne({ id: message_id, channel_id }).exec(); - if (!message) throw new HTTPError("Message not found", 404); const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); if (!already_added) throw new HTTPError("Reaction not found", 404); @@ -118,10 +114,7 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => { const emoji = getEmoji(req.params.emoji); const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); - const message = await MessageModel.findOne({ id: message_id, channel_id }).exec(); - if (!message) throw new HTTPError("Message not found", 404); const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); const permissions = await getPermission(req.user_id, undefined, channel_id); @@ -130,7 +123,6 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => { if (emoji.id) { const external_emoji = await EmojiModel.findOne({ id: emoji.id }).exec(); - if (!external_emoji) throw new HTTPError("Emoji not found", 404); if (!already_added) permissions.hasThrow("USE_EXTERNAL_EMOJIS"); emoji.animated = external_emoji.animated; emoji.name = external_emoji.name; @@ -168,10 +160,7 @@ router.delete("/:emoji/:user_id", async (req: Request, res: Response) => { const emoji = getEmoji(req.params.emoji); const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); - const message = await MessageModel.findOne({ id: message_id, channel_id }).exec(); - if (!message) throw new HTTPError("Message not found", 404); const permissions = await getPermission(req.user_id, undefined, channel_id); diff --git a/src/routes/channels/#channel_id/messages/bulk-delete.ts b/src/routes/channels/#channel_id/messages/bulk-delete.ts
index 8cb672d8..e53cd597 100644 --- a/src/routes/channels/#channel_id/messages/bulk-delete.ts +++ b/src/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -14,7 +14,7 @@ export default router; router.post("/", check({ messages: [String] }), async (req: Request, res: Response) => { const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }, { permission_overwrites: true, guild_id: true }).exec(); - if (!channel?.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400); + if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400); const permission = await getPermission(req.user_id, channel?.guild_id, channel_id, { channel }); permission.hasThrow("MANAGE_MESSAGES"); diff --git a/src/routes/channels/#channel_id/messages/index.ts b/src/routes/channels/#channel_id/messages/index.ts
index 5f1f6c54..053a2a02 100644 --- a/src/routes/channels/#channel_id/messages/index.ts +++ b/src/routes/channels/#channel_id/messages/index.ts
@@ -31,7 +31,6 @@ export function isTextChannel(type: ChannelType): boolean { router.get("/", async (req: Request, res: Response) => { const channel_id = req.params.channel_id; const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); isTextChannel(channel.type); diff --git a/src/routes/channels/#channel_id/permissions.ts b/src/routes/channels/#channel_id/permissions.ts
index 43e61821..f3cef53e 100644 --- a/src/routes/channels/#channel_id/permissions.ts +++ b/src/routes/channels/#channel_id/permissions.ts
@@ -12,7 +12,7 @@ router.put("/:overwrite_id", check({ allow: String, deny: String, type: Number, const body = req.body as { allow: bigint; deny: bigint; type: number; id: string }; var channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, permission_overwrites: true }).exec(); - if (!channel || !channel.guild_id) throw new HTTPError("Channel not found", 404); + if (!channel.guild_id) throw new HTTPError("Channel not found", 404); const permissions = await getPermission(req.user_id, channel.guild_id, channel_id); permissions.hasThrow("MANAGE_ROLES"); @@ -38,8 +38,8 @@ router.put("/:overwrite_id", check({ allow: String, deny: String, type: Number, overwrite.allow = body.allow; overwrite.deny = body.deny; + // @ts-ignore channel = await ChannelModel.findOneAndUpdate({ id: channel_id }, channel).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); await emitEvent({ event: "CHANNEL_UPDATE", @@ -59,7 +59,7 @@ router.delete("/:overwrite_id", async (req: Request, res: Response) => { permissions.hasThrow("MANAGE_ROLES"); const channel = await ChannelModel.findOneAndUpdate({ id: channel_id }, { $pull: { permission_overwrites: { id: overwrite_id } } }); - if (!channel || !channel.guild_id) throw new HTTPError("Channel not found", 404); + if (!channel.guild_id) throw new HTTPError("Channel not found", 404); await emitEvent({ event: "CHANNEL_UPDATE", diff --git a/src/routes/channels/#channel_id/pins.ts b/src/routes/channels/#channel_id/pins.ts
index 5b61f0d2..f5bd2ef7 100644 --- a/src/routes/channels/#channel_id/pins.ts +++ b/src/routes/channels/#channel_id/pins.ts
@@ -12,12 +12,10 @@ import { HTTPError } from "lambert-server"; import { emitEvent } from "../../../util/Event"; const router: Router = Router(); -// TODO: auto throw error if findOne doesn't find anything router.put("/:message_id", async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permission = await getPermission(req.user_id, channel.guild_id, channel_id); permission.hasThrow("VIEW_CHANNEL"); @@ -30,7 +28,6 @@ router.put("/:message_id", async (req: Request, res: Response) => { await MessageModel.updateOne({ id: message_id }, { pinned: true }).exec(); const message = toObject(await MessageModel.findOne({ id: message_id }).exec()); - if (!message) throw new HTTPError("Message not found", 404); await emitEvent({ event: "MESSAGE_UPDATE", @@ -57,7 +54,6 @@ router.delete("/:message_id", async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permission = await getPermission(req.user_id, channel.guild_id, channel_id); permission.hasThrow("VIEW_CHANNEL"); @@ -90,7 +86,6 @@ router.get("/", async (req: Request, res: Response) => { const { channel_id } = req.params; const channel = await ChannelModel.findOne({ id: channel_id }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); const permission = await getPermission(req.user_id, channel.guild_id, channel_id); permission.hasThrow("VIEW_CHANNEL"); diff --git a/src/routes/channels/#channel_id/typing.ts b/src/routes/channels/#channel_id/typing.ts
index f0ca138c..2c2b9bc9 100644 --- a/src/routes/channels/#channel_id/typing.ts +++ b/src/routes/channels/#channel_id/typing.ts
@@ -7,28 +7,26 @@ import { emitEvent } from "../../../util/Event"; const router: Router = Router(); router.post("/", async (req: Request, res: Response) => { - const { channel_id } = req.params; - const user_id = req.user_id; - const timestamp = Date.now() - const channel = await ChannelModel.findOne({ id: channel_id }); - if (!channel) throw new HTTPError("Channel not found", 404) - const member = await MemberModel.findOne({ id: user_id }).exec() - if (!member) throw new HTTPError("Member not found", 404) + const { channel_id } = req.params; + const user_id = req.user_id; + const timestamp = Date.now(); + const channel = await ChannelModel.findOne({ id: channel_id }); + const member = await MemberModel.findOne({ id: user_id }).exec(); - - await emitEvent({ - event: "TYPING_START", - channel_id: channel_id, - guild_id: channel.guild_id, - data: { // this is the paylod - member: toObject(member), - channel_id, - timestamp, - user_id, - guild_id: channel.guild_id - } - } as TypingStartEvent) - res.sendStatus(204) + await emitEvent({ + event: "TYPING_START", + channel_id: channel_id, + guild_id: channel.guild_id, + data: { + // this is the paylod + member: toObject(member), + channel_id, + timestamp, + user_id, + guild_id: channel.guild_id + } + } as TypingStartEvent); + res.sendStatus(204); }); export default router; diff --git a/src/routes/channels/#channel_id/webhooks.ts b/src/routes/channels/#channel_id/webhooks.ts
index b60f4d68..6c1aea2a 100644 --- a/src/routes/channels/#channel_id/webhooks.ts +++ b/src/routes/channels/#channel_id/webhooks.ts
@@ -11,7 +11,6 @@ const router: Router = Router(); router.post("/", check({ name: new Length(String, 1, 80), $avatar: String }), async (req: Request, res: Response) => { const channel_id = req.params.channel_id; const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true }).exec(); - if (!channel) throw new HTTPError("Channel not found", 404); isTextChannel(channel.type); if (!channel.guild_id) throw new HTTPError("Not a guild channel", 400); diff --git a/src/routes/guilds/#guild_id/bans.ts b/src/routes/guilds/#guild_id/bans.ts
index cf6a059b..4d9bad37 100644 --- a/src/routes/guilds/#guild_id/bans.ts +++ b/src/routes/guilds/#guild_id/bans.ts
@@ -25,7 +25,6 @@ router.get("/:user", async (req: Request, res: Response) => { const user_id = req.params.ban; var ban = await BanModel.findOne({ guild_id: guild_id, user_id: user_id }).exec(); - if (!ban) throw new HTTPError("Ban not found", 404); return res.json(ban); }); diff --git a/src/routes/guilds/#guild_id/channels.ts b/src/routes/guilds/#guild_id/channels.ts
index a3c6f4fe..90b4473d 100644 --- a/src/routes/guilds/#guild_id/channels.ts +++ b/src/routes/guilds/#guild_id/channels.ts
@@ -37,15 +37,7 @@ router.patch("/", check(ChannelModifySchema), async (req: Request, res: Response const body = req.body as ChannelModifySchema; const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - - const channel = { - ...body - }; - const channelm = await ChannelModel.find({ guild_id }).exec(); - if (!channelm) throw new HTTPError("Channel not found", 404); - - await new ChannelModel(channel).save(); + const channel = await ChannelModel.findOneAndUpdate({ guild_id }, body).exec(); await emitEvent({ event: "CHANNEL_UPDATE", data: channel } as ChannelUpdateEvent); diff --git a/src/routes/guilds/#guild_id/delete.ts b/src/routes/guilds/#guild_id/delete.ts
index 5d4db816..c363db25 100644 --- a/src/routes/guilds/#guild_id/delete.ts +++ b/src/routes/guilds/#guild_id/delete.ts
@@ -20,7 +20,6 @@ router.post("/", async (req: Request, res: Response) => { var { guild_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }, "owner_id").exec(); - if (!guild) throw new HTTPError("This guild does not exist", 404); if (guild.owner_id !== req.user_id) throw new HTTPError("You are not the owner of this guild", 401); await emitEvent({ diff --git a/src/routes/guilds/#guild_id/index.ts b/src/routes/guilds/#guild_id/index.ts
index 9ef0127a..3af49106 100644 --- a/src/routes/guilds/#guild_id/index.ts +++ b/src/routes/guilds/#guild_id/index.ts
@@ -27,7 +27,6 @@ router.get("/", async (req: Request, res: Response) => { const guild = await GuildModel.findOne({ id: guild_id }) .populate({ path: "joined_at", match: { id: req.user_id } }) .exec(); - if (!guild) throw new HTTPError("Guild does not exist", 404); const member = await MemberModel.exists({ guild_id: guild_id, id: req.user_id }); if (!member) throw new HTTPError("You are not a member of the guild you are trying to access", 401); diff --git a/src/routes/guilds/#guild_id/members/#member_id/index.ts b/src/routes/guilds/#guild_id/members/#member_id/index.ts
index 12eedfb2..9a1676e6 100644 --- a/src/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/src/routes/guilds/#guild_id/members/#member_id/index.ts
@@ -23,7 +23,6 @@ router.get("/", async (req: Request, res: Response) => { await isMember(req.user_id, guild_id); const member = await MemberModel.findOne({ id: member_id, guild_id }).exec(); - if (!member) throw new HTTPError("Member not found", 404); return res.json(toObject(member)); }); diff --git a/src/routes/guilds/#guild_id/members/index.ts b/src/routes/guilds/#guild_id/members/index.ts
index 1ec21226..a157d8f5 100644 --- a/src/routes/guilds/#guild_id/members/index.ts +++ b/src/routes/guilds/#guild_id/members/index.ts
@@ -11,7 +11,6 @@ const router = Router(); router.get("/", async (req: Request, res: Response) => { const { guild_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); await isMember(req.user_id, guild_id); try { diff --git a/src/routes/guilds/#guild_id/roles.ts b/src/routes/guilds/#guild_id/roles.ts
index e9360847..77206a0f 100644 --- a/src/routes/guilds/#guild_id/roles.ts +++ b/src/routes/guilds/#guild_id/roles.ts
@@ -35,10 +35,7 @@ router.post("/", check(RoleModifySchema), async (req: Request, res: Response) => const body = req.body as RoleModifySchema; const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_ROLES"); @@ -71,11 +68,7 @@ router.delete("/:role_id", async (req: Request, res: Response) => { const { role_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - if (!role_id) throw new HTTPError("Unknown role_id", 404); - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); const perms = await getPermission(req.user_id, guild_id); @@ -106,11 +99,7 @@ router.patch("/:role_id", check(RoleModifySchema), async (req: Request, res: Res const body = req.body as RoleModifySchema; const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - if (!role_id) throw new HTTPError("Unknown template_id", 404); - const user = await UserModel.findOne({ id: req.user_id }).exec(); - if (!user) throw new HTTPError("User not found", 404); const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_ROLES"); diff --git a/src/routes/guilds/#guild_id/templates.ts b/src/routes/guilds/#guild_id/templates.ts
index 03435c35..04ac196e 100644 --- a/src/routes/guilds/#guild_id/templates.ts +++ b/src/routes/guilds/#guild_id/templates.ts
@@ -21,7 +21,7 @@ const TemplateGuildProjection = { afk_channel_id: true, system_channel_id: true, system_channel_flags: true, - icon_hash: true, + icon_hash: true }; router.get("/", async (req: Request, res: Response) => { @@ -35,7 +35,6 @@ router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response const guild_id = req.params.guild_id; const guild = await GuildModel.findOne({ id: guild_id }, TemplateGuildProjection).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_GUILD"); @@ -47,7 +46,7 @@ router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response created_at: new Date(), updated_at: new Date(), source_guild_id: guild_id, - serialized_source_guild: guild, + serialized_source_guild: guild }).save(); res.json(toObject(template)).send(); @@ -61,7 +60,7 @@ router.delete("/:code", async (req: Request, res: Response) => { perms.hasThrow("MANAGE_GUILD"); const template = await TemplateModel.findOneAndDelete({ - code, + code }).exec(); res.send(toObject(template)); @@ -72,7 +71,6 @@ router.put("/:code", async (req: Request, res: Response) => { const { code } = req.params; const guild = await GuildModel.findOne({ id: guild_id }, TemplateGuildProjection).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_GUILD"); diff --git a/src/routes/guilds/#guild_id/vanity-url.ts b/src/routes/guilds/#guild_id/vanity-url.ts
index 052a638f..2d210e5d 100644 --- a/src/routes/guilds/#guild_id/vanity-url.ts +++ b/src/routes/guilds/#guild_id/vanity-url.ts
@@ -8,8 +8,6 @@ router.get("/", async (req: Request, res: Response) => { const { guild_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild does not exist", 404); - if (!guild.vanity_url) throw new HTTPError("This guild has no vanity url", 204); return res.json({ vanity_ur: guild.vanity_url }); diff --git a/src/routes/guilds/#guild_id/welcome_screen.ts b/src/routes/guilds/#guild_id/welcome_screen.ts
index 8fc5ac39..656a0ee0 100644 --- a/src/routes/guilds/#guild_id/welcome_screen.ts +++ b/src/routes/guilds/#guild_id/welcome_screen.ts
@@ -13,7 +13,6 @@ router.get("/", async (req: Request, res: Response) => { const guild_id = req.params.guild_id; const guild = await GuildModel.findOne({ id: guild_id }); - if (!guild) throw new HTTPError("Guild not found", 404); await isMember(req.user_id, guild_id); @@ -25,22 +24,21 @@ router.post("/", check(GuildAddChannelToWelcomeScreenSchema), async (req: Reques const body = req.body as GuildAddChannelToWelcomeScreenSchema; const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); var channelObject = { ...body - } + }; const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_GUILD"); - if(!guild.welcome_screen.enabled) throw new HTTPError("Welcome screen disabled", 400); - if(guild.welcome_screen.welcome_channels.some(channel => channel.channel_id === body.channel_id)) throw new Error("Welcome Channel exists") - + if (!guild.welcome_screen.enabled) throw new HTTPError("Welcome screen disabled", 400); + if (guild.welcome_screen.welcome_channels.some((channel) => channel.channel_id === body.channel_id)) + throw new Error("Welcome Channel exists"); await GuildModel.findOneAndUpdate( { - id: guild_id, + id: guild_id }, { $push: { "welcome_screen.welcome_channels": channelObject } } ).exec(); @@ -48,5 +46,4 @@ router.post("/", check(GuildAddChannelToWelcomeScreenSchema), async (req: Reques res.sendStatus(204); }); - export default router; diff --git a/src/routes/guilds/#guild_id/widget.json.ts b/src/routes/guilds/#guild_id/widget.json.ts
index 256a633d..6f777ab4 100644 --- a/src/routes/guilds/#guild_id/widget.json.ts +++ b/src/routes/guilds/#guild_id/widget.json.ts
@@ -18,7 +18,6 @@ router.get("/", async (req: Request, res: Response) => { const { guild_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild does not exist", 404); if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); // Fetch existing widget invite for widget channel @@ -43,68 +42,66 @@ router.get("/", async (req: Request, res: Response) => { invite = await new InviteModel(body).save(); } - + // Fetch voice channels, and the @everyone permissions object let channels: any[] = []; - await ChannelModel.find( - { guild_id: guild_id, type: 2 }, - { permission_overwrites: { $elemMatch: { id: guild_id } } } - ).lean() - .select("id name position permission_overwrites") - .sort({ position: 1 }) - .cursor() - .eachAsync(doc => { - // Only return channels where @everyone has the CONNECT permission - if (doc.permission_overwrites === undefined || Permissions.channelPermission(doc.permission_overwrites, Permissions.FLAGS.CONNECT) === Permissions.FLAGS.CONNECT) { - channels.push( - { + await ChannelModel.find({ guild_id: guild_id, type: 2 }, { permission_overwrites: { $elemMatch: { id: guild_id } } }) + .lean() + .select("id name position permission_overwrites") + .sort({ position: 1 }) + .cursor() + .eachAsync((doc) => { + // Only return channels where @everyone has the CONNECT permission + if ( + doc.permission_overwrites === undefined || + Permissions.channelPermission(doc.permission_overwrites, Permissions.FLAGS.CONNECT) === Permissions.FLAGS.CONNECT + ) { + channels.push({ id: doc.id, name: doc.name, position: doc.position - } - ) - } - }); + }); + } + }); // Fetch members // TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file) let members: any[] = []; await MemberModel.find({ guild_id: guild_id }) - .lean() - .populate({ path: "user", select: { _id: 0, username: 1, avatar: 1, presence: 1 } }) - .select("id user nick deaf mute") - .cursor() - .eachAsync(doc => { - const status = doc.user?.presence?.status || "offline"; - if (status == "offline")return - - let item = {} - - item = { - ...item, - id: null, // this is updated during the sort outside of the query - username: doc.nick || doc.user?.username, - discriminator: "0000", // intended (https://github.com/discord/discord-api-docs/issues/1287) - avatar: null, // intended, avatar_url below will return a unique guild + user url to the avatar - status: status - } + .lean() + .populate({ path: "user", select: { _id: 0, username: 1, avatar: 1, presence: 1 } }) + .select("id user nick deaf mute") + .cursor() + .eachAsync((doc) => { + const status = doc.user?.presence?.status || "offline"; + if (status == "offline") return; + + let item = {}; - const activity = doc.user?.presence?.activities?.[0]; - if (activity) { item = { ...item, - game: { name: activity.name } + id: null, // this is updated during the sort outside of the query + username: doc.nick || doc.user?.username, + discriminator: "0000", // intended (https://github.com/discord/discord-api-docs/issues/1287) + avatar: null, // intended, avatar_url below will return a unique guild + user url to the avatar + status: status + }; + + const activity = doc.user?.presence?.activities?.[0]; + if (activity) { + item = { + ...item, + game: { name: activity.name } + }; } - } - - // TODO: If the member is in a voice channel, return extra widget details - // Extra fields returned include deaf, mute, self_deaf, self_mute, supress, and channel_id (voice channel connected to) - // Get this from VoiceState + // TODO: If the member is in a voice channel, return extra widget details + // Extra fields returned include deaf, mute, self_deaf, self_mute, supress, and channel_id (voice channel connected to) + // Get this from VoiceState - // TODO: Implement a widget-avatar endpoint on the CDN, and implement logic here to request it - // Get unique avatar url for guild user, cdn to serve the actual avatar image on this url - /* + // TODO: Implement a widget-avatar endpoint on the CDN, and implement logic here to request it + // Get unique avatar url for guild user, cdn to serve the actual avatar image on this url + /* const avatar = doc.user?.avatar; if (avatar) { const CDN_HOST = Config.get().cdn.endpoint || "http://localhost:3003"; @@ -116,8 +113,8 @@ router.get("/", async (req: Request, res: Response) => { } */ - members.push(item); - }); + members.push(item); + }); // Sort members, and update ids (Unable to do under the mongoose query due to https://mongoosejs.com/docs/faq.html#populate_sort_order) members = members.sort((first, second) => 0 - (first.username > second.username ? -1 : 1)); @@ -133,7 +130,7 @@ router.get("/", async (req: Request, res: Response) => { channels: channels, members: members, presence_count: guild.presence_count - } + }; res.set("Cache-Control", "public, max-age=300"); return res.json(data); diff --git a/src/routes/guilds/#guild_id/widget.png.ts b/src/routes/guilds/#guild_id/widget.png.ts
index 839a8129..a0a8c938 100644 --- a/src/routes/guilds/#guild_id/widget.png.ts +++ b/src/routes/guilds/#guild_id/widget.png.ts
@@ -14,7 +14,6 @@ router.get("/", async (req: Request, res: Response) => { const { guild_id } = req.params; const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild does not exist", 404); if (!guild.widget_enabled) throw new HTTPError("Unknown Guild", 404); // Fetch guild information diff --git a/src/routes/guilds/#guild_id/widget.ts b/src/routes/guilds/#guild_id/widget.ts
index 7682bc87..0e6df186 100644 --- a/src/routes/guilds/#guild_id/widget.ts +++ b/src/routes/guilds/#guild_id/widget.ts
@@ -14,9 +14,8 @@ router.get("/", async (req: Request, res: Response) => { perms.hasThrow("MANAGE_GUILD"); const guild = await GuildModel.findOne({ id: guild_id }).exec(); - if (!guild) throw new HTTPError("Guild not found", 404); - return res.json({ enabled: guild.widget_enabled || false, channel_id: guild.widget_channel_id || null}); + return res.json({ enabled: guild.widget_enabled || false, channel_id: guild.widget_channel_id || null }); }); // https://discord.com/developers/docs/resources/guild#modify-guild-widget diff --git a/src/routes/guilds/templates/index.ts b/src/routes/guilds/templates/index.ts
index f23d4fbe..cc95069d 100644 --- a/src/routes/guilds/templates/index.ts +++ b/src/routes/guilds/templates/index.ts
@@ -11,7 +11,6 @@ router.get("/:code", async (req: Request, res: Response) => { const { code } = req.params; const template = await TemplateModel.findOne({ id: code }).exec(); - if (!template) throw new HTTPError("template not found", 404); res.json(toObject(template)).send(); }); @@ -28,7 +27,6 @@ router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res } const template = await TemplateModel.findOne({ code: code }).exec(); - if (!template) throw new HTTPError("template not found", 404); const guild_id = Snowflake.generate();