Rewrite getRouteDescriptions, fix message route not appearing in openapi spec
This commit is contained in:
parent
a263ebb1e5
commit
b438f2b071
@ -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/": {
|
"/channels/{channel_id}/messages/bulk-delete/": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1,80 +1,64 @@
|
|||||||
|
const express = require("express");
|
||||||
|
const path = require("path");
|
||||||
|
const { traverseDirectory } = require("lambert-server");
|
||||||
|
const RouteUtility = require("../../dist/api/util/handlers/route.js");
|
||||||
|
|
||||||
|
const methods = ["get", "post", "put", "delete", "patch"];
|
||||||
|
const routes = new Map();
|
||||||
|
let currentFile = "";
|
||||||
|
let currentPath = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
For some reason, if a route exports multiple functions, it won't be registered here!
|
||||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
If someone could fix that I'd really appreciate it, but for now just, don't do that :p
|
||||||
|
|
||||||
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 proxy = (file, method, prefix, path, ...args) => {
|
||||||
const path = require("path");
|
const opts = args.find((x) => x?.prototype?.OPTS_MARKER == true);
|
||||||
const express = require("express");
|
if (!opts)
|
||||||
const RouteUtility = require("../../dist/api/util/handlers/route.js");
|
return console.error(
|
||||||
const Router = express.Router;
|
`${file} has route without route() description middleware`,
|
||||||
|
|
||||||
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`,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function routeOptions(opts) {
|
console.log(prefix + path + " - " + method);
|
||||||
return opts;
|
opts.file = file.replace("/dist/", "/src/").replace(".js", ".ts");
|
||||||
}
|
routes.set(prefix + path + "|" + method, opts());
|
||||||
|
};
|
||||||
|
|
||||||
RouteUtility.route = routeOptions;
|
express.Router = () => {
|
||||||
|
return Object.fromEntries(
|
||||||
|
methods.map((method) => [
|
||||||
|
method,
|
||||||
|
proxy.bind(null, currentFile, method, currentPath),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
express.Router = (opts) => {
|
RouteUtility.route = (opts) => {
|
||||||
const path = currentPath;
|
const func = function () {
|
||||||
const file = currentFile;
|
return opts;
|
||||||
const router = Router(opts);
|
};
|
||||||
|
func.prototype.OPTS_MARKER = true;
|
||||||
for (const method of methods) {
|
return func;
|
||||||
router[method] = registerPath.bind(null, file, method, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return router;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = function getRouteDescriptions() {
|
module.exports = function getRouteDescriptions() {
|
||||||
const root = path.join(__dirname, "..", "..", "dist", "api", "routes", "/");
|
const root = path.join(__dirname, "..", "..", "dist", "api", "routes", "/");
|
||||||
traverseDirectory({ dirname: root, recursive: true }, (file) => {
|
traverseDirectory({ dirname: root, recursive: true }, (file) => {
|
||||||
currentFile = 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
|
currentPath = file.replace(root.slice(0, -1), "");
|
||||||
path = path.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
|
currentPath = currentPath.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
|
||||||
if (path.endsWith("/index")) path = path.slice(0, "/index".length * -1); // delete index from path
|
currentPath = currentPath.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
|
||||||
currentPath = path;
|
if (currentPath.endsWith("/index"))
|
||||||
|
currentPath = currentPath.slice(0, "/index".length * -1); // delete index from path
|
||||||
|
|
||||||
try {
|
try {
|
||||||
require(file);
|
require(file);
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
console.error("error loading file " + file, error);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
};
|
};
|
||||||
|
@ -25,10 +25,10 @@ import {
|
|||||||
PublicInviteRelation,
|
PublicInviteRelation,
|
||||||
User,
|
User,
|
||||||
emitEvent,
|
emitEvent,
|
||||||
|
isTextChannel,
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { HTTPError } from "lambert-server";
|
import { HTTPError } from "lambert-server";
|
||||||
import { isTextChannel } from "./messages";
|
|
||||||
|
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
User,
|
User,
|
||||||
emitEvent,
|
emitEvent,
|
||||||
getPermission,
|
getPermission,
|
||||||
|
isTextChannel,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
@ -45,32 +46,6 @@ import { URL } from "url";
|
|||||||
|
|
||||||
const router: Router = Router();
|
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
|
// https://discord.com/developers/docs/resources/channel#create-message
|
||||||
// get messages
|
// get messages
|
||||||
router.get(
|
router.get(
|
||||||
@ -407,3 +382,5 @@ router.post(
|
|||||||
return res.json(message);
|
return res.json(message);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export default router;
|
||||||
|
@ -25,11 +25,11 @@ import {
|
|||||||
emitEvent,
|
emitEvent,
|
||||||
getPermission,
|
getPermission,
|
||||||
getRights,
|
getRights,
|
||||||
|
isTextChannel,
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { HTTPError } from "lambert-server";
|
import { HTTPError } from "lambert-server";
|
||||||
import { Between, FindManyOptions, FindOperator, Not } from "typeorm";
|
import { Between, FindManyOptions, FindOperator, Not } from "typeorm";
|
||||||
import { isTextChannel } from "./messages";
|
|
||||||
|
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
|
@ -27,11 +27,11 @@ import {
|
|||||||
WebhookType,
|
WebhookType,
|
||||||
handleFile,
|
handleFile,
|
||||||
trimSpecial,
|
trimSpecial,
|
||||||
|
isTextChannel,
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { HTTPError } from "lambert-server";
|
import { HTTPError } from "lambert-server";
|
||||||
import { isTextChannel } from "./messages/index";
|
|
||||||
|
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
|
@ -17,11 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import { TenorMediaTypes } from "@spacebar/util";
|
import { TenorMediaTypes, getGifApiKey, parseGifResult } from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
import { getGifApiKey, parseGifResult } from "./trending";
|
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
@ -17,11 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import { TenorMediaTypes } from "@spacebar/util";
|
import { TenorMediaTypes, getGifApiKey, parseGifResult } from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
import { getGifApiKey, parseGifResult } from "./trending";
|
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
@ -18,40 +18,17 @@
|
|||||||
|
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import {
|
import {
|
||||||
Config,
|
|
||||||
TenorCategoriesResults,
|
TenorCategoriesResults,
|
||||||
TenorGif,
|
|
||||||
TenorTrendingResults,
|
TenorTrendingResults,
|
||||||
|
getGifApiKey,
|
||||||
|
parseGifResult,
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { HTTPError } from "lambert-server";
|
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
|
|
||||||
const router = Router();
|
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(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
route({
|
route({
|
||||||
|
@ -23,7 +23,7 @@ import { IsNull, LessThan } from "typeorm";
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
//Returns all inactive members, respecting role hierarchy
|
//Returns all inactive members, respecting role hierarchy
|
||||||
export const inactiveMembers = async (
|
const inactiveMembers = async (
|
||||||
guild_id: string,
|
guild_id: string,
|
||||||
user_id: string,
|
user_id: string,
|
||||||
days: number,
|
days: number,
|
||||||
|
@ -105,7 +105,7 @@ router.post(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export function getStickerFormat(mime_type: string) {
|
function getStickerFormat(mime_type: string) {
|
||||||
switch (mime_type) {
|
switch (mime_type) {
|
||||||
case "image/apng":
|
case "image/apng":
|
||||||
return StickerFormatType.APNG;
|
return StickerFormatType.APNG;
|
||||||
|
@ -482,3 +482,27 @@ export enum ChannelPermissionOverwriteType {
|
|||||||
member = 1,
|
member = 1,
|
||||||
group = 2,
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
25
src/util/util/Gifs.ts
Normal file
25
src/util/util/Gifs.ts
Normal file
@ -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;
|
||||||
|
}
|
@ -41,3 +41,4 @@ export * from "./String";
|
|||||||
export * from "./Token";
|
export * from "./Token";
|
||||||
export * from "./TraverseDirectory";
|
export * from "./TraverseDirectory";
|
||||||
export * from "./WebAuthn";
|
export * from "./WebAuthn";
|
||||||
|
export * from "./Gifs";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user