From 37bd06e14271aa3ff69389939f27d7814479234d Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:41:43 +0200 Subject: [PATCH 01/38] Add local image proxy using sharp/jimp pkgs --- package-lock.json | Bin 300713 -> 326795 bytes package.json | 1 + src/api/Server.ts | 4 +- src/api/middlewares/ImageProxy.ts | 143 ++++++++++++++++++++++++++++++ src/api/middlewares/index.ts | 1 + 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/api/middlewares/ImageProxy.ts diff --git a/package-lock.json b/package-lock.json index 875aba1b5a898e35da28cc0a36d5a6278844ed5b..32582d06dfdf1235d7dd44174db10c86f3f94aad 100644 GIT binary patch delta 14842 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 yfr=F3%8c?1oa7rL%@On diff --git a/package.json b/package.json index ac42c767..7f466e44 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ }, "optionalDependencies": { "erlpack": "^0.1.4", + "jimp": "^0.22.12", "mysql": "^2.18.1", "nodemailer-mailgun-transport": "^2.1.5", "nodemailer-mailjet-transport": "github:n0script22/nodemailer-mailjet-transport", diff --git a/src/api/Server.ts b/src/api/Server.ts index 472ab1d6..0f5df490 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -34,7 +34,7 @@ import "missing-native-js-functions"; import morgan from "morgan"; import path from "path"; import { red } from "picocolors"; -import { Authentication, CORS } from "./middlewares/"; +import { Authentication, CORS, ImageProxy } from "./middlewares/"; import { BodyParser } from "./middlewares/BodyParser"; import { ErrorHandler } from "./middlewares/ErrorHandler"; import { initRateLimits } from "./middlewares/RateLimit"; @@ -137,6 +137,8 @@ export class SpacebarServer extends Server { app.use("/api/v9", api); app.use("/api", api); // allow unversioned requests + app.use("/imageproxy/:hash/:size/:url", ImageProxy); + app.get("/", (req, res) => res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html")), ); diff --git a/src/api/middlewares/ImageProxy.ts b/src/api/middlewares/ImageProxy.ts new file mode 100644 index 00000000..2fa97660 --- /dev/null +++ b/src/api/middlewares/ImageProxy.ts @@ -0,0 +1,143 @@ +/* + 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 . +*/ + +import { Config } from "@spacebar/util"; +import { Request, Response } from "express"; +import { yellow } from "picocolors"; +import crypto from "crypto"; +import fetch from "node-fetch"; + +let sharp: undefined | false | { default: typeof import("sharp") } = undefined; +let Jimp: undefined | false | typeof import("jimp") = undefined; + +const sharpSupported = new Set([ + "image/jpeg", + "image/png", + "image/bmp", + "image/tiff", + "image/gif", + "image/webp", + "image/avif", + "image/svg+xml", +]); +const jimpSupported = new Set([ + "image/jpeg", + "image/png", + "image/bmp", + "image/tiff", + "image/gif", +]); +const resizeSupported = new Set([...sharpSupported, ...jimpSupported]); + +export async function ImageProxy(req: Request, res: Response) { + const path = req.originalUrl.split("/").slice(2); + + const secret = Config.get().security.requestSignature; + + // src/api/util/utility/EmbedHandlers.ts getProxyUrl + const hash = crypto + .createHmac("sha1", secret) + .update(path.slice(1).join("/")) + .digest("base64") + .replace(/\+/g, "-") + .replace(/\//g, "_"); + + try { + if (!crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(path[0]))) throw new Error("Invalid signature"); + } catch { + console.log("Invalid signature, expected " + hash + " got " + path[0]); + res.status(403).send("Invalid signature"); + return; + } + + const abort = new AbortController(); + setTimeout(() => abort.abort(), 5000); + + const request = await fetch(path.slice(2).join("/"), { + headers: { + "User-Agent": "SpacebarImageProxy/1.0.0 (https://spacebar.chat)", + }, + signal: abort.signal, + }).catch((e) => { + if (e.name === "AbortError") res.status(504).send("Request timed out"); + else res.status(500).send("Unable to proxy origin: " + e.message); + }); + if (!request) return; + + if (request.status !== 200) { + res.status(request.status).send("Origin failed to respond: " + request.status + " " + request.statusText); + return; + } + + if (!request.headers.get("Content-Type") || !request.headers.get("Content-Length")) { + res.status(500).send("Origin did not provide a Content-Type or Content-Length header"); + return; + } + + // @ts-expect-error TS doesn't believe that the header cannot be null (it's checked for falsiness above) + if (parseInt(request.headers.get("Content-Length")) > 1024 * 1024 * 10) { + res.status(500).send("Origin provided a Content-Length header that is too large"); + return; + } + + // @ts-expect-error TS doesn't believe that the header cannot be null (it's checked for falsiness above) + let contentType: string = request.headers.get("Content-Type"); + + const arrayBuffer = await request.arrayBuffer(); + let resultBuffer = Buffer.from(arrayBuffer); + + if (/^\d+x\d+$/.test(path[1]) && resizeSupported.has(contentType)) { + if (sharp !== false) { + try { + sharp = await import("sharp"); + } catch (e) { + sharp = false; + } + } + if (sharp === false && Jimp !== false) { + try { + // @ts-expect-error Typings don't fit + Jimp = await import("jimp"); + } catch { + Jimp = false; + console.log(`[ImageProxy] ${yellow("Neither \"sharp\" or \"jimp\" NPM packages are installed, image resizing will be disabled")}`); + } + } + + const [width, height] = path[1].split("x").map((x) => parseInt(x)); + + const buffer = Buffer.from(arrayBuffer); + if (sharp && sharpSupported.has(contentType)) { + resultBuffer = await sharp.default(buffer) + // Sharp doesn't support "scaleToFit" + .resize(width) + .toBuffer(); + } else if (Jimp && jimpSupported.has(contentType)) { + resultBuffer = await Jimp.read(buffer).then((image) => { + contentType = image.getMIME(); + // @ts-expect-error Jimp is defined at this point + return image.scaleToFit(width, height).getBufferAsync(Jimp.AUTO); + }); + } + } + + res.header("Content-Type", contentType); + res.setHeader("Cache-Control", "public, max-age=" + (1000 * 60 * 60 * 24)); + + res.send(resultBuffer); +} diff --git a/src/api/middlewares/index.ts b/src/api/middlewares/index.ts index 6384e1aa..9fd617f6 100644 --- a/src/api/middlewares/index.ts +++ b/src/api/middlewares/index.ts @@ -21,3 +21,4 @@ export * from "./BodyParser"; export * from "./CORS"; export * from "./ErrorHandler"; export * from "./RateLimit"; +export * from "./ImageProxy"; From e90f8e88c0ae44e3183632cce300b07c5cc992f6 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:43:54 +0200 Subject: [PATCH 02/38] Run Prettier (tabs -> spaces???) --- src/api/middlewares/ImageProxy.ts | 62 ++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/api/middlewares/ImageProxy.ts b/src/api/middlewares/ImageProxy.ts index 2fa97660..64d5ddc1 100644 --- a/src/api/middlewares/ImageProxy.ts +++ b/src/api/middlewares/ImageProxy.ts @@ -1,19 +1,19 @@ /* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors + 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 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. + 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 . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ import { Config } from "@spacebar/util"; @@ -58,7 +58,8 @@ export async function ImageProxy(req: Request, res: Response) { .replace(/\//g, "_"); try { - if (!crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(path[0]))) throw new Error("Invalid signature"); + if (!crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(path[0]))) + throw new Error("Invalid signature"); } catch { console.log("Invalid signature, expected " + hash + " got " + path[0]); res.status(403).send("Invalid signature"); @@ -80,18 +81,30 @@ export async function ImageProxy(req: Request, res: Response) { if (!request) return; if (request.status !== 200) { - res.status(request.status).send("Origin failed to respond: " + request.status + " " + request.statusText); + res.status(request.status).send( + "Origin failed to respond: " + + request.status + + " " + + request.statusText, + ); return; } - if (!request.headers.get("Content-Type") || !request.headers.get("Content-Length")) { - res.status(500).send("Origin did not provide a Content-Type or Content-Length header"); + if ( + !request.headers.get("Content-Type") || + !request.headers.get("Content-Length") + ) { + res.status(500).send( + "Origin did not provide a Content-Type or Content-Length header", + ); return; } // @ts-expect-error TS doesn't believe that the header cannot be null (it's checked for falsiness above) if (parseInt(request.headers.get("Content-Length")) > 1024 * 1024 * 10) { - res.status(500).send("Origin provided a Content-Length header that is too large"); + res.status(500).send( + "Origin provided a Content-Length header that is too large", + ); return; } @@ -115,7 +128,11 @@ export async function ImageProxy(req: Request, res: Response) { Jimp = await import("jimp"); } catch { Jimp = false; - console.log(`[ImageProxy] ${yellow("Neither \"sharp\" or \"jimp\" NPM packages are installed, image resizing will be disabled")}`); + console.log( + `[ImageProxy] ${yellow( + 'Neither "sharp" or "jimp" NPM packages are installed, image resizing will be disabled', + )}`, + ); } } @@ -123,7 +140,8 @@ export async function ImageProxy(req: Request, res: Response) { const buffer = Buffer.from(arrayBuffer); if (sharp && sharpSupported.has(contentType)) { - resultBuffer = await sharp.default(buffer) + resultBuffer = await sharp + .default(buffer) // Sharp doesn't support "scaleToFit" .resize(width) .toBuffer(); @@ -131,13 +149,15 @@ export async function ImageProxy(req: Request, res: Response) { resultBuffer = await Jimp.read(buffer).then((image) => { contentType = image.getMIME(); // @ts-expect-error Jimp is defined at this point - return image.scaleToFit(width, height).getBufferAsync(Jimp.AUTO); + return image + .scaleToFit(width, height) + .getBufferAsync(Jimp.AUTO); }); } } res.header("Content-Type", contentType); - res.setHeader("Cache-Control", "public, max-age=" + (1000 * 60 * 60 * 24)); + res.setHeader("Cache-Control", "public, max-age=" + 1000 * 60 * 60 * 24); res.send(resultBuffer); } From 93bb891d7915639a7e405e1553b3b0ad52d53175 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:50:11 +0200 Subject: [PATCH 03/38] Fix @ts-expect-error comment after Prettier --- src/api/middlewares/ImageProxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/middlewares/ImageProxy.ts b/src/api/middlewares/ImageProxy.ts index 64d5ddc1..80a3adcb 100644 --- a/src/api/middlewares/ImageProxy.ts +++ b/src/api/middlewares/ImageProxy.ts @@ -148,9 +148,9 @@ export async function ImageProxy(req: Request, res: Response) { } else if (Jimp && jimpSupported.has(contentType)) { resultBuffer = await Jimp.read(buffer).then((image) => { contentType = image.getMIME(); - // @ts-expect-error Jimp is defined at this point return image .scaleToFit(width, height) + // @ts-expect-error Jimp is defined at this point .getBufferAsync(Jimp.AUTO); }); } From af6e15b9e5467293b8d95d8968429226a98d19f5 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:06:08 +0200 Subject: [PATCH 04/38] Prettier stuff -.- --- src/api/middlewares/ImageProxy.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/middlewares/ImageProxy.ts b/src/api/middlewares/ImageProxy.ts index 80a3adcb..f642ff27 100644 --- a/src/api/middlewares/ImageProxy.ts +++ b/src/api/middlewares/ImageProxy.ts @@ -148,10 +148,12 @@ export async function ImageProxy(req: Request, res: Response) { } else if (Jimp && jimpSupported.has(contentType)) { resultBuffer = await Jimp.read(buffer).then((image) => { contentType = image.getMIME(); - return image - .scaleToFit(width, height) - // @ts-expect-error Jimp is defined at this point - .getBufferAsync(Jimp.AUTO); + return ( + image + .scaleToFit(width, height) + // @ts-expect-error Jimp is defined at this point + .getBufferAsync(Jimp.AUTO) + ); }); } } From 16f8a1c7ac4eb1dafd571b5b3082f0df129fd39f Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:17:24 +0200 Subject: [PATCH 05/38] Add config value for cache duration --- package-lock.json | Bin 326795 -> 326819 bytes src/api/middlewares/ImageProxy.ts | 9 +++++---- src/util/config/types/CdnConfiguration.ts | 8 +++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 32582d06dfdf1235d7dd44174db10c86f3f94aad..a350da90ed542fefb4b45804b9d3ff14e07e5ea6 100644 GIT binary patch delta 36 pcmeDFDZKcn@P~k9m&KX`nA-!G8G)Dyh?%zsFtb?y1OWZu3@rcv delta 30 icmZ4dQ@H!5@P Date: Fri, 28 Jun 2024 12:13:17 +0200 Subject: [PATCH 07/38] Add meta section to nix package, fix nix update script writing to wrong variable in hashes.json --- flake.lock | Bin 1497 -> 1497 bytes flake.nix | 12 +++++++++++- hashes.json | 2 +- nix-update.sh | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index ae5e8b23070de1f0618864a223c9a3c17f752ca5..77bf2b8620a5f7d1a37dc5bb4b8c1c26c3c997b4 100644 GIT binary patch delta 254 zcmcb~eUp1a2Zy17p^2G+vBAU%vf9B>raoq=j^-X-`gyt8RqpQQ`kukbIfbca`B5qU zQ6YZ$sl}O|dD#&Gfs^O6h);ZPp^;>mVwsp^ZeV6+WNBiSnr2{OYLH@LVUdz(m~3fa zXqjf5XlZV0lsNeSqw-`PX3dH34JV&rjNve}G%_`@FgFER>*}1BsqL9v9+6dA>`|O+ z8Jt>?Qc`G9p6XbrUm03iVi*$cnVK6>V(gs{v{rJmIkUjz^^9zj^O%M8i&D#!tQ3@t yEG&)FOwCeK4J-_d43pE+QY@3qlFU-llFbc(?BwJWQ^V9GGXsz_HuEr_WdZ;vC{N-5 delta 254 zcmcb~eUp1a2Zw>Fv4N$LvB|^k2LW`W7;8QCW1F$?P#rIsmKDJYp* ym>DMCnp&vTNr?xv6+YYEE52THBEy6 diff --git a/flake.nix b/flake.nix index 00a18f64..cc624004 100644 --- a/flake.nix +++ b/flake.nix @@ -13,11 +13,21 @@ inherit system; }; hashesFile = builtins.fromJSON (builtins.readFile ./hashes.json); + lib = pkgs.lib; in rec { packages.default = pkgs.buildNpmPackage { pname = "spacebar-server-ts"; - src = ./.; name = "spacebar-server-ts"; + + meta = with lib; { + description = "Spacebar server, a FOSS reimplementation of the Discord backend."; + homepage = "https://github.com/spacebarchat/server"; + license = licenses.agpl3Plus; + platforms = platforms.all; + mainProgram = "start-bundle"; + }; + + src = ./.; nativeBuildInputs = with pkgs; [ python3 ]; npmDepsHash = hashesFile.npmDepsHash; makeCacheWritable = true; diff --git a/hashes.json b/hashes.json index dd55b81d..bc319094 100644 --- a/hashes.json +++ b/hashes.json @@ -1,3 +1,3 @@ { - "npmDepsHash": "sha256-fZNDN2/fNy6Nu7tbr0RhQ8j4BP7X1Yhrh/fSTH7hbJc=" + "npmDepsHash": "sha256-RxGkjCU9qqqDMjhJ5aEq1w7c7lS4nAp0/3F0zASJQms=" } diff --git a/nix-update.sh b/nix-update.sh index 4413e6e0..a676e294 100755 --- a/nix-update.sh +++ b/nix-update.sh @@ -3,8 +3,8 @@ nix flake update DEPS_HASH=`prefetch-npm-deps package-lock.json` TMPFILE=$(mktemp) -jq '.npm_deps_hash = "'$DEPS_HASH'"' hashes.json > $TMPFILE +jq '.npmDepsHash = "'$DEPS_HASH'"' hashes.json > $TMPFILE mv -- "$TMPFILE" hashes.json nom build .# || exit $? -git add hashes.json flake.lock flake.nix \ No newline at end of file +git add hashes.json flake.lock flake.nix From e069db134f8f75c197fd6df72ee639d1d165f8fc Mon Sep 17 00:00:00 2001 From: "Emma [it/its]@Rory&" Date: Fri, 28 Jun 2024 12:17:35 +0200 Subject: [PATCH 08/38] Add hashes.json to .prettierignore as this is a generated file --- .prettierignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 51116757..9531c159 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,4 +2,5 @@ assets dist node_modules .github -.vscode \ No newline at end of file +.vscode +hashes.json From a987671e4a1249ae23914165c1b3edd0f29d9ffd Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:43:53 +0200 Subject: [PATCH 09/38] "Fix" jimp import typings --- src/api/middlewares/ImageProxy.ts | 21 +++++++++++++++------ src/util/imports/Jimp.ts | 23 +++++++++++++++++++++++ src/util/imports/index.ts | 1 + 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 src/util/imports/Jimp.ts diff --git a/src/api/middlewares/ImageProxy.ts b/src/api/middlewares/ImageProxy.ts index 4c324afd..27c69ae2 100644 --- a/src/api/middlewares/ImageProxy.ts +++ b/src/api/middlewares/ImageProxy.ts @@ -16,14 +16,22 @@ along with this program. If not, see . */ -import { Config } from "@spacebar/util"; +import { Config, JimpType } from "@spacebar/util"; import { Request, Response } from "express"; import { yellow } from "picocolors"; import crypto from "crypto"; import fetch from "node-fetch"; let sharp: undefined | false | { default: typeof import("sharp") } = undefined; -let Jimp: undefined | false | typeof import("jimp") = undefined; + +let Jimp: JimpType | undefined = undefined; +try { + Jimp = require("jimp") as JimpType; +} catch { + // empty +} + +let sentImageProxyWarning = false; const sharpSupported = new Set([ "image/jpeg", @@ -112,20 +120,21 @@ export async function ImageProxy(req: Request, res: Response) { const arrayBuffer = await request.arrayBuffer(); let resultBuffer = Buffer.from(arrayBuffer); - if (/^\d+x\d+$/.test(path[1]) && resizeSupported.has(contentType)) { + if (!sentImageProxyWarning && resizeSupported.has(contentType) && /^\d+x\d+$/.test(path[1])) { if (sharp !== false) { try { sharp = await import("sharp"); - } catch (e) { + } catch { sharp = false; } } - if (sharp === false && Jimp !== false) { + + if (sharp === false && !Jimp) { try { // @ts-expect-error Typings don't fit Jimp = await import("jimp"); } catch { - Jimp = false; + sentImageProxyWarning = true; console.log( `[ImageProxy] ${yellow( 'Neither "sharp" or "jimp" NPM packages are installed, image resizing will be disabled', diff --git a/src/util/imports/Jimp.ts b/src/util/imports/Jimp.ts new file mode 100644 index 00000000..c1389e03 --- /dev/null +++ b/src/util/imports/Jimp.ts @@ -0,0 +1,23 @@ +/* + 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 . +*/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export type JimpType = { + read: (data: Buffer) => Promise; +}; diff --git a/src/util/imports/index.ts b/src/util/imports/index.ts index 08b870bc..4bc5a6c5 100644 --- a/src/util/imports/index.ts +++ b/src/util/imports/index.ts @@ -18,3 +18,4 @@ export * from "./OrmUtils"; export * from "./Erlpack"; +export * from "./Jimp"; From c135de9c866fd23b862155faf97c5704e9e0d8e6 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:59:13 +0200 Subject: [PATCH 10/38] Fix style + nix? --- package-lock.json | Bin 326819 -> 326812 bytes src/api/middlewares/ImageProxy.ts | 8 ++++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a350da90ed542fefb4b45804b9d3ff14e07e5ea6..83d1852bdb4aa74638b2aeb672c241f9e5aa8fa1 100644 GIT binary patch delta 32 lcmZ4dQ+Uo#;SCYYj9SeJ% Date: Fri, 28 Jun 2024 13:05:03 +0200 Subject: [PATCH 11/38] Fix build by using ts-ignore --- package-lock.json | Bin 326812 -> 326819 bytes src/api/middlewares/ImageProxy.ts | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 83d1852bdb4aa74638b2aeb672c241f9e5aa8fa1..a350da90ed542fefb4b45804b9d3ff14e07e5ea6 100644 GIT binary patch delta 34 ncmbR9Q+V-D;SCYYlhZE?G$%5*Co(evF%u9oZ%<@qvHl4F^Jok~ delta 32 lcmZ4dQ+Uo#;SCYYj9SeJ% Date: Sat, 17 Aug 2024 12:33:32 +0200 Subject: [PATCH 12/38] Add utf8mb4 "engine" property to all entitys --- src/util/entities/Application.ts | 8 ++++---- src/util/entities/Attachment.ts | 8 ++++---- src/util/entities/AuditLog.ts | 8 ++++---- src/util/entities/BackupCodes.ts | 8 ++++---- src/util/entities/Badge.ts | 8 ++++---- src/util/entities/Ban.ts | 8 ++++---- src/util/entities/Categories.ts | 2 +- src/util/entities/Channel.ts | 2 +- src/util/entities/ClientRelease.ts | 8 ++++---- src/util/entities/Config.ts | 8 ++++---- src/util/entities/ConnectedAccount.ts | 8 ++++---- src/util/entities/ConnectionConfigEntity.ts | 8 ++++---- src/util/entities/EmbedCache.ts | 8 ++++---- src/util/entities/Emoji.ts | 8 ++++---- src/util/entities/Encryption.ts | 8 ++++---- src/util/entities/Guild.ts | 8 ++++---- src/util/entities/Invite.ts | 8 ++++---- src/util/entities/Member.ts | 2 +- src/util/entities/Message.ts | 2 +- src/util/entities/Migration.ts | 8 ++++---- src/util/entities/Note.ts | 8 ++++---- src/util/entities/RateLimit.ts | 8 ++++---- src/util/entities/ReadState.ts | 8 ++++---- src/util/entities/Recipient.ts | 8 ++++---- src/util/entities/Relationship.ts | 8 ++++---- src/util/entities/Role.ts | 8 ++++---- src/util/entities/SecurityKey.ts | 8 ++++---- src/util/entities/Session.ts | 2 +- src/util/entities/Sticker.ts | 8 ++++---- src/util/entities/StickerPack.ts | 8 ++++---- src/util/entities/Team.ts | 8 ++++---- src/util/entities/TeamMember.ts | 8 ++++---- src/util/entities/Template.ts | 8 ++++---- src/util/entities/User.ts | 2 +- src/util/entities/UserSettings.ts | 8 ++++---- src/util/entities/ValidRegistrationTokens.ts | 8 ++++---- src/util/entities/VoiceState.ts | 8 ++++---- src/util/entities/Webhook.ts | 2 +- 38 files changed, 131 insertions(+), 131 deletions(-) diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index 962b2a8e..1ecd4475 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { BaseClass } from "./BaseClass"; import { Team } from "./Team"; import { User } from "./User"; -@Entity("applications") +@Entity({name: "applications", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Application extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index d60ac41c..68d8aa54 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -28,7 +28,7 @@ import { URL } from "url"; import { deleteFile } from "../util/cdn"; import { BaseClass } from "./BaseClass"; -@Entity("attachments") +@Entity({name: "attachments", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Attachment extends BaseClass { @Column() filename: string; // name of file attached diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index b375f771..6ac2802b 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -111,7 +111,7 @@ export enum AuditLogEvents { ROUTE_UPDATE = 226, } -@Entity("audit_logs") +@Entity({name: "audit_logs", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class AuditLog extends BaseClass { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 61e8f12a..638bcd04 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { BaseClass } from "./BaseClass"; import { User } from "./User"; import crypto from "crypto"; -@Entity("backup_codes") +@Entity({name: "backup_codes", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class BackupCode extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) diff --git a/src/util/entities/Badge.ts b/src/util/entities/Badge.ts index 9535e207..d403c655 100644 --- a/src/util/entities/Badge.ts +++ b/src/util/entities/Badge.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; -@Entity("badges") +@Entity({name: "badges", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Badge extends BaseClassWithoutId { @Column({ primary: true }) id: string; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 1693cd40..2535f3e3 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; -@Entity("bans") +@Entity({name: "bans", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Ban extends BaseClass { @Column({ nullable: true }) @RelationId((ban: Ban) => ban.user) diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts index 13d969de..d3eada5a 100644 --- a/src/util/entities/Categories.ts +++ b/src/util/entities/Categories.ts @@ -33,7 +33,7 @@ import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; // }] // Also populate discord default categories -@Entity("categories") +@Entity({name: "categories", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Categories extends BaseClassWithoutId { // Not using snowflake diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 71ccf49e..e3856e8d 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -69,7 +69,7 @@ export enum ChannelType { UNHANDLED = 255, // unhandled unowned pass-through channel type } -@Entity("channels") +@Entity({name: "channels", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Channel extends BaseClass { @Column() created_at: Date; diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index cfbc3a9b..2282b1ff 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity("client_release") +@Entity({name: "client_release", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Release extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts index 3c436ff0..efe8c563 100644 --- a/src/util/entities/Config.ts +++ b/src/util/entities/Config.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; -@Entity("config") +@Entity({name: "config", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class ConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() key: string; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 6e089de1..78dec432 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -26,7 +26,7 @@ export type PublicConnectedAccount = Pick< "name" | "type" | "verified" >; -@Entity("connected_accounts") +@Entity({name: "connected_accounts", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class ConnectedAccount extends BaseClass { @Column() external_id: string; diff --git a/src/util/entities/ConnectionConfigEntity.ts b/src/util/entities/ConnectionConfigEntity.ts index e4b7cea8..0c367c1c 100644 --- a/src/util/entities/ConnectionConfigEntity.ts +++ b/src/util/entities/ConnectionConfigEntity.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; -@Entity("connection_config") +@Entity({name: "connection_config", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class ConnectionConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() key: string; diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index 8ff2a457..f2dcd893 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -20,7 +20,7 @@ import { BaseClass } from "./BaseClass"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; -@Entity("embed_cache") +@Entity({name: "embed_cache", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class EmbedCache extends BaseClass { @Column() url: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index 4d851698..65d54d5e 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { User } from "."; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; -@Entity("emojis") +@Entity({name: "emojis", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Emoji extends BaseClass { @Column() animated: boolean; diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 8325bdee..97f9052c 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity("security_settings") +@Entity({name: "security_settings", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class SecuritySettings extends BaseClass { @Column({ nullable: true }) guild_id: string; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index fcd6b729..7a918220 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -66,7 +66,7 @@ export const PublicGuildRelations = [ // "members.user", ]; -@Entity("guilds") +@Entity({name: "guilds", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Guild extends BaseClass { @Column({ nullable: true }) @RelationId((guild: Guild) => guild.afk_channel) diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts index f7e54fbe..a7b17a8a 100644 --- a/src/util/entities/Invite.ts +++ b/src/util/entities/Invite.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -25,7 +25,7 @@ import { User } from "./User"; export const PublicInviteRelation = ["inviter", "guild", "channel"]; -@Entity("invites") +@Entity({name: "invites", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Invite extends BaseClassWithoutId { @PrimaryIdColumn() code: string; diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 3ef778ac..f43d5a92 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -65,7 +65,7 @@ export const MemberPrivateProjection: (keyof Member)[] = [ "user", ]; -@Entity("members") +@Entity({name: "members", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) @Index(["id", "guild_id"], { unique: true }) export class Member extends BaseClassWithoutId { @PrimaryGeneratedColumn() diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index 1dd89dc1..f340bbc0 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -68,7 +68,7 @@ export enum MessageType { UNHANDLED = 255, } -@Entity("messages") +@Entity({name: "messages", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) @Index(["channel_id", "id"], { unique: true }) export class Message extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts index 5c4e951d..742e3621 100644 --- a/src/util/entities/Migration.ts +++ b/src/util/entities/Migration.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -30,7 +30,7 @@ export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith( ? ObjectIdColumn : PrimaryGeneratedColumn; -@Entity("migrations") +@Entity({name: "migrations", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Migration extends BaseEntity { @PrimaryIdAutoGenerated() id: number; diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index 196f6861..d220367f 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -20,7 +20,7 @@ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; -@Entity("notes") +@Entity({name: "notes", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) @Unique(["owner", "target"]) export class Note extends BaseClass { @JoinColumn({ name: "owner_id" }) diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index 8d00f59a..836a8af5 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity("rate_limits") +@Entity({name: "rate_limits", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class RateLimit extends BaseClass { @Column() // no relation as it also executor_id: string; diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 1b280d12..7d367ecc 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -32,7 +32,7 @@ import { User } from "./User"; // notification cursor and public read receipt need to be forwards-only (the former to prevent re-pinging when marked as unread, and the latter to be acceptable as a legal acknowledgement in criminal proceedings), and private read marker needs to be advance-rewind capable // public read receipt ≥ notification cursor ≥ private fully read marker -@Entity("read_states") +@Entity({name: "read_states", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) @Index(["channel_id", "user_id"], { unique: true }) export class ReadState extends BaseClass { @Column() diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index 797349e5..5e2cd800 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity("recipients") +@Entity({name: "recipients", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Recipient extends BaseClass { @Column() @RelationId((recipient: Recipient) => recipient.channel) diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index 740095c2..6472aaa1 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -34,7 +34,7 @@ export enum RelationshipType { friends = 1, } -@Entity("relationships") +@Entity({name: "relationships", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) @Index(["from_id", "to_id"], { unique: true }) export class Relationship extends BaseClass { @Column({}) diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index 2783a279..8a752047 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; -@Entity("roles") +@Entity({name: "roles", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Role extends BaseClass { @Column() @RelationId((role: Role) => role.guild) diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index fd7a4c5e..652bbb39 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -20,7 +20,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; -@Entity("security_keys") +@Entity({name: "security_keys", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class SecurityKey extends BaseClass { @Column({ nullable: true }) @RelationId((key: SecurityKey) => key.user) diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index 15f8faa2..1fbdd2bb 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -24,7 +24,7 @@ import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them -@Entity("sessions") +@Entity({name: "sessions", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Session extends BaseClass { @Column({ nullable: true }) @RelationId((session: Session) => session.user) diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index e9294f92..95eeb32a 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -33,7 +33,7 @@ export enum StickerFormatType { LOTTIE = 3, } -@Entity("stickers") +@Entity({name: "stickers", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Sticker extends BaseClass { @Column() name: string; diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index 61ab1287..257fb6e4 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -27,7 +27,7 @@ import { import { Sticker } from "."; import { BaseClass } from "./BaseClass"; -@Entity("sticker_packs") +@Entity({name: "sticker_packs", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class StickerPack extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index 7bedc4af..e98344c8 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -28,7 +28,7 @@ import { BaseClass } from "./BaseClass"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; -@Entity("teams") +@Entity({name: "teams", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Team extends BaseClass { @Column({ nullable: true }) icon?: string; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index 539da957..54c90a5a 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -25,7 +25,7 @@ export enum TeamMemberState { ACCEPTED = 2, } -@Entity("team_members") +@Entity({name: "team_members", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class TeamMember extends BaseClass { @Column({ type: "int" }) membership_state: TeamMemberState; diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index c417f1f0..4cf98651 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -21,7 +21,7 @@ import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; -@Entity("templates") +@Entity({name: "templates", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Template extends BaseClass { @Column({ unique: true }) code: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index b299bcfc..e2290d0b 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -86,7 +86,7 @@ export interface UserPrivate extends Pick { locale: string; } -@Entity("users") +@Entity({name: "users", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class User extends BaseClass { @Column() username: string; // username max length 32, min 2 (should be configurable) diff --git a/src/util/entities/UserSettings.ts b/src/util/entities/UserSettings.ts index d3efe79b..0df2ff86 100644 --- a/src/util/entities/UserSettings.ts +++ b/src/util/entities/UserSettings.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; -@Entity("user_settings") +@Entity({name: "user_settings", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class UserSettings extends BaseClassWithoutId { @PrimaryGeneratedColumn() index: string; diff --git a/src/util/entities/ValidRegistrationTokens.ts b/src/util/entities/ValidRegistrationTokens.ts index 94fd1542..77da100a 100644 --- a/src/util/entities/ValidRegistrationTokens.ts +++ b/src/util/entities/ValidRegistrationTokens.ts @@ -1,24 +1,24 @@ /* 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 . */ import { BaseEntity, Column, Entity, PrimaryColumn } from "typeorm"; -@Entity("valid_registration_tokens") +@Entity({name: "valid_registration_tokens", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class ValidRegistrationToken extends BaseEntity { @PrimaryColumn() token: string; diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index 84b0ca71..3678fa1a 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -24,7 +24,7 @@ import { Member } from "./Member"; import { User } from "./User"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex -@Entity("voice_states") +@Entity({name: "voice_states", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class VoiceState extends BaseClass { @Column({ nullable: true }) @RelationId((voice_state: VoiceState) => voice_state.guild) diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index 9539d6e8..5d50333e 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -29,7 +29,7 @@ export enum WebhookType { Application = 3, } -@Entity("webhooks") +@Entity({name: "webhooks", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) export class Webhook extends BaseClass { @Column({ type: "int" }) type: WebhookType; From 99c75d3ae42180d96552ed1be363f65412ebb21b Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:54:17 +0200 Subject: [PATCH 13/38] Run prettier for @Entity() --- src/util/entities/Application.ts | 5 ++++- src/util/entities/Attachment.ts | 5 ++++- src/util/entities/AuditLog.ts | 5 ++++- src/util/entities/BackupCodes.ts | 5 ++++- src/util/entities/Badge.ts | 5 ++++- src/util/entities/Ban.ts | 5 ++++- src/util/entities/Categories.ts | 5 ++++- src/util/entities/Channel.ts | 5 ++++- src/util/entities/ClientRelease.ts | 5 ++++- src/util/entities/Config.ts | 5 ++++- src/util/entities/ConnectedAccount.ts | 5 ++++- src/util/entities/ConnectionConfigEntity.ts | 5 ++++- src/util/entities/EmbedCache.ts | 5 ++++- src/util/entities/Emoji.ts | 5 ++++- src/util/entities/Encryption.ts | 5 ++++- src/util/entities/Guild.ts | 5 ++++- src/util/entities/Invite.ts | 5 ++++- src/util/entities/Member.ts | 5 ++++- src/util/entities/Message.ts | 5 ++++- src/util/entities/Migration.ts | 5 ++++- src/util/entities/Note.ts | 5 ++++- src/util/entities/RateLimit.ts | 5 ++++- src/util/entities/ReadState.ts | 5 ++++- src/util/entities/Recipient.ts | 5 ++++- src/util/entities/Relationship.ts | 5 ++++- src/util/entities/Role.ts | 5 ++++- src/util/entities/SecurityKey.ts | 5 ++++- src/util/entities/Session.ts | 5 ++++- src/util/entities/Sticker.ts | 5 ++++- src/util/entities/StickerPack.ts | 5 ++++- src/util/entities/Team.ts | 5 ++++- src/util/entities/TeamMember.ts | 5 ++++- src/util/entities/Template.ts | 5 ++++- src/util/entities/User.ts | 5 ++++- src/util/entities/UserSettings.ts | 5 ++++- src/util/entities/ValidRegistrationTokens.ts | 5 ++++- src/util/entities/VoiceState.ts | 5 ++++- src/util/entities/Webhook.ts | 5 ++++- 38 files changed, 152 insertions(+), 38 deletions(-) diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index 1ecd4475..c60a6547 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -21,7 +21,10 @@ import { BaseClass } from "./BaseClass"; import { Team } from "./Team"; import { User } from "./User"; -@Entity({name: "applications", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "applications", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Application extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index 68d8aa54..f5124154 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -28,7 +28,10 @@ import { URL } from "url"; import { deleteFile } from "../util/cdn"; import { BaseClass } from "./BaseClass"; -@Entity({name: "attachments", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "attachments", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Attachment extends BaseClass { @Column() filename: string; // name of file attached diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index 6ac2802b..b8a02d75 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -111,7 +111,10 @@ export enum AuditLogEvents { ROUTE_UPDATE = 226, } -@Entity({name: "audit_logs", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "audit_logs", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class AuditLog extends BaseClass { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 638bcd04..b4c6f395 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -21,7 +21,10 @@ import { BaseClass } from "./BaseClass"; import { User } from "./User"; import crypto from "crypto"; -@Entity({name: "backup_codes", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "backup_codes", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class BackupCode extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) diff --git a/src/util/entities/Badge.ts b/src/util/entities/Badge.ts index d403c655..e716525a 100644 --- a/src/util/entities/Badge.ts +++ b/src/util/entities/Badge.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; -@Entity({name: "badges", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "badges", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Badge extends BaseClassWithoutId { @Column({ primary: true }) id: string; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 2535f3e3..407569fc 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -21,7 +21,10 @@ import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; -@Entity({name: "bans", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "bans", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Ban extends BaseClass { @Column({ nullable: true }) @RelationId((ban: Ban) => ban.user) diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts index d3eada5a..9fa64335 100644 --- a/src/util/entities/Categories.ts +++ b/src/util/entities/Categories.ts @@ -33,7 +33,10 @@ import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; // }] // Also populate discord default categories -@Entity({name: "categories", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "categories", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Categories extends BaseClassWithoutId { // Not using snowflake diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index e3856e8d..66eaa0eb 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -69,7 +69,10 @@ export enum ChannelType { UNHANDLED = 255, // unhandled unowned pass-through channel type } -@Entity({name: "channels", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "channels", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Channel extends BaseClass { @Column() created_at: Date; diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index 2282b1ff..f6577b2c 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity({name: "client_release", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "client_release", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Release extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts index efe8c563..9a3fd55e 100644 --- a/src/util/entities/Config.ts +++ b/src/util/entities/Config.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; -@Entity({name: "config", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "config", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class ConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() key: string; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 78dec432..f0ee62fe 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -26,7 +26,10 @@ export type PublicConnectedAccount = Pick< "name" | "type" | "verified" >; -@Entity({name: "connected_accounts", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "connected_accounts", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class ConnectedAccount extends BaseClass { @Column() external_id: string; diff --git a/src/util/entities/ConnectionConfigEntity.ts b/src/util/entities/ConnectionConfigEntity.ts index 0c367c1c..19d11627 100644 --- a/src/util/entities/ConnectionConfigEntity.ts +++ b/src/util/entities/ConnectionConfigEntity.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; -@Entity({name: "connection_config", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "connection_config", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class ConnectionConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() key: string; diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index f2dcd893..853fa73d 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -20,7 +20,10 @@ import { BaseClass } from "./BaseClass"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; -@Entity({name: "embed_cache", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "embed_cache", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class EmbedCache extends BaseClass { @Column() url: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index 65d54d5e..ac44b8f7 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -21,7 +21,10 @@ import { User } from "."; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; -@Entity({name: "emojis", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "emojis", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Emoji extends BaseClass { @Column() animated: boolean; diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 97f9052c..3ef933fb 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity({name: "security_settings", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "security_settings", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class SecuritySettings extends BaseClass { @Column({ nullable: true }) guild_id: string; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index 7a918220..8517ca36 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -66,7 +66,10 @@ export const PublicGuildRelations = [ // "members.user", ]; -@Entity({name: "guilds", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "guilds", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Guild extends BaseClass { @Column({ nullable: true }) @RelationId((guild: Guild) => guild.afk_channel) diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts index a7b17a8a..6ab75302 100644 --- a/src/util/entities/Invite.ts +++ b/src/util/entities/Invite.ts @@ -25,7 +25,10 @@ import { User } from "./User"; export const PublicInviteRelation = ["inviter", "guild", "channel"]; -@Entity({name: "invites", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "invites", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Invite extends BaseClassWithoutId { @PrimaryIdColumn() code: string; diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index f43d5a92..0ca1a15b 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -65,7 +65,10 @@ export const MemberPrivateProjection: (keyof Member)[] = [ "user", ]; -@Entity({name: "members", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "members", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) @Index(["id", "guild_id"], { unique: true }) export class Member extends BaseClassWithoutId { @PrimaryGeneratedColumn() diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index f340bbc0..ba6b1ac7 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -68,7 +68,10 @@ export enum MessageType { UNHANDLED = 255, } -@Entity({name: "messages", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "messages", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) @Index(["channel_id", "id"], { unique: true }) export class Message extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts index 742e3621..cd572c03 100644 --- a/src/util/entities/Migration.ts +++ b/src/util/entities/Migration.ts @@ -30,7 +30,10 @@ export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith( ? ObjectIdColumn : PrimaryGeneratedColumn; -@Entity({name: "migrations", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "migrations", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Migration extends BaseEntity { @PrimaryIdAutoGenerated() id: number; diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index d220367f..4821d2d9 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -20,7 +20,10 @@ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; -@Entity({name: "notes", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "notes", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) @Unique(["owner", "target"]) export class Note extends BaseClass { @JoinColumn({ name: "owner_id" }) diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index 836a8af5..f0f597e0 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -19,7 +19,10 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity({name: "rate_limits", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "rate_limits", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class RateLimit extends BaseClass { @Column() // no relation as it also executor_id: string; diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 7d367ecc..8e555de6 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -32,7 +32,10 @@ import { User } from "./User"; // notification cursor and public read receipt need to be forwards-only (the former to prevent re-pinging when marked as unread, and the latter to be acceptable as a legal acknowledgement in criminal proceedings), and private read marker needs to be advance-rewind capable // public read receipt ≥ notification cursor ≥ private fully read marker -@Entity({name: "read_states", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "read_states", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) @Index(["channel_id", "user_id"], { unique: true }) export class ReadState extends BaseClass { @Column() diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index 5e2cd800..fecb051f 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -19,7 +19,10 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; -@Entity({name: "recipients", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "recipients", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Recipient extends BaseClass { @Column() @RelationId((recipient: Recipient) => recipient.channel) diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index 6472aaa1..3aa057e7 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -34,7 +34,10 @@ export enum RelationshipType { friends = 1, } -@Entity({name: "relationships", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "relationships", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) @Index(["from_id", "to_id"], { unique: true }) export class Relationship extends BaseClass { @Column({}) diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index 8a752047..f4509827 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -21,7 +21,10 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; -@Entity({name: "roles", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "roles", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Role extends BaseClass { @Column() @RelationId((role: Role) => role.guild) diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index 652bbb39..f0b156c9 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -20,7 +20,10 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; -@Entity({name: "security_keys", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "security_keys", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class SecurityKey extends BaseClass { @Column({ nullable: true }) @RelationId((key: SecurityKey) => key.user) diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index 1fbdd2bb..b7657d97 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -24,7 +24,10 @@ import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them -@Entity({name: "sessions", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "sessions", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Session extends BaseClass { @Column({ nullable: true }) @RelationId((session: Session) => session.user) diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index 95eeb32a..5b17c9b8 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -33,7 +33,10 @@ export enum StickerFormatType { LOTTIE = 3, } -@Entity({name: "stickers", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "stickers", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Sticker extends BaseClass { @Column() name: string; diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index 257fb6e4..5f7bf671 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -27,7 +27,10 @@ import { import { Sticker } from "."; import { BaseClass } from "./BaseClass"; -@Entity({name: "sticker_packs", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "sticker_packs", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class StickerPack extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index e98344c8..7c804260 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -28,7 +28,10 @@ import { BaseClass } from "./BaseClass"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; -@Entity({name: "teams", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "teams", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Team extends BaseClass { @Column({ nullable: true }) icon?: string; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index 54c90a5a..5b82d30e 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -25,7 +25,10 @@ export enum TeamMemberState { ACCEPTED = 2, } -@Entity({name: "team_members", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "team_members", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class TeamMember extends BaseClass { @Column({ type: "int" }) membership_state: TeamMemberState; diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index 4cf98651..3d5c1764 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -21,7 +21,10 @@ import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; -@Entity({name: "templates", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "templates", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Template extends BaseClass { @Column({ unique: true }) code: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index e2290d0b..43c4aea6 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -86,7 +86,10 @@ export interface UserPrivate extends Pick { locale: string; } -@Entity({name: "users", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "users", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class User extends BaseClass { @Column() username: string; // username max length 32, min 2 (should be configurable) diff --git a/src/util/entities/UserSettings.ts b/src/util/entities/UserSettings.ts index 0df2ff86..1f27630d 100644 --- a/src/util/entities/UserSettings.ts +++ b/src/util/entities/UserSettings.ts @@ -19,7 +19,10 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; -@Entity({name: "user_settings", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "user_settings", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class UserSettings extends BaseClassWithoutId { @PrimaryGeneratedColumn() index: string; diff --git a/src/util/entities/ValidRegistrationTokens.ts b/src/util/entities/ValidRegistrationTokens.ts index 77da100a..737adfc1 100644 --- a/src/util/entities/ValidRegistrationTokens.ts +++ b/src/util/entities/ValidRegistrationTokens.ts @@ -18,7 +18,10 @@ import { BaseEntity, Column, Entity, PrimaryColumn } from "typeorm"; -@Entity({name: "valid_registration_tokens", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "valid_registration_tokens", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class ValidRegistrationToken extends BaseEntity { @PrimaryColumn() token: string; diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index 3678fa1a..de0a52d3 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -24,7 +24,10 @@ import { Member } from "./Member"; import { User } from "./User"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex -@Entity({name: "voice_states", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "voice_states", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class VoiceState extends BaseClass { @Column({ nullable: true }) @RelationId((voice_state: VoiceState) => voice_state.guild) diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index 5d50333e..7005bf64 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -29,7 +29,10 @@ export enum WebhookType { Application = 3, } -@Entity({name: "webhooks", engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"}) +@Entity({ + name: "webhooks", + engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", +}) export class Webhook extends BaseClass { @Column({ type: "int" }) type: WebhookType; From 8e28f2539c493aab902a9eff190806caca5a9f34 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 17 Aug 2024 15:39:55 +0200 Subject: [PATCH 14/38] Consistent username length requirement --- src/api/routes/auth/register.ts | 16 +++++++++++++--- src/util/schemas/RegisterSchema.ts | 7 +++---- src/util/schemas/UserModifySchema.ts | 3 +-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts index de1cbd3d..ea5de53b 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -287,6 +287,16 @@ router.post( }); } + const { maxUsername } = Config.get().limits.user; + if (body.username.length > maxUsername) { + throw FieldErrors({ + username: { + code: "USERNAME_INVALID", + message: `Username must be less than ${maxUsername} in length`, + }, + }); + } + const user = await User.register({ ...body, req }); if (body.invite) { diff --git a/src/util/schemas/RegisterSchema.ts b/src/util/schemas/RegisterSchema.ts index 7b7de9c7..cfee0f02 100644 --- a/src/util/schemas/RegisterSchema.ts +++ b/src/util/schemas/RegisterSchema.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,6 @@ export interface RegisterSchema { /** * @minLength 2 - * @maxLength 32 */ username: string; /** diff --git a/src/util/schemas/UserModifySchema.ts b/src/util/schemas/UserModifySchema.ts index 4be6ad43..e4ed1071 100644 --- a/src/util/schemas/UserModifySchema.ts +++ b/src/util/schemas/UserModifySchema.ts @@ -18,8 +18,7 @@ export interface UserModifySchema { /** - * @minLength 1 - * @maxLength 100 + * @minLength 2 */ username?: string; avatar?: string | null; From 95bbccb6f723264e514618b18d1af9e3679e0e6d Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 17 Aug 2024 18:24:38 +0200 Subject: [PATCH 15/38] Same error message if username too long --- src/api/routes/auth/register.ts | 4 ++-- src/api/routes/users/@me/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts index ea5de53b..62152440 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts @@ -291,8 +291,8 @@ router.post( if (body.username.length > maxUsername) { throw FieldErrors({ username: { - code: "USERNAME_INVALID", - message: `Username must be less than ${maxUsername} in length`, + code: "BASE_TYPE_BAD_LENGTH", + message: `Must be between 2 and ${maxUsername} in length.`, }, }); } diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts index 5caf0d11..9cd8bfda 100644 --- a/src/api/routes/users/@me/index.ts +++ b/src/api/routes/users/@me/index.ts @@ -155,8 +155,8 @@ router.patch( if (check_username.length > maxUsername) { throw FieldErrors({ username: { - code: "USERNAME_INVALID", - message: `Username must be less than ${maxUsername} in length`, + code: "BASE_TYPE_BAD_LENGTH", + message: `Must be between 2 and ${maxUsername} in length.`, }, }); } From e0b6dd05814453d54103d64d1631519019405a8b Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 06:45:11 +0200 Subject: [PATCH 16/38] Fix bug & handle 75k/large_threshold in opcode 8 Also fixes a bug that only allowed "guild_id" and "user_ids" to be an Array instead of also a String Co-Authored-By: Puyodead1 --- assets/openapi.json | Bin 617024 -> 617567 bytes assets/schemas.json | Bin 21209522 -> 23504303 bytes src/gateway/opcodes/Identify.ts | 1 + src/gateway/opcodes/RequestGuildMembers.ts | 109 ++++++++++++++---- src/gateway/util/WebSocket.ts | 7 +- src/util/schemas/RequestGuildMembersSchema.ts | 2 +- 6 files changed, 92 insertions(+), 27 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index 2af0a2c700b59b034ce0c5ad1fdb65d6592a5404..68adb4556eac99d06647d081f6de81280f125da2 100644 GIT binary patch delta 153 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 delta 20655 zcmd6v`BPI@6vyX6LIObupaI!5ZfHdot-B7O2n7WZabXz@xPz_WiVK*6fYo797*43l ziwiB{0@@C@TBk1#h#L;nI$E_=JBYPaMB9!IR};WAIaRm90G6recsHRCplvV=AtFX`lZ8WB=8T#q59QQyx0qlTnJv zV+OySzjCL@!3!5&$d`ODL1W~`vV$moGpqbCibI0qg=>YDpXGI z0M0>@s2q689{&~W|8kbb-uS66~#q}|vB{D3u%rRIz?=?Jk{wxDr#Ph1Q$je~fNj2bui0B5q zB=0QF`2@~ElBgWH!=$<4c!ISz%nQNGq-7%#3SF?$L!X8gCOHoh8aBo;cQTDlbffzx z7mkF3lnhl+>CnVj9vPI7$S5nWPELkV33F+Qj3!fgXr2pY{mncp;_SzelTM}Jxqbyz=SDITOvor5>?-x+i}@Miuy=cViMs9qK=55Ze5pJuD};c3;9laY-_)zq_QIi7FsWd_I2>~1^XwPa3bKr_pE81_`T}60{ddX04OfLnKI-DuE!L{TR z-um7$53cPgD{?}+KJgpQ`-Z_e$~PBPuEVRwG8o-~3ohQWwYnRx?zv^F4B)!A`)%QZ zi<-JzMw2lnbRyL}J2J?;&mnZAjb;&4c2=(t)OQ!Lv1DYe3n`!>bs*_C)WpKg+PS|Q zhvNw=Q7QR5-H|LfH2(Z{?M^rCV5UJFNIM}0AzV7w&qWC&cr#$%cr`r#Gd zl2%IIIpvHao{d?jzc%1eeKwNUz}d*_jAswvEd(xlp2u6D^W?qX>EYta+L4f^yzmUp zMl0G6`OU7Ns%7?G{L}%h`m(4-_uAD?T)*XVFQ|0yUt9&;cCj=L2`jIoqJ`XVe*4 zI(^2o5#-#fa=qk!&Wc2d)upIS`m7et&d`a$G5$dDnftsg>;l{<|OS-$@mh|+E z{fj!dy0hoiUvl!A9zB2>NAk(kSX?=aV%wa3grL0vQqP$>-o=vy*1CxLw%fRqPp*xc zylT&mLK_E{#^D7Qh-6lmmw)`a2M(>Nt2e_P%|+_?wNFMp*>81dWLzQ(hAa1~x_Xtu z?v;#HqUj|FKijgSa8xbx?bs1CD$C7z@!1t6+Xfe5)+bJdKciGE6HPY@TMi_ZO6VM~ zX3OE&t{it|wQy8D+5v1o9F@x8&JMy+jdJn?q>9|>&Fay#lCF+2anl=LmZLyJ6V`6l z0@_&8J(N|$Y4zpO5qRn0zfx5$w%r-Y?BF_!%(bDIoG_X_8VKj8sdEe?II15Lg8=8` ztM;)>K-0>y@bHZo&km!JiDBm_vdwTCfWqYQQvfTkCC8_+VmJ#|YC~8y*bNNnQB0}h zR!O$kZ_W`@u8U;-&NjY#kofxjTzkBj&uMnh(7O zSni#PA@ND98IMwWS%zHPbv1=W!x?LSIfb2=7`B9Yz_E#c@HEyR534v}89M=n^;%=& Gkoym>8_Wv; diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index c535cd45..94320eee 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -82,6 +82,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { const identify: IdentifySchema = data.d; this.capabilities = new Capabilities(identify.capabilities || 0); + this.large_threshold = identify.large_threshold || 250; const user = await tryGetUserFromToken(identify.token, { relations: ["relationships", "relationships.to", "settings"], diff --git a/src/gateway/opcodes/RequestGuildMembers.ts b/src/gateway/opcodes/RequestGuildMembers.ts index c84bf893..3381caed 100644 --- a/src/gateway/opcodes/RequestGuildMembers.ts +++ b/src/gateway/opcodes/RequestGuildMembers.ts @@ -17,6 +17,7 @@ */ import { + getDatabase, getPermission, GuildMembersChunkEvent, Member, @@ -29,51 +30,103 @@ import { check } from "./instanceOf"; import { FindManyOptions, In, Like } from "typeorm"; export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) { - // TODO: check data + // Schema validation can only accept either string or array, so transforming it here to support both + if (!d.guild_id) throw new Error('"guild_id" is required'); + d.guild_id = Array.isArray(d.guild_id) ? d.guild_id[0] : d.guild_id; + + if (d.user_ids && !Array.isArray(d.user_ids)) d.user_ids = [d.user_ids]; + check.call(this, RequestGuildMembersSchema, d); - const { guild_id, query, presences, nonce } = - d as RequestGuildMembersSchema; - let { limit, user_ids } = d as RequestGuildMembersSchema; + const { query, presences, nonce } = d as RequestGuildMembersSchema; + let { limit, user_ids, guild_id } = d as RequestGuildMembersSchema; + + guild_id = guild_id as string; + user_ids = user_ids as string[] | undefined; if ("query" in d && (!limit || Number.isNaN(limit))) throw new Error('"query" requires "limit" to be set'); if ("query" in d && user_ids) throw new Error('"query" and "user_ids" are mutually exclusive'); - if (user_ids && !Array.isArray(user_ids)) user_ids = [user_ids]; - user_ids = user_ids as string[] | undefined; // TODO: Configurable limit? if ((query || (user_ids && user_ids.length > 0)) && (!limit || limit > 100)) limit = 100; - const permissions = await getPermission( - this.user_id, - Array.isArray(guild_id) ? guild_id[0] : guild_id, - ); + const permissions = await getPermission(this.user_id, guild_id); permissions.hasThrow("VIEW_CHANNEL"); - const whereQuery: FindManyOptions["where"] = {}; - if (query) { - whereQuery.user = { - username: Like(query + "%"), - }; - } else if (user_ids && user_ids.length > 0) { - whereQuery.id = In(user_ids); - } + const memberCount = await Member.count({ + where: { + guild_id, + }, + }); const memberFind: FindManyOptions = { where: { - ...whereQuery, - guild_id: Array.isArray(guild_id) ? guild_id[0] : guild_id, + guild_id, }, relations: ["user", "roles"], }; if (limit) memberFind.take = Math.abs(Number(limit || 100)); - const members = await Member.find(memberFind); + + let members: Member[] = []; + + if (memberCount > 75000) { + // since we dont have voice channels yet, just return the connecting users member object + members = await Member.find({ + ...memberFind, + where: { + ...memberFind.where, + user: { + id: this.user_id, + }, + }, + }); + } else if (memberCount > this.large_threshold) { + // find all members who are online, have a role, have a nickname, or are in a voice channel, as well as respecting the query and user_ids + const db = getDatabase(); + if (!db) throw new Error("Database not initialized"); + const repo = db.getRepository(Member); + const q = repo + .createQueryBuilder("member") + .where("member.guild_id = :guild_id", { guild_id }) + .leftJoinAndSelect("member.roles", "role") + .leftJoinAndSelect("member.user", "user") + .leftJoinAndSelect("user.sessions", "session") + .andWhere( + "',' || member.roles || ',' NOT LIKE :everyoneRoleIdList", + { everyoneRoleIdList: "%," + guild_id + ",%" }, + ) + .andWhere("session.status != 'offline'") + .addOrderBy("user.username", "ASC") + .limit(memberFind.take); + + if (query && query != "") { + q.andWhere(`user.username ILIKE :query`, { + query: `${query}%`, + }); + } else if (user_ids) { + q.andWhere(`user.id IN (:...user_ids)`, { user_ids }); + } + + members = await q.getMany(); + } else { + if (query) { + // @ts-expect-error memberFind.where is very much defined + memberFind.where.user = { + username: Like(query + "%"), + }; + } else if (user_ids && user_ids.length > 0) { + // @ts-expect-error memberFind.where is still very much defined + memberFind.where.id = In(user_ids); + } + + members = await Member.find(memberFind); + } const baseData = { - guild_id: Array.isArray(guild_id) ? guild_id[0] : guild_id, + guild_id, nonce, }; @@ -114,7 +167,17 @@ export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) { }); } - if (notFound.length > 0) chunks[0].not_found = notFound; + if (notFound.length > 0) { + if (chunks.length == 0) + chunks.push({ + ...baseData, + members: [], + presences: presences ? [] : undefined, + chunk_index: 0, + chunk_count: 1, + }); + chunks[0].not_found = notFound; + } chunks.forEach((chunk) => { Send(this, { diff --git a/src/gateway/util/WebSocket.ts b/src/gateway/util/WebSocket.ts index 833756ff..8cfc5e08 100644 --- a/src/gateway/util/WebSocket.ts +++ b/src/gateway/util/WebSocket.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -43,4 +43,5 @@ export interface WebSocket extends WS { listen_options: ListenEventOpts; capabilities?: Capabilities; // client?: Client; + large_threshold: number; } diff --git a/src/util/schemas/RequestGuildMembersSchema.ts b/src/util/schemas/RequestGuildMembersSchema.ts index 6909ba85..9e60d26e 100644 --- a/src/util/schemas/RequestGuildMembersSchema.ts +++ b/src/util/schemas/RequestGuildMembersSchema.ts @@ -26,7 +26,7 @@ export interface RequestGuildMembersSchema { } export const RequestGuildMembersSchema = { - guild_id: [] as string | string[], + guild_id: "" as string | string[], $query: String, $limit: Number, $presences: Boolean, From db38e3e3ed7d3fa33b4092fa78de559d74a6299e Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 09:31:54 +0200 Subject: [PATCH 17/38] Send "pinned" as "true" in pins update event --- src/api/routes/channels/#channel_id/pins.ts | 23 +++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index 724ebffd..1e1da018 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -1,24 +1,23 @@ /* 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 . */ import { route } from "@spacebar/api"; import { - Channel, ChannelPinsUpdateEvent, Config, DiscordApiErrors, @@ -60,8 +59,10 @@ router.put( if (pinned_count >= maxPins) throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins); + message.pinned = true; + await Promise.all([ - Message.update({ id: message_id }, { pinned: true }), + message.save(), emitEvent({ event: "MESSAGE_UPDATE", channel_id, @@ -98,31 +99,27 @@ router.delete( async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; - const channel = await Channel.findOneOrFail({ - where: { id: channel_id }, - }); - if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); - const message = await Message.findOneOrFail({ where: { id: message_id }, }); + + if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); + message.pinned = false; await Promise.all([ message.save(), - emitEvent({ event: "MESSAGE_UPDATE", channel_id, data: message, } as MessageUpdateEvent), - emitEvent({ event: "CHANNEL_PINS_UPDATE", channel_id, data: { channel_id, - guild_id: channel.guild_id, + guild_id: message.guild_id, last_pin_timestamp: undefined, }, } as ChannelPinsUpdateEvent), From cae9d7ebed47d39a3143771241bb32148d473eee Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 10:41:45 +0200 Subject: [PATCH 18/38] widget.json channel_ordering, fix channel deletion --- src/api/routes/channels/#channel_id/index.ts | 2 +- src/api/routes/guilds/#guild_id/widget.json.ts | 13 +++++++++---- src/util/entities/Channel.ts | 16 ++++++++++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts index 291b6472..883bb266 100644 --- a/src/api/routes/channels/#channel_id/index.ts +++ b/src/api/routes/channels/#channel_id/index.ts @@ -115,7 +115,7 @@ router.delete( } await Promise.all([ - Channel.delete({ id: channel_id }), + Channel.deleteChannel(channel), emitEvent({ event: "CHANNEL_DELETE", data: channel, diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts index 39f49804..362a4a1c 100644 --- a/src/api/routes/guilds/#guild_id/widget.json.ts +++ b/src/api/routes/guilds/#guild_id/widget.json.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -47,7 +47,12 @@ router.get( async (req: Request, res: Response) => { const { guild_id } = req.params; - const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); + const guild = await Guild.findOneOrFail({ + where: { id: guild_id }, + select: { + channel_ordering: true, + } + }); if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); // Fetch existing widget invite for widget channel diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 71ccf49e..9f19cb0d 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -462,6 +462,16 @@ export class Channel extends BaseClass { await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util //TODO before deleting the channel we should check and delete other relations await Channel.delete({ id: channel.id }); + + const guild = await Guild.findOneOrFail({ + where: { id: channel.guild_id }, + select: { channel_ordering: true }, + }); + + const updatedOrdering = guild.channel_ordering.filter( + (id) => id != channel.id, + ); + await Guild.update({id: channel.guild_id}, { channel_ordering: updatedOrdering }); } static async calculatePosition( @@ -487,11 +497,13 @@ export class Channel extends BaseClass { const channels = await Promise.all( guild.channel_ordering.map((id) => - Channel.findOneOrFail({ where: { id } }), + Channel.findOne({ where: { id } }), ), ); - return channels.reduce((r, v) => { + return channels.filter(channel => channel !== null).reduce((r, v) => { + v = v as Channel; + v.position = (guild as Guild).channel_ordering.indexOf(v.id); r[v.position] = v; return r; From b7f966c8c2f88c02845417c0d54a681fcfda77d0 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 10:46:17 +0200 Subject: [PATCH 19/38] Prettier, remove manual deletion of msgs --- .../routes/guilds/#guild_id/widget.json.ts | 2 +- src/util/entities/Channel.ts | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts index 362a4a1c..12b31b88 100644 --- a/src/api/routes/guilds/#guild_id/widget.json.ts +++ b/src/api/routes/guilds/#guild_id/widget.json.ts @@ -51,7 +51,7 @@ router.get( where: { id: guild_id }, select: { channel_ordering: true, - } + }, }); if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 9f19cb0d..6538b523 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -459,8 +459,6 @@ export class Channel extends BaseClass { } static async deleteChannel(channel: Channel) { - await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util - //TODO before deleting the channel we should check and delete other relations await Channel.delete({ id: channel.id }); const guild = await Guild.findOneOrFail({ @@ -471,7 +469,10 @@ export class Channel extends BaseClass { const updatedOrdering = guild.channel_ordering.filter( (id) => id != channel.id, ); - await Guild.update({id: channel.guild_id}, { channel_ordering: updatedOrdering }); + await Guild.update( + { id: channel.guild_id }, + { channel_ordering: updatedOrdering }, + ); } static async calculatePosition( @@ -501,13 +502,15 @@ export class Channel extends BaseClass { ), ); - return channels.filter(channel => channel !== null).reduce((r, v) => { - v = v as Channel; + return channels + .filter((channel) => channel !== null) + .reduce((r, v) => { + v = v as Channel; - v.position = (guild as Guild).channel_ordering.indexOf(v.id); - r[v.position] = v; - return r; - }, [] as Array); + v.position = (guild as Guild).channel_ordering.indexOf(v.id); + r[v.position] = v; + return r; + }, [] as Array); } isDm() { From 63bd6d97c60e464a0d6ce2cea70cb4217f2c749c Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 10:50:45 +0200 Subject: [PATCH 20/38] re-add CDN TODO comment --- src/util/entities/Channel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 6538b523..4cd6c539 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -459,6 +459,7 @@ export class Channel extends BaseClass { } static async deleteChannel(channel: Channel) { + // TODO Delete attachments from the CDN for messages in the channel await Channel.delete({ id: channel.id }); const guild = await Guild.findOneOrFail({ From 5679318be0d4bc96002864f21be1b966d578a567 Mon Sep 17 00:00:00 2001 From: Cyber Date: Sun, 18 Aug 2024 11:17:19 +0200 Subject: [PATCH 21/38] feat: message pinned message --- src/api/routes/channels/#channel_id/pins.ts | 33 ++++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index 1e1da018..9a806b5a 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -1,23 +1,24 @@ /* 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 . */ import { route } from "@spacebar/api"; import { + Channel, ChannelPinsUpdateEvent, Config, DiscordApiErrors, @@ -77,6 +78,20 @@ router.put( last_pin_timestamp: undefined, }, } as ChannelPinsUpdateEvent), + + Message.create({ + type: 6, + embeds: [], + reactions: [], + channel_id: message.channel_id, + guild_id: message.guild_id, + author_id: req.user_id, + message_reference: { + message_id: message.id, + channel_id: message.channel_id, + guild_id: message.guild_id, + }, + }).save(), ]); res.sendStatus(204); @@ -99,27 +114,31 @@ router.delete( async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; + const channel = await Channel.findOneOrFail({ + where: { id: channel_id }, + }); + if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); + const message = await Message.findOneOrFail({ where: { id: message_id }, }); - - if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); - message.pinned = false; await Promise.all([ message.save(), + emitEvent({ event: "MESSAGE_UPDATE", channel_id, data: message, } as MessageUpdateEvent), + emitEvent({ event: "CHANNEL_PINS_UPDATE", channel_id, data: { channel_id, - guild_id: message.guild_id, + guild_id: channel.guild_id, last_pin_timestamp: undefined, }, } as ChannelPinsUpdateEvent), From 7853ad3acf8f79d904a808382aa4ccc6d5df78fd Mon Sep 17 00:00:00 2001 From: Cyber Date: Sun, 18 Aug 2024 11:31:15 +0200 Subject: [PATCH 22/38] fix: update the code with latest commit --- src/api/routes/channels/#channel_id/pins.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index 9a806b5a..7b2236e8 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -1,24 +1,23 @@ /* 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 . */ import { route } from "@spacebar/api"; import { - Channel, ChannelPinsUpdateEvent, Config, DiscordApiErrors, @@ -114,31 +113,27 @@ router.delete( async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; - const channel = await Channel.findOneOrFail({ - where: { id: channel_id }, - }); - if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); - const message = await Message.findOneOrFail({ where: { id: message_id }, }); + + if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); + message.pinned = false; await Promise.all([ message.save(), - emitEvent({ event: "MESSAGE_UPDATE", channel_id, data: message, } as MessageUpdateEvent), - emitEvent({ event: "CHANNEL_PINS_UPDATE", channel_id, data: { channel_id, - guild_id: channel.guild_id, + guild_id: message.guild_id, last_pin_timestamp: undefined, }, } as ChannelPinsUpdateEvent), From 917f394cc562bbf5c23b8a14ee0c8d70783bc29d Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:05:50 +0200 Subject: [PATCH 23/38] Consistent widget disabled error --- src/api/routes/guilds/#guild_id/widget.json.ts | 18 ++++++++++++------ src/api/routes/guilds/#guild_id/widget.png.ts | 10 +++++----- src/util/util/Constants.ts | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts index 39f49804..eb2dd102 100644 --- a/src/api/routes/guilds/#guild_id/widget.json.ts +++ b/src/api/routes/guilds/#guild_id/widget.json.ts @@ -1,25 +1,31 @@ /* 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 . */ import { random, route } from "@spacebar/api"; -import { Channel, Guild, Invite, Member, Permissions } from "@spacebar/util"; +import { + Channel, + DiscordApiErrors, + Guild, + Invite, + Member, + Permissions, +} from "@spacebar/util"; import { Request, Response, Router } from "express"; -import { HTTPError } from "lambert-server"; const router: Router = Router(); @@ -48,7 +54,7 @@ router.get( const { guild_id } = req.params; const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); - if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); + if (!guild.widget_enabled) throw DiscordApiErrors.EMBED_DISABLED; // Fetch existing widget invite for widget channel let invite = await Invite.findOne({ diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts index c9ba8afc..f0f94ea0 100644 --- a/src/api/routes/guilds/#guild_id/widget.png.ts +++ b/src/api/routes/guilds/#guild_id/widget.png.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -19,7 +19,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { route } from "@spacebar/api"; -import { Guild } from "@spacebar/util"; +import { DiscordApiErrors, Guild } from "@spacebar/util"; import { Request, Response, Router } from "express"; import fs from "fs"; import { HTTPError } from "lambert-server"; @@ -48,7 +48,7 @@ router.get( const { guild_id } = req.params; const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); - if (!guild.widget_enabled) throw new HTTPError("Unknown Guild", 404); + if (!guild.widget_enabled) throw DiscordApiErrors.EMBED_DISABLED; // Fetch guild information const icon = guild.icon; diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts index a6caae00..34e925e5 100644 --- a/src/util/util/Constants.ts +++ b/src/util/util/Constants.ts @@ -812,7 +812,7 @@ export const DiscordApiErrors = { "Cannot execute action on a DM channel", 50003, ), - EMBED_DISABLED: new ApiError("Guild widget disabled", 50004), + EMBED_DISABLED: new ApiError("Widget Disabled", 50004), CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError( "Cannot edit a message authored by another user", 50005, From a401f63318ededb7a20c88dc5a06a7dd73f27076 Mon Sep 17 00:00:00 2001 From: Cyber Date: Sun, 18 Aug 2024 12:08:04 +0200 Subject: [PATCH 24/38] fix: message timestamp --- src/api/routes/channels/#channel_id/pins.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index 7b2236e8..b6bb66b9 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -79,6 +79,7 @@ router.put( } as ChannelPinsUpdateEvent), Message.create({ + timestamp: new Date(), type: 6, embeds: [], reactions: [], From c505db07236e9c786b8540d6ef80604ff3003f22 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:28:24 +0200 Subject: [PATCH 25/38] Fix widget.png guild icon loading --- src/api/routes/guilds/#guild_id/widget.png.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts index c9ba8afc..271728a4 100644 --- a/src/api/routes/guilds/#guild_id/widget.png.ts +++ b/src/api/routes/guilds/#guild_id/widget.png.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -24,6 +24,7 @@ import { Request, Response, Router } from "express"; import fs from "fs"; import { HTTPError } from "lambert-server"; import path from "path"; +import { storage } from "../../../../cdn/util/Storage"; const router: Router = Router(); @@ -51,7 +52,7 @@ router.get( if (!guild.widget_enabled) throw new HTTPError("Unknown Guild", 404); // Fetch guild information - const icon = guild.icon; + const icon = "avatars/" + guild_id + "/" + guild.icon; const name = guild.name; const presence = guild.presence_count + " ONLINE"; @@ -69,8 +70,7 @@ router.get( } // Setup canvas - const { createCanvas } = require("canvas"); - const { loadImage } = require("canvas"); + const { createCanvas, loadImage } = require("canvas"); const sizeOf = require("image-size"); // TODO: Widget style templates need Spacebar branding @@ -211,8 +211,8 @@ async function drawIcon( scale: number, icon: string, ) { - const img = new (require("canvas").Image)(); - img.src = icon; + const { loadImage } = require("canvas"); + const img = await loadImage(await storage.get(icon)); // Do some canvas clipping magic! canvas.save(); From 39e3b5ad7a8eb8f33d3d2278ba70c3747affd4ee Mon Sep 17 00:00:00 2001 From: Cyber Date: Sun, 18 Aug 2024 13:32:19 +0200 Subject: [PATCH 26/38] feat: emit `MESSAGE_CREATE` --- src/api/routes/channels/#channel_id/pins.ts | 45 ++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index b6bb66b9..d43db6ec 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -23,7 +23,9 @@ import { DiscordApiErrors, emitEvent, Message, + MessageCreateEvent, MessageUpdateEvent, + User, } from "@spacebar/util"; import { Request, Response, Router } from "express"; @@ -61,6 +63,30 @@ router.put( message.pinned = true; + const author = await User.getPublicUser(req.user_id); + + const systemPinMessage = Message.create({ + timestamp: new Date(), + type: 6, + guild_id: message.guild_id, + channel_id: message.channel_id, + author, + message_reference: { + message_id: message.id, + channel_id: message.channel_id, + guild_id: message.guild_id, + }, + reactions: [], + attachments: [], + embeds: [], + sticker_items: [], + edited_timestamp: undefined, + mentions: [], + mention_channels: [], + mention_roles: [], + mention_everyone: false, + }); + await Promise.all([ message.save(), emitEvent({ @@ -77,21 +103,12 @@ router.put( last_pin_timestamp: undefined, }, } as ChannelPinsUpdateEvent), - - Message.create({ - timestamp: new Date(), - type: 6, - embeds: [], - reactions: [], + systemPinMessage.save(), + emitEvent({ + event: "MESSAGE_CREATE", channel_id: message.channel_id, - guild_id: message.guild_id, - author_id: req.user_id, - message_reference: { - message_id: message.id, - channel_id: message.channel_id, - guild_id: message.guild_id, - }, - }).save(), + data: systemPinMessage, + } as MessageCreateEvent), ]); res.sendStatus(204); From dfbbef3637af1e3777c200d0c2b05757404dd2f5 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 17:58:24 +0200 Subject: [PATCH 27/38] "engine" const value shared --- src/util/entities/Application.ts | 3 ++- src/util/entities/Attachment.ts | 3 ++- src/util/entities/AuditLog.ts | 3 ++- src/util/entities/BackupCodes.ts | 3 ++- src/util/entities/Badge.ts | 3 ++- src/util/entities/Ban.ts | 3 ++- src/util/entities/Categories.ts | 3 ++- src/util/entities/Channel.ts | 3 ++- src/util/entities/ClientRelease.ts | 3 ++- src/util/entities/Config.ts | 3 ++- src/util/entities/ConnectedAccount.ts | 3 ++- src/util/entities/ConnectionConfigEntity.ts | 3 ++- src/util/entities/EmbedCache.ts | 3 ++- src/util/entities/Emoji.ts | 3 ++- src/util/entities/Encryption.ts | 3 ++- src/util/entities/Guild.ts | 3 ++- src/util/entities/Invite.ts | 3 ++- src/util/entities/Member.ts | 3 ++- src/util/entities/Message.ts | 3 ++- src/util/entities/Migration.ts | 3 ++- src/util/entities/Note.ts | 3 ++- src/util/entities/RateLimit.ts | 3 ++- src/util/entities/ReadState.ts | 3 ++- src/util/entities/Recipient.ts | 3 ++- src/util/entities/Relationship.ts | 3 ++- src/util/entities/Role.ts | 3 ++- src/util/entities/SecurityKey.ts | 3 ++- src/util/entities/Session.ts | 3 ++- src/util/entities/Sticker.ts | 3 ++- src/util/entities/StickerPack.ts | 3 ++- src/util/entities/Team.ts | 3 ++- src/util/entities/TeamMember.ts | 3 ++- src/util/entities/Template.ts | 3 ++- src/util/entities/User.ts | 3 ++- src/util/entities/UserSettings.ts | 3 ++- src/util/entities/ValidRegistrationTokens.ts | 3 ++- src/util/entities/VoiceState.ts | 3 ++- src/util/entities/Webhook.ts | 3 ++- src/util/util/Database.ts | 9 ++++++--- 39 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index c60a6547..4ed75f27 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Team } from "./Team"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "applications", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Application extends BaseClass { @Column() diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index f5124154..e489609d 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -27,10 +27,11 @@ import { import { URL } from "url"; import { deleteFile } from "../util/cdn"; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "attachments", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Attachment extends BaseClass { @Column() diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index b8a02d75..49c836c3 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -20,6 +20,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export enum AuditLogEvents { // guild level @@ -113,7 +114,7 @@ export enum AuditLogEvents { @Entity({ name: "audit_logs", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class AuditLog extends BaseClass { @JoinColumn({ name: "target_id" }) diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index b4c6f395..9afc181a 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; import crypto from "crypto"; +import { dbEngine } from "../util/Database"; @Entity({ name: "backup_codes", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class BackupCode extends BaseClass { @JoinColumn({ name: "user_id" }) diff --git a/src/util/entities/Badge.ts b/src/util/entities/Badge.ts index e716525a..4b98006a 100644 --- a/src/util/entities/Badge.ts +++ b/src/util/entities/Badge.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "badges", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Badge extends BaseClassWithoutId { @Column({ primary: true }) diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 407569fc..ed5f47e1 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "bans", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Ban extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts index 9fa64335..990e7fdd 100644 --- a/src/util/entities/Categories.ts +++ b/src/util/entities/Categories.ts @@ -18,6 +18,7 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; +import { dbEngine } from "../util/Database"; // TODO: categories: // [{ @@ -35,7 +36,7 @@ import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; @Entity({ name: "categories", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Categories extends BaseClassWithoutId { // Not using snowflake diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 66eaa0eb..3b841c8f 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -44,6 +44,7 @@ import { Recipient } from "./Recipient"; import { PublicUserProjection, User } from "./User"; import { VoiceState } from "./VoiceState"; import { Webhook } from "./Webhook"; +import { dbEngine } from "../util/Database"; export enum ChannelType { GUILD_TEXT = 0, // a text channel within a guild @@ -71,7 +72,7 @@ export enum ChannelType { @Entity({ name: "channels", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Channel extends BaseClass { @Column() diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index f6577b2c..aa697939 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "client_release", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Release extends BaseClass { @Column() diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts index 9a3fd55e..8d725a12 100644 --- a/src/util/entities/Config.ts +++ b/src/util/entities/Config.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "config", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class ConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index f0ee62fe..0c9eb402 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -20,6 +20,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { ConnectedAccountTokenData } from "../interfaces"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export type PublicConnectedAccount = Pick< ConnectedAccount, @@ -28,7 +29,7 @@ export type PublicConnectedAccount = Pick< @Entity({ name: "connected_accounts", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class ConnectedAccount extends BaseClass { @Column() diff --git a/src/util/entities/ConnectionConfigEntity.ts b/src/util/entities/ConnectionConfigEntity.ts index 19d11627..9d4dde60 100644 --- a/src/util/entities/ConnectionConfigEntity.ts +++ b/src/util/entities/ConnectionConfigEntity.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "connection_config", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class ConnectionConfigEntity extends BaseClassWithoutId { @PrimaryIdColumn() diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index 853fa73d..8d68b0ac 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -19,10 +19,11 @@ import { BaseClass } from "./BaseClass"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; +import { dbEngine } from "../util/Database"; @Entity({ name: "embed_cache", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class EmbedCache extends BaseClass { @Column() diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index ac44b8f7..198d5faf 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "."; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; +import { dbEngine } from "../util/Database"; @Entity({ name: "emojis", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Emoji extends BaseClass { @Column() diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 3ef933fb..21e77b48 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "security_settings", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class SecuritySettings extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index 8517ca36..4e49ce9b 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -37,6 +37,7 @@ import { Template } from "./Template"; import { User } from "./User"; import { VoiceState } from "./VoiceState"; import { Webhook } from "./Webhook"; +import { dbEngine } from "../util/Database"; // TODO: application_command_count, application_command_counts: {1: 0, 2: 0, 3: 0} // TODO: guild_scheduled_events @@ -68,7 +69,7 @@ export const PublicGuildRelations = [ @Entity({ name: "guilds", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Guild extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts index 6ab75302..e1b8cabd 100644 --- a/src/util/entities/Invite.ts +++ b/src/util/entities/Invite.ts @@ -22,12 +22,13 @@ import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { Member } from "./Member"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export const PublicInviteRelation = ["inviter", "guild", "channel"]; @Entity({ name: "invites", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Invite extends BaseClassWithoutId { @PrimaryIdColumn() diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 0ca1a15b..62ab9398 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -48,6 +48,7 @@ import { Guild } from "./Guild"; import { Message } from "./Message"; import { Role } from "./Role"; import { PublicUser, User } from "./User"; +import { dbEngine } from "../util/Database"; export const MemberPrivateProjection: (keyof Member)[] = [ "id", @@ -67,7 +68,7 @@ export const MemberPrivateProjection: (keyof Member)[] = [ @Entity({ name: "members", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) @Index(["id", "guild_id"], { unique: true }) export class Member extends BaseClassWithoutId { diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index ba6b1ac7..9dc2949d 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -39,6 +39,7 @@ import { Guild } from "./Guild"; import { Webhook } from "./Webhook"; import { Sticker } from "./Sticker"; import { Attachment } from "./Attachment"; +import { dbEngine } from "../util/Database"; export enum MessageType { DEFAULT = 0, @@ -70,7 +71,7 @@ export enum MessageType { @Entity({ name: "messages", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) @Index(["channel_id", "id"], { unique: true }) export class Message extends BaseClass { diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts index cd572c03..f0ee3e07 100644 --- a/src/util/entities/Migration.ts +++ b/src/util/entities/Migration.ts @@ -23,6 +23,7 @@ import { PrimaryGeneratedColumn, BaseEntity, } from "typeorm"; +import { dbEngine } from "../util/Database"; export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith( "mongodb", @@ -32,7 +33,7 @@ export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith( @Entity({ name: "migrations", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Migration extends BaseEntity { @PrimaryIdAutoGenerated() diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index 4821d2d9..9773c802 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -19,10 +19,11 @@ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "notes", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) @Unique(["owner", "target"]) export class Note extends BaseClass { diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index f0f597e0..ba2b7931 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -18,10 +18,11 @@ import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "rate_limits", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class RateLimit extends BaseClass { @Column() // no relation as it also diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 8e555de6..9f362547 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -27,6 +27,7 @@ import { import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; // for read receipts // notification cursor and public read receipt need to be forwards-only (the former to prevent re-pinging when marked as unread, and the latter to be acceptable as a legal acknowledgement in criminal proceedings), and private read marker needs to be advance-rewind capable @@ -34,7 +35,7 @@ import { User } from "./User"; @Entity({ name: "read_states", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) @Index(["channel_id", "user_id"], { unique: true }) export class ReadState extends BaseClass { diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index fecb051f..26896220 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -18,10 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "recipients", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Recipient extends BaseClass { @Column() diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index 3aa057e7..d8dfc289 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -26,6 +26,7 @@ import { } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export enum RelationshipType { outgoing = 4, @@ -36,7 +37,7 @@ export enum RelationshipType { @Entity({ name: "relationships", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) @Index(["from_id", "to_id"], { unique: true }) export class Relationship extends BaseClass { diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index f4509827..c5df6068 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; +import { dbEngine } from "../util/Database"; @Entity({ name: "roles", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Role extends BaseClass { @Column() diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index f0b156c9..efe46c81 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -19,10 +19,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "security_keys", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class SecurityKey extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index b7657d97..5c3d5a4f 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -21,12 +21,13 @@ import { BaseClass } from "./BaseClass"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { ClientStatus, Status } from "../interfaces/Status"; import { Activity } from "../interfaces/Activity"; +import { dbEngine } from "../util/Database"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them @Entity({ name: "sessions", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Session extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index 5b17c9b8..78b6d207 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -20,6 +20,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export enum StickerType { STANDARD = 1, @@ -35,7 +36,7 @@ export enum StickerFormatType { @Entity({ name: "stickers", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Sticker extends BaseClass { @Column() diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index 5f7bf671..43d27d60 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -26,10 +26,11 @@ import { } from "typeorm"; import { Sticker } from "."; import { BaseClass } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "sticker_packs", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class StickerPack extends BaseClass { @Column() diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index 7c804260..6b3fa554 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -27,10 +27,11 @@ import { import { BaseClass } from "./BaseClass"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "teams", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Team extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index 5b82d30e..2cd04710 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -19,6 +19,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export enum TeamMemberState { INVITED = 1, @@ -27,7 +28,7 @@ export enum TeamMemberState { @Entity({ name: "team_members", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class TeamMember extends BaseClass { @Column({ type: "int" }) diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index 3d5c1764..faf6454a 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -20,10 +20,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; @Entity({ name: "templates", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Template extends BaseClass { @Column({ unique: true }) diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index 43c4aea6..0323de52 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -34,6 +34,7 @@ import { Relationship } from "./Relationship"; import { SecurityKey } from "./SecurityKey"; import { Session } from "./Session"; import { UserSettings } from "./UserSettings"; +import { dbEngine } from "../util/Database"; export enum PublicUserEnum { username, @@ -88,7 +89,7 @@ export interface UserPrivate extends Pick { @Entity({ name: "users", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class User extends BaseClass { @Column() diff --git a/src/util/entities/UserSettings.ts b/src/util/entities/UserSettings.ts index 1f27630d..cbb1cbcf 100644 --- a/src/util/entities/UserSettings.ts +++ b/src/util/entities/UserSettings.ts @@ -18,10 +18,11 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { BaseClassWithoutId } from "./BaseClass"; +import { dbEngine } from "../util/Database"; @Entity({ name: "user_settings", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class UserSettings extends BaseClassWithoutId { @PrimaryGeneratedColumn() diff --git a/src/util/entities/ValidRegistrationTokens.ts b/src/util/entities/ValidRegistrationTokens.ts index 737adfc1..70945765 100644 --- a/src/util/entities/ValidRegistrationTokens.ts +++ b/src/util/entities/ValidRegistrationTokens.ts @@ -17,10 +17,11 @@ */ import { BaseEntity, Column, Entity, PrimaryColumn } from "typeorm"; +import { dbEngine } from "../util/Database"; @Entity({ name: "valid_registration_tokens", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class ValidRegistrationToken extends BaseEntity { @PrimaryColumn() diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index de0a52d3..83a0af63 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -22,11 +22,12 @@ import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { Member } from "./Member"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex @Entity({ name: "voice_states", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class VoiceState extends BaseClass { @Column({ nullable: true }) diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index 7005bf64..473352c8 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -22,6 +22,7 @@ import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; +import { dbEngine } from "../util/Database"; export enum WebhookType { Incoming = 1, @@ -31,7 +32,7 @@ export enum WebhookType { @Entity({ name: "webhooks", - engine: "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + engine: dbEngine, }) export class Webhook extends BaseClass { @Column({ type: "int" }) diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index 3a45eea0..af0960cd 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -1,17 +1,17 @@ /* 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 . */ @@ -134,3 +134,6 @@ export { DataSourceOptions, DatabaseType, dbConnection }; export async function closeDatabase() { await dbConnection?.destroy(); } + +export const dbEngine = + "InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"; From c9a51cfd179270775f631a6139c87d271bab3a66 Mon Sep 17 00:00:00 2001 From: "Emma [it/its]@Rory&" Date: Sun, 18 Aug 2024 18:54:51 +0200 Subject: [PATCH 28/38] Fix .DS_Store ignore, add gitattributes for nix/scripts --- .gitattributes | 4 ++++ .gitignore | 4 ++-- src/webrtc/.DS_Store | Bin 6148 -> 0 bytes 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 .gitattributes delete mode 100644 src/webrtc/.DS_Store diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..5859d46d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto +*.sh -crlf +*.nix -crlf +.husky/pre-commit -crlf \ No newline at end of file diff --git a/.gitignore b/.gitignore index e62c03d6..0fcd6d2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.DS_STORE +**/.DS_STORE db/ dist/ node_modules @@ -19,4 +19,4 @@ build *.tmp tmp/ dump/ -result +result \ No newline at end of file diff --git a/src/webrtc/.DS_Store b/src/webrtc/.DS_Store deleted file mode 100644 index bfb0a4165ee92c5850a98ab16b2c02a383ec7a7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ5Iwu5S<||EYYN-px6^2asv~Y6XXKOiGU)JBM`kiI1IPo2AqgDAHb1CN(y)* z%|7qUyj}Sf9*>CV@@caWnTtpbHeE23 zRDcRlfiDH@`%vJ9P2v#fpAIZO0s!qd-VM(_O8|=nfKB2MhzLxB3Jj{|h@nA8ykuRI zI0Ob=)NjT)d9&t(qJBH##mhyTK(17P3LGjhi|yR{|26!F`Tvl_9TlJge@X$Z+Eu&6 zD`jt;yqxvg0>6QO8fv{9i??E+w_ZG%D~L3VZ+r CM Date: Sun, 18 Aug 2024 18:57:19 +0200 Subject: [PATCH 29/38] Update nix inputs --- flake.lock | Bin 1497 -> 1497 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/flake.lock b/flake.lock index 29505fc365815eccadfee3b290d344f4e9d9dcd9..42952374c13a35769b490038fb91fbf81b588142 100644 GIT binary patch delta 134 zcmV;10D1q}3)u^>Dgp*JGdDOjG?9=UD{W4l4H)1$BGdN-~ oH(_OBWHMxBWn*SHVr4KkGd3_VFl06|VKQPllfVHZvkU{x0{+t|>i_@% delta 134 zcmcb~eUp2G789GXnUST5@x%$T+9_^PL1Dq^xn9|oz6MFz0R@SXK_%|`*+ITRA^An2 zo-SDyP8Iq7C59m;ljpNYPBv#2n7p2mZE_y7uzpc$nUa-)QlhCvQnE#2in+O^nW<^2 lxut=jp{bFHiK)4vxv52}MM|mxP}n$S@&QKW%{ Date: Sun, 18 Aug 2024 18:59:09 +0200 Subject: [PATCH 30/38] update nix cache/deps/flake --- flake.lock | Bin 1497 -> 1497 bytes hashes.json | 2 +- nix-update.sh | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 29505fc365815eccadfee3b290d344f4e9d9dcd9..42952374c13a35769b490038fb91fbf81b588142 100644 GIT binary patch delta 134 zcmV;10D1q}3)u^>Dgp*JGdDOjG?9=UD{W4l4H)1$BGdN-~ oH(_OBWHMxBWn*SHVr4KkGd3_VFl06|VKQPllfVHZvkU{x0{+t|>i_@% delta 134 zcmcb~eUp2G789GXnUST5@x%$T+9_^PL1Dq^xn9|oz6MFz0R@SXK_%|`*+ITRA^An2 zo-SDyP8Iq7C59m;ljpNYPBv#2n7p2mZE_y7uzpc$nUa-)QlhCvQnE#2in+O^nW<^2 lxut=jp{bFHiK)4vxv52}MM|mxP}n$S@&QKW%{ $TMPFILE mv -- "$TMPFILE" hashes.json -nom build .# || exit $? +nom build .# --extra-experimental-features 'nix-command flakes' || exit $? git add hashes.json flake.lock flake.nix From 0cb0b9d2fe0c22d0fd575d715e1897807779679b Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 19:16:16 +0200 Subject: [PATCH 31/38] update deps so nix hashes.json is correct? --- hashes.json | 2 +- package-lock.json | Bin 361091 -> 361171 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes.json b/hashes.json index 6883eafd..ffba8089 100644 --- a/hashes.json +++ b/hashes.json @@ -1,3 +1,3 @@ { - "npmDepsHash": "sha256-q1Q7rpSzfiRvrkoDPER9wjBOzZ5Bn5B+d41MFssM7nU=" + "npmDepsHash": "sha256-9Nf/61L6pX6vrWWYPV7hy5/Cj3bWgTd6Ed8qNCQfuLs=" } diff --git a/package-lock.json b/package-lock.json index 9f77c3859ce342b6dc38a85bba1e410feab7abad..055d2a1a70a54c1f8dd2503630f9e17f9c4c50e3 100644 GIT binary patch delta 3012 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 delta 2954 zcmaKtNsQap8OK3sR!_#ucs!0X-ex9FJVRR|MNuR(iEXWvL`u{`Qj}5$mNcX`Y9XmT zE^H@A+8{{a^c{#^>iCc%IkXKhEer%rqHj)A+- zW9G_D+a54wgY9ky4k+8a9e1E0W5cW-1FzYPDa_$oJhNxgIu_02XY7X`S$yi`;&Yh8 z<3JYAn0MXw*@@>+hjm(a*Y4SuK;3=_a)B4^U)c!<0xpkaCN0y>1bK1fAoyZr!J;@Y z`uM#2zM*ZLZ8X>9t*KGOK{;IDjVI^ku?O}+OK$4*Ej!|{kPvWf^c+Ni+oQ8~(pu(E zqt9B4Vq=d(IFQCp0dagkcx~)}&4q$D$DG!~kH?m*MgL~K-~mU*k6WLTQ*#5C;!@XMM3oCnzW}Giy16FGzARuA6si^<;(b;-nuY zitb@PY(!!%)jv!c0^)W_y|A+?H?)Ld$Y_X z;Kmt;^%Oe01U8;wz>o0>kbPxpojW@+w%egSz{F{4ZFxJecZHwT7dkC)bvtaMaBRl$jBjLs~e;zSE{K$R+T(~v~e*e@2 z_^0o&-MAA#@Xu~%NUrI0NddhcZ#B{>HOaE1#QCHBPMi=TI?X8VN_(vu*4n{(z?IO9 zb|Wi$A~88AazVD0BP+FbwQEFlQHQm@8j;YXS}*y*f%+-1u_}UR19KMe&E?&x@r~$6 zsQJi4((B?Z_-kr$iF4`L7NBL%}$yNAB-%e)od|T zYv{2gnG!@93B(dXgsMv|(eg71E7TUViGsfdP(gpwCI zIt6QbFU3`KCmC;II8BraB8!JQS+|GiV*@0}=AE7%QgtHX7>vu>koNjAL@UiYxiA+m zXBaixD-m>UYfo8XO&QJ2YPGY6_RWIu<-O}yF1|hk#+g;nQm4R1a|~o#kAft##D`K6 zTWlmUlCP;bd8*!^8+uDC>uDyQuDe{i7DZShfx4Msx?Z3=y>iG&1ler1FGX6VMx<46 z`Xho^j|g}$NUBB#6?xf2|FBD|zbv2JDLlu(oh#FzR(N#%+uE-lXmilo^LxPc&av&? zQE!D(p?rc;s#3W}#w#g40js_QlVW0NW~lfFyp)vmq(9wsD_$W#B-w<&NQ!IPpc$|C z-G0``rxdji46}Vap+p*9Bw*-Z;o|cB>IXFPAh<|A32yffgWHw-x~KPwZA+W42h^q} z0-caNYmIt`r30ZB;WucF_77D#*o+T!O0Jc-VcOR&vUr1$U^uRK`W&I4$zjx6C}z7u zq_oC#hZIf<91>&23T_{o zFb^+4drkezkwu}>z6WtJ^{l!hB-|It|V{r_4JG(9_@sv1$dU39inK zfb05E^Ts*o(ydpPpd0gM@ydwP{QPO_XMdd-HJj(5Bjzu=BPRtSm(S#)Tvh1j@p7r& zi5aayo9sG=qESX@DccDVT-RS;D;C7OvtMX1$!69Mcd|^U;nh+!U+Y)7L5K7AD7_vM zLY$`g5qTSHAB%!Z79Yc-ATepM2sn_b))> zW>0{o&Cdnsp!ua_TM~NhIvH&ngJQc}3lGq&*FCI8%C2@fT8bp8E?sM;JQx-5^>LL| z*|>mo-LyB=O6F?1D^ry^GU0CIh**VBXB1IqYl8rps)3uc4>UUq{_8xknb5cPXP{T7 zwq&vbHw|9*?ltcfpp|WvkV=m)F-+YXQQ&Tf6-lL9aiP(ItJO!*TALC31ha0c8!&H?yk2e{;0 zFn|6fv}9f?K=a^zYTSHh4Vv2xHDgZ8(8+Bmnd&6-dX!NlZ>z?~VtOaC)(^Mza#5;u z!>FQW{W2L%1^8jD#`eiIFDBwqlFq4Vo*F2DN-9%}wsKKbkmxv-DpKAx8RND>XZ}Wp ler<&e23G~o1EOj3N(q|$4qSq)X0w{zY9qJc(&*ds{{t9Q#Jm6i From abf91d974f3915ff54b1b12d51f012cdcaf407d0 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 18 Aug 2024 19:43:35 +0200 Subject: [PATCH 32/38] "fix" nix dep hashes.json --- hashes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes.json b/hashes.json index ffba8089..e5996816 100644 --- a/hashes.json +++ b/hashes.json @@ -1,3 +1,3 @@ { - "npmDepsHash": "sha256-9Nf/61L6pX6vrWWYPV7hy5/Cj3bWgTd6Ed8qNCQfuLs=" + "npmDepsHash": "sha256-qcHlktC4qrhOJ6AwKbccPkr0cVrAtPhGK+xD/eV+scU=" } From e67b28a57aa6d026625dbbbe2c6dc4670b71eaf9 Mon Sep 17 00:00:00 2001 From: Scott Gould Date: Mon, 19 Aug 2024 00:05:58 -0400 Subject: [PATCH 33/38] feat (bodyparser): do proper errors --- src/api/middlewares/BodyParser.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/api/middlewares/BodyParser.ts b/src/api/middlewares/BodyParser.ts index ac8e0432..34433aeb 100644 --- a/src/api/middlewares/BodyParser.ts +++ b/src/api/middlewares/BodyParser.ts @@ -20,6 +20,19 @@ import bodyParser, { OptionsJson } from "body-parser"; import { NextFunction, Request, Response } from "express"; import { HTTPError } from "lambert-server"; +const errorMessages: { [key: string]: [string, number] } = { + "entity.too.large": ["Request body too large", 413], + "entity.parse.failed": ["Invalid JSON body", 400], + "entity.verify.failed": ["Entity verification failed", 403], + "request.aborted": ["Request aborted", 400], + "request.size.invalid": ["Request size did not match content length", 400], + "stream.encoding.set": ["Stream encoding should not be set", 500], + "stream.not.readable": ["Stream is not readable", 500], + "parameters.too.many": ["Too many parameters", 413], + "charset.unsupported": ["Unsupported charset", 415], + "encoding.unsupported": ["Unsupported content encoding", 415], +}; + export function BodyParser(opts?: OptionsJson) { const jsonParser = bodyParser.json(opts); @@ -29,8 +42,15 @@ export function BodyParser(opts?: OptionsJson) { jsonParser(req, res, (err) => { if (err) { - // TODO: different errors for body parser (request size limit, wrong body type, invalid body, ...) - return next(new HTTPError("Invalid Body", 400)); + const [message, status] = errorMessages[err.type] || [ + "Invalid Body", + 400, + ]; + const errorMessage = + message.includes("charset") || message.includes("encoding") + ? `${message} "${err.charset || err.encoding}"` + : message; + return next(new HTTPError(errorMessage, status)); } next(); }); From 2212a84ded37d7385016af3aac20e7b26f2e9673 Mon Sep 17 00:00:00 2001 From: Cyber Date: Mon, 19 Aug 2024 08:10:19 +0200 Subject: [PATCH 34/38] fix: nickmane reset by command --- src/util/entities/Member.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 3ef778ac..df97e469 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -290,7 +290,9 @@ export class Member extends BaseClassWithoutId { }, relations: ["user"], }); - member.nick = nickname; + + // @ts-expect-error Member nickname is nullable + member.nick = nickname || null; await Promise.all([ member.save(), @@ -300,7 +302,7 @@ export class Member extends BaseClassWithoutId { data: { guild_id, user: member.user, - nick: nickname, + nick: nickname || null, }, guild_id, } as GuildMemberUpdateEvent), From 339b947a8d471a42686ad58b950c9eafe10463e0 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:50:31 +0200 Subject: [PATCH 35/38] Exclude more internal schemas --- assets/openapi.json | Bin 617567 -> 608216 bytes assets/schemas.json | Bin 23504303 -> 21128458 bytes scripts/schema.js | 11 ++++++++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index 68adb4556eac99d06647d081f6de81280f125da2..ea95a1bde82e97a794d2dbe98b2ec7932b641039 100644 GIT binary patch delta 152 zcmcbAL-j_#>V|BN$@j$twr907i7-#IXW`y{tBdKmXtRcRyM{R9b`5c+Pf?Tk#HF?$ zT)-qaZTf~2Ot#Yx#51c-f7iuqvVEdCvxnLAZD!0elN;h~rZ=o+W}AM%f~jS?|6j(~ z=@U#@W=-F4kjY{Cg#s4I>2fB_?9(00nPow0+ou*V12GE_vjQ<25VLQeTEKDYHvnq{ BI*R}R delta 1789 zcmeHHU2GIp6wbYOW_F<$Dx7*Gxtx_7=t!RUxg_csa5W_;LHDG`4?%sBX-OkL; zOp#3*X*I};hLmf18XwFyDzB^|u_U}uV}gl4Dd`I_CeSw$jiDG5LQM4TY=7iIpM5Zy zlexL)-1D7#zVF<-mmBWgZOEs*}S#qI7S)peF`hSg<~0JRAzs2gUk;zo$v z#BDJ0B9hT5-u2NdS1No`lFuqx<$%|uj>9ZH3ZV(o;vG5@+57TfQ$0*S zkoL^Jf%d`@;GNL9fVV?Fs0{E@uUgEK>BoU}xXwFrHPkgBk3hQ9U&$j^Yo*uLp!{%u z7Y=jt?FN~eCez_W33{G)9t}g(k9+wKPZXG1RVpDTDO>o|Ta9qskB`DLJ7xdVTR2I1 zmsC6%35$@jcVyqwAthtX>0?f}VWc!bKjU5(LLN1&9tvgGa2?$GMkzfIWtP|)w^b*} zRNG{6ZB%0kmBt;-&{g458I31ZmS*EjcT`PRsrW35W}6{YLFzY($0-Jj7bO+)KE?ms zT8tVubXybD=wqre>SCl=)?Q!3{O_V0>-Xd%gED{L-t31Y5G`1_fJ1K5)_+Z^o}=jr zrkYf<{vrR?;o(kA&`TWy7DqPw{sN4Aj$ZYwdEw9lR6_(ie5JjbfB(b-pPk13Vkwau zB%rt*j6-Hl@{{lw19}@({k_>dv%jjq&-~X_L|nG;$96HSa6>r!uGH!|$!t@!hEIj| zOW_!`A)iClByLzx)`|i=e@lV*ZRCR?ii5IY(#!;W@j4Eahy}A)LbF($hkh%E{C83% z&jkbglOKKW>7h${2rcL#ET2Kc?hI^*Jj5f-!J-aZcgU5nwB1{S3^-ANS|Ha$nhUd` z@Ov)>`N&rtMJc<30%}%zQ+A65^)cGV)suss^$J!FsnAKuK@@{kS+3#HUKyf2xOeuZ zQv0lsJdLGUpJOpP-cI%GLB8760j0I139e0|vr5cJWczIhQ8Kv2Rn*~$(NVtAw0lES zB$hUS)@@SN3#Bra$Pwy5W=5(lOp^oCGTF0ngfI2W{MWu3*CoZ%hQ1;GBF~#pF#i*( zmIOo$X1r20O7Q76zbCv_7LA|)5yuO3x~P&srF{CLe{Zf@`}vnKR_xNpOO|B@(~3UpRE7s`p?sKJ>{(@O3!)I zVm3Tn7L#M_z`^U6OCD7&d^m~AX5s!E-iG!8S`_3z%z7HRIZy?;t)$`0ax&Ql+sesq z_+<{ChWxi=7mo%?VQLu#W-p+2SSphSp+mxFOctgH^DLOhyvaZQ0@BD= Av;Y7A diff --git a/assets/schemas.json b/assets/schemas.json index a4da25385e69d5599b0b857eb65b3dec14846f59..588914aafabafd7551c41385f82a1f59d9f060d8 100644 GIT binary patch delta 3207 zcmZvedr;I>6vyZ80~Qw81?3?N=;i|qM4<4Q0|;Uo_`p{@MnNMHG{t=23pNqg#{epf zX9?v;Dn+0!ro#z!`r+VP3^OMpOKpfUh0tnjaD@8p?o8vk?tj1E=X}q(-`~0Sckead z_*lK?`fle2cLl681!_?(SLVvfhB`(I_eEExM*UN#r7ypStZ*^1m*Qy;-0mtMt=VTP zwx_tOtsyjgGiW`tz*s!^wpW%l9}hMAoU}bXoS^ey5Mm09!3wi~h)ZFCpRvG?VS%5l zJ`3Z+ho#6U(trM1A%{llM_y)BCHXH^QnYo@>kDWiNXQw}_J$O5+1awO7dUi$Q+O%O z#`90#$mdk&vc~051P|J#DDn9H2}N>Z$Hwv9$+c9El76u26{#8xiP6Oh!m;Ga)Ky*- zZJjr*f)0cSTc=;;67R>)G;<%L5feV3i69{tbe=Ffj+3^T=SFd+OGnKwawkq;VTxv` zU|v6mc|&tV@*uc(Vqp+fNOc^sWO#BU&BVC6RIZ5_reB=Ex#%~g7jQ26HOoGv2%hfD z+$TI(7R<(An=vzk>%%FQb$}+|#k}lX4mI|!%;eV6q3qSYoFA9Y+#W7*bILlCntt=P zq)jTUyt^TTlS+IAMG%Gt1?F7a;%Sd7qx0)1M@es@p5RI49t9?jE%c>Q8}F_u%5$LZ zEPD7|ziTtBGG-38_ALb5rnu_L<~XTf*lGV9h;B}Z1>w=aTFdJS_}Z8mVAJ8b5xdUN zaZsw~N0D`Cp;;Tp9MR-ae3DyoR>L>;mhN;T#_+c0zzA9hH|{K7%gstQgAQ5{FK({r z;ilj_xhfRXUsTFzL1^r94~FW*=#Al^kFy_DkK{^9NQM3BN7qn}f3(-^pa>-7h|g!$I&(W<(XBcom16Pq6H#>H zFtNq#%FVr`Qeo$$FI>3nHK)#)IJ7$mt7taXRyQ5uewItV=eebbsr$b&&|0=_Ekkvo zn`Ybix7%Ah?CEp*E`8)ox@pzJ-8QWo8a7?+vzPSmlk5Dtw(hmU@|$*f)V;Rn_UecW zZkz3Jkhl}}x8Cux6U2(x_U(2Y<0ma0b7?Cf@$@|vZkhZe$5G;S+(vJe8p3}*#;xL- zy3PWwpVH>+fb}DOUCK#I4nG{l8Gb)7-5nZi)v@pW55{ zmR?q>fNEWck1ZCV@r7YmlmTVY{#qRC_4o)aib=&iU33w`mrhS==_K|(`&$XRDKkBx zAqXczgRy)X%xcy63t{_1rE@`>v8ylJnmMuQV@QUvttxpoaexf5@g-g z#O`Y0UUPWr5Gg8YkY2aGD2dkl|SMSLxDN>uf*TdOo|jXE>{%s?U~<;+*{7bfwtZ5yTwmE^TSFm^we0 z{W63WYVI7vfTHh{!*~bJ+9H@hRMwdbh>v7P2o__`k7pa{-yuwloWyr>N&Q>QNHdq~ zqgXEY7fUCT3gkEMB#0*}Vps`Xc((bsoN8yaq?FL0nZaB|6~wbZYDKg}Qn^7a=Y?2q ze21;%>Px4Ct5`CS$cnf?W87k$^_E2sBQgJR61z&Z;+3Tf*jkRA?O4Pb?6`ocH+7!Y zO+$=IN?|RWM7lsK#a-9a*i2f_a%Xf9lVg@J9~uz<#0)l=W5&?;*zuRyu`HSMw*LTs CeC!ke delta 106855 zcmeI*dsLKl8VB(64s+!q3m~ICUL6EyU}iMgR-nu% zO9Q8TEH8tp>*crz%WiMAM-flE$F!4qvdebasLZwOf}Sp?bameuN?q%Z{rlOkN6vwF zhIekC_dCz~{C@mq{fWoI51o8AqQk7U6jn*gTyC$gs=_ zXdQl06HmRBx|q-=VXnVtTcW>7mlfueC2BpBX`{a3?zBM5w?l+f633MdrjnOTBLW45 z>4IJ_`Fyg+MRi|?Wtbd`7G!6QyKh)JUF?3V+<&w*R{e^iqptdUL;E`YNv4H1ki}q_ z;;xh(nc?&xSuEPQ@@gOTNJFgtd{cq2IC$r7+;quVZGyg7mMUdWz+4-r-hg7A$mhS8KF?=5KAm z$4d52yO9cW>5QIb$eD&XHQaY|Ifm5GN-qtQTD45rF7M)v)y!EO+^h! zj|z!5HVvf_%A(&iUcWKfqdwc>P5&I~O_u*+n|gnLZCjaFuDo@7MUC4Pd#)%Ua|j3_llEB?p9ws^(j~?Rmh@8 zuJy=X_2H>6nEHcM84Lx{8%l-XOH^L(lf_E)XrP`5%NQyNx1@*FxGN~l7negz+81sJ zb5~ST>*tZ+QjLG}F-IfxwmKg+>APBJ(R(OqfU zI?d*Ia|+(#@fOeKEna`u>R|0aJ%ieEDEIUDLgTM*z5yu>(u_zCD^08hX^`eany$UGU#AouPFfd+P98dWOgeeHo&ByK7?QFNd5yg0 zme+6iQ=^T@YveVvyxyd)f~SRRxMt&8dA%-ug%zYhnh)voeS@FD*&?cHK2^1ndEb!Z zC_F%#5$V8*VTUlH2-18=2eLCJ2zuq(=;2P3AArpbHmR`niv79lLc}(7^Um30k8iI^q=`+V#x#TSYT=Q|Q?ChQ?W4%3)W<FLkR`4WW(NHZe+Nm$vI2uusXv=BDa zLX^R)@2x^gBc&Oo^!ShGfiz}>aGDV^YsNwwQW`1ED5YbcU(^oLAkBz$wJ2>t6Az>r zk#2vy!j6;%X-1^)|5pCJ9!)$n@z^x+Xh)^9Av7_MO7in3Q+uo?nF{tb+i&^^=p#AC z#L#rUyf{tTjn9Inf`7g}=+=*mzCPnG_zTLMWzIk2EdXx;eBJ^Ac{aOXR9-y2JPxn{ zn-T1jYegYKSvz4xI~IllY(B7+_xHNj4?xk5qMc3Au9#Cj=_o&t(u`8N_fek*6SF~@ z4{1_K>lDrRtInXHhHGxFAE~H6kNK={&B*n}7q=TJFE@Fxzt=p5Zti5;{V`_W=6G`o zP9t#|$>cP0kCPJ48ip$3AB=mF9-?<#s391u5)rlJAn2e1@8#pc6 za5?g+EhxBAa&Rd*)N{zZ`#0~vU$}!bAJX*NJzEXR#*eo=jn6ZHYd)?O)pb0o50GX= zTAkb11kxbQhcsP#XTMH4GN|nfR3C87&Gr1&=VFo9aLvv2z{|TI49D;bhF{nWzx3B3 zGhKTP=hK|q=h>0ngrl~a=sVnKKemopkJ?=L~N9Bls)d5yg0mDf6Y zAX#HlrYCg%0l0yiCGG%p&!AJwX zm=;A17V{eaDNAAC&hG;gTm8r+x&%rcnR3z*w zl3}Aid6B2PzLf zm4~A}S*XJ&DnpV|YQmEFocMR}M5(yDL$&@d zVe{$O0fBqw-YMjw;zq^IrsAf+iDA0#35UlD(@>%y&iTZ7cXq}E!4A_f&B*i*Efa+} an1*RareF9mUpNTUFwMpEcBdwM&3^#rKNp1n diff --git a/scripts/schema.js b/scripts/schema.js index ff3280ac..fd5b09f5 100644 --- a/scripts/schema.js +++ b/scripts/schema.js @@ -1,17 +1,17 @@ /* 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 . */ @@ -41,11 +41,16 @@ const Excluded = [ "EntitySchema", "ServerResponse", "Http2ServerResponse", + "ExpressResponse", "global.Express.Response", + "global.Response", "Response", "e.Response", "request.Response", "supertest.Response", + "DiagnosticsChannel.Response", + "_Response", + "ReadableStream", // TODO: Figure out how to exclude schemas from node_modules? "SomeJSONSchema", From 0d6cb6309627cecce31ed78768c8b960260125c1 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:08:25 +0200 Subject: [PATCH 36/38] Slight code cleanup & update project desc --- assets/openapi.json | Bin 608216 -> 608332 bytes scripts/openapi.js | 62 +++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index ea95a1bde82e97a794d2dbe98b2ec7932b641039..71356aaa4dce819754eef54508b1cb62bb1194d7 100644 GIT binary patch delta 236 zcmYk0Jr2S!428u%oPgC!x2mT=;v7-pwwBVkO40%oV#o}a;Q-z_0LLL!7dAiXz0cqG zS$tl_%im8FG<#EN?jWEa(F1k8#SUFmk=TK92Jjlug`7&bP;4Q#2n{O>Tti;wenhBI z#la)=%2T|}#Xo!r%38RzWD%4xgF(g%D9Hv5QZ|V=wYIi(0dw{&d21T+11nx gem3KNnuY2iNft?#NmfbLNj6EgNp?y0Z#f*#Kl{sC^8f$< delta 129 zcmX>zLG?zz>VzWyw4&5hh5UllJcZ)?(xT*4h2qqlw2b`XlEkE(RE3nx;^h3I6ousc z+=9fCOps7=Mq-JMLRo$$P;Fvfib7dtN@~7BK~7>xT7FS(vngY{DI*9o0WmWWvj8zG S5VHX>I}mehH)Z4$cLxANt|~GB diff --git a/scripts/openapi.js b/scripts/openapi.js index 8258a76c..225c5175 100644 --- a/scripts/openapi.js +++ b/scripts/openapi.js @@ -1,17 +1,17 @@ /* 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 . */ @@ -28,15 +28,13 @@ require("missing-native-js-functions"); const openapiPath = path.join(__dirname, "..", "assets", "openapi.json"); const SchemaPath = path.join(__dirname, "..", "assets", "schemas.json"); const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" })); -// const specification = JSON.parse( -// fs.readFileSync(openapiPath, { encoding: "utf8" }), -// ); + let specification = { openapi: "3.1.0", info: { title: "Spacebar Server", description: - "Spacebar is a free open source selfhostable discord compatible chat, voice and video platform", + "Spacebar is a Discord.com server implementation and extension, with the goal of complete feature parity with Discord.com, all while adding some additional goodies, security, privacy, and configuration options.", license: { name: "AGPLV3", url: "https://www.gnu.org/licenses/agpl-3.0.en.html", @@ -68,8 +66,9 @@ let specification = { paths: {}, }; +const schemaRegEx = new RegExp(/^[\w.]+$/); function combineSchemas(schemas) { - var definitions = {}; + let definitions = {}; for (const name in schemas) { definitions = { @@ -84,9 +83,8 @@ function combineSchemas(schemas) { } for (const key in definitions) { - const reg = new RegExp(/^[a-zA-Z0-9.\-_]+$/, "gm"); - if (!reg.test(key)) { - console.error(`Invalid schema name: ${key} (${reg.test(key)})`); + if (!schemaRegEx.test(key)) { + console.error(`Invalid schema name: ${key}`); continue; } specification.components = specification.components || {}; @@ -157,32 +155,30 @@ function apiRoutes() { }, }, }, - }.merge(obj.requestBody); + }; } if (route.responses) { - for (const [k, v] of Object.entries(route.responses)) { - let schema = { - $ref: `#/components/schemas/${v.body}`, - }; + obj.responses = {}; - obj.responses = { - [k]: { - ...(v.body - ? { - description: - obj?.responses?.[k]?.description || "", - content: { - "application/json": { - schema: schema, - }, - }, - } - : { - description: "No description available", - }), - }, - }.merge(obj.responses); + for (const [k, v] of Object.entries(route.responses)) { + if (v.body) + obj.responses[k] = { + description: obj?.responses?.[k]?.description || "", + content: { + "application/json": { + schema: { + $ref: `#/components/schemas/${v.body}`, + }, + }, + }, + }; + else + obj.responses[k] = { + description: + obj?.responses?.[k]?.description || + "No description available", + }; } } else { obj.responses = { From d1fe2914180c4d03537f8bd0b77190366296c7e0 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:19:33 +0200 Subject: [PATCH 37/38] Highlight sb-only routes --- assets/openapi.json | Bin 608332 -> 610698 bytes scripts/openapi.js | 26 +++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index 71356aaa4dce819754eef54508b1cb62bb1194d7..fcfc9aac7ee51cb41c7e0e17e1fdef583a812316 100644 GIT binary patch delta 978 zcmX>zLA7hKYC{WS3sVbo3(FSPC*{)xmaz!4SLh}srlhA%Z!~8$o&2Gdjo(T^DYzgp zIW;M{Nhc)EfZtIBqc3RYo8Y8Yf+$vQ=j z8U}rz&ML@Bp+Nh{DHteVs?sD1q^ zRv=~rV)pIpS8;HAQWjLx3-mZux8MKFp~^}PgEW6~gz!_tphX;#8_3f@2g-HW`r0Nu+jG0ZFAgu(tqPo# g{L_I<&FvKeoB?(a;}`jJ3V|(^;NVgKf?BRx0O-Fpa{vGU diff --git a/scripts/openapi.js b/scripts/openapi.js index 225c5175..62623800 100644 --- a/scripts/openapi.js +++ b/scripts/openapi.js @@ -114,7 +114,7 @@ function getTag(key) { return key.match(/\/([\w-]+)/)[1]; } -function apiRoutes() { +function apiRoutes(missingRoutes) { const routes = getRouteDescriptions(); // populate tags @@ -214,6 +214,15 @@ function apiRoutes() { obj.tags = [...(obj.tags || []), getTag(p)].unique(); + if (missingRoutes.additional.includes(path.replace(/\/$/, ""))) { + obj["x-badges"] = [ + { + label: "Spacebar-only", + color: "red", + }, + ]; + } + specification.paths[path] = Object.assign( specification.paths[path] || {}, { @@ -223,10 +232,21 @@ function apiRoutes() { }); } -function main() { +async function main() { console.log("Generating OpenAPI Specification..."); + + const routesRes = await fetch( + "https://github.com/spacebarchat/missing-routes/raw/main/missing.json", + { + headers: { + Accept: "application/json", + }, + }, + ); + const missingRoutes = await routesRes.json(); + combineSchemas(schemas); - apiRoutes(); + apiRoutes(missingRoutes); fs.writeFileSync( openapiPath, From 98c1b93133e3710b4f9afff0dfeffbc3f5cd6a5a Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:50:42 +0200 Subject: [PATCH 38/38] Send 204 regardless of user existance --- src/api/routes/auth/forgot.ts | 66 +++++++---------------------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/src/api/routes/auth/forgot.ts b/src/api/routes/auth/forgot.ts index 6fa86021..d5a8a2f4 100644 --- a/src/api/routes/auth/forgot.ts +++ b/src/api/routes/auth/forgot.ts @@ -1,31 +1,24 @@ /* 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 . */ import { getIpAdress, route, verifyCaptcha } from "@spacebar/api"; -import { - Config, - Email, - FieldErrors, - ForgotPasswordSchema, - User, -} from "@spacebar/util"; +import { Config, Email, ForgotPasswordSchema, User } from "@spacebar/util"; import { Request, Response, Router } from "express"; -import { HTTPError } from "lambert-server"; const router = Router(); router.post( @@ -37,9 +30,6 @@ router.post( 400: { body: "APIErrorOrCaptchaResponse", }, - 500: { - body: "APIErrorResponse", - }, }, }), async (req: Request, res: Response) => { @@ -71,50 +61,20 @@ router.post( } } - const user = await User.findOneOrFail({ + res.sendStatus(204); + + const user = await User.findOne({ where: [{ phone: login }, { email: login }], - select: ["username", "id", "disabled", "deleted", "email"], - relations: ["security_keys"], - }).catch(() => { - throw FieldErrors({ - login: { - message: req.t("auth:password_reset.EMAIL_DOES_NOT_EXIST"), - code: "EMAIL_DOES_NOT_EXIST", - }, - }); - }); + select: ["username", "id", "email"], + }).catch(() => {}); - if (!user.email) - throw FieldErrors({ - login: { - message: - "This account does not have an email address associated with it.", - code: "NO_EMAIL", - }, - }); - - if (user.deleted) - return res.status(400).json({ - message: "This account is scheduled for deletion.", - code: 20011, - }); - - if (user.disabled) - return res.status(400).json({ - message: req.t("auth:login.ACCOUNT_DISABLED"), - code: 20013, - }); - - return await Email.sendResetPassword(user, user.email) - .then(() => { - return res.sendStatus(204); - }) - .catch((e) => { + if (user && user.email) { + Email.sendResetPassword(user, user.email).catch((e) => { console.error( - `Failed to send password reset email to ${user.username}#${user.discriminator}: ${e}`, + `Failed to send password reset email to ${user.username}#${user.discriminator} (${user.id}): ${e}`, ); - throw new HTTPError("Failed to send password reset email", 500); }); + } }, );