diff --git a/api/src/routes/channels/#channel_id/index.ts b/api/src/routes/channels/#channel_id/index.ts
index 46554d70..02ac9884 100644
--- a/api/src/routes/channels/#channel_id/index.ts
+++ b/api/src/routes/channels/#channel_id/index.ts
@@ -1,48 +1,59 @@
-import { ChannelDeleteEvent, Channel, ChannelUpdateEvent, emitEvent, getPermission } from "@fosscord/util";
+import { ChannelDeleteEvent, Channel, ChannelUpdateEvent, emitEvent, ChannelType, ChannelPermissionOverwriteType } from "@fosscord/util";
import { Router, Response, Request } from "express";
-import { HTTPError } from "lambert-server";
-import { ChannelModifySchema } from "../../../schema/Channel";
-import { check } from "@fosscord/api";
+import { route } from "@fosscord/api";
const router: Router = Router();
// TODO: delete channel
// TODO: Get channel
-router.get("/", async (req: Request, res: Response) => {
+router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
- const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
- permission.hasThrow("VIEW_CHANNEL");
-
return res.send(channel);
});
-router.delete("/", async (req: Request, res: Response) => {
+router.delete("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
- const permission = await getPermission(req.user_id, channel?.guild_id, channel_id);
- permission.hasThrow("MANAGE_CHANNELS");
-
// TODO: Dm channel "close" not delete
const data = channel;
- await emitEvent({ event: "CHANNEL_DELETE", data, channel_id } as ChannelDeleteEvent);
-
- await Channel.delete({ id: channel_id });
+ await Promise.all([emitEvent({ event: "CHANNEL_DELETE", data, channel_id } as ChannelDeleteEvent), Channel.delete({ id: channel_id })]);
res.send(data);
});
-router.patch("/", check(ChannelModifySchema), async (req: Request, res: Response) => {
+export interface ChannelModifySchema {
+ /**
+ * @maxLength 100
+ */
+ name: string;
+ type: ChannelType;
+ topic?: string;
+ bitrate?: number;
+ user_limit?: number;
+ rate_limit_per_user?: number;
+ position?: number;
+ permission_overwrites?: {
+ id: string;
+ type: ChannelPermissionOverwriteType;
+ allow: bigint;
+ deny: bigint;
+ }[];
+ parent_id?: string;
+ id?: string; // is not used (only for guild create)
+ nsfw?: boolean;
+ rtc_region?: string;
+ default_auto_archive_duration?: number;
+}
+
+router.patch("/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
var payload = req.body as ChannelModifySchema;
const { channel_id } = req.params;
- const permission = await getPermission(req.user_id, undefined, channel_id);
- permission.hasThrow("MANAGE_CHANNELS");
-
const channel = await Channel.findOneOrFail({ id: channel_id });
channel.assign(payload);
diff --git a/api/src/routes/channels/#channel_id/invites.ts b/api/src/routes/channels/#channel_id/invites.ts
index c6909fd0..39263185 100644
--- a/api/src/routes/channels/#channel_id/invites.ts
+++ b/api/src/routes/channels/#channel_id/invites.ts
@@ -1,14 +1,25 @@
import { Router, Request, Response } from "express";
import { HTTPError } from "lambert-server";
-import { check } from "@fosscord/api";
+import { route } from "@fosscord/api";
import { random } from "@fosscord/api";
-import { InviteCreateSchema } from "../../../schema/Invite";
import { getPermission, Channel, Invite, InviteCreateEvent, emitEvent, User, Guild, PublicInviteRelation } from "@fosscord/util";
import { isTextChannel } from "./messages";
const router: Router = Router();
-router.post("/", check(InviteCreateSchema), async (req: Request, res: Response) => {
+export interface InviteCreateSchema {
+ target_user_id?: string;
+ target_type?: string;
+ validate?: string; //? wtf is this
+ max_age?: number;
+ max_uses?: number;
+ temporary?: boolean;
+ unique?: boolean;
+ target_user?: string;
+ target_user_type?: number;
+}
+
+router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE" }), async (req: Request, res: Response) => {
const { user_id } = req;
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
@@ -19,23 +30,6 @@ router.post("/", check(InviteCreateSchema), async (req: Request, res: Response)
}
const { guild_id } = channel;
- const permission = await getPermission(user_id, guild_id, undefined, {
- guild_select: [
- "banner",
- "description",
- "features",
- "icon",
- "id",
- "name",
- "nsfw",
- "nsfw_level",
- "splash",
- "vanity_url_code",
- "verification_level"
- ] as (keyof Guild)[]
- });
- permission.hasThrow("CREATE_INSTANT_INVITE");
-
const expires_at = new Date(req.body.max_age * 1000 + Date.now());
const invite = await new Invite({
@@ -52,14 +46,14 @@ router.post("/", check(InviteCreateSchema), async (req: Request, res: Response)
}).save();
const data = invite.toJSON();
data.inviter = await User.getPublicUser(req.user_id);
- data.guild = permission.cache.guild;
+ data.guild = await Guild.findOne({ id: guild_id });
data.channel = channel;
await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
res.status(201).send(data);
});
-router.get("/", async (req: Request, res: Response) => {
+router.get("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
const { user_id } = req;
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
@@ -68,8 +62,6 @@ router.get("/", async (req: Request, res: Response) => {
throw new HTTPError("This channel doesn't exist", 404);
}
const { guild_id } = channel;
- const permission = await getPermission(user_id, guild_id);
- permission.hasThrow("MANAGE_CHANNELS");
const invites = await Invite.find({ where: { guild_id }, relations: PublicInviteRelation });
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
index aab51484..97d1d19e 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
@@ -1,14 +1,18 @@
import { emitEvent, getPermission, MessageAckEvent, ReadState } from "@fosscord/util";
import { Request, Response, Router } from "express";
-
-import { check } from "@fosscord/api";
+import { route } from "@fosscord/api";
const router = Router();
// TODO: check if message exists
// TODO: send read state event to all channel members
-router.post("/", check({ $manual: Boolean, $mention_count: Number }), async (req: Request, res: Response) => {
+export interface MessageAcknowledgeSchema {
+ manual?: boolean;
+ mention_count?: number;
+}
+
+router.post("/", route({ body: "MessageAcknowledgeSchema" }), async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
const permission = await getPermission(req.user_id, undefined, channel_id);
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
index e9588bd3..d0f780db 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -1,12 +1,13 @@
import { Channel, emitEvent, getPermission, MessageDeleteEvent, Message, MessageUpdateEvent } from "@fosscord/util";
import { Router, Response, Request } from "express";
-import { MessageCreateSchema } from "../../../../../schema/Message";
-import { check } from "@fosscord/api";
+import { route } from "@fosscord/api";
import { handleMessage, postHandleMessage } from "@fosscord/api";
+import { MessageCreateSchema } from "../index";
const router = Router();
+// TODO: message content/embed string length limit
-router.patch("/", check(MessageCreateSchema), async (req: Request, res: Response) => {
+router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
var body = req.body as MessageCreateSchema;
@@ -47,14 +48,17 @@ router.patch("/", check(MessageCreateSchema), async (req: Request, res: Response
// TODO: delete attachments in message
-router.delete("/", async (req: Request, res: Response) => {
+// permission check only if deletes messagr from other user
+router.delete("/", route({}), async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
const message = await Message.findOneOrFail({ id: message_id });
- const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
- if (message.author_id !== req.user_id) permission.hasThrow("MANAGE_MESSAGES");
+ if (message.author_id !== req.user_id) {
+ const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
+ permission.hasThrow("MANAGE_MESSAGES");
+ }
await Message.delete({ id: message_id });
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..f2b83d40 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
@@ -13,6 +13,7 @@ import {
PublicUserProjection,
User
} from "@fosscord/util";
+import { route } from "@fosscord/api";
import { Router, Response, Request } from "express";
import { HTTPError } from "lambert-server";
import { In } from "typeorm";
@@ -35,14 +36,11 @@ function getEmoji(emoji: string): PartialEmoji {
};
}
-router.delete("/", async (req: Request, res: Response) => {
+router.delete("/", route({ permission: "MANAGE_MESSAGES" }), async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
- const permissions = await getPermission(req.user_id, undefined, channel_id);
- permissions.hasThrow("MANAGE_MESSAGES");
-
await Message.update({ id: message_id, channel_id }, { reactions: [] });
await emitEvent({
@@ -58,13 +56,10 @@ router.delete("/", async (req: Request, res: Response) => {
res.sendStatus(204);
});
-router.delete("/:emoji", async (req: Request, res: Response) => {
+router.delete("/:emoji", route({ permission: "MANAGE_MESSAGES" }), async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const emoji = getEmoji(req.params.emoji);
- const permissions = await getPermission(req.user_id, undefined, channel_id);
- permissions.hasThrow("MANAGE_MESSAGES");
-
const message = await Message.findOneOrFail({ id: message_id, channel_id });
const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
@@ -88,7 +83,7 @@ router.delete("/:emoji", async (req: Request, res: Response) => {
res.sendStatus(204);
});
-router.get("/:emoji", async (req: Request, res: Response) => {
+router.get("/:emoji", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const emoji = getEmoji(req.params.emoji);
@@ -96,9 +91,6 @@ router.get("/:emoji", async (req: Request, res: Response) => {
const reaction = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
if (!reaction) throw new HTTPError("Reaction not found", 404);
- const permissions = await getPermission(req.user_id, undefined, channel_id);
- permissions.hasThrow("VIEW_CHANNEL");
-
const users = await User.find({
where: {
id: In(reaction.user_ids)
@@ -109,7 +101,7 @@ router.get("/:emoji", async (req: Request, res: Response) => {
res.json(users);
});
-router.put("/:emoji/:user_id", async (req: Request, res: Response) => {
+router.put("/:emoji/:user_id", route({ permission: "READ_MESSAGE_HISTORY" }), async (req: Request, res: Response) => {
const { message_id, channel_id, user_id } = req.params;
if (user_id !== "@me") throw new HTTPError("Invalid user");
const emoji = getEmoji(req.params.emoji);
@@ -118,13 +110,11 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => {
const message = await Message.findOneOrFail({ id: message_id, channel_id });
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);
- permissions.hasThrow("READ_MESSAGE_HISTORY");
- if (!already_added) permissions.hasThrow("ADD_REACTIONS");
+ if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
if (emoji.id) {
const external_emoji = await Emoji.findOneOrFail({ id: emoji.id });
- if (!already_added) permissions.hasThrow("USE_EXTERNAL_EMOJIS");
+ if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
emoji.animated = external_emoji.animated;
emoji.name = external_emoji.name;
}
@@ -154,7 +144,7 @@ router.put("/:emoji/:user_id", async (req: Request, res: Response) => {
res.sendStatus(204);
});
-router.delete("/:emoji/:user_id", async (req: Request, res: Response) => {
+router.delete("/:emoji/:user_id", route({}), async (req: Request, res: Response) => {
var { message_id, channel_id, user_id } = req.params;
const emoji = getEmoji(req.params.emoji);
@@ -162,10 +152,11 @@ router.delete("/:emoji/:user_id", async (req: Request, res: Response) => {
const channel = await Channel.findOneOrFail({ id: channel_id });
const message = await Message.findOneOrFail({ id: message_id, channel_id });
- const permissions = await getPermission(req.user_id, undefined, channel_id);
-
if (user_id === "@me") user_id = req.user_id;
- else permissions.hasThrow("MANAGE_MESSAGES");
+ else {
+ const permissions = await getPermission(req.user_id, undefined, channel_id);
+ permissions.hasThrow("MANAGE_MESSAGES");
+ }
const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
if (!already_added || !already_added.user_ids.includes(user_id)) throw new HTTPError("Reaction not found", 404);
diff --git a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
index 5d7566e1..a0fe7cc0 100644
--- a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -1,18 +1,21 @@
import { Router, Response, Request } from "express";
import { Channel, Config, emitEvent, getPermission, MessageDeleteBulkEvent, Message } from "@fosscord/util";
import { HTTPError } from "lambert-server";
-
-import { check } from "@fosscord/api";
+import { route } from "@fosscord/api";
import { In } from "typeorm";
const router: Router = Router();
export default router;
+export interface BulkDeleteSchema {
+ messages: string[];
+}
+
// TODO: should users be able to bulk delete messages or only bots?
// TODO: should this request fail, if you provide messages older than 14 days/invalid ids?
// https://discord.com/developers/docs/resources/channel#bulk-delete-messages
-router.post("/", check({ messages: [String] }), async (req: Request, res: Response) => {
+router.post("/", route({ body: "BulkDeleteSchema" }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts
index 591ebbbe..11334367 100644
--- a/api/src/routes/channels/#channel_id/messages/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/index.ts
@@ -1,10 +1,8 @@
import { Router, Response, Request } from "express";
-import { Attachment, Channel, ChannelType, getPermission, Message } from "@fosscord/util";
+import { Attachment, Channel, ChannelType, Embed, getPermission, Message } from "@fosscord/util";
import { HTTPError } from "lambert-server";
-import { MessageCreateSchema } from "../../../../schema/Message";
-import { check, instanceOf, Length } from "@fosscord/api";
+import { instanceOf, Length, route } from "@fosscord/api";
import multer from "multer";
-import { Query } from "mongoose";
import { sendMessage } from "@fosscord/api";
import { uploadFile } from "@fosscord/api";
import { FindManyOptions, LessThan, MoreThan } from "typeorm";
@@ -31,6 +29,30 @@ export function isTextChannel(type: ChannelType): boolean {
}
}
+export interface MessageCreateSchema {
+ content?: string;
+ nonce?: string;
+ tts?: boolean;
+ flags?: string;
+ embeds?: Embed[];
+ embed?: Embed;
+ // TODO: ^ embed is deprecated in favor of embeds (https://discord.com/developers/docs/resources/channel#message-object)
+ allowed_mentions?: {
+ parse?: string[];
+ roles?: string[];
+ users?: string[];
+ replied_user?: boolean;
+ };
+ message_reference?: {
+ message_id: string;
+ channel_id: string;
+ guild_id?: string;
+ fail_if_not_exists?: boolean;
+ };
+ payload_json?: string;
+ file?: any;
+}
+
// https://discord.com/developers/docs/resources/channel#create-message
// get messages
router.get("/", async (req: Request, res: Response) => {
@@ -109,39 +131,44 @@ const messageUpload = multer({
// TODO: check allowed_mentions
// Send message
-router.post("/", messageUpload.single("file"), async (req: Request, res: Response) => {
- const { channel_id } = req.params;
- var body = req.body as MessageCreateSchema;
- const attachments: Attachment[] = [];
-
- if (req.file) {
- try {
- const file = await uploadFile(`/attachments/${channel_id}`, req.file);
- attachments.push({ ...file, proxy_url: file.url });
- } catch (error) {
- return res.status(400).json(error);
+router.post(
+ "/",
+ messageUpload.single("file"),
+ async (req, res, next) => {
+ if (req.body.payload_json) {
+ req.body = JSON.parse(req.body.payload_json);
}
- }
- if (body.payload_json) {
- body = JSON.parse(body.payload_json);
- }
+ next();
+ },
+ route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES" }),
+ async (req: Request, res: Response) => {
+ const { channel_id } = req.params;
+ var body = req.body as MessageCreateSchema;
+ const attachments: Attachment[] = [];
+
+ if (req.file) {
+ try {
+ const file = await uploadFile(`/attachments/${req.params.channel_id}`, req.file);
+ attachments.push({ ...file, proxy_url: file.url });
+ } catch (error) {
+ return res.status(400).json(error);
+ }
+ }
- const errors = instanceOf(MessageCreateSchema, body, { req });
- if (errors !== true) throw errors;
-
- const embeds = [];
- if (body.embed) embeds.push(body.embed);
- const data = await sendMessage({
- ...body,
- type: 0,
- pinned: false,
- author_id: req.user_id,
- embeds,
- channel_id,
- attachments,
- edited_timestamp: undefined
- });
-
- return res.json(data);
-});
+ const embeds = [];
+ if (body.embed) embeds.push(body.embed);
+ const data = await sendMessage({
+ ...body,
+ type: 0,
+ pinned: false,
+ author_id: req.user_id,
+ embeds,
+ channel_id,
+ attachments,
+ edited_timestamp: undefined
+ });
+
+ return res.json(data);
+ }
+);
diff --git a/api/src/routes/channels/#channel_id/permissions.ts b/api/src/routes/channels/#channel_id/permissions.ts
index 0465ca31..827e46f2 100644
--- a/api/src/routes/channels/#channel_id/permissions.ts
+++ b/api/src/routes/channels/#channel_id/permissions.ts
@@ -2,61 +2,61 @@ import { Channel, ChannelPermissionOverwrite, ChannelUpdateEvent, emitEvent, get
import { Router, Response, Request } from "express";
import { HTTPError } from "lambert-server";
-import { check } from "@fosscord/api";
+import { check, route } from "@fosscord/api";
const router: Router = Router();
// TODO: Only permissions your bot has in the guild or channel can be allowed/denied (unless your bot has a MANAGE_ROLES overwrite in the channel)
-router.put("/:overwrite_id", check({ allow: String, deny: String, type: Number, id: String }), async (req: Request, res: Response) => {
- const { channel_id, overwrite_id } = req.params;
- const body = req.body as { allow: bigint; deny: bigint; type: number; id: string };
+export interface ChannelPermissionOverwriteSchema extends ChannelPermissionOverwrite {}
- var channel = await Channel.findOneOrFail({ id: channel_id });
- if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
+router.put(
+ "/:overwrite_id",
+ route({ body: "ChannelPermissionOverwriteSchema", permission: "MANAGE_ROLES" }),
+ async (req: Request, res: Response) => {
+ const { channel_id, overwrite_id } = req.params;
+ const body = req.body as { allow: bigint; deny: bigint; type: number; id: string };
- const permissions = await getPermission(req.user_id, channel.guild_id, channel_id);
- permissions.hasThrow("MANAGE_ROLES");
+ var channel = await Channel.findOneOrFail({ id: channel_id });
+ if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
- 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);
- } else throw new HTTPError("type not supported", 501);
+ 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);
+ } else throw new HTTPError("type not supported", 501);
- // @ts-ignore
- var overwrite: ChannelPermissionOverwrite = channel.permission_overwrites.find((x) => x.id === overwrite_id);
- if (!overwrite) {
// @ts-ignore
- overwrite = {
- id: overwrite_id,
- type: body.type,
- allow: body.allow,
- deny: body.deny
- };
- channel.permission_overwrites.push(overwrite);
+ var overwrite: ChannelPermissionOverwrite = channel.permission_overwrites.find((x) => x.id === overwrite_id);
+ if (!overwrite) {
+ // @ts-ignore
+ overwrite = {
+ id: overwrite_id,
+ type: body.type,
+ allow: body.allow,
+ deny: body.deny
+ };
+ channel.permission_overwrites.push(overwrite);
+ }
+ overwrite.allow = body.allow;
+ overwrite.deny = body.deny;
+
+ await Promise.all([
+ channel.save(),
+ emitEvent({
+ event: "CHANNEL_UPDATE",
+ channel_id,
+ data: channel
+ } as ChannelUpdateEvent)
+ ]);
+
+ return res.sendStatus(204);
}
- overwrite.allow = body.allow;
- overwrite.deny = body.deny;
-
- // @ts-ignore
- channel = await Channel.findOneOrFailAndUpdate({ id: channel_id }, channel, { new: true });
-
- await emitEvent({
- event: "CHANNEL_UPDATE",
- channel_id,
- data: channel
- } as ChannelUpdateEvent);
-
- return res.sendStatus(204);
-});
+);
// TODO: check permission hierarchy
-router.delete("/:overwrite_id", async (req: Request, res: Response) => {
+router.delete("/:overwrite_id", route({ permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
const { channel_id, overwrite_id } = req.params;
- const permissions = await getPermission(req.user_id, undefined, channel_id);
- permissions.hasThrow("MANAGE_ROLES");
-
const channel = await Channel.findOneOrFail({ id: channel_id });
if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
diff --git a/api/src/routes/channels/#channel_id/pins.ts b/api/src/routes/channels/#channel_id/pins.ts
index 33309c86..e71e659f 100644
--- a/api/src/routes/channels/#channel_id/pins.ts
+++ b/api/src/routes/channels/#channel_id/pins.ts
@@ -1,19 +1,26 @@
-import { Channel, ChannelPinsUpdateEvent, Config, emitEvent, getPermission, Message, MessageUpdateEvent } from "@fosscord/util";
+import {
+ Channel,
+ ChannelPinsUpdateEvent,
+ Config,
+ emitEvent,
+ getPermission,
+ Message,
+ MessageUpdateEvent,
+ DiscordApiErrors
+} from "@fosscord/util";
import { Router, Request, Response } from "express";
import { HTTPError } from "lambert-server";
-import { DiscordApiErrors } from "@fosscord/util";
+import { route } from "@fosscord/api";
const router: Router = Router();
-router.put("/:message_id", async (req: Request, res: Response) => {
+router.put("/:message_id", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
const message = await Message.findOneOrFail({ id: message_id });
- const permission = await getPermission(req.user_id, message.guild_id, channel_id);
- permission.hasThrow("VIEW_CHANNEL");
// * in dm channels anyone can pin messages -> only check for guilds
- if (message.guild_id) permission.hasThrow("MANAGE_MESSAGES");
+ if (message.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
const pinned_count = await Message.count({ channel: { id: channel_id }, pinned: true });
const { maxPins } = Config.get().limits.channel;
@@ -26,7 +33,6 @@ router.put("/:message_id", async (req: Request, res: Response) => {
channel_id,
data: message
} as MessageUpdateEvent),
-
emitEvent({
event: "CHANNEL_PINS_UPDATE",
channel_id,
@@ -41,14 +47,11 @@ router.put("/:message_id", async (req: Request, res: Response) => {
res.sendStatus(204);
});
-router.delete("/:message_id", async (req: Request, res: Response) => {
+router.delete("/:message_id", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
-
- const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
- permission.hasThrow("VIEW_CHANNEL");
- if (channel.guild_id) permission.hasThrow("MANAGE_MESSAGES");
+ if (channel.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
const message = await Message.findOneOrFail({ id: message_id });
message.pinned = false;
@@ -76,13 +79,9 @@ router.delete("/:message_id", async (req: Request, res: Response) => {
res.sendStatus(204);
});
-router.get("/", async (req: Request, res: Response) => {
+router.get("/", route({ permission: ["READ_MESSAGE_HISTORY"] }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
- const channel = await Channel.findOneOrFail({ id: channel_id });
- const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
- permission.hasThrow("VIEW_CHANNEL");
-
let pins = await Message.find({ channel_id: channel_id, pinned: true });
res.send(pins);
diff --git a/api/src/routes/channels/#channel_id/typing.ts b/api/src/routes/channels/#channel_id/typing.ts
index f1fb3c86..ad973bca 100644
--- a/api/src/routes/channels/#channel_id/typing.ts
+++ b/api/src/routes/channels/#channel_id/typing.ts
@@ -1,11 +1,10 @@
import { Channel, emitEvent, Member, TypingStartEvent } from "@fosscord/util";
+import { route } from "@fosscord/api";
import { Router, Request, Response } from "express";
-import { HTTPError } from "lambert-server";
-
const router: Router = Router();
-router.post("/", async (req: Request, res: Response) => {
+router.post("/", route({ permission: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
const user_id = req.user_id;
const timestamp = Date.now();
@@ -24,6 +23,7 @@ router.post("/", async (req: Request, res: Response) => {
guild_id: channel.guild_id
}
} as TypingStartEvent);
+
res.sendStatus(204);
});
diff --git a/api/src/routes/channels/#channel_id/webhooks.ts b/api/src/routes/channels/#channel_id/webhooks.ts
index 821a62db..f84dfcc5 100644
--- a/api/src/routes/channels/#channel_id/webhooks.ts
+++ b/api/src/routes/channels/#channel_id/webhooks.ts
@@ -1,5 +1,5 @@
import { Router, Response, Request } from "express";
-import { check, Length } from "@fosscord/api";
+import { check, Length, route } from "@fosscord/api";
import { Channel, Config, getPermission, trimSpecial, Webhook } from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { isTextChannel } from "./messages/index";
@@ -7,9 +7,16 @@ import { DiscordApiErrors } from "@fosscord/util";
const router: Router = Router();
// TODO: webhooks
+export interface WebhookCreateSchema {
+ /**
+ * @maxLength 80
+ */
+ name: string;
+ avatar: string;
+}
// TODO: use Image Data Type for avatar instead of String
-router.post("/", check({ name: new Length(String, 1, 80), $avatar: String }), async (req: Request, res: Response) => {
+router.post("/", route({ body: "WebhookCreateSchema", permission: "MANAGE_WEBHOOKS" }), async (req: Request, res: Response) => {
const channel_id = req.params.channel_id;
const channel = await Channel.findOneOrFail({ id: channel_id });
@@ -20,12 +27,11 @@ router.post("/", check({ name: new Length(String, 1, 80), $avatar: String }), as
const { maxWebhooks } = Config.get().limits.channel;
if (webhook_count > maxWebhooks) throw DiscordApiErrors.MAXIMUM_WEBHOOKS.withParams(maxWebhooks);
- const permission = await getPermission(req.user_id, channel.guild_id);
- permission.hasThrow("MANAGE_WEBHOOKS");
-
var { avatar, name } = req.body as { name: string; avatar?: string };
name = trimSpecial(name);
if (name === "clyde") throw new HTTPError("Invalid name", 400);
+
+ // TODO: save webhook in database and send response
});
export default router;
|