summary refs log tree commit diff
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2023-04-16 01:51:52 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2023-04-16 01:51:52 +1000
commitb438f2b071dbaa82371016168ab843f24be5063e (patch)
treeeea50564f94b6992089ce097455404d89cd0ba56
parentgenerated files (diff)
downloadserver-b438f2b071dbaa82371016168ab843f24be5063e.tar.xz
Rewrite getRouteDescriptions, fix message route not appearing in openapi spec
-rw-r--r--assets/openapi.json141
-rw-r--r--scripts/util/getRouteDescriptions.js98
-rw-r--r--src/api/routes/channels/#channel_id/invites.ts2
-rw-r--r--src/api/routes/channels/#channel_id/messages/index.ts29
-rw-r--r--src/api/routes/channels/#channel_id/purge.ts2
-rw-r--r--src/api/routes/channels/#channel_id/webhooks.ts2
-rw-r--r--src/api/routes/gifs/search.ts3
-rw-r--r--src/api/routes/gifs/trending-gifs.ts3
-rw-r--r--src/api/routes/gifs/trending.ts27
-rw-r--r--src/api/routes/guilds/#guild_id/prune.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/stickers.ts2
-rw-r--r--src/util/entities/Channel.ts24
-rw-r--r--src/util/util/Gifs.ts25
-rw-r--r--src/util/util/index.ts1
14 files changed, 244 insertions, 117 deletions
diff --git a/assets/openapi.json b/assets/openapi.json
index 567d4bb8..8c1920f9 100644
--- a/assets/openapi.json
+++ b/assets/openapi.json
@@ -14646,6 +14646,147 @@
                 ]
             }
         },
+        "/channels/{channel_id}/messages/": {
+            "get": {
+                "security": [
+                    {
+                        "bearer": []
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/APIMessageArray"
+                                }
+                            }
+                        }
+                    },
+                    "400": {
+                        "description": "",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/APIErrorResponse"
+                                }
+                            }
+                        }
+                    },
+                    "403": {
+                        "description": "No description available"
+                    },
+                    "404": {
+                        "description": "No description available"
+                    }
+                },
+                "parameters": [
+                    {
+                        "name": "channel_id",
+                        "in": "path",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        },
+                        "description": "channel_id"
+                    },
+                    {
+                        "name": "around",
+                        "in": "query",
+                        "schema": {
+                            "type": "string"
+                        }
+                    },
+                    {
+                        "name": "before",
+                        "in": "query",
+                        "schema": {
+                            "type": "string"
+                        }
+                    },
+                    {
+                        "name": "after",
+                        "in": "query",
+                        "schema": {
+                            "type": "string"
+                        }
+                    },
+                    {
+                        "name": "limit",
+                        "in": "query",
+                        "schema": {
+                            "type": "number"
+                        },
+                        "description": "max number of messages to return (1-100). defaults to 50"
+                    }
+                ],
+                "tags": [
+                    "channels"
+                ]
+            },
+            "post": {
+                "x-right-required": "SEND_MESSAGES",
+                "x-permission-required": "SEND_MESSAGES",
+                "security": [
+                    {
+                        "bearer": []
+                    }
+                ],
+                "requestBody": {
+                    "required": true,
+                    "content": {
+                        "application/json": {
+                            "schema": {
+                                "$ref": "#/components/schemas/MessageCreateSchema"
+                            }
+                        }
+                    }
+                },
+                "responses": {
+                    "200": {
+                        "description": "",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/Message"
+                                }
+                            }
+                        }
+                    },
+                    "400": {
+                        "description": "",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/APIErrorResponse"
+                                }
+                            }
+                        }
+                    },
+                    "403": {
+                        "description": "No description available"
+                    },
+                    "404": {
+                        "description": "No description available"
+                    }
+                },
+                "parameters": [
+                    {
+                        "name": "channel_id",
+                        "in": "path",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        },
+                        "description": "channel_id"
+                    }
+                ],
+                "tags": [
+                    "channels"
+                ]
+            }
+        },
         "/channels/{channel_id}/messages/bulk-delete/": {
             "post": {
                 "security": [
diff --git a/scripts/util/getRouteDescriptions.js b/scripts/util/getRouteDescriptions.js
index fe36c238..a79dac96 100644
--- a/scripts/util/getRouteDescriptions.js
+++ b/scripts/util/getRouteDescriptions.js
@@ -1,80 +1,64 @@
-/*
-	Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
-	Copyright (C) 2023 Spacebar and Spacebar Contributors
-	
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-	
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-	
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-const { traverseDirectory } = require("lambert-server");
-const path = require("path");
 const express = require("express");
+const path = require("path");
+const { traverseDirectory } = require("lambert-server");
 const RouteUtility = require("../../dist/api/util/handlers/route.js");
-const Router = express.Router;
 
+const methods = ["get", "post", "put", "delete", "patch"];
 const routes = new Map();
-let currentPath = "";
 let currentFile = "";
-const methods = ["get", "post", "put", "delete", "patch"];
-
-function registerPath(file, method, prefix, path, ...args) {
-	const urlPath = prefix + path;
-	const sourceFile = file.replace("/dist/", "/src/").replace(".js", ".ts");
-	const opts = args.find((x) => typeof x === "object");
-	if (opts) {
-		routes.set(urlPath + "|" + method, opts);
-		opts.file = sourceFile;
-		// console.log(method, urlPath, opts);
-	} else {
-		console.log(
-			`${sourceFile}\nrouter.${method}("${path}") is missing the "route()" description middleware\n`,
-		);
-	}
-}
+let currentPath = "";
 
-function routeOptions(opts) {
-	return opts;
-}
+/*
+	For some reason, if a route exports multiple functions, it won't be registered here!
+	If someone could fix that I'd really appreciate it, but for now just, don't do that :p
+*/
 
-RouteUtility.route = routeOptions;
+const proxy = (file, method, prefix, path, ...args) => {
+	const opts = args.find((x) => x?.prototype?.OPTS_MARKER == true);
+	if (!opts)
+		return console.error(
+			`${file} has route without route() description middleware`,
+		);
 
-express.Router = (opts) => {
-	const path = currentPath;
-	const file = currentFile;
-	const router = Router(opts);
+	console.log(prefix + path + " - " + method);
+	opts.file = file.replace("/dist/", "/src/").replace(".js", ".ts");
+	routes.set(prefix + path + "|" + method, opts());
+};
 
-	for (const method of methods) {
-		router[method] = registerPath.bind(null, file, method, path);
-	}
+express.Router = () => {
+	return Object.fromEntries(
+		methods.map((method) => [
+			method,
+			proxy.bind(null, currentFile, method, currentPath),
+		]),
+	);
+};
 
-	return router;
+RouteUtility.route = (opts) => {
+	const func = function () {
+		return opts;
+	};
+	func.prototype.OPTS_MARKER = true;
+	return func;
 };
 
 module.exports = function getRouteDescriptions() {
 	const root = path.join(__dirname, "..", "..", "dist", "api", "routes", "/");
 	traverseDirectory({ dirname: root, recursive: true }, (file) => {
 		currentFile = file;
-		let path = file.replace(root.slice(0, -1), "");
-		path = path.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
-		path = path.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
-		if (path.endsWith("/index")) path = path.slice(0, "/index".length * -1); // delete index from path
-		currentPath = path;
+
+		currentPath = file.replace(root.slice(0, -1), "");
+		currentPath = currentPath.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
+		currentPath = currentPath.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
+		if (currentPath.endsWith("/index"))
+			currentPath = currentPath.slice(0, "/index".length * -1); // delete index from path
 
 		try {
 			require(file);
-		} catch (error) {
-			console.error("error loading file " + file, error);
+		} catch (e) {
+			console.error(e);
 		}
 	});
+
 	return routes;
 };
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index f608cca2..b02f65d3 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -25,10 +25,10 @@ import {
 	PublicInviteRelation,
 	User,
 	emitEvent,
+	isTextChannel,
 } from "@spacebar/util";
 import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
-import { isTextChannel } from "./messages";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index 811d2b4c..f031fa75 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -35,6 +35,7 @@ import {
 	User,
 	emitEvent,
 	getPermission,
+	isTextChannel,
 	uploadFile,
 } from "@spacebar/util";
 import { Request, Response, Router } from "express";
@@ -45,32 +46,6 @@ import { URL } from "url";
 
 const router: Router = Router();
 
-export default router;
-
-export function isTextChannel(type: ChannelType): boolean {
-	switch (type) {
-		case ChannelType.GUILD_STORE:
-		case ChannelType.GUILD_VOICE:
-		case ChannelType.GUILD_STAGE_VOICE:
-		case ChannelType.GUILD_CATEGORY:
-		case ChannelType.GUILD_FORUM:
-		case ChannelType.DIRECTORY:
-			throw new HTTPError("not a text channel", 400);
-		case ChannelType.DM:
-		case ChannelType.GROUP_DM:
-		case ChannelType.GUILD_NEWS:
-		case ChannelType.GUILD_NEWS_THREAD:
-		case ChannelType.GUILD_PUBLIC_THREAD:
-		case ChannelType.GUILD_PRIVATE_THREAD:
-		case ChannelType.GUILD_TEXT:
-		case ChannelType.ENCRYPTED:
-		case ChannelType.ENCRYPTED_THREAD:
-			return true;
-		default:
-			throw new HTTPError("unimplemented", 400);
-	}
-}
-
 // https://discord.com/developers/docs/resources/channel#create-message
 // get messages
 router.get(
@@ -407,3 +382,5 @@ router.post(
 		return res.json(message);
 	},
 );
+
+export default router;
diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts
index cbd46bd0..012fec1c 100644
--- a/src/api/routes/channels/#channel_id/purge.ts
+++ b/src/api/routes/channels/#channel_id/purge.ts
@@ -25,11 +25,11 @@ import {
 	emitEvent,
 	getPermission,
 	getRights,
+	isTextChannel,
 } from "@spacebar/util";
 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();
 
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index 6b81298f..d54756a1 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -27,11 +27,11 @@ import {
 	WebhookType,
 	handleFile,
 	trimSpecial,
+	isTextChannel,
 } from "@spacebar/util";
 import crypto from "crypto";
 import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
-import { isTextChannel } from "./messages/index";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts
index b51bba37..f125a463 100644
--- a/src/api/routes/gifs/search.ts
+++ b/src/api/routes/gifs/search.ts
@@ -17,11 +17,10 @@
 */
 
 import { route } from "@spacebar/api";
-import { TenorMediaTypes } from "@spacebar/util";
+import { TenorMediaTypes, getGifApiKey, parseGifResult } from "@spacebar/util";
 import { Request, Response, Router } from "express";
 import fetch from "node-fetch";
 import ProxyAgent from "proxy-agent";
-import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
 
diff --git a/src/api/routes/gifs/trending-gifs.ts b/src/api/routes/gifs/trending-gifs.ts
index 899250cf..d6fa89ac 100644
--- a/src/api/routes/gifs/trending-gifs.ts
+++ b/src/api/routes/gifs/trending-gifs.ts
@@ -17,11 +17,10 @@
 */
 
 import { route } from "@spacebar/api";
-import { TenorMediaTypes } from "@spacebar/util";
+import { TenorMediaTypes, getGifApiKey, parseGifResult } from "@spacebar/util";
 import { Request, Response, Router } from "express";
 import fetch from "node-fetch";
 import ProxyAgent from "proxy-agent";
-import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
 
diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts
index 3c2ab6ab..e3d6e974 100644
--- a/src/api/routes/gifs/trending.ts
+++ b/src/api/routes/gifs/trending.ts
@@ -18,40 +18,17 @@
 
 import { route } from "@spacebar/api";
 import {
-	Config,
 	TenorCategoriesResults,
-	TenorGif,
 	TenorTrendingResults,
+	getGifApiKey,
+	parseGifResult,
 } from "@spacebar/util";
 import { Request, Response, Router } from "express";
-import { HTTPError } from "lambert-server";
 import fetch from "node-fetch";
 import ProxyAgent from "proxy-agent";
 
 const router = Router();
 
-export function parseGifResult(result: TenorGif) {
-	return {
-		id: result.id,
-		title: result.title,
-		url: result.itemurl,
-		src: result.media[0].mp4.url,
-		gif_src: result.media[0].gif.url,
-		width: result.media[0].mp4.dims[0],
-		height: result.media[0].mp4.dims[1],
-		preview: result.media[0].mp4.preview,
-	};
-}
-
-export function getGifApiKey() {
-	const { enabled, provider, apiKey } = Config.get().gif;
-	if (!enabled) throw new HTTPError(`Gifs are disabled`);
-	if (provider !== "tenor" || !apiKey)
-		throw new HTTPError(`${provider} gif provider not supported`);
-
-	return apiKey;
-}
-
 router.get(
 	"/",
 	route({
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
index 92ea91fc..2c77340d 100644
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ b/src/api/routes/guilds/#guild_id/prune.ts
@@ -23,7 +23,7 @@ import { IsNull, LessThan } from "typeorm";
 const router = Router();
 
 //Returns all inactive members, respecting role hierarchy
-export const inactiveMembers = async (
+const inactiveMembers = async (
 	guild_id: string,
 	user_id: string,
 	days: number,
diff --git a/src/api/routes/guilds/#guild_id/stickers.ts b/src/api/routes/guilds/#guild_id/stickers.ts
index 2da9a21e..88f9a40e 100644
--- a/src/api/routes/guilds/#guild_id/stickers.ts
+++ b/src/api/routes/guilds/#guild_id/stickers.ts
@@ -105,7 +105,7 @@ router.post(
 	},
 );
 
-export function getStickerFormat(mime_type: string) {
+function getStickerFormat(mime_type: string) {
 	switch (mime_type) {
 		case "image/apng":
 			return StickerFormatType.APNG;
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 9ce04848..e23d93db 100644
--- a/src/util/entities/Channel.ts
+++ b/src/util/entities/Channel.ts
@@ -482,3 +482,27 @@ export enum ChannelPermissionOverwriteType {
 	member = 1,
 	group = 2,
 }
+
+export function isTextChannel(type: ChannelType): boolean {
+	switch (type) {
+		case ChannelType.GUILD_STORE:
+		case ChannelType.GUILD_VOICE:
+		case ChannelType.GUILD_STAGE_VOICE:
+		case ChannelType.GUILD_CATEGORY:
+		case ChannelType.GUILD_FORUM:
+		case ChannelType.DIRECTORY:
+			throw new HTTPError("not a text channel", 400);
+		case ChannelType.DM:
+		case ChannelType.GROUP_DM:
+		case ChannelType.GUILD_NEWS:
+		case ChannelType.GUILD_NEWS_THREAD:
+		case ChannelType.GUILD_PUBLIC_THREAD:
+		case ChannelType.GUILD_PRIVATE_THREAD:
+		case ChannelType.GUILD_TEXT:
+		case ChannelType.ENCRYPTED:
+		case ChannelType.ENCRYPTED_THREAD:
+			return true;
+		default:
+			throw new HTTPError("unimplemented", 400);
+	}
+}
diff --git a/src/util/util/Gifs.ts b/src/util/util/Gifs.ts
new file mode 100644
index 00000000..a5a5e64c
--- /dev/null
+++ b/src/util/util/Gifs.ts
@@ -0,0 +1,25 @@
+import { HTTPError } from "lambert-server";
+import { Config } from "./Config";
+import { TenorGif } from "..";
+
+export function parseGifResult(result: TenorGif) {
+	return {
+		id: result.id,
+		title: result.title,
+		url: result.itemurl,
+		src: result.media[0].mp4.url,
+		gif_src: result.media[0].gif.url,
+		width: result.media[0].mp4.dims[0],
+		height: result.media[0].mp4.dims[1],
+		preview: result.media[0].mp4.preview,
+	};
+}
+
+export function getGifApiKey() {
+	const { enabled, provider, apiKey } = Config.get().gif;
+	if (!enabled) throw new HTTPError(`Gifs are disabled`);
+	if (provider !== "tenor" || !apiKey)
+		throw new HTTPError(`${provider} gif provider not supported`);
+
+	return apiKey;
+}
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 838239b7..3a98be15 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -41,3 +41,4 @@ export * from "./String";
 export * from "./Token";
 export * from "./TraverseDirectory";
 export * from "./WebAuthn";
+export * from "./Gifs";