diff --git a/src/Server.ts b/src/Server.ts
index 0c92e1b7..19a0fc5f 100644
--- a/src/Server.ts
+++ b/src/Server.ts
@@ -10,6 +10,8 @@ import i18nextMiddleware, { I18next } from "i18next-http-middleware";
import i18nextBackend from "i18next-node-fs-backend";
import { ErrorHandler } from "./middlewares/ErrorHandler";
import { BodyParser } from "./middlewares/BodyParser";
+import { Router } from "express";
+import fetch from "node-fetch";
export interface DiscordServerOptions extends ServerOptions {}
@@ -69,15 +71,52 @@ export class DiscordServer extends Server {
});
this.app.use(i18nextMiddleware.handle(i18next, {}));
+ const app = this.app;
+ const prefix = Router();
+ // @ts-ignore
+ this.app = prefix;
+
this.routes = await this.registerRoutes(__dirname + "/routes/");
+ app.use("/api/v8", prefix);
+ this.app = app;
this.app.use(ErrorHandler);
const indexHTML = await fs.readFile(__dirname + "/../client_test/index.html");
- // this.app.get("*", (req, res) => {
- // res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
- // res.set("content-type", "text/html");
- // res.send(indexHTML);
- // });
+ this.app.get("/assets/:file", async (req, res) => {
+ delete req.headers.host;
+ const response = await fetch(`https://discord.com/assets/${req.params.file}`, {
+ // @ts-ignore
+ headers: {
+ ...req.headers,
+ },
+ });
+ const buffer = await response.buffer();
+
+ response.headers.forEach((value, name) => {
+ if (
+ [
+ "content-length",
+ "content-security-policy",
+ "strict-transport-security",
+ "set-cookie",
+ "transfer-encoding",
+ "expect-ct",
+ "access-control-allow-origin",
+ "content-encoding",
+ ].includes(name.toLowerCase())
+ ) {
+ return;
+ }
+ res.set(name, value);
+ });
+
+ return res.send(buffer);
+ });
+ this.app.get("*", (req, res) => {
+ res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
+ res.set("content-type", "text/html");
+ res.send(indexHTML);
+ });
return super.start();
}
}
diff --git a/src/middlewares/Authentication.ts b/src/middlewares/Authentication.ts
index 65d5a2cf..30445815 100644
--- a/src/middlewares/Authentication.ts
+++ b/src/middlewares/Authentication.ts
@@ -2,7 +2,13 @@ import { NextFunction, Request, Response } from "express";
import { HTTPError } from "lambert-server";
import { checkToken } from "fosscord-server-util";
-export const NO_AUTHORIZATION_ROUTES = ["/api/v8/auth/login", "/api/v8/auth/register", "/api/v8/webhooks/"];
+export const NO_AUTHORIZATION_ROUTES = [
+ "/api/v8/auth/login",
+ "/api/v8/auth/register",
+ "/api/v8/webhooks/",
+ "/api/v8/gateway",
+ "/api/v8/experiments",
+];
declare global {
namespace Express {
@@ -14,6 +20,8 @@ declare global {
}
export async function Authentication(req: Request, res: Response, next: NextFunction) {
+ if (!req.url.startsWith("/api")) return next();
+ if (req.url.startsWith("/api/v8/invites") && req.method === "GET") return next();
if (NO_AUTHORIZATION_ROUTES.some((x) => req.url.startsWith(x))) return next();
if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401));
// TODO: check if user is banned/token expired
@@ -22,7 +30,7 @@ export async function Authentication(req: Request, res: Response, next: NextFunc
const decoded: any = await checkToken(req.headers.authorization);
req.token = decoded;
- req.user_id = BigInt(decoded.id);
+ req.user_id = decoded.id;
return next();
} catch (error) {
return next(new HTTPError(error.toString(), 400));
diff --git a/src/middlewares/ErrorHandler.ts b/src/middlewares/ErrorHandler.ts
index 52fa949c..25a68865 100644
--- a/src/middlewares/ErrorHandler.ts
+++ b/src/middlewares/ErrorHandler.ts
@@ -16,14 +16,15 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne
errors = error.errors;
} else {
console.error(error);
- if (req.server.options.production) {
+ if (req.server?.options?.production) {
message = "Internal Server Error";
}
code = httpcode = 500;
}
res.status(httpcode).json({ code: code, message, errors });
- return next();
+
+ return;
} catch (error) {
console.error(error);
return res.status(500).json({ code: 500, message: "Internal Server Error" });
diff --git a/src/routes/api/v8/channels/#channel_id/invites.ts b/src/routes/api/v8/channels/#channel_id/invites.ts
deleted file mode 100644
index e3f2b77e..00000000
--- a/src/routes/api/v8/channels/#channel_id/invites.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Router, Request, Response } from "express";
-import { HTTPError } from "lambert-server";
-
-import { check } from "@util/instanceOf";
-import { random } from "@util/RandomInviteID";
-import { emitEvent } from "@util/Event";
-
-import { InviteCreateSchema } from "@schema/Invite";
-
-import { getPermission, ChannelModel, InviteModel, InviteCreateEvent } from "fosscord-server-util";
-
-const router: Router = Router();
-
-router.post("/", check(InviteCreateSchema), async (req: Request, res: Response) => {
- const usID = req.user_id;
- const chID = BigInt(req.params.channel_id);
- const channel = await ChannelModel.findOne({ id: chID }).exec();
-
- if (!channel || !channel.guild_id) {
- throw new HTTPError("This channel doesn't exist", 404);
- }
- const { guild_id: guID } = channel;
-
- const permission = await getPermission(usID, guID);
-
- if (!permission.has("CREATE_INSTANT_INVITE")) {
- throw new HTTPError("You aren't authorised to access this endpoint", 401);
- }
-
- const invite = {
- code: random(),
- temporary: req.body.temporary,
- uses: 0,
- max_uses: req.body.max_uses,
- max_age: req.body.max_age,
- created_at: new Date(),
- guild_id: guID,
- channel_id: chID,
- inviter_id: usID,
- };
-
- await new InviteModel(invite).save();
-
- await emitEvent({ event: "INVITE_CREATE", data: invite } as InviteCreateEvent);
- res.status(201).send(invite);
-});
-
-export default router;
diff --git a/src/routes/api/v8/invites/index.ts b/src/routes/api/v8/invites/index.ts
deleted file mode 100644
index 9a4e81fa..00000000
--- a/src/routes/api/v8/invites/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { Router } from "express";
-const router: Router = Router();
-
-export default router;
diff --git a/src/routes/assets/index.ts b/src/routes/assets/index.ts
deleted file mode 100644
index df30d13e..00000000
--- a/src/routes/assets/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * * patch to redirect requests from cloned client
- * (../../client/index.html)
- */
-import { Router } from "express";
-import fetch, { Response } from "node-fetch";
-
-const router: Router = Router();
-const cache = new Map<string, Response>();
-const assetEndpoint = "https://discord.com/assets/";
-
-export async function getCache(key: string): Promise<Response> {
- let cachedRessource = cache.get(key);
-
- if (!cachedRessource) {
- const res = await fetch(assetEndpoint + key);
- // @ts-ignore
- res.bufferResponse = await res.buffer();
- cache.set(key, res);
- cachedRessource = res;
- }
-
- return cachedRessource;
-}
-
-router.get("/:hash", async (req, res) => {
- res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
- const cache = await getCache(req.params.hash);
- res.set("content-type", <string>cache.headers.get("content-type"));
- // @ts-ignore
- res.send(cache.bufferResponse);
-});
-
-export default router;
diff --git a/src/routes/api/v8/auth/login.ts b/src/routes/auth/login.ts
index 3f924e7c..cc2b6202 100644
--- a/src/routes/api/v8/auth/login.ts
+++ b/src/routes/auth/login.ts
@@ -1,9 +1,9 @@
import { Request, Response, Router } from "express";
-import { check, FieldErrors, Length } from "../../../../util/instanceOf";
+import { check, FieldErrors, Length } from "../../util/instanceOf";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { User, UserModel } from "fosscord-server-util";
-import Config from "../../../../util/Config";
+import Config from "../../util/Config";
import { adjustEmail } from "./register";
const router: Router = Router();
@@ -25,12 +25,11 @@ router.post(
const query: any[] = [{ phone: login }];
if (email) query.push({ email });
- // * MongoDB Specific query for user with same email or phone number
const user = await UserModel.findOne(
{
$or: query,
},
- `hash id user_settings.locale user_settings.theme`
+ `user_data.hash id user_settings.locale user_settings.theme`
).exec();
if (!user) {
@@ -40,7 +39,7 @@ router.post(
}
// the salt is saved in the password refer to bcrypt docs
- const same_password = await bcrypt.compare(password, user.hash);
+ const same_password = await bcrypt.compare(password, user.user_data.hash);
if (!same_password) {
throw FieldErrors({
password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" },
@@ -57,13 +56,13 @@ router.post(
}
);
-export async function generateToken(id: bigint) {
+export async function generateToken(id: string) {
const iat = Math.floor(Date.now() / 1000);
const algorithm = "HS256";
return new Promise((res, rej) => {
jwt.sign(
- { id: `${id}`, iat },
+ { id: id, iat },
Config.get().security.jwtSecret,
{
algorithm,
@@ -80,7 +79,6 @@ export async function generateToken(id: bigint) {
* POST /auth/login
* @argument { login: "email@gmail.com", password: "cleartextpassword", undelete: false, captcha_key: null, login_source: null, gift_code_sku_id: null, }
-
* MFA required:
* @returns {"token": null, "mfa": true, "sms": true, "ticket": "SOME TICKET JWT TOKEN"}
diff --git a/src/routes/api/v8/auth/register.ts b/src/routes/auth/register.ts
index 99df82f1..5501203d 100644
--- a/src/routes/api/v8/auth/register.ts
+++ b/src/routes/auth/register.ts
@@ -1,8 +1,8 @@
import { Request, Response, Router } from "express";
-import Config from "../../../../util/Config";
+import Config from "../../util/Config";
import { trimSpecial, User, Snowflake, UserModel } from "fosscord-server-util";
import bcrypt from "bcrypt";
-import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../../../util/instanceOf";
+import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf";
import "missing-native-js-functions";
import { generateToken } from "./login";
@@ -52,7 +52,7 @@ router.post(
let discriminator = "";
// get register Config
- const { register } = Config.get();
+ const { register, security } = Config.get();
// check if registration is allowed
if (!register.allowNewRegistration) {
@@ -129,9 +129,9 @@ router.post(
}
}
- if (register.requireCaptcha) {
+ if (register.requireCaptcha && security.captcha.enabled) {
if (!captcha_key) {
- const { sitekey, service } = Config.get().security.captcha;
+ const { sitekey, service } = security.captcha;
return res.status(400).json({
captcha_key: ["captcha-required"],
captcha_sitekey: sitekey,
@@ -165,9 +165,10 @@ router.post(
});
}
- // constructing final user object
- // TODO fix:
- // @ts-ignore
+ // TODO: save date_of_birth
+ // appearently discord doesn't save the date of birth and just calculate if nsfw is allowed
+ // if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
+
const user: User = {
id: Snowflake.generate(),
created_at: new Date(),
@@ -176,13 +177,34 @@ router.post(
avatar: null,
bot: false,
system: false,
+ desktop: false,
+ mobile: false,
+ premium: false,
+ premium_type: 0,
+ phone: undefined,
mfa_enabled: false,
verified: false,
+ presence: {
+ activities: [],
+ client_status: {
+ desktop: undefined,
+ mobile: undefined,
+ web: undefined,
+ },
+ status: "offline",
+ },
email: adjusted_email,
+ nsfw_allowed: true, // TODO: depending on age
+ public_flags: 0n,
flags: 0n, // TODO: generate default flags
- hash: adjusted_password,
guilds: [],
- valid_tokens_since: new Date(),
+ user_data: {
+ hash: adjusted_password,
+ valid_tokens_since: new Date(),
+ relationships: [],
+ connected_accounts: [],
+ fingerprints: [],
+ },
user_settings: {
afk_timeout: 300,
allow_accessibility_detection: true,
@@ -225,7 +247,7 @@ router.post(
};
// insert user into database
- await new UserModel(user).save({});
+ await new UserModel(user).save();
return res.json({ token: await generateToken(user.id) });
}
diff --git a/src/routes/api/v8/channels/#channel_id/followers.ts b/src/routes/channels/#channel_id/followers.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/followers.ts
+++ b/src/routes/channels/#channel_id/followers.ts
diff --git a/src/routes/api/v8/channels/#channel_id/index.ts b/src/routes/channels/#channel_id/index.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/index.ts
+++ b/src/routes/channels/#channel_id/index.ts
diff --git a/src/routes/channels/#channel_id/invites.ts b/src/routes/channels/#channel_id/invites.ts
new file mode 100644
index 00000000..da802800
--- /dev/null
+++ b/src/routes/channels/#channel_id/invites.ts
@@ -0,0 +1,68 @@
+import { Router, Request, Response } from "express";
+import { HTTPError } from "lambert-server";
+
+import { check } from "../../../util/instanceOf";
+import { random } from "../../../util/RandomInviteID";
+import { emitEvent } from "../../../util/Event";
+
+import { InviteCreateSchema } from "../../../schema/Invite";
+
+import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject } from "fosscord-server-util";
+
+const router: Router = Router();
+
+router.post("/", check(InviteCreateSchema), async (req: Request, res: Response) => {
+ const { user_id } = req;
+ const { channel_id } = req.params;
+ const channel = await ChannelModel.findOne({ id: channel_id }).exec();
+
+ if (!channel || !channel.guild_id) {
+ throw new HTTPError("This channel doesn't exist", 404);
+ }
+ const { guild_id } = channel;
+
+ const permission = await getPermission(user_id, guild_id);
+
+ if (!permission.has("CREATE_INSTANT_INVITE")) {
+ throw new HTTPError("You aren't authorised to access this endpoint", 401);
+ }
+
+ const invite = {
+ code: random(),
+ temporary: req.body.temporary,
+ uses: 0,
+ max_uses: req.body.max_uses,
+ max_age: req.body.max_age,
+ created_at: new Date(),
+ guild_id,
+ channel_id: channel_id,
+ inviter_id: user_id,
+ };
+
+ await new InviteModel(invite).save();
+
+ await emitEvent({ event: "INVITE_CREATE", data: invite, guild_id } as InviteCreateEvent);
+ res.status(201).send(invite);
+});
+
+router.get("/", async (req: Request, res: Response) => {
+ const { user_id } = req;
+ const { channel_id } = req.params;
+ const channel = await ChannelModel.findOne({ id: channel_id }).exec();
+
+ if (!channel || !channel.guild_id) {
+ throw new HTTPError("This channel doesn't exist", 404);
+ }
+ const { guild_id } = channel;
+ const permission = await getPermission(user_id, guild_id);
+
+ if (!permission.has("MANAGE_CHANNELS")) {
+ throw new HTTPError("You aren't authorised to access this endpoint", 401);
+ }
+
+ const invites = await InviteModel.find({ guild_id }).exec();
+
+ res.status(200).send(toObject(invites));
+});
+
+export default router;
diff --git a/src/routes/api/v8/channels/#channel_id/messages/bulk-delete.ts b/src/routes/channels/#channel_id/messages/bulk-delete.ts
index dc7d5f66..89e9d720 100644
--- a/src/routes/api/v8/channels/#channel_id/messages/bulk-delete.ts
+++ b/src/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -1,9 +1,9 @@
import { Router } from "express";
import { ChannelModel, getPermission, MessageDeleteBulkEvent, MessageModel } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import Config from "@util/Config";
-import { emitEvent } from "@util/Event";
-import { check } from "@util/instanceOf";
+import Config from "../../../../util/Config";
+import { emitEvent } from "../../../../util/Event";
+import { check } from "../../../../util/instanceOf";
const router: Router = Router();
@@ -12,8 +12,8 @@ export default router;
// TODO: should users be able to bulk delete messages or only bots?
// TODO: should this request fail, if you provide messages older than 14 days/invalid ids?
// https://discord.com/developers/docs/resources/channel#bulk-delete-messages
-router.post("/", check({ messages: [BigInt] }), async (req, res) => {
- const channel_id = BigInt(req.params.channel_id);
+router.post("/", check({ messages: [String] }), async (req, res) => {
+ const channel_id = req.params.channel_id
const channel = await ChannelModel.findOne({ id: channel_id }, { permission_overwrites: true, guild_id: true }).exec();
if (!channel?.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
@@ -22,7 +22,7 @@ router.post("/", check({ messages: [BigInt] }), async (req, res) => {
const { maxBulkDelete } = Config.get().limits.message;
- const { messages } = req.body as { messages: bigint[] };
+ const { messages } = req.body as { messages: string[] };
if (messages.length < 2) throw new HTTPError("You must at least specify 2 messages to bulk delete");
if (messages.length > maxBulkDelete) throw new HTTPError(`You cannot delete more than ${maxBulkDelete} messages`);
diff --git a/src/routes/api/v8/channels/#channel_id/messages/index.ts b/src/routes/channels/#channel_id/messages/index.ts
index b2eb8ef4..4978b98a 100644
--- a/src/routes/api/v8/channels/#channel_id/messages/index.ts
+++ b/src/routes/channels/#channel_id/messages/index.ts
@@ -1,11 +1,23 @@
import { Router } from "express";
-import { ChannelModel, ChannelType, getPermission, Message, MessageCreateEvent, MessageModel, Snowflake } from "fosscord-server-util";
+import {
+ ChannelModel,
+ ChannelType,
+ getPermission,
+ Message,
+ MessageCreateEvent,
+ MessageDocument,
+ MessageModel,
+ Snowflake,
+ toObject,
+} from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { MessageCreateSchema } from "@schema/Message";
-import { check, instanceOf, Length } from "@util/instanceOf";
-import { PublicUserProjection } from "@util/User";
+import { MessageCreateSchema } from "../../../../schema/Message";
+import { check, instanceOf, Length } from "../../../../util/instanceOf";
+import { PublicUserProjection } from "../../../../util/User";
import multer from "multer";
-import { emitEvent } from "@util/Event";
+import { emitEvent } from "../../../../util/Event";
+import { Query } from "mongoose";
+import { PublicMemberProjection } from "../../../../util/Member";
const router: Router = Router();
export default router;
@@ -27,23 +39,23 @@ function isTextChannel(type: ChannelType): boolean {
// https://discord.com/developers/docs/resources/channel#create-message
// get messages
router.get("/", async (req, res) => {
- const channel_id = BigInt(req.params.channel_id);
+ const channel_id = req.params.channel_id;
const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec();
if (!channel) throw new HTTPError("Channel not found", 404);
isTextChannel(channel.type);
try {
- instanceOf({ $around: BigInt, $after: BigInt, $before: BigInt, $limit: new Length(Number, 1, 100) }, req.query, {
+ instanceOf({ $around: String, $after: String, $before: String, $limit: new Length(Number, 1, 100) }, req.query, {
path: "query",
req,
});
} catch (error) {
return res.status(400).json({ code: 50035, message: "Invalid Query", success: false, errors: error });
}
- var { around, after, before, limit }: { around?: bigint; after?: bigint; before?: bigint; limit?: number } = req.query;
+ var { around, after, before, limit }: { around?: string; after?: string; before?: string; limit?: number } = req.query;
if (!limit) limit = 50;
- var halfLimit = BigInt(Math.floor(limit / 2));
+ var halfLimit = Math.floor(limit / 2);
if ([ChannelType.GUILD_VOICE, ChannelType.GUILD_CATEGORY, ChannelType.GUILD_STORE].includes(channel.type))
throw new HTTPError("Not a text channel");
@@ -57,24 +69,21 @@ router.get("/", async (req, res) => {
if (!channel.recipients.includes(req.user_id)) throw new HTTPError("You don't have permission to view this channel", 401);
}
- var query: any;
+ var query: Query<MessageDocument[], MessageDocument, {}>;
if (after) query = MessageModel.find({ channel_id, id: { $gt: after } });
else if (before) query = MessageModel.find({ channel_id, id: { $lt: before } });
- else if (around) query = MessageModel.find({ channel_id, id: { $gt: around - halfLimit, $lt: around + halfLimit } });
+ else if (around)
+ query = MessageModel.find({
+ channel_id,
+ id: { $gt: (BigInt(around) - BigInt(halfLimit)).toString(), $lt: (BigInt(around) + BigInt(halfLimit)).toString() },
+ });
else {
query = MessageModel.find({ channel_id }).sort({ id: -1 });
}
- const messages = await query
- .limit(limit)
- .populate({ path: "author", select: PublicUserProjection })
- .populate({ path: "mentions", select: PublicUserProjection })
- .populate({ path: "mention_channels", select: { id: true, guild_id: true, type: true, name: true } })
- .populate("mention_roles")
- // .populate({ path: "member", select: PublicMemberProjection })
- .exec();
+ const messages = await query.limit(limit).exec();
- return res.json(messages);
+ return res.json(toObject(messages));
});
// TODO: config max upload size
@@ -88,11 +97,12 @@ const messageUpload = multer({ limits: { fieldSize: 1024 * 1024 * 1024 * 50 } })
// TODO: trim and replace message content and every embed field
// Send message
router.post("/", check(MessageCreateSchema), async (req, res) => {
- const channel_id = BigInt(req.params.channel_id);
+ const channel_id = req.params.channel_id;
const body = req.body as MessageCreateSchema;
const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec();
if (!channel) throw new HTTPError("Channel not found", 404);
+ // TODO: are tts messages allowed in dm channels? should permission be checked?
if (channel.guild_id) {
const permissions = await getPermission(req.user_id, channel.guild_id, channel_id, { channel });
@@ -108,24 +118,36 @@ router.post("/", check(MessageCreateSchema), async (req, res) => {
if (body.message_reference) {
if (body.message_reference.channel_id !== channel_id) throw new HTTPError("You can only reference messages from this channel");
- // TODO: should it be checked if the message exists?
+ // TODO: should be checked if the referenced message exists?
}
const embeds = [];
if (body.embed) embeds.push(body.embed);
+ // TODO: check and put all in body in it
const message: Message = {
id: Snowflake.generate(),
channel_id,
guild_id: channel.guild_id,
author_id: req.user_id,
- content: req.body,
+ content: body.content,
timestamp: new Date(),
- embeds,
+ mention_channels_ids: [],
+ mention_role_ids: [],
+ mention_user_ids: [],
attachments: [],
+ embeds: [],
+ reactions: [],
+ type: 0,
+ tts: body.tts,
+ nonce: body.nonce,
+ pinned: false,
};
- await new MessageModel(message).save();
+ const doc = await new MessageModel(message).populate({ path: "member", select: PublicMemberProjection }).save();
+ const data = toObject(doc);
+
+ await emitEvent({ event: "MESSAGE_CREATE", channel_id, data, guild_id: channel.guild_id } as MessageCreateEvent);
- await emitEvent({ event: "MESSAGE_CREATE", channel_id, data: {} } as MessageCreateEvent);
+ return res.send(data);
});
diff --git a/src/routes/api/v8/channels/#channel_id/permissions.ts b/src/routes/channels/#channel_id/permissions.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/permissions.ts
+++ b/src/routes/channels/#channel_id/permissions.ts
diff --git a/src/routes/api/v8/channels/#channel_id/pins.ts b/src/routes/channels/#channel_id/pins.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/pins.ts
+++ b/src/routes/channels/#channel_id/pins.ts
diff --git a/src/routes/api/v8/channels/#channel_id/recipients.ts b/src/routes/channels/#channel_id/recipients.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/recipients.ts
+++ b/src/routes/channels/#channel_id/recipients.ts
diff --git a/src/routes/api/v8/channels/#channel_id/typing.ts b/src/routes/channels/#channel_id/typing.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/typing.ts
+++ b/src/routes/channels/#channel_id/typing.ts
diff --git a/src/routes/api/v8/channels/#channel_id/webhooks.ts b/src/routes/channels/#channel_id/webhooks.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/channels/#channel_id/webhooks.ts
+++ b/src/routes/channels/#channel_id/webhooks.ts
diff --git a/src/routes/experiments.ts b/src/routes/experiments.ts
new file mode 100644
index 00000000..6bca49c5
--- /dev/null
+++ b/src/routes/experiments.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.get("/", (req, res) => {
+ // TODO:
+ res.send({ fingerprint: "", assignments: [] });
+});
+
+export default router;
diff --git a/src/routes/gateway.ts b/src/routes/gateway.ts
new file mode 100644
index 00000000..53302f12
--- /dev/null
+++ b/src/routes/gateway.ts
@@ -0,0 +1,9 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.get("/", (req, res) => {
+ res.send({ url: "ws://localhost:8080" });
+});
+
+export default router;
diff --git a/src/routes/api/v8/guilds/#id/bans.ts b/src/routes/guilds/#guild_id/bans.ts
index 9fbcf01c..3de80a32 100644
--- a/src/routes/api/v8/guilds/#id/bans.ts
+++ b/src/routes/guilds/#guild_id/bans.ts
@@ -1,28 +1,28 @@
import { Request, Response, Router } from "express";
-import { BanModel, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel } from "fosscord-server-util";
+import { BanModel, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { getIpAdress } from "@middlewares/GlobalRateLimit";
-import { BanCreateSchema } from "@schema/Ban";
-import { emitEvent } from "@util/Event";
-import { check } from "@util/instanceOf";
-import { removeMember } from "@util/Member";
-import { getPublicUser } from "@util/User";
+import { getIpAdress } from "../../../middlewares/GlobalRateLimit";
+import { BanCreateSchema } from "../../../schema/Ban";
+import { emitEvent } from "../../../util/Event";
+import { check } from "../../../util/instanceOf";
+import { removeMember } from "../../../util/Member";
+import { getPublicUser } from "../../../util/User";
const router: Router = Router();
router.get("/", async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
+ const guild_id = req.params.id;
- const guild = await GuildModel.findOne({ id: guild_id }).exec();
+ const guild = await GuildModel.exists({ id: guild_id });
if (!guild) throw new HTTPError("Guild not found", 404);
var bans = await BanModel.find({ guild_id: guild_id }).exec();
- return res.json(bans);
+ return res.json(toObject(bans));
});
router.get("/:user", async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
- const user_id = BigInt(req.params.ban);
+ const guild_id = req.params.id;
+ const user_id = req.params.ban;
var ban = await BanModel.findOne({ guild_id: guild_id, user_id: user_id }).exec();
if (!ban) throw new HTTPError("Ban not found", 404);
@@ -30,8 +30,8 @@ router.get("/:user", async (req: Request, res: Response) => {
});
router.post("/:user_id", check(BanCreateSchema), async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
- const banned_user_id = BigInt(req.params.user_id);
+ const guild_id = req.params.id;
+ const banned_user_id = req.params.user_id;
const banned_user = await getPublicUser(banned_user_id);
const perms = await getPermission(req.user_id, guild_id);
@@ -61,30 +61,30 @@ router.post("/:user_id", check(BanCreateSchema), async (req: Request, res: Respo
});
router.delete("/:user_id", async (req: Request, res: Response) => {
- var guild_id = BigInt(req.params.id);
- var banned_user_id = BigInt(req.params.user_id);
+ var { guild_id } = req.params;
+ var banned_user_id = req.params.user_id;
const banned_user = await getPublicUser(banned_user_id);
- const guild = await GuildModel.findOne({ id: guild_id }, { id: true }).exec();
+ const guild = await GuildModel.exists({ id: guild_id });
if (!guild) throw new HTTPError("Guild not found", 404);
- const perms = await getPermission(req.user_id, guild.id);
+ const perms = await getPermission(req.user_id, guild_id);
if (!perms.has("BAN_MEMBERS")) {
throw new HTTPError("No permissions", 403);
}
await BanModel.deleteOne({
user_id: banned_user_id,
- guild_id: guild.id,
+ guild_id,
}).exec();
await emitEvent({
event: "GUILD_BAN_REMOVE",
data: {
- guild_id: guild.id,
+ guild_id,
user: banned_user,
},
- guild_id: guild.id,
+ guild_id,
} as GuildBanRemoveEvent);
return res.status(204).send();
diff --git a/src/routes/api/v8/guilds/#id/channels.ts b/src/routes/guilds/#guild_id/channels.ts
index 1316a2ca..e0d8f3ac 100644
--- a/src/routes/api/v8/guilds/#id/channels.ts
+++ b/src/routes/guilds/#guild_id/channels.ts
@@ -1,19 +1,20 @@
import { Router } from "express";
-import { ChannelModel, ChannelType, GuildModel, Snowflake } from "fosscord-server-util";
+import { ChannelCreateEvent, ChannelModel, ChannelType, GuildModel, Snowflake, toObject } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { ChannelModifySchema } from "../../../../../schema/Channel";
-import { check } from "../../../../../util/instanceOf";
+import { ChannelModifySchema } from "../../../schema/Channel";
+import { emitEvent } from "../../../util/Event";
+import { check } from "../../../util/instanceOf";
const router = Router();
router.get("/", async (req, res) => {
- const guild_id = BigInt(req.params.id);
+ const { guild_id } = req.params;
const channels = await ChannelModel.find({ guild_id }).exec();
- res.json(channels);
+ res.json(toObject(channels));
});
router.post("/", check(ChannelModifySchema), async (req, res) => {
- const guild_id = BigInt(req.params.id);
+ const { guild_id } = req.params;
const body = req.body as ChannelModifySchema;
if (!body.permission_overwrites) body.permission_overwrites = [];
if (!body.topic) body.topic = "";
@@ -45,6 +46,8 @@ router.post("/", check(ChannelModifySchema), async (req, res) => {
};
await new ChannelModel(channel).save();
+ await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id } as ChannelCreateEvent);
+
res.json(channel);
});
diff --git a/src/routes/api/v8/guilds/#id/index.ts b/src/routes/guilds/#guild_id/index.ts
index e86d9416..7e5f49d3 100644
--- a/src/routes/api/v8/guilds/#id/index.ts
+++ b/src/routes/guilds/#guild_id/index.ts
@@ -5,26 +5,31 @@ import {
getPermission,
GuildDeleteEvent,
GuildModel,
+ GuildUpdateEvent,
InviteModel,
MemberModel,
MessageModel,
RoleModel,
+ toObject,
UserModel,
} from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { GuildUpdateSchema } from "../../../../../schema/Guild";
-import { emitEvent } from "../../../../../util/Event";
-import { check } from "../../../../../util/instanceOf";
+import { GuildUpdateSchema } from "../../../schema/Guild";
+import { emitEvent } from "../../../util/Event";
+import { check } from "../../../util/instanceOf";
+import "missing-native-js-functions";
const router = Router();
router.get("/", async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
+ const { guild_id } = req.params;
- const guild = await GuildModel.findOne({ id: guild_id }).exec();
+ const guild = await GuildModel.findOne({ id: guild_id })
+ .populate({ path: "joined_at", match: { id: req.user_id } })
+ .exec();
if (!guild) throw new HTTPError("Guild does not exist", 404);
- const member = await MemberModel.findOne({ guild_id: guild_id, id: req.user_id }, "id").exec();
+ const member = await MemberModel.exists({ guild_id: guild_id, id: req.user_id });
if (!member) throw new HTTPError("You are not a member of the guild you are trying to access", 401);
return res.json(guild);
@@ -32,20 +37,27 @@ router.get("/", async (req: Request, res: Response) => {
router.patch("/", check(GuildUpdateSchema), async (req: Request, res: Response) => {
const body = req.body as GuildUpdateSchema;
- const guild_id = BigInt(req.params.id);
-
- const guild = await GuildModel.findOne({ id: guild_id }).exec();
- if (!guild) throw new HTTPError("This guild does not exist", 404);
+ const { guild_id } = req.params;
+ // TODO: guild update check image
const perms = await getPermission(req.user_id, guild_id);
if (!perms.has("MANAGE_GUILD")) throw new HTTPError("You do not have the MANAGE_GUILD permission", 401);
- await GuildModel.updateOne({ id: guild_id }, body).exec();
- return res.status(204);
+ const guild = await GuildModel.findOneAndUpdate({ id: guild_id }, body)
+ .populate({ path: "joined_at", match: { id: req.user_id } })
+ .exec();
+
+ const data = toObject(guild);
+
+ emitEvent({ event: "GUILD_UPDATE", data: data, guild_id } as GuildUpdateEvent);
+
+ return res.send(data);
});
-router.delete("/", async (req: Request, res: Response) => {
- var guild_id = BigInt(req.params.id);
+// discord prefixes this route with /delete instead of using the delete method
+// docs are wrong https://discord.com/developers/docs/resources/guild#delete-guild
+router.post("/delete", async (req: Request, res: Response) => {
+ var { guild_id } = req.params;
const guild = await GuildModel.findOne({ id: guild_id }, "owner_id").exec();
if (!guild) throw new HTTPError("This guild does not exist", 404);
@@ -67,7 +79,7 @@ router.delete("/", async (req: Request, res: Response) => {
await InviteModel.deleteMany({ guild_id }).exec();
await MessageModel.deleteMany({ guild_id }).exec();
- return res.status(204).send();
+ return res.sendStatus(204);
});
export default router;
diff --git a/src/routes/api/v8/guilds/#id/members.ts b/src/routes/guilds/#guild_id/members.ts
index 0aed61ae..f4e6d4e8 100644
--- a/src/routes/api/v8/guilds/#id/members.ts
+++ b/src/routes/guilds/#guild_id/members.ts
@@ -1,21 +1,21 @@
import { Request, Response, Router } from "express";
-import { GuildModel, MemberModel } from "fosscord-server-util";
+import { GuildModel, MemberModel, toObject } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { instanceOf, Length } from "../../../../../util/instanceOf";
-import { PublicMemberProjection } from "../../../../../util/Member";
-import { PublicUserProjection } from "../../../../../util/User";
+import { instanceOf, Length } from "../../../util/instanceOf";
+import { PublicMemberProjection } from "../../../util/Member";
+import { PublicUserProjection } from "../../../util/User";
const router = Router();
// TODO: not allowed for user -> only allowed for bots with privileged intents
// TODO: send over websocket
router.get("/", async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
+ const { guild_id } = req.params;
const guild = await GuildModel.findOne({ id: guild_id }).exec();
if (!guild) throw new HTTPError("Guild not found", 404);
try {
- instanceOf({ $limit: new Length(Number, 1, 1000), $after: BigInt }, req.query, {
+ instanceOf({ $limit: new Length(Number, 1, 1000), $after: String }, req.query, {
path: "query",
req,
ref: { obj: null, key: "" },
@@ -26,22 +26,21 @@ router.get("/", async (req: Request, res: Response) => {
// @ts-ignore
if (!req.query.limit) req.query.limit = 1;
- const { limit, after } = (<unknown>req.query) as { limit: number; after: bigint };
+ const { limit, after } = (<unknown>req.query) as { limit: number; after: string };
const query = after ? { id: { $gt: after } } : {};
var members = await MemberModel.find({ guild_id, ...query }, PublicMemberProjection)
.limit(limit)
- .populate({ path: "user", select: PublicUserProjection })
.exec();
- return res.json(members);
+ return res.json(toObject(members));
});
router.get("/:member", async (req: Request, res: Response) => {
- const guild_id = BigInt(req.params.id);
- const user_id = BigInt(req.params.member);
+ const { guild_id } = req.params;
+ const user_id = req.params.member;
- const member = await MemberModel.findOne({ id: user_id, guild_id }).populate({ path: "user", select: PublicUserProjection }).exec();
+ const member = await MemberModel.findOne({ id: user_id, guild_id }).exec();
if (!member) throw new HTTPError("Member not found", 404);
return res.json(member);
diff --git a/src/routes/api/v8/guilds/index.ts b/src/routes/guilds/index.ts
index 319184ad..57d7ddc4 100644
--- a/src/routes/api/v8/guilds/index.ts
+++ b/src/routes/guilds/index.ts
@@ -1,11 +1,11 @@
import { Router, Request, Response } from "express";
import { RoleModel, GuildModel, Snowflake, Guild } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { check } from "./../../../../util/instanceOf";
-import { GuildCreateSchema } from "../../../../schema/Guild";
-import Config from "../../../../util/Config";
-import { getPublicUser } from "../../../../util/User";
-import { addMember } from "../../../../util/Member";
+import { check } from "./../../util/instanceOf";
+import { GuildCreateSchema } from "../../schema/Guild";
+import Config from "../../util/Config";
+import { getPublicUser } from "../../util/User";
+import { addMember } from "../../util/Member";
const router: Router = Router();
@@ -29,11 +29,11 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) =
afk_timeout: 300,
application_id: undefined,
banner: undefined,
- default_message_notifications: undefined,
+ default_message_notifications: 0,
description: undefined,
splash: undefined,
discovery_splash: undefined,
- explicit_content_filter: undefined,
+ explicit_content_filter: 0,
features: [],
id: guild_id,
large: undefined,
@@ -48,11 +48,11 @@ router.post("/", check(GuildCreateSchema), async (req: Request, res: Response) =
premium_tier: 0,
public_updates_channel_id: undefined,
rules_channel_id: undefined,
- system_channel_flags: undefined,
+ system_channel_flags: 0,
system_channel_id: undefined,
unavailable: false,
vanity_url_code: undefined,
- verification_level: undefined,
+ verification_level: 0,
welcome_screen: [],
widget_channel_id: undefined,
widget_enabled: false,
diff --git a/src/routes/api/v8/guilds/templates/index.ts b/src/routes/guilds/templates/index.ts
index 9a4e81fa..9a4e81fa 100644
--- a/src/routes/api/v8/guilds/templates/index.ts
+++ b/src/routes/guilds/templates/index.ts
diff --git a/src/routes/invites/index.ts b/src/routes/invites/index.ts
new file mode 100644
index 00000000..c40fb0af
--- /dev/null
+++ b/src/routes/invites/index.ts
@@ -0,0 +1,28 @@
+import { Router, Request, Response } from "express";
+import { getPermission, InviteModel, toObject } from "fosscord-server-util";
+import { HTTPError } from "lambert-server";
+const router: Router = Router();
+
+router.get("/:invite_code", async (req: Request, res: Response) => {
+ const { invite_code: code } = req.params;
+
+ const invite = await InviteModel.findOne({ code }).exec();
+
+ if (!invite) throw new HTTPError("Unknown Invite", 404);
+ res.status(200).send({ invite: toObject(invite) });
+});
+
+router.delete("/:invite_code", async (req: Request, res: Response) => {
+ const { invite_code: code } = req.params;
+ const invite = await InviteModel.findOne({ code }).exec();
+
+ if (!invite) throw new HTTPError("Unknown Invite", 404);
+
+ const { guild_id, channel_id } = invite;
+ const perms = await getPermission(req.user_id, guild_id, channel_id);
+
+ if (!perms.has("MANAGE_GUILD") || !perms.has("MANAGE_CHANNELS")) throw new HTTPError("You aren't allow", 401);
+ res.status(200).send({ invite: toObject(invite) });
+});
+
+export default router;
diff --git a/src/routes/science.ts b/src/routes/science.ts
new file mode 100644
index 00000000..ab3ce58c
--- /dev/null
+++ b/src/routes/science.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.post("/", (req, res) => {
+ // TODO:
+ res.sendStatus(204);
+});
+
+export default router;
diff --git a/src/routes/test.ts b/src/routes/test.ts
deleted file mode 100644
index b488d6e4..00000000
--- a/src/routes/test.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Router } from "express";
-import { getPermission, MemberModel, db } from "fosscord-server-util";
-import { Types } from "mongoose";
-const router: Router = Router();
-
-router.get("/", async (req, res) => {
- // @ts-ignore
- const perm = await getPermission(813185668657184768n, 813189959920910336n);
- console.log(perm);
- if (perm.has("ADD_REACTIONS")) console.log("add");
- res.send("OK");
-});
-
-export default router;
diff --git a/src/routes/users/@me/affinities/guilds.ts b/src/routes/users/@me/affinities/guilds.ts
new file mode 100644
index 00000000..ea0fe59d
--- /dev/null
+++ b/src/routes/users/@me/affinities/guilds.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.get("/", (req, res) => {
+ // TODO:
+ res.status(200).send({ guild_affinities: [] });
+});
+
+export default router;
diff --git a/src/routes/api/v8/users/@me/guilds.ts b/src/routes/users/@me/guilds.ts
index a2a64ce6..d0fbaa3e 100644
--- a/src/routes/api/v8/users/@me/guilds.ts
+++ b/src/routes/users/@me/guilds.ts
@@ -1,8 +1,8 @@
import { Router, Request, Response } from "express";
-import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent } from "fosscord-server-util";
+import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../../../util/Event";
-import { getPublicUser } from "../../../../../util/User";
+import { emitEvent } from "../../../util/Event";
+import { getPublicUser } from "../../../util/User";
const router: Router = Router();
@@ -11,37 +11,42 @@ router.get("/", async (req: Request, res: Response) => {
if (!user) throw new HTTPError("User not found", 404);
var guildIDs = user.guilds || [];
- var guild = await GuildModel.find({ id: { $in: guildIDs } }).exec();
- res.json(guild);
+ var guild = await GuildModel.find({ id: { $in: guildIDs } })
+ .populate({ path: "joined_at", match: { id: req.user_id } })
+ .exec();
+
+ res.json(toObject(guild));
});
// user send to leave a certain guild
router.delete("/:id", async (req: Request, res: Response) => {
- const guildID = BigInt(req.params.id);
- const guild = await GuildModel.findOne({ id: guildID }).exec();
+ const guild_id = req.params.id;
+ const guild = await GuildModel.findOne({ id: guild_id }, { guild_id: true }).exec();
if (!guild) throw new HTTPError("Guild doesn't exist", 404);
if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
- await MemberModel.deleteOne({ id: req.user_id, guild_id: guildID }).exec();
- await UserModel.updateOne({ id: req.user_id }, { $pull: { guilds: guildID } }).exec();
- const user = await getPublicUser(req.user_id);
+ await Promise.all([
+ MemberModel.deleteOne({ id: req.user_id, guild_id: guild_id }).exec(),
+ UserModel.updateOne({ id: req.user_id }, { $pull: { guilds: guild_id } }).exec(),
+ emitEvent({
+ event: "GUILD_DELETE",
+ data: {
+ id: guild_id,
+ },
+ user_id: req.user_id,
+ } as GuildDeleteEvent),
+ ]);
- await emitEvent({
- event: "GUILD_DELETE",
- data: {
- id: guildID,
- },
- user_id: req.user_id,
- } as GuildDeleteEvent);
+ const user = await getPublicUser(req.user_id);
await emitEvent({
event: "GUILD_MEMBER_REMOVE",
data: {
- guild_id: guildID,
+ guild_id: guild_id,
user: user,
},
- guild_id: guildID,
+ guild_id: guild_id,
} as GuildMemberRemoveEvent);
return res.status(204).send();
diff --git a/src/routes/api/v8/users/@me/index.ts b/src/routes/users/@me/index.ts
index 32877dcc..32877dcc 100644
--- a/src/routes/api/v8/users/@me/index.ts
+++ b/src/routes/users/@me/index.ts
diff --git a/src/routes/users/@me/library.ts b/src/routes/users/@me/library.ts
new file mode 100644
index 00000000..2ffff851
--- /dev/null
+++ b/src/routes/users/@me/library.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.get("/", (req, res) => {
+ // TODO:
+ res.status(200).send([]);
+});
+
+export default router;
diff --git a/src/routes/users/@me/settings.ts b/src/routes/users/@me/settings.ts
new file mode 100644
index 00000000..f1d95caf
--- /dev/null
+++ b/src/routes/users/@me/settings.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+
+const router = Router();
+
+router.patch("/", (req, res) => {
+ // TODO:
+ res.sendStatus(204);
+});
+
+export default router;
diff --git a/src/schema/Channel.ts b/src/schema/Channel.ts
index 2e7d1214..0fafc54d 100644
--- a/src/schema/Channel.ts
+++ b/src/schema/Channel.ts
@@ -10,7 +10,7 @@ export const ChannelModifySchema = {
$position: Number,
$permission_overwrites: [
{
- id: BigInt,
+ id: String,
type: new Length(Number, 0, 1), // either 0 (role) or 1 (member)
allow: BigInt,
deny: BigInt,
@@ -29,23 +29,23 @@ export interface ChannelModifySchema {
rate_limit_per_user?: Number;
position?: number;
permission_overwrites?: {
- id: bigint;
+ id: string;
type: number;
allow: bigint;
deny: bigint;
}[];
- parent_id?: bigint;
+ parent_id?: string;
nsfw?: boolean;
}
export const ChannelGuildPositionUpdateSchema = [
{
- id: BigInt,
+ id: String,
$position: Number,
},
];
export type ChannelGuildPositionUpdateSchema = {
- id: bigint;
+ id: string;
position?: number;
}[];
diff --git a/src/schema/Guild.ts b/src/schema/Guild.ts
index 489c37ff..6527f35d 100644
--- a/src/schema/Guild.ts
+++ b/src/schema/Guild.ts
@@ -1,13 +1,22 @@
+import { ChannelSchema, GuildChannel } from "fosscord-server-util";
import { Length } from "../util/instanceOf";
export const GuildCreateSchema = {
- name: new Length(String, 2, 100), // ! 2-100 chars
+ name: new Length(String, 2, 100),
$region: String, // auto complete voice region of the user
+ $icon: String,
+ $channels: [Object],
+ $guild_template_code: String,
+ $system_channel_id: String,
};
export interface GuildCreateSchema {
name: string;
region?: string;
+ icon?: string;
+ channels?: GuildChannel[];
+ guild_template_code?: string;
+ system_channel_id?: string;
}
export const GuildUpdateSchema = {
@@ -20,27 +29,27 @@ export const GuildUpdateSchema = {
$verification_level: Number,
$default_message_notifications: Number,
$system_channel_flags: Number,
- $system_channel_id: BigInt,
+ $system_channel_id: String,
$explicit_content_filter: Number,
- $public_updates_channel_id: BigInt,
+ $public_updates_channel_id: String,
$afk_timeout: Number,
- $afk_channel_id: BigInt,
+ $afk_channel_id: String,
};
+// @ts-ignore
+delete GuildUpdateSchema.$channels;
-export interface GuildUpdateSchema extends GuildCreateSchema {
+export interface GuildUpdateSchema extends Omit<GuildCreateSchema, "channels"> {
banner?: string;
splash?: string;
description?: string;
features?: [string];
- icon?: string;
verification_level?: number;
default_message_notifications?: number;
system_channel_flags?: number;
- system_channel_id?: bigint;
explicit_content_filter?: number;
- public_updates_channel_id?: bigint;
+ public_updates_channel_id?: string;
afk_timeout?: number;
- afk_channel_id?: bigint;
+ afk_channel_id?: string;
}
export const GuildGetSchema = {
diff --git a/src/schema/Invite.ts b/src/schema/Invite.ts
index 61f566d1..3c944037 100644
--- a/src/schema/Invite.ts
+++ b/src/schema/Invite.ts
@@ -1,4 +1,7 @@
export const InviteCreateSchema = {
+ $target_user_id: String,
+ $target_type: String,
+ $validate: String, //? wtf is this
$max_age: Number,
$max_uses: Number,
$temporary: Boolean,
@@ -7,6 +10,9 @@ export const InviteCreateSchema = {
$target_user_type: Number,
};
export interface InviteCreateSchema {
+ target_user_id?: String;
+ target_type?: String;
+ validate?: String; //? wtf is this
max_age?: Number;
max_uses?: Number;
temporary?: Boolean;
diff --git a/src/schema/Message.ts b/src/schema/Message.ts
index 910d1393..c0e2315a 100644
--- a/src/schema/Message.ts
+++ b/src/schema/Message.ts
@@ -44,9 +44,9 @@ export const MessageCreateSchema = {
},
$allowed_mentions: [],
$message_reference: {
- message_id: BigInt,
- channel_id: BigInt,
- $guild_id: BigInt,
+ message_id: String,
+ channel_id: String,
+ $guild_id: String,
$fail_if_not_exists: Boolean,
},
$payload_json: String,
@@ -60,9 +60,9 @@ export interface MessageCreateSchema {
embed?: Embed & { timestamp?: string };
allowed_mentions?: [];
message_reference?: {
- message_id: bigint;
- channel_id: bigint;
- guild_id?: bigint;
+ message_id: string;
+ channel_id: string;
+ guild_id?: string;
fail_if_not_exists: boolean;
};
payload_json?: string;
diff --git a/src/test/mongo_test.ts b/src/test/mongo_test.ts
index f1a7f3f6..44b04c5b 100644
--- a/src/test/mongo_test.ts
+++ b/src/test/mongo_test.ts
@@ -1,13 +1,12 @@
import mongoose, { Schema, Types } from "mongoose";
-import { Long as MongoTypeLong } from "mongodb";
require("mongoose-long")(mongoose);
const userSchema = new Schema({
- id: MongoTypeLong,
+ id: String,
});
const messageSchema = new Schema({
- id: MongoTypeLong,
+ id: String,
content: String,
});
const message = mongoose.model("message", messageSchema, "messages");
diff --git a/src/test/test.ts b/src/test/test.ts
index fd50ab9a..eb0cb8b3 100644
--- a/src/test/test.ts
+++ b/src/test/test.ts
@@ -1,7 +1,7 @@
import { getPermission } from "fosscord-server-util";
async function main() {
- const t = await getPermission(811642917432066048n, 812327318532915201n);
+ const t = await getPermission("811642917432066048", "812327318532915201");
console.log(t);
}
diff --git a/src/util/Config.ts b/src/util/Config.ts
index a9cbddde..60d83e1a 100644
--- a/src/util/Config.ts
+++ b/src/util/Config.ts
@@ -23,7 +23,7 @@ export interface RateLimit {
export interface DefaultOptions {
general: {
- instance_id: bigint;
+ instance_id: string;
};
permissions: {
user: {
diff --git a/src/util/Event.ts b/src/util/Event.ts
index 43c51d5c..8a24e4bb 100644
--- a/src/util/Event.ts
+++ b/src/util/Event.ts
@@ -5,6 +5,7 @@ export async function emitEvent(payload: Omit<Event, "created_at">) {
created_at: new Date(), // in seconds
...payload,
};
+ // TODO: bigint isn't working
return await new EventModel(obj).save();
}
diff --git a/src/util/Member.ts b/src/util/Member.ts
index 319eab60..4d1b8ac5 100644
--- a/src/util/Member.ts
+++ b/src/util/Member.ts
@@ -25,12 +25,10 @@ export const PublicMemberProjection = {
premium_since: true,
};
-export async function addMember(user_id: bigint, guild_id: bigint, cache?: { guild?: Guild }) {
+export async function addMember(user_id: string, guild_id: string, cache?: { guild?: Guild }) {
const user = await getPublicUser(user_id, { guilds: true });
const guildSize = user.guilds.length;
- // @ts-ignore
- user.guilds = undefined;
const { maxGuilds } = Config.get().limits.user;
if (guildSize >= maxGuilds) {
@@ -77,6 +75,7 @@ export async function addMember(user_id: bigint, guild_id: bigint, cache?: { gui
},
guild_id: guild_id,
} as GuildMemberAddEvent),
+
emitEvent({
event: "GUILD_CREATE",
data: guild,
@@ -85,7 +84,7 @@ export async function addMember(user_id: bigint, guild_id: bigint, cache?: { gui
]);
}
-export async function removeMember(user_id: bigint, guild_id: bigint) {
+export async function removeMember(user_id: string, guild_id: string) {
const user = await getPublicUser(user_id);
const guild = await GuildModel.findOne({ id: guild_id }, { owner_id: true }).exec();
diff --git a/src/util/User.ts b/src/util/User.ts
index 1b13e153..05213642 100644
--- a/src/util/User.ts
+++ b/src/util/User.ts
@@ -1,4 +1,4 @@
-import { UserModel } from "fosscord-server-util";
+import { toObject, UserModel } from "fosscord-server-util";
import { HTTPError } from "lambert-server";
export const PublicUserProjection = {
@@ -9,7 +9,7 @@ export const PublicUserProjection = {
avatar: true,
};
-export async function getPublicUser(user_id: bigint, additional_fields?: any) {
+export async function getPublicUser(user_id: string, additional_fields?: any) {
const user = await UserModel.findOne(
{ id: user_id },
{
@@ -18,5 +18,5 @@ export async function getPublicUser(user_id: bigint, additional_fields?: any) {
}
).exec();
if (!user) throw new HTTPError("User not found", 404);
- return user;
+ return toObject(user);
}
diff --git a/src/util/instanceOf.ts b/src/util/instanceOf.ts
index 4f30bd46..b4a231ba 100644
--- a/src/util/instanceOf.ts
+++ b/src/util/instanceOf.ts
@@ -114,8 +114,6 @@ export function instanceOf(
}
if (typeof type === "object") {
- if (typeof value !== "object") throw new FieldError("BASE_TYPE_OBJECT", req.t("common:field.BASE_TYPE_OBJECT"));
-
if (Array.isArray(type)) {
if (!Array.isArray(value)) throw new FieldError("BASE_TYPE_ARRAY", req.t("common:field.BASE_TYPE_ARRAY"));
if (!type.length) return true; // type array didn't specify any type
@@ -123,7 +121,8 @@ export function instanceOf(
return (
value.every((val, i) => {
errors[i] = {};
- return (
+
+ if (
instanceOf(type[0], val, {
path: `${path}[${i}]`,
optional,
@@ -131,7 +130,12 @@ export function instanceOf(
req,
ref: { key: i, obj: value },
}) === true
- );
+ ) {
+ delete errors[i];
+ return true;
+ }
+
+ return false;
}) || errors
);
} else if (type?.constructor?.name != "Object") {
@@ -150,10 +154,15 @@ export function instanceOf(
})
);
}
- if (value instanceof type) return true;
- throw new FieldError("BASE_TYPE_CLASS", req.t("common:field.BASE_TYPE_CLASS", { type }));
+ try {
+ if (value instanceof type) return true;
+ } catch (error) {
+ throw new FieldError("BASE_TYPE_CLASS", req.t("common:field.BASE_TYPE_CLASS", { type }));
+ }
}
+ if (typeof value !== "object") throw new FieldError("BASE_TYPE_OBJECT", req.t("common:field.BASE_TYPE_OBJECT"));
+
const diff = Object.keys(value).missing(
Object.keys(type).map((x) => (x.startsWith(OPTIONAL_PREFIX) ? x.slice(OPTIONAL_PREFIX.length) : x))
);
@@ -167,7 +176,7 @@ export function instanceOf(
if (OPTIONAL) newKey = newKey.slice(OPTIONAL_PREFIX.length);
errors[newKey] = {};
- return (
+ if (
instanceOf(type[key], value[newKey], {
path: `${path}.${newKey}`,
optional: OPTIONAL,
@@ -175,7 +184,12 @@ export function instanceOf(
req,
ref: { key: newKey, obj: value },
}) === true
- );
+ ) {
+ delete errors[newKey];
+ return true;
+ }
+
+ return false;
}) || errors
);
} else if (typeof type === "number" || typeof type === "string" || typeof type === "boolean") {
|