diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts
index db0d4242..74e21a02 100644
--- a/src/api/routes/channels/#channel_id/index.ts
+++ b/src/api/routes/channels/#channel_id/index.ts
@@ -16,18 +16,18 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { route } from "@spacebar/api";
import {
Channel,
ChannelDeleteEvent,
+ ChannelModifySchema,
ChannelType,
ChannelUpdateEvent,
- emitEvent,
Recipient,
+ emitEvent,
handleFile,
- ChannelModifySchema,
} from "@spacebar/util";
import { Request, Response, Router } from "express";
-import { route } from "@spacebar/api";
const router: Router = Router();
// TODO: delete channel
@@ -35,7 +35,15 @@ const router: Router = Router();
router.get(
"/",
- route({ permission: "VIEW_CHANNEL" }),
+ route({
+ permission: "VIEW_CHANNEL",
+ responses: {
+ 200: {
+ body: "Channel",
+ },
+ 404: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
@@ -49,7 +57,15 @@ router.get(
router.delete(
"/",
- route({ permission: "MANAGE_CHANNELS" }),
+ route({
+ permission: "MANAGE_CHANNELS",
+ responses: {
+ 200: {
+ body: "Channel",
+ },
+ 404: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
@@ -90,7 +106,19 @@ router.delete(
router.patch(
"/",
- route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }),
+ route({
+ body: "ChannelModifySchema",
+ permission: "MANAGE_CHANNELS",
+ responses: {
+ 200: {
+ body: "Channel",
+ },
+ 404: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
async (req: Request, res: Response) => {
const payload = req.body as ChannelModifySchema;
const { channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index 9f247fe8..35cdbca8 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -16,19 +16,18 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Router, Request, Response } from "express";
-import { HTTPError } from "lambert-server";
-import { route } from "@spacebar/api";
-import { random } from "@spacebar/api";
+import { random, route } from "@spacebar/api";
import {
Channel,
+ Guild,
Invite,
InviteCreateEvent,
- emitEvent,
- User,
- Guild,
PublicInviteRelation,
+ User,
+ emitEvent,
} from "@spacebar/util";
+import { Request, Response, Router } from "express";
+import { HTTPError } from "lambert-server";
import { isTextChannel } from "./messages";
const router: Router = Router();
@@ -39,6 +38,15 @@ router.post(
body: "InviteCreateSchema",
permission: "CREATE_INSTANT_INVITE",
right: "CREATE_INVITES",
+ responses: {
+ 201: {
+ body: "Invite",
+ },
+ 404: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
}),
async (req: Request, res: Response) => {
const { user_id } = req;
@@ -84,7 +92,15 @@ router.post(
router.get(
"/",
- route({ permission: "MANAGE_CHANNELS" }),
+ route({
+ permission: "MANAGE_CHANNELS",
+ responses: {
+ 200: {
+ body: "ChannelInvitesResponse",
+ },
+ 404: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
index f098fa8e..f11fdcb2 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
@@ -16,6 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { route } from "@spacebar/api";
import {
emitEvent,
getPermission,
@@ -23,7 +24,6 @@ import {
ReadState,
} from "@spacebar/util";
import { Request, Response, Router } from "express";
-import { route } from "@spacebar/api";
const router = Router();
@@ -33,7 +33,13 @@ const router = Router();
router.post(
"/",
- route({ body: "MessageAcknowledgeSchema" }),
+ route({
+ body: "MessageAcknowledgeSchema",
+ responses: {
+ 200: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
index 909a459e..5ca645c0 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
@@ -16,14 +16,21 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Router, Response, Request } from "express";
import { route } from "@spacebar/api";
+import { Request, Response, Router } from "express";
const router = Router();
router.post(
"/",
- route({ permission: "MANAGE_MESSAGES" }),
+ route({
+ permission: "MANAGE_MESSAGES",
+ responses: {
+ 200: {
+ body: "Message",
+ },
+ },
+ }),
(req: Request, res: Response) => {
// TODO:
res.json({
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
index cd4b243e..77bc1e0e 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -19,24 +19,23 @@
import {
Attachment,
Channel,
- emitEvent,
- SpacebarApiErrors,
- getPermission,
- getRights,
Message,
MessageCreateEvent,
+ MessageCreateSchema,
MessageDeleteEvent,
+ MessageEditSchema,
MessageUpdateEvent,
Snowflake,
+ SpacebarApiErrors,
+ emitEvent,
+ getPermission,
+ getRights,
uploadFile,
- MessageCreateSchema,
- MessageEditSchema,
} from "@spacebar/util";
-import { Router, Response, Request } from "express";
-import multer from "multer";
-import { route } from "@spacebar/api";
-import { handleMessage, postHandleMessage } from "@spacebar/api";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
+import multer from "multer";
+import { handleMessage, postHandleMessage, route } from "../../../../../util";
const router = Router();
// TODO: message content/embed string length limit
@@ -56,6 +55,16 @@ router.patch(
body: "MessageEditSchema",
permission: "SEND_MESSAGES",
right: "SEND_MESSAGES",
+ responses: {
+ 200: {
+ body: "Message",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
}),
async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
@@ -146,6 +155,16 @@ router.put(
body: "MessageCreateSchema",
permission: "SEND_MESSAGES",
right: "SEND_BACKDATED_EVENTS",
+ responses: {
+ 200: {
+ body: "Message",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
}),
async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
@@ -230,7 +249,19 @@ router.put(
router.get(
"/",
- route({ permission: "VIEW_CHANNEL" }),
+ route({
+ permission: "VIEW_CHANNEL",
+ responses: {
+ 200: {
+ body: "Message",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
@@ -252,38 +283,54 @@ router.get(
},
);
-router.delete("/", route({}), async (req: Request, res: Response) => {
- const { message_id, channel_id } = req.params;
+router.delete(
+ "/",
+ route({
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { message_id, channel_id } = req.params;
- const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
- const message = await Message.findOneOrFail({ where: { id: message_id } });
+ const channel = await Channel.findOneOrFail({
+ where: { id: channel_id },
+ });
+ const message = await Message.findOneOrFail({
+ where: { id: message_id },
+ });
- const rights = await getRights(req.user_id);
+ const rights = await getRights(req.user_id);
- if (message.author_id !== req.user_id) {
- if (!rights.has("MANAGE_MESSAGES")) {
- const permission = await getPermission(
- req.user_id,
- channel.guild_id,
- channel_id,
- );
- permission.hasThrow("MANAGE_MESSAGES");
- }
- } else rights.hasThrow("SELF_DELETE_MESSAGES");
+ if (message.author_id !== req.user_id) {
+ if (!rights.has("MANAGE_MESSAGES")) {
+ const permission = await getPermission(
+ req.user_id,
+ channel.guild_id,
+ channel_id,
+ );
+ permission.hasThrow("MANAGE_MESSAGES");
+ }
+ } else rights.hasThrow("SELF_DELETE_MESSAGES");
- await Message.delete({ id: message_id });
+ await Message.delete({ id: message_id });
- await emitEvent({
- event: "MESSAGE_DELETE",
- channel_id,
- data: {
- id: message_id,
+ await emitEvent({
+ event: "MESSAGE_DELETE",
channel_id,
- guild_id: channel.guild_id,
- },
- } as MessageDeleteEvent);
+ data: {
+ id: message_id,
+ channel_id,
+ guild_id: channel.guild_id,
+ },
+ } as MessageDeleteEvent);
- res.sendStatus(204);
-});
+ res.sendStatus(204);
+ },
+);
export default router;
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
index cb66cd64..c6db772b 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
@@ -16,6 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { route } from "@spacebar/api";
import {
Channel,
emitEvent,
@@ -32,8 +33,7 @@ import {
PublicUserProjection,
User,
} from "@spacebar/util";
-import { route } from "@spacebar/api";
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { In } from "typeorm";
@@ -57,7 +57,17 @@ function getEmoji(emoji: string): PartialEmoji {
router.delete(
"/",
- route({ permission: "MANAGE_MESSAGES" }),
+ route({
+ permission: "MANAGE_MESSAGES",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
@@ -83,7 +93,17 @@ router.delete(
router.delete(
"/:emoji",
- route({ permission: "MANAGE_MESSAGES" }),
+ route({
+ permission: "MANAGE_MESSAGES",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const emoji = getEmoji(req.params.emoji);
@@ -120,7 +140,19 @@ router.delete(
router.get(
"/:emoji",
- route({ permission: "VIEW_CHANNEL" }),
+ route({
+ permission: "VIEW_CHANNEL",
+ responses: {
+ 200: {
+ body: "UserPublic",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { message_id, channel_id } = req.params;
const emoji = getEmoji(req.params.emoji);
@@ -148,7 +180,18 @@ router.get(
router.put(
"/:emoji/:user_id",
- route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }),
+ route({
+ permission: "READ_MESSAGE_HISTORY",
+ right: "SELF_ADD_REACTIONS",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { message_id, channel_id, user_id } = req.params;
if (user_id !== "@me") throw new HTTPError("Invalid user");
@@ -219,7 +262,16 @@ router.put(
router.delete(
"/:emoji/:user_id",
- route({}),
+ route({
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
let { user_id } = req.params;
const { message_id, channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
index 18476d5c..db1617e2 100644
--- a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -16,18 +16,18 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Router, Response, Request } from "express";
+import { route } from "@spacebar/api";
import {
Channel,
Config,
emitEvent,
getPermission,
getRights,
- MessageDeleteBulkEvent,
Message,
+ MessageDeleteBulkEvent,
} from "@spacebar/util";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
-import { route } from "@spacebar/api";
const router: Router = Router();
@@ -38,7 +38,17 @@ export default router;
// https://discord.com/developers/docs/resources/channel#bulk-delete-messages
router.post(
"/",
- route({ body: "BulkDeleteSchema" }),
+ route({
+ body: "BulkDeleteSchema",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index 7f0c9fb5..8e3c43d7 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Router, Response, Request } from "express";
+import { handleMessage, postHandleMessage, route } from "@spacebar/api";
import {
Attachment,
Channel,
@@ -26,19 +26,19 @@ import {
emitEvent,
FieldErrors,
getPermission,
+ Member,
Message,
MessageCreateEvent,
- Snowflake,
- uploadFile,
- Member,
MessageCreateSchema,
+ Reaction,
ReadState,
Rights,
- Reaction,
+ Snowflake,
+ uploadFile,
User,
} from "@spacebar/util";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
-import { handleMessage, postHandleMessage, route } from "@spacebar/api";
import multer from "multer";
import { FindManyOptions, FindOperator, LessThan, MoreThan } from "typeorm";
import { URL } from "url";
@@ -73,108 +73,123 @@ export function isTextChannel(type: ChannelType): boolean {
// https://discord.com/developers/docs/resources/channel#create-message
// get messages
-router.get("/", route({}), async (req: Request, res: Response) => {
- const channel_id = req.params.channel_id;
- const channel = await Channel.findOneOrFail({
- where: { id: channel_id },
- });
- if (!channel) throw new HTTPError("Channel not found", 404);
-
- isTextChannel(channel.type);
- const around = req.query.around ? `${req.query.around}` : undefined;
- const before = req.query.before ? `${req.query.before}` : undefined;
- const after = req.query.after ? `${req.query.after}` : undefined;
- const limit = Number(req.query.limit) || 50;
- if (limit < 1 || limit > 100)
- throw new HTTPError("limit must be between 1 and 100", 422);
-
- const halfLimit = Math.floor(limit / 2);
-
- const permissions = await getPermission(
- req.user_id,
- channel.guild_id,
- channel_id,
- );
- permissions.hasThrow("VIEW_CHANNEL");
- if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
-
- const query: FindManyOptions<Message> & {
- where: { id?: FindOperator<string> | FindOperator<string>[] };
- } = {
- order: { timestamp: "DESC" },
- take: limit,
- where: { channel_id },
- relations: [
- "author",
- "webhook",
- "application",
- "mentions",
- "mention_roles",
- "mention_channels",
- "sticker_items",
- "attachments",
- ],
- };
-
- if (after) {
- if (BigInt(after) > BigInt(Snowflake.generate()))
- return res.status(422);
- query.where.id = MoreThan(after);
- } else if (before) {
- if (BigInt(before) < BigInt(req.params.channel_id))
- return res.status(422);
- query.where.id = LessThan(before);
- } else if (around) {
- query.where.id = [
- MoreThan((BigInt(around) - BigInt(halfLimit)).toString()),
- LessThan((BigInt(around) + BigInt(halfLimit)).toString()),
- ];
-
- return res.json([]); // TODO: fix around
- }
+router.get(
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "ChannelMessagesResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const channel_id = req.params.channel_id;
+ const channel = await Channel.findOneOrFail({
+ where: { id: channel_id },
+ });
+ if (!channel) throw new HTTPError("Channel not found", 404);
- const messages = await Message.find(query);
- const endpoint = Config.get().cdn.endpointPublic;
+ isTextChannel(channel.type);
+ const around = req.query.around ? `${req.query.around}` : undefined;
+ const before = req.query.before ? `${req.query.before}` : undefined;
+ const after = req.query.after ? `${req.query.after}` : undefined;
+ const limit = Number(req.query.limit) || 50;
+ if (limit < 1 || limit > 100)
+ throw new HTTPError("limit must be between 1 and 100", 422);
- return res.json(
- messages.map((x: Partial<Message>) => {
- (x.reactions || []).forEach((y: Partial<Reaction>) => {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- //@ts-ignore
- if ((y.user_ids || []).includes(req.user_id)) y.me = true;
- delete y.user_ids;
- });
- if (!x.author)
- x.author = User.create({
- id: "4",
- discriminator: "0000",
- username: "Spacebar Ghost",
- public_flags: 0,
+ const halfLimit = Math.floor(limit / 2);
+
+ const permissions = await getPermission(
+ req.user_id,
+ channel.guild_id,
+ channel_id,
+ );
+ permissions.hasThrow("VIEW_CHANNEL");
+ if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
+
+ const query: FindManyOptions<Message> & {
+ where: { id?: FindOperator<string> | FindOperator<string>[] };
+ } = {
+ order: { timestamp: "DESC" },
+ take: limit,
+ where: { channel_id },
+ relations: [
+ "author",
+ "webhook",
+ "application",
+ "mentions",
+ "mention_roles",
+ "mention_channels",
+ "sticker_items",
+ "attachments",
+ ],
+ };
+
+ if (after) {
+ if (BigInt(after) > BigInt(Snowflake.generate()))
+ return res.status(422);
+ query.where.id = MoreThan(after);
+ } else if (before) {
+ if (BigInt(before) < BigInt(req.params.channel_id))
+ return res.status(422);
+ query.where.id = LessThan(before);
+ } else if (around) {
+ query.where.id = [
+ MoreThan((BigInt(around) - BigInt(halfLimit)).toString()),
+ LessThan((BigInt(around) + BigInt(halfLimit)).toString()),
+ ];
+
+ return res.json([]); // TODO: fix around
+ }
+
+ const messages = await Message.find(query);
+ const endpoint = Config.get().cdn.endpointPublic;
+
+ return res.json(
+ messages.map((x: Partial<Message>) => {
+ (x.reactions || []).forEach((y: Partial<Reaction>) => {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ //@ts-ignore
+ if ((y.user_ids || []).includes(req.user_id)) y.me = true;
+ delete y.user_ids;
+ });
+ if (!x.author)
+ x.author = User.create({
+ id: "4",
+ discriminator: "0000",
+ username: "Fosscord Ghost",
+ public_flags: 0,
+ });
+ x.attachments?.forEach((y: Attachment) => {
+ // dynamically set attachment proxy_url in case the endpoint changed
+ const uri = y.proxy_url.startsWith("http")
+ ? y.proxy_url
+ : `https://example.org${y.proxy_url}`;
+ y.proxy_url = `${endpoint == null ? "" : endpoint}${
+ new URL(uri).pathname
+ }`;
});
- x.attachments?.forEach((y: Attachment) => {
- // dynamically set attachment proxy_url in case the endpoint changed
- const uri = y.proxy_url.startsWith("http")
- ? y.proxy_url
- : `https://example.org${y.proxy_url}`;
- y.proxy_url = `${endpoint == null ? "" : endpoint}${
- new URL(uri).pathname
- }`;
- });
- /**
+ /**
Some clients ( discord.js ) only check if a property exists within the response,
which causes errors when, say, the `application` property is `null`.
**/
- // for (var curr in x) {
- // if (x[curr] === null)
- // delete x[curr];
- // }
+ // for (var curr in x) {
+ // if (x[curr] === null)
+ // delete x[curr];
+ // }
- return x;
- }),
- );
-});
+ return x;
+ }),
+ );
+ },
+);
// TODO: config max upload size
const messageUpload = multer({
@@ -208,6 +223,16 @@ router.post(
body: "MessageCreateSchema",
permission: "SEND_MESSAGES",
right: "SEND_MESSAGES",
+ responses: {
+ 200: {
+ body: "Message",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ 404: {},
+ },
}),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts
index 68dbc2f2..c6a9def6 100644
--- a/src/api/routes/channels/#channel_id/permissions.ts
+++ b/src/api/routes/channels/#channel_id/permissions.ts
@@ -19,13 +19,13 @@
import {
Channel,
ChannelPermissionOverwrite,
+ ChannelPermissionOverwriteSchema,
ChannelUpdateEvent,
emitEvent,
Member,
Role,
- ChannelPermissionOverwriteSchema,
} from "@spacebar/util";
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { route } from "@spacebar/api";
@@ -38,6 +38,12 @@ router.put(
route({
body: "ChannelPermissionOverwriteSchema",
permission: "MANAGE_ROLES",
+ responses: {
+ 204: {},
+ 404: {},
+ 501: {},
+ 400: { body: "APIErrorResponse" },
+ },
}),
async (req: Request, res: Response) => {
const { channel_id, overwrite_id } = req.params;
@@ -92,7 +98,7 @@ router.put(
// TODO: check permission hierarchy
router.delete(
"/:overwrite_id",
- route({ permission: "MANAGE_ROLES" }),
+ route({ permission: "MANAGE_ROLES", responses: { 204: {}, 404: {} } }),
async (req: Request, res: Response) => {
const { channel_id, overwrite_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts
index 32820916..7b379c30 100644
--- a/src/api/routes/channels/#channel_id/pins.ts
+++ b/src/api/routes/channels/#channel_id/pins.ts
@@ -16,23 +16,33 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { route } from "@spacebar/api";
import {
Channel,
ChannelPinsUpdateEvent,
Config,
+ DiscordApiErrors,
emitEvent,
Message,
MessageUpdateEvent,
- DiscordApiErrors,
} from "@spacebar/util";
-import { Router, Request, Response } from "express";
-import { route } from "@spacebar/api";
+import { Request, Response, Router } from "express";
const router: Router = Router();
router.put(
"/:message_id",
- route({ permission: "VIEW_CHANNEL" }),
+ route({
+ permission: "VIEW_CHANNEL",
+ responses: {
+ 204: {},
+ 403: {},
+ 404: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
@@ -74,7 +84,17 @@ router.put(
router.delete(
"/:message_id",
- route({ permission: "VIEW_CHANNEL" }),
+ route({
+ permission: "VIEW_CHANNEL",
+ responses: {
+ 204: {},
+ 403: {},
+ 404: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params;
@@ -114,7 +134,17 @@ router.delete(
router.get(
"/",
- route({ permission: ["READ_MESSAGE_HISTORY"] }),
+ route({
+ permission: ["READ_MESSAGE_HISTORY"],
+ responses: {
+ 200: {
+ body: "ChannelPinsResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts
index c8da6760..cbd46bd0 100644
--- a/src/api/routes/channels/#channel_id/purge.ts
+++ b/src/api/routes/channels/#channel_id/purge.ts
@@ -16,20 +16,20 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { HTTPError } from "lambert-server";
import { route } from "@spacebar/api";
-import { isTextChannel } from "./messages";
-import { FindManyOptions, Between, Not, FindOperator } from "typeorm";
import {
Channel,
- emitEvent,
- getPermission,
- getRights,
Message,
MessageDeleteBulkEvent,
PurgeSchema,
+ emitEvent,
+ getPermission,
+ getRights,
} from "@spacebar/util";
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
+import { HTTPError } from "lambert-server";
+import { Between, FindManyOptions, FindOperator, Not } from "typeorm";
+import { isTextChannel } from "./messages";
const router: Router = Router();
@@ -42,6 +42,14 @@ router.post(
"/",
route({
/*body: "PurgeSchema",*/
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {},
+ 403: {},
+ },
}),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/recipients.ts b/src/api/routes/channels/#channel_id/recipients.ts
index f1fb48af..569bb5cd 100644
--- a/src/api/routes/channels/#channel_id/recipients.ts
+++ b/src/api/routes/channels/#channel_id/recipients.ts
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Request, Response, Router } from "express";
+import { route } from "@spacebar/api";
import {
Channel,
ChannelRecipientAddEvent,
@@ -28,80 +28,98 @@ import {
Recipient,
User,
} from "@spacebar/util";
-import { route } from "@spacebar/api";
+import { Request, Response, Router } from "express";
const router: Router = Router();
-router.put("/:user_id", route({}), async (req: Request, res: Response) => {
- const { channel_id, user_id } = req.params;
- const channel = await Channel.findOneOrFail({
- where: { id: channel_id },
- relations: ["recipients"],
- });
+router.put(
+ "/:user_id",
+ route({
+ responses: {
+ 201: {},
+ 404: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { channel_id, user_id } = req.params;
+ const channel = await Channel.findOneOrFail({
+ where: { id: channel_id },
+ relations: ["recipients"],
+ });
- if (channel.type !== ChannelType.GROUP_DM) {
- const recipients = [
- ...(channel.recipients?.map((r) => r.user_id) || []),
- user_id,
- ].unique();
+ if (channel.type !== ChannelType.GROUP_DM) {
+ const recipients = [
+ ...(channel.recipients?.map((r) => r.user_id) || []),
+ user_id,
+ ].unique();
- const new_channel = await Channel.createDMChannel(
- recipients,
- req.user_id,
- );
- return res.status(201).json(new_channel);
- } else {
- if (channel.recipients?.map((r) => r.user_id).includes(user_id)) {
- throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
- }
+ const new_channel = await Channel.createDMChannel(
+ recipients,
+ req.user_id,
+ );
+ return res.status(201).json(new_channel);
+ } else {
+ if (channel.recipients?.map((r) => r.user_id).includes(user_id)) {
+ throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
+ }
- channel.recipients?.push(
- Recipient.create({ channel_id: channel_id, user_id: user_id }),
- );
- await channel.save();
+ channel.recipients?.push(
+ Recipient.create({ channel_id: channel_id, user_id: user_id }),
+ );
+ await channel.save();
- await emitEvent({
- event: "CHANNEL_CREATE",
- data: await DmChannelDTO.from(channel, [user_id]),
- user_id: user_id,
- });
+ await emitEvent({
+ event: "CHANNEL_CREATE",
+ data: await DmChannelDTO.from(channel, [user_id]),
+ user_id: user_id,
+ });
- await emitEvent({
- event: "CHANNEL_RECIPIENT_ADD",
- data: {
+ await emitEvent({
+ event: "CHANNEL_RECIPIENT_ADD",
+ data: {
+ channel_id: channel_id,
+ user: await User.findOneOrFail({
+ where: { id: user_id },
+ select: PublicUserProjection,
+ }),
+ },
channel_id: channel_id,
- user: await User.findOneOrFail({
- where: { id: user_id },
- select: PublicUserProjection,
- }),
- },
- channel_id: channel_id,
- } as ChannelRecipientAddEvent);
- return res.sendStatus(204);
- }
-});
+ } as ChannelRecipientAddEvent);
+ return res.sendStatus(204);
+ }
+ },
+);
-router.delete("/:user_id", route({}), async (req: Request, res: Response) => {
- const { channel_id, user_id } = req.params;
- const channel = await Channel.findOneOrFail({
- where: { id: channel_id },
- relations: ["recipients"],
- });
- if (
- !(
- channel.type === ChannelType.GROUP_DM &&
- (channel.owner_id === req.user_id || user_id === req.user_id)
+router.delete(
+ "/:user_id",
+ route({
+ responses: {
+ 204: {},
+ 404: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { channel_id, user_id } = req.params;
+ const channel = await Channel.findOneOrFail({
+ where: { id: channel_id },
+ relations: ["recipients"],
+ });
+ if (
+ !(
+ channel.type === ChannelType.GROUP_DM &&
+ (channel.owner_id === req.user_id || user_id === req.user_id)
+ )
)
- )
- throw DiscordApiErrors.MISSING_PERMISSIONS;
+ throw DiscordApiErrors.MISSING_PERMISSIONS;
- if (!channel.recipients?.map((r) => r.user_id).includes(user_id)) {
- throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
- }
+ if (!channel.recipients?.map((r) => r.user_id).includes(user_id)) {
+ throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
+ }
- await Channel.removeRecipientFromChannel(channel, user_id);
+ await Channel.removeRecipientFromChannel(channel, user_id);
- return res.sendStatus(204);
-});
+ return res.sendStatus(204);
+ },
+);
export default router;
diff --git a/src/api/routes/channels/#channel_id/typing.ts b/src/api/routes/channels/#channel_id/typing.ts
index 6a2fef39..b5d61d74 100644
--- a/src/api/routes/channels/#channel_id/typing.ts
+++ b/src/api/routes/channels/#channel_id/typing.ts
@@ -16,15 +16,22 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Channel, emitEvent, Member, TypingStartEvent } from "@spacebar/util";
import { route } from "@spacebar/api";
-import { Router, Request, Response } from "express";
+import { Channel, emitEvent, Member, TypingStartEvent } from "@spacebar/util";
+import { Request, Response, Router } from "express";
const router: Router = Router();
router.post(
"/",
- route({ permission: "SEND_MESSAGES" }),
+ route({
+ permission: "SEND_MESSAGES",
+ responses: {
+ 204: {},
+ 404: {},
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const { channel_id } = req.params;
const user_id = req.user_id;
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index 14791a1c..4e98a1c9 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -16,34 +16,56 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { Router, Response, Request } from "express";
import { route } from "@spacebar/api";
import {
Channel,
Config,
- handleFile,
- trimSpecial,
+ DiscordApiErrors,
User,
Webhook,
WebhookCreateSchema,
WebhookType,
+ handleFile,
+ trimSpecial,
} from "@spacebar/util";
+import crypto from "crypto";
+import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { isTextChannel } from "./messages/index";
-import { DiscordApiErrors } from "@spacebar/util";
-import crypto from "crypto";
const router: Router = Router();
//TODO: implement webhooks
-router.get("/", route({}), async (req: Request, res: Response) => {
- res.json([]);
-});
+router.get(
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "ChannelWebhooksResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ res.json([]);
+ },
+);
// TODO: use Image Data Type for avatar instead of String
router.post(
"/",
- route({ body: "WebhookCreateSchema", permission: "MANAGE_WEBHOOKS" }),
+ route({
+ body: "WebhookCreateSchema",
+ permission: "MANAGE_WEBHOOKS",
+ responses: {
+ 200: {
+ body: "WebhookCreateResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 403: {},
+ },
+ }),
async (req: Request, res: Response) => {
const channel_id = req.params.channel_id;
const channel = await Channel.findOneOrFail({
diff --git a/src/util/schemas/responses/ChannelInvitesResponse.ts b/src/util/schemas/responses/ChannelInvitesResponse.ts
new file mode 100644
index 00000000..c50d033c
--- /dev/null
+++ b/src/util/schemas/responses/ChannelInvitesResponse.ts
@@ -0,0 +1,3 @@
+import { Invite } from "../../entities";
+
+export type ChannelInvitesResponse = Invite[];
diff --git a/src/util/schemas/responses/ChannelMessagesResponse.ts b/src/util/schemas/responses/ChannelMessagesResponse.ts
new file mode 100644
index 00000000..65b7dab5
--- /dev/null
+++ b/src/util/schemas/responses/ChannelMessagesResponse.ts
@@ -0,0 +1,3 @@
+import { Message } from "../../entities";
+
+export type ChannelMessagesResponse = Message[];
diff --git a/src/util/schemas/responses/ChannelPinsResponse.ts b/src/util/schemas/responses/ChannelPinsResponse.ts
new file mode 100644
index 00000000..7a1b8d43
--- /dev/null
+++ b/src/util/schemas/responses/ChannelPinsResponse.ts
@@ -0,0 +1,3 @@
+import { Message } from "../../entities";
+
+export type ChannelPinsResponse = Message[];
diff --git a/src/util/schemas/responses/ChannelWebhooksResponse.ts b/src/util/schemas/responses/ChannelWebhooksResponse.ts
new file mode 100644
index 00000000..84f49dce
--- /dev/null
+++ b/src/util/schemas/responses/ChannelWebhooksResponse.ts
@@ -0,0 +1,3 @@
+import { Webhook } from "../../entities";
+
+export type ChannelWebhooksResponse = Webhook[];
diff --git a/src/util/schemas/responses/WebhookCreateResponse.ts b/src/util/schemas/responses/WebhookCreateResponse.ts
new file mode 100644
index 00000000..ae142632
--- /dev/null
+++ b/src/util/schemas/responses/WebhookCreateResponse.ts
@@ -0,0 +1,6 @@
+import { User, Webhook } from "../../entities";
+
+export interface WebhookCreateResponse {
+ user: User;
+ hook: Webhook;
+}
diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts
index 6dde4d24..2a1180ad 100644
--- a/src/util/schemas/responses/index.ts
+++ b/src/util/schemas/responses/index.ts
@@ -6,6 +6,10 @@ export * from "./ApplicationSkusResponse";
export * from "./ApplicationsResponse";
export * from "./BackupCodesChallengeResponse";
export * from "./CaptchaRequiredResponse";
+export * from "./ChannelInvitesResponse";
+export * from "./ChannelPinsResponse";
+export * from "./ChannelWebhooksResponse";
export * from "./GenerateRegistrationTokensResponse";
export * from "./LocationMetadataResponse";
export * from "./TokenResponse";
+export * from "./WebhookCreateResponse";
|