diff --git a/src/api/routes/guilds/#guild_id/audit-logs.ts b/src/api/routes/guilds/#guild_id/audit-logs.ts
deleted file mode 100644
index 76a11f6b..00000000
--- a/src/api/routes/guilds/#guild_id/audit-logs.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Router, Response, Request } from "express";
-import { route } from "@fosscord/api";
-const router = Router();
-
-//TODO: implement audit logs
-router.get("/", route({}), async (req: Request, res: Response) => {
- res.json({
- audit_log_entries: [],
- users: [],
- integrations: [],
- webhooks: [],
- guild_scheduled_events: [],
- threads: [],
- application_commands: [],
- });
-});
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts
deleted file mode 100644
index 930985d7..00000000
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- DiscordApiErrors,
- emitEvent,
- GuildBanAddEvent,
- GuildBanRemoveEvent,
- Ban,
- User,
- Member,
- BanRegistrySchema,
- BanModeratorSchema,
-} from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { getIpAdress, route } from "@fosscord/api";
-
-const router: Router = Router();
-
-/* TODO: Deleting the secrets is just a temporary go-around. Views should be implemented for both safety and better handling. */
-
-router.get(
- "/",
- route({ permission: "BAN_MEMBERS" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- let bans = await Ban.find({ where: { guild_id: guild_id } });
- let promisesToAwait: object[] = [];
- const bansObj: object[] = [];
-
- bans.filter((ban) => ban.user_id !== ban.executor_id); // pretend self-bans don't exist to prevent victim chasing
-
- bans.forEach((ban) => {
- promisesToAwait.push(User.getPublicUser(ban.user_id));
- });
-
- const bannedUsers: object[] = await Promise.all(promisesToAwait);
-
- bans.forEach((ban, index) => {
- const user = bannedUsers[index] as User;
- bansObj.push({
- reason: ban.reason,
- user: {
- username: user.username,
- discriminator: user.discriminator,
- id: user.id,
- avatar: user.avatar,
- public_flags: user.public_flags,
- },
- });
- });
-
- return res.json(bansObj);
- },
-);
-
-router.get(
- "/:user",
- route({ permission: "BAN_MEMBERS" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const user_id = req.params.ban;
-
- let ban = (await Ban.findOneOrFail({
- where: { guild_id: guild_id, user_id: user_id },
- })) as BanRegistrySchema;
-
- if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
- // pretend self-bans don't exist to prevent victim chasing
-
- /* Filter secret from registry. */
-
- ban = ban as BanModeratorSchema;
-
- delete ban.ip;
-
- return res.json(ban);
- },
-);
-
-router.put(
- "/:user_id",
- route({ body: "BanCreateSchema", permission: "BAN_MEMBERS" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const banned_user_id = req.params.user_id;
-
- if (
- req.user_id === banned_user_id &&
- banned_user_id === req.permission!.cache.guild?.owner_id
- )
- throw new HTTPError(
- "You are the guild owner, hence can't ban yourself",
- 403,
- );
-
- if (req.permission!.cache.guild?.owner_id === banned_user_id)
- throw new HTTPError("You can't ban the owner", 400);
-
- const banned_user = await User.getPublicUser(banned_user_id);
-
- const ban = Ban.create({
- user_id: banned_user_id,
- guild_id: guild_id,
- ip: getIpAdress(req),
- executor_id: req.user_id,
- reason: req.body.reason, // || otherwise empty
- });
-
- await Promise.all([
- Member.removeFromGuild(banned_user_id, guild_id),
- ban.save(),
- emitEvent({
- event: "GUILD_BAN_ADD",
- data: {
- guild_id: guild_id,
- user: banned_user,
- },
- guild_id: guild_id,
- } as GuildBanAddEvent),
- ]);
-
- return res.json(ban);
- },
-);
-
-router.put(
- "/@me",
- route({ body: "BanCreateSchema" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const banned_user = await User.getPublicUser(req.params.user_id);
-
- if (req.permission!.cache.guild?.owner_id === req.params.user_id)
- throw new HTTPError(
- "You are the guild owner, hence can't ban yourself",
- 403,
- );
-
- const ban = Ban.create({
- user_id: req.params.user_id,
- guild_id: guild_id,
- ip: getIpAdress(req),
- executor_id: req.params.user_id,
- reason: req.body.reason, // || otherwise empty
- });
-
- await Promise.all([
- Member.removeFromGuild(req.user_id, guild_id),
- ban.save(),
- emitEvent({
- event: "GUILD_BAN_ADD",
- data: {
- guild_id: guild_id,
- user: banned_user,
- },
- guild_id: guild_id,
- } as GuildBanAddEvent),
- ]);
-
- return res.json(ban);
- },
-);
-
-router.delete(
- "/:user_id",
- route({ permission: "BAN_MEMBERS" }),
- async (req: Request, res: Response) => {
- const { guild_id, user_id } = req.params;
-
- let ban = await Ban.findOneOrFail({
- where: { guild_id: guild_id, user_id: user_id },
- });
-
- if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
- // make self-bans irreversible and hide them from view to avoid victim chasing
-
- const banned_user = await User.getPublicUser(user_id);
-
- await Promise.all([
- Ban.delete({
- user_id: user_id,
- guild_id,
- }),
-
- emitEvent({
- event: "GUILD_BAN_REMOVE",
- data: {
- guild_id,
- user: banned_user,
- },
- guild_id,
- } as GuildBanRemoveEvent),
- ]);
-
- return res.status(204).send();
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts
deleted file mode 100644
index eae93607..00000000
--- a/src/api/routes/guilds/#guild_id/channels.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { Router, Response, Request } from "express";
-import {
- Channel,
- ChannelUpdateEvent,
- emitEvent,
- ChannelModifySchema,
- ChannelReorderSchema,
-} from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const channels = await Channel.find({ where: { guild_id } });
-
- res.json(channels);
-});
-
-router.post(
- "/",
- route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }),
- async (req: Request, res: Response) => {
- // creates a new guild channel https://discord.com/developers/docs/resources/guild#create-guild-channel
- const { guild_id } = req.params;
- const body = req.body as ChannelModifySchema;
-
- const channel = await Channel.createChannel(
- { ...body, guild_id },
- req.user_id,
- );
-
- res.status(201).json(channel);
- },
-);
-
-router.patch(
- "/",
- route({ body: "ChannelReorderSchema", permission: "MANAGE_CHANNELS" }),
- async (req: Request, res: Response) => {
- // changes guild channel position
- const { guild_id } = req.params;
- const body = req.body as ChannelReorderSchema;
-
- await Promise.all([
- body.map(async (x) => {
- if (x.position == null && !x.parent_id)
- throw new HTTPError(
- `You need to at least specify position or parent_id`,
- 400,
- );
-
- const opts: any = {};
- if (x.position != null) opts.position = x.position;
-
- if (x.parent_id) {
- opts.parent_id = x.parent_id;
- const parent_channel = await Channel.findOneOrFail({
- where: { id: x.parent_id, guild_id },
- select: ["permission_overwrites"],
- });
- if (x.lock_permissions) {
- opts.permission_overwrites =
- parent_channel.permission_overwrites;
- }
- }
-
- await Channel.update({ guild_id, id: x.id }, opts);
- const channel = await Channel.findOneOrFail({
- where: { guild_id, id: x.id },
- });
-
- await emitEvent({
- event: "CHANNEL_UPDATE",
- data: channel,
- channel_id: x.id,
- guild_id,
- } as ChannelUpdateEvent);
- }),
- ]);
-
- res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts
deleted file mode 100644
index b951e4f4..00000000
--- a/src/api/routes/guilds/#guild_id/delete.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import {
- Channel,
- emitEvent,
- GuildDeleteEvent,
- Guild,
- Member,
- Message,
- Role,
- Invite,
- Emoji,
-} from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-
-const router = Router();
-
-// 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("/", route({}), async (req: Request, res: Response) => {
- var { guild_id } = req.params;
-
- const guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- select: ["owner_id"],
- });
- if (guild.owner_id !== req.user_id)
- throw new HTTPError("You are not the owner of this guild", 401);
-
- await Promise.all([
- Guild.delete({ id: guild_id }), // this will also delete all guild related data
- emitEvent({
- event: "GUILD_DELETE",
- data: {
- id: guild_id,
- },
- guild_id: guild_id,
- } as GuildDeleteEvent),
- ]);
-
- return res.sendStatus(204);
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
deleted file mode 100644
index 7e63c06b..00000000
--- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Guild, Config } from "@fosscord/util";
-
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- // TODO:
- // Load from database
- // Admin control, but for now it allows anyone to be discoverable
-
- res.send({
- guild_id: guild_id,
- safe_environment: true,
- healthy: true,
- health_score_pending: false,
- size: true,
- nsfw_properties: {},
- protected: true,
- sufficient: true,
- sufficient_without_grace_period: true,
- valid_rules_channel: true,
- retention_healthy: true,
- engagement_healthy: true,
- age: true,
- minimum_age: 0,
- health_score: {
- avg_nonnew_participators: 0,
- avg_nonnew_communicators: 0,
- num_intentful_joiners: 0,
- perc_ret_w1_intentful: 0,
- },
- minimum_size: 0,
- });
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts
deleted file mode 100644
index 6e8570eb..00000000
--- a/src/api/routes/guilds/#guild_id/emojis.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import { Router, Request, Response } from "express";
-import {
- Config,
- DiscordApiErrors,
- emitEvent,
- Emoji,
- GuildEmojisUpdateEvent,
- handleFile,
- Member,
- Snowflake,
- User,
- EmojiCreateSchema,
- EmojiModifySchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- const emojis = await Emoji.find({
- where: { guild_id: guild_id },
- relations: ["user"],
- });
-
- return res.json(emojis);
-});
-
-router.get("/:emoji_id", route({}), async (req: Request, res: Response) => {
- const { guild_id, emoji_id } = req.params;
-
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- const emoji = await Emoji.findOneOrFail({
- where: { guild_id: guild_id, id: emoji_id },
- relations: ["user"],
- });
-
- return res.json(emoji);
-});
-
-router.post(
- "/",
- route({
- body: "EmojiCreateSchema",
- permission: "MANAGE_EMOJIS_AND_STICKERS",
- }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const body = req.body as EmojiCreateSchema;
-
- const id = Snowflake.generate();
- const emoji_count = await Emoji.count({
- where: { guild_id: guild_id },
- });
- const { maxEmojis } = Config.get().limits.guild;
-
- if (emoji_count >= maxEmojis)
- throw DiscordApiErrors.MAXIMUM_NUMBER_OF_EMOJIS_REACHED.withParams(
- maxEmojis,
- );
- if (body.require_colons == null) body.require_colons = true;
-
- const user = await User.findOneOrFail({ where: { id: req.user_id } });
- body.image = (await handleFile(`/emojis/${id}`, body.image)) as string;
-
- const emoji = await Emoji.create({
- id: id,
- guild_id: guild_id,
- ...body,
- require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not
- user: user,
- managed: false,
- animated: false, // TODO: Add support animated emojis
- available: true,
- roles: [],
- }).save();
-
- await emitEvent({
- event: "GUILD_EMOJIS_UPDATE",
- guild_id: guild_id,
- data: {
- guild_id: guild_id,
- emojis: await Emoji.find({ where: { guild_id: guild_id } }),
- },
- } as GuildEmojisUpdateEvent);
-
- return res.status(201).json(emoji);
- },
-);
-
-router.patch(
- "/:emoji_id",
- route({
- body: "EmojiModifySchema",
- permission: "MANAGE_EMOJIS_AND_STICKERS",
- }),
- async (req: Request, res: Response) => {
- const { emoji_id, guild_id } = req.params;
- const body = req.body as EmojiModifySchema;
-
- const emoji = await Emoji.create({
- ...body,
- id: emoji_id,
- guild_id: guild_id,
- }).save();
-
- await emitEvent({
- event: "GUILD_EMOJIS_UPDATE",
- guild_id: guild_id,
- data: {
- guild_id: guild_id,
- emojis: await Emoji.find({ where: { guild_id: guild_id } }),
- },
- } as GuildEmojisUpdateEvent);
-
- return res.json(emoji);
- },
-);
-
-router.delete(
- "/:emoji_id",
- route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }),
- async (req: Request, res: Response) => {
- const { emoji_id, guild_id } = req.params;
-
- await Emoji.delete({
- id: emoji_id,
- guild_id: guild_id,
- });
-
- await emitEvent({
- event: "GUILD_EMOJIS_UPDATE",
- guild_id: guild_id,
- data: {
- guild_id: guild_id,
- emojis: await Emoji.find({ where: { guild_id: guild_id } }),
- },
- } as GuildEmojisUpdateEvent);
-
- res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts
deleted file mode 100644
index 79c20678..00000000
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- DiscordApiErrors,
- emitEvent,
- getPermission,
- getRights,
- Guild,
- GuildUpdateEvent,
- handleFile,
- Member,
- GuildUpdateSchema,
- FosscordApiErrors,
-} from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const [guild, member] = await Promise.all([
- Guild.findOneOrFail({ where: { id: guild_id } }),
- Member.findOne({ where: { 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,
- );
-
- // @ts-ignore
- guild.joined_at = member?.joined_at;
-
- return res.send(guild);
-});
-
-router.patch(
- "/",
- route({ body: "GuildUpdateSchema" }),
- async (req: Request, res: Response) => {
- const body = req.body as GuildUpdateSchema;
- const { guild_id } = req.params;
-
- const rights = await getRights(req.user_id);
- const permission = await getPermission(req.user_id, guild_id);
-
- if (!rights.has("MANAGE_GUILDS") && !permission.has("MANAGE_GUILD"))
- throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(
- "MANAGE_GUILDS",
- );
-
- var guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- relations: ["emojis", "roles", "stickers"],
- });
-
- // TODO: guild update check image
-
- if (body.icon && body.icon != guild.icon)
- body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
-
- if (body.banner && body.banner !== guild.banner)
- body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
-
- if (body.splash && body.splash !== guild.splash)
- body.splash = await handleFile(
- `/splashes/${guild_id}`,
- body.splash,
- );
-
- if (
- body.discovery_splash &&
- body.discovery_splash !== guild.discovery_splash
- )
- body.discovery_splash = await handleFile(
- `/discovery-splashes/${guild_id}`,
- body.discovery_splash,
- );
-
- if (body.features) {
- const diff = guild.features
- .filter((x) => !body.features?.includes(x))
- .concat(
- body.features.filter((x) => !guild.features.includes(x)),
- );
-
- // TODO move these
- const MUTABLE_FEATURES = [
- "COMMUNITY",
- "INVITES_DISABLED",
- "DISCOVERABLE",
- ];
-
- for (var feature of diff) {
- if (MUTABLE_FEATURES.includes(feature)) continue;
-
- throw FosscordApiErrors.FEATURE_IS_IMMUTABLE.withParams(
- feature,
- );
- }
-
- // for some reason, they don't update in the assign.
- guild.features = body.features;
- }
-
- // TODO: check if body ids are valid
- guild.assign(body);
-
- const data = guild.toJSON();
- // TODO: guild hashes
- // TODO: fix vanity_url_code, template_id
- delete data.vanity_url_code;
- delete data.template_id;
-
- await Promise.all([
- guild.save(),
- emitEvent({
- event: "GUILD_UPDATE",
- data,
- guild_id,
- } as GuildUpdateEvent),
- ]);
-
- return res.json(data);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/integrations.ts b/src/api/routes/guilds/#guild_id/integrations.ts
deleted file mode 100644
index a8e78062..00000000
--- a/src/api/routes/guilds/#guild_id/integrations.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Router, Response, Request } from "express";
-import { route } from "@fosscord/api";
-const router = Router();
-
-//TODO: implement integrations list
-router.get("/", route({}), async (req: Request, res: Response) => {
- res.json([]);
-});
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts
deleted file mode 100644
index 4d033e9c..00000000
--- a/src/api/routes/guilds/#guild_id/invites.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { getPermission, Invite, PublicInviteRelation } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Request, Response, Router } from "express";
-
-const router = Router();
-
-router.get(
- "/",
- route({ permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const invites = await Invite.find({
- where: { guild_id },
- relations: PublicInviteRelation,
- });
-
- return res.json(invites);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/member-verification.ts b/src/api/routes/guilds/#guild_id/member-verification.ts
deleted file mode 100644
index c2f946b2..00000000
--- a/src/api/routes/guilds/#guild_id/member-verification.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- // TODO: member verification
-
- res.status(404).json({
- message: "Unknown Guild Member Verification Form",
- code: 10068,
- });
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
deleted file mode 100644
index 0fcdd57c..00000000
--- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- Member,
- getPermission,
- getRights,
- Role,
- GuildMemberUpdateEvent,
- emitEvent,
- Sticker,
- Emoji,
- Guild,
- handleFile,
- MemberChangeSchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id, member_id } = req.params;
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- const member = await Member.findOneOrFail({
- where: { id: member_id, guild_id },
- });
-
- return res.json(member);
-});
-
-router.patch(
- "/",
- route({ body: "MemberChangeSchema" }),
- async (req: Request, res: Response) => {
- let { guild_id, member_id } = req.params;
- if (member_id === "@me") member_id = req.user_id;
- const body = req.body as MemberChangeSchema;
-
- let member = await Member.findOneOrFail({
- where: { id: member_id, guild_id },
- relations: ["roles", "user"],
- });
- const permission = await getPermission(req.user_id, guild_id);
- const everyone = await Role.findOneOrFail({
- where: { guild_id: guild_id, name: "@everyone", position: 0 },
- });
-
- if (body.avatar)
- body.avatar = await handleFile(
- `/guilds/${guild_id}/users/${member_id}/avatars`,
- body.avatar as string,
- );
-
- member.assign(body);
-
- if ("roles" in body) {
- permission.hasThrow("MANAGE_ROLES");
-
- body.roles = body.roles || [];
- body.roles.filter((x) => !!x);
-
- if (body.roles.indexOf(everyone.id) === -1)
- body.roles.push(everyone.id);
- member.roles = body.roles.map((x) => Role.create({ id: x })); // foreign key constraint will fail if role doesn't exist
- }
-
- await member.save();
-
- member.roles = member.roles.filter((x) => x.id !== everyone.id);
-
- // do not use promise.all as we have to first write to db before emitting the event to catch errors
- await emitEvent({
- event: "GUILD_MEMBER_UPDATE",
- guild_id,
- data: { ...member, roles: member.roles.map((x) => x.id) },
- } as GuildMemberUpdateEvent);
-
- res.json(member);
- },
-);
-
-router.put("/", route({}), async (req: Request, res: Response) => {
- // TODO: Lurker mode
-
- const rights = await getRights(req.user_id);
-
- let { guild_id, member_id } = req.params;
- if (member_id === "@me") {
- member_id = req.user_id;
- rights.hasThrow("JOIN_GUILDS");
- } else {
- // TODO: join others by controller
- }
-
- var guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- });
-
- var emoji = await Emoji.find({
- where: { guild_id: guild_id },
- });
-
- var roles = await Role.find({
- where: { guild_id: guild_id },
- });
-
- var stickers = await Sticker.find({
- where: { guild_id: guild_id },
- });
-
- await Member.addToGuild(member_id, guild_id);
- res.send({ ...guild, emojis: emoji, roles: roles, stickers: stickers });
-});
-
-router.delete("/", route({}), async (req: Request, res: Response) => {
- const { guild_id, member_id } = req.params;
- const permission = await getPermission(req.user_id, guild_id);
- const rights = await getRights(req.user_id);
- if (member_id === "@me" || member_id === req.user_id) {
- // TODO: unless force-joined
- rights.hasThrow("SELF_LEAVE_GROUPS");
- } else {
- rights.hasThrow("KICK_BAN_MEMBERS");
- permission.hasThrow("KICK_MEMBERS");
- }
-
- await Member.removeFromGuild(member_id, guild_id);
- res.sendStatus(204);
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
deleted file mode 100644
index 20443821..00000000
--- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { getPermission, Member, PermissionResolvable } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Request, Response, Router } from "express";
-
-const router = Router();
-
-router.patch(
- "/",
- route({ body: "MemberNickChangeSchema" }),
- async (req: Request, res: Response) => {
- var { guild_id, member_id } = req.params;
- var permissionString: PermissionResolvable = "MANAGE_NICKNAMES";
- if (member_id === "@me") {
- member_id = req.user_id;
- permissionString = "CHANGE_NICKNAME";
- }
-
- const perms = await getPermission(req.user_id, guild_id);
- perms.hasThrow(permissionString);
-
- await Member.changeNickname(member_id, guild_id, req.body.nick);
- res.status(200).send();
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
deleted file mode 100644
index c0383912..00000000
--- a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { getPermission, Member } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Request, Response, Router } from "express";
-
-const router = Router();
-
-router.delete(
- "/",
- route({ permission: "MANAGE_ROLES" }),
- async (req: Request, res: Response) => {
- const { guild_id, role_id, member_id } = req.params;
-
- await Member.removeRole(member_id, guild_id, role_id);
- res.sendStatus(204);
- },
-);
-
-router.put(
- "/",
- route({ permission: "MANAGE_ROLES" }),
- async (req: Request, res: Response) => {
- const { guild_id, role_id, member_id } = req.params;
-
- await Member.addRole(member_id, guild_id, role_id);
- res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts
deleted file mode 100644
index b516b9e9..00000000
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Request, Response, Router } from "express";
-import { Guild, Member, PublicMemberProjection } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { MoreThan } from "typeorm";
-import { HTTPError } from "lambert-server";
-
-const router = Router();
-
-// TODO: send over websocket
-// TODO: check for GUILD_MEMBERS intent
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const limit = Number(req.query.limit) || 1;
- if (limit > 1000 || limit < 1)
- throw new HTTPError("Limit must be between 1 and 1000");
- const after = `${req.query.after}`;
- const query = after ? { id: MoreThan(after) } : {};
-
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- const members = await Member.find({
- where: { guild_id, ...query },
- select: PublicMemberProjection,
- take: limit,
- order: { id: "ASC" },
- });
-
- return res.json(members);
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts
deleted file mode 100644
index 88488871..00000000
--- a/src/api/routes/guilds/#guild_id/messages/search.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import { Request, Response, Router } from "express";
-import { route } from "@fosscord/api";
-import { getPermission, FieldErrors, Message, Channel } from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { FindManyOptions, In, Like } from "typeorm";
-
-const router: Router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const {
- channel_id,
- content,
- include_nsfw, // TODO
- offset,
- sort_order,
- sort_by, // TODO: Handle 'relevance'
- limit,
- author_id,
- } = req.query;
-
- const parsedLimit = Number(limit) || 50;
- if (parsedLimit < 1 || parsedLimit > 100)
- throw new HTTPError("limit must be between 1 and 100", 422);
-
- if (sort_order) {
- if (
- typeof sort_order != "string" ||
- ["desc", "asc"].indexOf(sort_order) == -1
- )
- throw FieldErrors({
- sort_order: {
- message: "Value must be one of ('desc', 'asc').",
- code: "BASE_TYPE_CHOICES",
- },
- }); // todo this is wrong
- }
-
- const permissions = await getPermission(
- req.user_id,
- req.params.guild_id,
- channel_id as string | undefined,
- );
- permissions.hasThrow("VIEW_CHANNEL");
- if (!permissions.has("READ_MESSAGE_HISTORY"))
- return res.json({ messages: [], total_results: 0 });
-
- var query: FindManyOptions<Message> = {
- order: {
- timestamp: sort_order
- ? (sort_order.toUpperCase() as "ASC" | "DESC")
- : "DESC",
- },
- take: parsedLimit || 0,
- where: {
- guild: {
- id: req.params.guild_id,
- },
- },
- relations: [
- "author",
- "webhook",
- "application",
- "mentions",
- "mention_roles",
- "mention_channels",
- "sticker_items",
- "attachments",
- ],
- skip: offset ? Number(offset) : 0,
- };
- //@ts-ignore
- if (channel_id) query.where!.channel = { id: channel_id };
- else {
- // get all channel IDs that this user can access
- const channels = await Channel.find({
- where: { guild_id: req.params.guild_id },
- select: ["id"],
- });
- const ids = [];
-
- for (var channel of channels) {
- const perm = await getPermission(
- req.user_id,
- req.params.guild_id,
- channel.id,
- );
- if (!perm.has("VIEW_CHANNEL") || !perm.has("READ_MESSAGE_HISTORY"))
- continue;
- ids.push(channel.id);
- }
-
- //@ts-ignore
- query.where!.channel = { id: In(ids) };
- }
- //@ts-ignore
- if (author_id) query.where!.author = { id: author_id };
- //@ts-ignore
- if (content) query.where!.content = Like(`%${content}%`);
-
- const messages: Message[] = await Message.find(query);
-
- const messagesDto = messages.map((x) => [
- {
- id: x.id,
- type: x.type,
- content: x.content,
- channel_id: x.channel_id,
- author: {
- id: x.author?.id,
- username: x.author?.username,
- avatar: x.author?.avatar,
- avatar_decoration: null,
- discriminator: x.author?.discriminator,
- public_flags: x.author?.public_flags,
- },
- attachments: x.attachments,
- embeds: x.embeds,
- mentions: x.mentions,
- mention_roles: x.mention_roles,
- pinned: x.pinned,
- mention_everyone: x.mention_everyone,
- tts: x.tts,
- timestamp: x.timestamp,
- edited_timestamp: x.edited_timestamp,
- flags: x.flags,
- components: x.components,
- hit: true,
- },
- ]);
-
- return res.json({
- messages: messagesDto,
- total_results: messages.length,
- });
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/premium.ts b/src/api/routes/guilds/#guild_id/premium.ts
deleted file mode 100644
index 75361ac6..00000000
--- a/src/api/routes/guilds/#guild_id/premium.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-const router = Router();
-
-router.get("/subscriptions", route({}), async (req: Request, res: Response) => {
- // TODO:
- res.json([]);
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/profile/index.ts b/src/api/routes/guilds/#guild_id/profile/index.ts
deleted file mode 100644
index 20a7fa95..00000000
--- a/src/api/routes/guilds/#guild_id/profile/index.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { route } from "@fosscord/api";
-import {
- emitEvent,
- GuildMemberUpdateEvent,
- handleFile,
- Member,
- MemberChangeProfileSchema,
- OrmUtils,
-} from "@fosscord/util";
-import { Request, Response, Router } from "express";
-
-const router = Router();
-
-router.patch(
- "/:member_id",
- route({ body: "MemberChangeProfileSchema" }),
- async (req: Request, res: Response) => {
- let { guild_id, member_id } = req.params;
- if (member_id === "@me") member_id = req.user_id;
- const body = req.body as MemberChangeProfileSchema;
-
- let member = await Member.findOneOrFail({
- where: { id: req.user_id, guild_id },
- relations: ["roles", "user"],
- });
-
- if (body.banner)
- body.banner = await handleFile(
- `/guilds/${guild_id}/users/${req.user_id}/avatars`,
- body.banner as string,
- );
-
- member = await OrmUtils.mergeDeep(member, body);
-
- await member.save();
-
- // do not use promise.all as we have to first write to db before emitting the event to catch errors
- await emitEvent({
- event: "GUILD_MEMBER_UPDATE",
- guild_id,
- data: { ...member, roles: member.roles.map((x) => x.id) },
- } as GuildMemberUpdateEvent);
-
- res.json(member);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
deleted file mode 100644
index 8089ad84..00000000
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Router, Request, Response } from "express";
-import { Guild, Member, Snowflake } from "@fosscord/util";
-import { LessThan, IsNull } from "typeorm";
-import { route } from "@fosscord/api";
-const router = Router();
-
-//Returns all inactive members, respecting role hierarchy
-export const inactiveMembers = async (
- guild_id: string,
- user_id: string,
- days: number,
- roles: string[] = [],
-) => {
- var date = new Date();
- date.setDate(date.getDate() - days);
- //Snowflake should have `generateFromTime` method? Or similar?
- var minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22);
-
- /**
- idea: ability to customise the cutoff variable
- possible candidates: public read receipt, last presence, last VC leave
- **/
- var members = await Member.find({
- where: [
- {
- guild_id,
- last_message_id: LessThan(minId.toString()),
- },
- {
- guild_id,
- last_message_id: IsNull(),
- },
- ],
- relations: ["roles"],
- });
- if (!members.length) return [];
-
- //I'm sure I can do this in the above db query ( and it would probably be better to do so ), but oh well.
- if (roles.length && members.length)
- members = members.filter((user) =>
- user.roles?.some((role) => roles.includes(role.id)),
- );
-
- const me = await Member.findOneOrFail({
- where: { id: user_id, guild_id },
- relations: ["roles"],
- });
- const myHighestRole = Math.max(...(me.roles?.map((x) => x.position) || []));
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
- members = members.filter(
- (member) =>
- member.id !== guild.owner_id && //can't kick owner
- member.roles?.some(
- (role) =>
- role.position < myHighestRole || //roles higher than me can't be kicked
- me.id === guild.owner_id, //owner can kick anyone
- ),
- );
-
- return members;
-};
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const days = parseInt(req.query.days as string);
-
- var roles = req.query.include_roles;
- if (typeof roles === "string") roles = [roles]; //express will return array otherwise
-
- const members = await inactiveMembers(
- req.params.guild_id,
- req.user_id,
- days,
- roles as string[],
- );
-
- res.send({ pruned: members.length });
-});
-
-router.post(
- "/",
- route({ permission: "KICK_MEMBERS", right: "KICK_BAN_MEMBERS" }),
- async (req: Request, res: Response) => {
- const days = parseInt(req.body.days);
-
- var roles = req.query.include_roles;
- if (typeof roles === "string") roles = [roles];
-
- const { guild_id } = req.params;
- const members = await inactiveMembers(
- guild_id,
- req.user_id,
- days,
- roles as string[],
- );
-
- await Promise.all(
- members.map((x) => Member.removeFromGuild(x.id, guild_id)),
- );
-
- res.send({ purged: members.length });
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts
deleted file mode 100644
index 0b275ea4..00000000
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Config, Guild, Member } from "@fosscord/util";
-import { Request, Response, Router } from "express";
-import { getVoiceRegions, route } from "@fosscord/api";
-import { getIpAdress } from "@fosscord/api";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- //TODO we should use an enum for guild's features and not hardcoded strings
- return res.json(
- await getVoiceRegions(
- getIpAdress(req),
- guild.features.includes("VIP_REGIONS"),
- ),
- );
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
deleted file mode 100644
index 84648703..00000000
--- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { Router, Request, Response } from "express";
-import {
- Role,
- Member,
- GuildRoleUpdateEvent,
- GuildRoleDeleteEvent,
- emitEvent,
- handleFile,
- RoleModifySchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { HTTPError } from "lambert-server";
-
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id, role_id } = req.params;
- await Member.IsInGuildOrFail(req.user_id, guild_id);
- const role = await Role.findOneOrFail({ where: { guild_id, id: role_id } });
- return res.json(role);
-});
-
-router.delete(
- "/",
- route({ permission: "MANAGE_ROLES" }),
- async (req: Request, res: Response) => {
- const { guild_id, role_id } = req.params;
- if (role_id === guild_id)
- throw new HTTPError("You can't delete the @everyone role");
-
- await Promise.all([
- Role.delete({
- id: role_id,
- guild_id: guild_id,
- }),
- emitEvent({
- event: "GUILD_ROLE_DELETE",
- guild_id,
- data: {
- guild_id,
- role_id,
- },
- } as GuildRoleDeleteEvent),
- ]);
-
- res.sendStatus(204);
- },
-);
-
-// TODO: check role hierarchy
-
-router.patch(
- "/",
- route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }),
- async (req: Request, res: Response) => {
- const { role_id, guild_id } = req.params;
- const body = req.body as RoleModifySchema;
-
- if (body.icon && body.icon.length)
- body.icon = await handleFile(
- `/role-icons/${role_id}`,
- body.icon as string,
- );
- else body.icon = undefined;
-
- const role = await Role.findOneOrFail({
- where: { id: role_id, guild: { id: guild_id } },
- });
- role.assign({
- ...body,
- permissions: String(
- req.permission!.bitfield & BigInt(body.permissions || "0"),
- ),
- });
-
- await Promise.all([
- role.save(),
- emitEvent({
- event: "GUILD_ROLE_UPDATE",
- guild_id,
- data: {
- guild_id,
- role,
- },
- } as GuildRoleUpdateEvent),
- ]);
-
- res.json(role);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts
deleted file mode 100644
index 4cd47cf3..00000000
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- Role,
- getPermission,
- Member,
- GuildRoleCreateEvent,
- GuildRoleUpdateEvent,
- emitEvent,
- Config,
- DiscordApiErrors,
- RoleModifySchema,
- RolePositionUpdateSchema,
- Snowflake,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Not } from "typeorm";
-
-const router: Router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const guild_id = req.params.guild_id;
-
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- const roles = await Role.find({ where: { guild_id: guild_id } });
-
- return res.json(roles);
-});
-
-router.post(
- "/",
- route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }),
- async (req: Request, res: Response) => {
- const guild_id = req.params.guild_id;
- const body = req.body as RoleModifySchema;
-
- const role_count = await Role.count({ where: { guild_id } });
- const { maxRoles } = Config.get().limits.guild;
-
- if (role_count > maxRoles)
- throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
-
- const role = Role.create({
- // values before ...body are default and can be overriden
- position: 1,
- hoist: false,
- color: 0,
- mentionable: false,
- ...body,
- guild_id: guild_id,
- managed: false,
- permissions: String(
- req.permission!.bitfield & BigInt(body.permissions || "0"),
- ),
- tags: undefined,
- icon: undefined,
- unicode_emoji: undefined,
- id: Snowflake.generate(),
- });
-
- await Promise.all([
- role.save(),
- // Move all existing roles up one position, to accommodate the new role
- Role.createQueryBuilder("roles")
- .where({
- guild: { id: guild_id },
- name: Not("@everyone"),
- id: Not(role.id),
- })
- .update({ position: () => "position + 1" })
- .execute(),
- emitEvent({
- event: "GUILD_ROLE_CREATE",
- guild_id,
- data: {
- guild_id,
- role: role,
- },
- } as GuildRoleCreateEvent),
- ]);
-
- res.json(role);
- },
-);
-
-router.patch(
- "/",
- route({ body: "RolePositionUpdateSchema" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const body = req.body as RolePositionUpdateSchema;
-
- const perms = await getPermission(req.user_id, guild_id);
- perms.hasThrow("MANAGE_ROLES");
-
- await Promise.all(
- body.map(async (x) =>
- Role.update({ guild_id, id: x.id }, { position: x.position }),
- ),
- );
-
- const roles = await Role.find({
- where: body.map((x) => ({ id: x.id, guild_id })),
- });
-
- await Promise.all(
- roles.map((x) =>
- emitEvent({
- event: "GUILD_ROLE_UPDATE",
- guild_id,
- data: {
- guild_id,
- role: x,
- },
- } as GuildRoleUpdateEvent),
- ),
- );
-
- res.json(roles);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/stickers.ts b/src/api/routes/guilds/#guild_id/stickers.ts
deleted file mode 100644
index 3b1f5f8e..00000000
--- a/src/api/routes/guilds/#guild_id/stickers.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import {
- emitEvent,
- GuildStickersUpdateEvent,
- Member,
- Snowflake,
- Sticker,
- StickerFormatType,
- StickerType,
- uploadFile,
- ModifyGuildStickerSchema,
-} from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-import multer from "multer";
-import { HTTPError } from "lambert-server";
-const router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- res.json(await Sticker.find({ where: { guild_id } }));
-});
-
-const bodyParser = multer({
- limits: {
- fileSize: 1024 * 1024 * 100,
- fields: 10,
- files: 1,
- },
- storage: multer.memoryStorage(),
-}).single("file");
-
-router.post(
- "/",
- bodyParser,
- route({
- permission: "MANAGE_EMOJIS_AND_STICKERS",
- body: "ModifyGuildStickerSchema",
- }),
- async (req: Request, res: Response) => {
- if (!req.file) throw new HTTPError("missing file");
-
- const { guild_id } = req.params;
- const body = req.body as ModifyGuildStickerSchema;
- const id = Snowflake.generate();
-
- const [sticker] = await Promise.all([
- Sticker.create({
- ...body,
- guild_id,
- id,
- type: StickerType.GUILD,
- format_type: getStickerFormat(req.file.mimetype),
- available: true,
- }).save(),
- uploadFile(`/stickers/${id}`, req.file),
- ]);
-
- await sendStickerUpdateEvent(guild_id);
-
- res.json(sticker);
- },
-);
-
-export function getStickerFormat(mime_type: string) {
- switch (mime_type) {
- case "image/apng":
- return StickerFormatType.APNG;
- case "application/json":
- return StickerFormatType.LOTTIE;
- case "image/png":
- return StickerFormatType.PNG;
- case "image/gif":
- return StickerFormatType.GIF;
- default:
- throw new HTTPError(
- "invalid sticker format: must be png, apng or lottie",
- );
- }
-}
-
-router.get("/:sticker_id", route({}), async (req: Request, res: Response) => {
- const { guild_id, sticker_id } = req.params;
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- res.json(
- await Sticker.findOneOrFail({ where: { guild_id, id: sticker_id } }),
- );
-});
-
-router.patch(
- "/:sticker_id",
- route({
- body: "ModifyGuildStickerSchema",
- permission: "MANAGE_EMOJIS_AND_STICKERS",
- }),
- async (req: Request, res: Response) => {
- const { guild_id, sticker_id } = req.params;
- const body = req.body as ModifyGuildStickerSchema;
-
- const sticker = await Sticker.create({
- ...body,
- guild_id,
- id: sticker_id,
- }).save();
- await sendStickerUpdateEvent(guild_id);
-
- return res.json(sticker);
- },
-);
-
-async function sendStickerUpdateEvent(guild_id: string) {
- return emitEvent({
- event: "GUILD_STICKERS_UPDATE",
- guild_id: guild_id,
- data: {
- guild_id: guild_id,
- stickers: await Sticker.find({ where: { guild_id: guild_id } }),
- },
- } as GuildStickersUpdateEvent);
-}
-
-router.delete(
- "/:sticker_id",
- route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }),
- async (req: Request, res: Response) => {
- const { guild_id, sticker_id } = req.params;
-
- await Sticker.delete({ guild_id, id: sticker_id });
- await sendStickerUpdateEvent(guild_id);
-
- return res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts
deleted file mode 100644
index 3b5eddaa..00000000
--- a/src/api/routes/guilds/#guild_id/templates.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { Request, Response, Router } from "express";
-import { Guild, Template } from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-import { generateCode } from "@fosscord/api";
-
-const router: Router = Router();
-
-const TemplateGuildProjection: (keyof Guild)[] = [
- "name",
- "description",
- "region",
- "verification_level",
- "default_message_notifications",
- "explicit_content_filter",
- "preferred_locale",
- "afk_timeout",
- "roles",
- // "channels",
- "afk_channel_id",
- "system_channel_id",
- "system_channel_flags",
- "icon",
-];
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- var templates = await Template.find({
- where: { source_guild_id: guild_id },
- });
-
- return res.json(templates);
-});
-
-router.post(
- "/",
- route({ body: "TemplateCreateSchema", permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- select: TemplateGuildProjection,
- });
- const exists = await Template.findOneOrFail({
- where: { id: guild_id },
- }).catch((e) => {});
- if (exists) throw new HTTPError("Template already exists", 400);
-
- const template = await Template.create({
- ...req.body,
- code: generateCode(),
- creator_id: req.user_id,
- created_at: new Date(),
- updated_at: new Date(),
- source_guild_id: guild_id,
- serialized_source_guild: guild,
- }).save();
-
- res.json(template);
- },
-);
-
-router.delete(
- "/:code",
- route({ permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { code, guild_id } = req.params;
-
- const template = await Template.delete({
- code,
- source_guild_id: guild_id,
- });
-
- res.json(template);
- },
-);
-
-router.put(
- "/:code",
- route({ permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { code, guild_id } = req.params;
- const guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- select: TemplateGuildProjection,
- });
-
- const template = await Template.create({
- code,
- serialized_source_guild: guild,
- }).save();
-
- res.json(template);
- },
-);
-
-router.patch(
- "/:code",
- route({ body: "TemplateModifySchema", permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { code, guild_id } = req.params;
- const { name, description } = req.body;
-
- const template = await Template.create({
- code,
- name: name,
- description: description,
- source_guild_id: guild_id,
- }).save();
-
- res.json(template);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/vanity-url.ts b/src/api/routes/guilds/#guild_id/vanity-url.ts
deleted file mode 100644
index 9a96b066..00000000
--- a/src/api/routes/guilds/#guild_id/vanity-url.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import {
- Channel,
- ChannelType,
- Guild,
- Invite,
- VanityUrlSchema,
-} from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-import { HTTPError } from "lambert-server";
-
-const router = Router();
-
-const InviteRegex = /\W/g;
-
-router.get(
- "/",
- route({ permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
- if (!guild.features.includes("ALIASABLE_NAMES")) {
- const invite = await Invite.findOne({
- where: { guild_id: guild_id, vanity_url: true },
- });
- if (!invite) return res.json({ code: null });
-
- return res.json({ code: invite.code, uses: invite.uses });
- } else {
- const invite = await Invite.find({
- where: { guild_id: guild_id, vanity_url: true },
- });
- if (!invite || invite.length == 0) return res.json({ code: null });
-
- return res.json(
- invite.map((x) => ({ code: x.code, uses: x.uses })),
- );
- }
- },
-);
-
-router.patch(
- "/",
- route({ body: "VanityUrlSchema", permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const body = req.body as VanityUrlSchema;
- const code = body.code?.replace(InviteRegex, "");
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- if (!guild.features.includes("VANITY_URL"))
- throw new HTTPError("Your guild doesn't support vanity urls");
-
- if (!code || code.length === 0)
- throw new HTTPError("Code cannot be null or empty");
-
- const invite = await Invite.findOne({ where: { code } });
- if (invite) throw new HTTPError("Invite already exists");
-
- const { id } = await Channel.findOneOrFail({
- where: { guild_id, type: ChannelType.GUILD_TEXT },
- });
-
- await Invite.create({
- vanity_url: true,
- code: code,
- temporary: false,
- uses: 0,
- max_uses: 0,
- max_age: 0,
- created_at: new Date(),
- expires_at: new Date(),
- guild_id: guild_id,
- channel_id: id,
- }).save();
-
- return res.json({ code: code });
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
deleted file mode 100644
index af03a07e..00000000
--- a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import {
- Channel,
- ChannelType,
- DiscordApiErrors,
- emitEvent,
- getPermission,
- VoiceState,
- VoiceStateUpdateEvent,
- VoiceStateUpdateSchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Request, Response, Router } from "express";
-
-const router = Router();
-//TODO need more testing when community guild and voice stage channel are working
-
-router.patch(
- "/",
- route({ body: "VoiceStateUpdateSchema" }),
- async (req: Request, res: Response) => {
- const body = req.body as VoiceStateUpdateSchema;
- var { guild_id, user_id } = req.params;
- if (user_id === "@me") user_id = req.user_id;
-
- const perms = await getPermission(
- req.user_id,
- guild_id,
- body.channel_id,
- );
-
- /*
- From https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state
- You must have the MUTE_MEMBERS permission to unsuppress others. You can always suppress yourself.
- You must have the REQUEST_TO_SPEAK permission to request to speak. You can always clear your own request to speak.
- */
- if (body.suppress && user_id !== req.user_id) {
- perms.hasThrow("MUTE_MEMBERS");
- }
- if (!body.suppress) body.request_to_speak_timestamp = new Date();
- if (body.request_to_speak_timestamp) perms.hasThrow("REQUEST_TO_SPEAK");
-
- const voice_state = await VoiceState.findOne({
- where: {
- guild_id,
- channel_id: body.channel_id,
- user_id,
- },
- });
- if (!voice_state) throw DiscordApiErrors.UNKNOWN_VOICE_STATE;
-
- voice_state.assign(body);
- const channel = await Channel.findOneOrFail({
- where: { guild_id, id: body.channel_id },
- });
- if (channel.type !== ChannelType.GUILD_STAGE_VOICE) {
- throw DiscordApiErrors.CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE;
- }
-
- await Promise.all([
- voice_state.save(),
- emitEvent({
- event: "VOICE_STATE_UPDATE",
- data: voice_state,
- guild_id,
- } as VoiceStateUpdateEvent),
- ]);
- return res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/webhooks.ts b/src/api/routes/guilds/#guild_id/webhooks.ts
deleted file mode 100644
index 9c4e8a8d..00000000
--- a/src/api/routes/guilds/#guild_id/webhooks.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Router, Response, Request } from "express";
-import { route } from "@fosscord/api";
-const router = Router();
-
-//TODO: implement webhooks
-router.get("/", route({}), async (req: Request, res: Response) => {
- res.json([]);
-});
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/welcome-screen.ts b/src/api/routes/guilds/#guild_id/welcome-screen.ts
deleted file mode 100644
index 80ab138b..00000000
--- a/src/api/routes/guilds/#guild_id/welcome-screen.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Request, Response, Router } from "express";
-import { Guild, Member, GuildUpdateWelcomeScreenSchema } from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-
-const router: Router = Router();
-
-router.get("/", route({}), async (req: Request, res: Response) => {
- const guild_id = req.params.guild_id;
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- await Member.IsInGuildOrFail(req.user_id, guild_id);
-
- res.json(guild.welcome_screen);
-});
-
-router.patch(
- "/",
- route({
- body: "GuildUpdateWelcomeScreenSchema",
- permission: "MANAGE_GUILD",
- }),
- async (req: Request, res: Response) => {
- const guild_id = req.params.guild_id;
- const body = req.body as GuildUpdateWelcomeScreenSchema;
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
- if (!guild.welcome_screen.enabled)
- throw new HTTPError("Welcome screen disabled", 400);
- if (body.welcome_channels)
- guild.welcome_screen.welcome_channels = body.welcome_channels; // TODO: check if they exist and are valid
- if (body.description)
- guild.welcome_screen.description = body.description;
- if (body.enabled != null) guild.welcome_screen.enabled = body.enabled;
-
- await guild.save();
-
- res.sendStatus(204);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts
deleted file mode 100644
index 2c3124a2..00000000
--- a/src/api/routes/guilds/#guild_id/widget.json.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- Config,
- Permissions,
- Guild,
- Invite,
- Channel,
- Member,
-} from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { random, route } from "@fosscord/api";
-
-const router: Router = Router();
-
-// Undocumented API notes:
-// An invite is created for the widget_channel_id on request (only if an existing one created by the widget doesn't already exist)
-// This invite created doesn't include an inviter object like user created ones and has a default expiry of 24 hours
-// Missing user object information is intentional (https://github.com/discord/discord-api-docs/issues/1287)
-// channels returns voice channel objects where @everyone has the CONNECT permission
-// members (max 100 returned) is a sample of all members, and bots par invisible status, there exists some alphabetical distribution pattern between the members returned
-
-// https://discord.com/developers/docs/resources/guild#get-guild-widget
-// TODO: Cache the response for a guild for 5 minutes regardless of response
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404);
-
- // Fetch existing widget invite for widget channel
- var invite = await Invite.findOne({
- where: { channel_id: guild.widget_channel_id },
- });
-
- if (guild.widget_channel_id && !invite) {
- // Create invite for channel if none exists
- // TODO: Refactor invite create code to a shared function
- const max_age = 86400; // 24 hours
- const expires_at = new Date(max_age * 1000 + Date.now());
-
- invite = await Invite.create({
- code: random(),
- temporary: false,
- uses: 0,
- max_uses: 0,
- max_age: max_age,
- expires_at,
- created_at: new Date(),
- guild_id,
- channel_id: guild.widget_channel_id,
- }).save();
- }
-
- // Fetch voice channels, and the @everyone permissions object
- const channels = [] as any[];
-
- (
- await Channel.find({
- where: { guild_id: guild_id, type: 2 },
- order: { position: "ASC" },
- })
- ).filter((doc) => {
- // Only return channels where @everyone has the CONNECT permission
- if (
- doc.permission_overwrites === undefined ||
- Permissions.channelPermission(
- doc.permission_overwrites,
- Permissions.FLAGS.CONNECT,
- ) === Permissions.FLAGS.CONNECT
- ) {
- channels.push({
- id: doc.id,
- name: doc.name,
- position: doc.position,
- });
- }
- });
-
- // Fetch members
- // TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file)
- let members = await Member.find({ where: { guild_id: guild_id } });
-
- // Construct object to respond with
- const data = {
- id: guild_id,
- name: guild.name,
- instant_invite: invite?.code,
- channels: channels,
- members: members,
- presence_count: guild.presence_count,
- };
-
- res.set("Cache-Control", "public, max-age=300");
- return res.json(data);
-});
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts
deleted file mode 100644
index eaec8f07..00000000
--- a/src/api/routes/guilds/#guild_id/widget.png.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Request, Response, Router } from "express";
-import { Guild } from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-import { route } from "@fosscord/api";
-import fs from "fs";
-import path from "path";
-
-const router: Router = Router();
-
-// TODO: use svg templates instead of node-canvas for improved performance and to change it easily
-
-// https://discord.com/developers/docs/resources/guild#get-guild-widget-image
-// TODO: Cache the response
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- if (!guild.widget_enabled) throw new HTTPError("Unknown Guild", 404);
-
- // Fetch guild information
- const icon = guild.icon;
- const name = guild.name;
- const presence = guild.presence_count + " ONLINE";
-
- // Fetch parameter
- const style = req.query.style?.toString() || "shield";
- if (
- !["shield", "banner1", "banner2", "banner3", "banner4"].includes(style)
- ) {
- throw new HTTPError(
- "Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
- 400,
- );
- }
-
- // Setup canvas
- const { createCanvas } = require("canvas");
- const { loadImage } = require("canvas");
- const sizeOf = require("image-size");
-
- // TODO: Widget style templates need Fosscord branding
- const source = path.join(
- __dirname,
- "..",
- "..",
- "..",
- "..",
- "..",
- "assets",
- "widget",
- `${style}.png`,
- );
- if (!fs.existsSync(source)) {
- throw new HTTPError("Widget template does not exist.", 400);
- }
-
- // Create base template image for parameter
- const { width, height } = await sizeOf(source);
- const canvas = createCanvas(width, height);
- const ctx = canvas.getContext("2d");
- const template = await loadImage(source);
- ctx.drawImage(template, 0, 0);
-
- // Add the guild specific information to the template asset image
- switch (style) {
- case "shield":
- ctx.textAlign = "center";
- await drawText(
- ctx,
- 73,
- 13,
- "#FFFFFF",
- "thin 10px Verdana",
- presence,
- );
- break;
- case "banner1":
- if (icon) await drawIcon(ctx, 20, 27, 50, icon);
- await drawText(ctx, 83, 51, "#FFFFFF", "12px Verdana", name, 22);
- await drawText(
- ctx,
- 83,
- 66,
- "#C9D2F0FF",
- "thin 11px Verdana",
- presence,
- );
- break;
- case "banner2":
- if (icon) await drawIcon(ctx, 13, 19, 36, icon);
- await drawText(ctx, 62, 34, "#FFFFFF", "12px Verdana", name, 15);
- await drawText(
- ctx,
- 62,
- 49,
- "#C9D2F0FF",
- "thin 11px Verdana",
- presence,
- );
- break;
- case "banner3":
- if (icon) await drawIcon(ctx, 20, 20, 50, icon);
- await drawText(ctx, 83, 44, "#FFFFFF", "12px Verdana", name, 27);
- await drawText(
- ctx,
- 83,
- 58,
- "#C9D2F0FF",
- "thin 11px Verdana",
- presence,
- );
- break;
- case "banner4":
- if (icon) await drawIcon(ctx, 21, 136, 50, icon);
- await drawText(ctx, 84, 156, "#FFFFFF", "13px Verdana", name, 27);
- await drawText(
- ctx,
- 84,
- 171,
- "#C9D2F0FF",
- "thin 12px Verdana",
- presence,
- );
- break;
- default:
- throw new HTTPError(
- "Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
- 400,
- );
- }
-
- // Return final image
- const buffer = canvas.toBuffer("image/png");
- res.set("Content-Type", "image/png");
- res.set("Cache-Control", "public, max-age=3600");
- return res.send(buffer);
-});
-
-async function drawIcon(
- canvas: any,
- x: number,
- y: number,
- scale: number,
- icon: string,
-) {
- // @ts-ignore
- const img = new require("canvas").Image();
- img.src = icon;
-
- // Do some canvas clipping magic!
- canvas.save();
- canvas.beginPath();
-
- const r = scale / 2; // use scale to determine radius
- canvas.arc(x + r, y + r, r, 0, 2 * Math.PI, false); // start circle at x, and y coords + radius to find center
-
- canvas.clip();
- canvas.drawImage(img, x, y, scale, scale);
-
- canvas.restore();
-}
-
-async function drawText(
- canvas: any,
- x: number,
- y: number,
- color: string,
- font: string,
- text: string,
- maxcharacters?: number,
-) {
- canvas.fillStyle = color;
- canvas.font = font;
- if (text.length > (maxcharacters || 0) && maxcharacters)
- text = text.slice(0, maxcharacters) + "...";
- canvas.fillText(text, x, y);
-}
-
-export default router;
diff --git a/src/api/routes/guilds/#guild_id/widget.ts b/src/api/routes/guilds/#guild_id/widget.ts
deleted file mode 100644
index 108339e1..00000000
--- a/src/api/routes/guilds/#guild_id/widget.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Request, Response, Router } from "express";
-import { Guild, WidgetModifySchema } from "@fosscord/util";
-import { route } from "@fosscord/api";
-
-const router: Router = Router();
-
-// https://discord.com/developers/docs/resources/guild#get-guild-widget-settings
-router.get("/", route({}), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
-
- const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
- return res.json({
- enabled: guild.widget_enabled || false,
- channel_id: guild.widget_channel_id || null,
- });
-});
-
-// https://discord.com/developers/docs/resources/guild#modify-guild-widget
-router.patch(
- "/",
- route({ body: "WidgetModifySchema", permission: "MANAGE_GUILD" }),
- async (req: Request, res: Response) => {
- const body = req.body as WidgetModifySchema;
- const { guild_id } = req.params;
-
- await Guild.update(
- { id: guild_id },
- {
- widget_enabled: body.enabled,
- widget_channel_id: body.channel_id,
- },
- );
- // Widget invite for the widget_channel_id gets created as part of the /guilds/{guild.id}/widget.json request
-
- return res.json(body);
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
deleted file mode 100644
index 69575aea..00000000
--- a/src/api/routes/guilds/index.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Router, Request, Response } from "express";
-import {
- Role,
- Guild,
- Config,
- getRights,
- Member,
- DiscordApiErrors,
- GuildCreateSchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-
-const router: Router = Router();
-
-//TODO: create default channel
-
-router.post(
- "/",
- route({ body: "GuildCreateSchema", right: "CREATE_GUILDS" }),
- async (req: Request, res: Response) => {
- const body = req.body as GuildCreateSchema;
-
- const { maxGuilds } = Config.get().limits.user;
- const guild_count = await Member.count({ where: { id: req.user_id } });
- const rights = await getRights(req.user_id);
- if (guild_count >= maxGuilds && !rights.has("MANAGE_GUILDS")) {
- throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
- }
-
- const guild = await Guild.createGuild({
- ...body,
- owner_id: req.user_id,
- });
-
- const { autoJoin } = Config.get().guild;
- if (autoJoin.enabled && !autoJoin.guilds?.length) {
- // @ts-ignore
- await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
- }
-
- await Member.addToGuild(req.user_id, guild.id);
-
- res.status(201).json({ id: guild.id });
- },
-);
-
-export default router;
diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts
deleted file mode 100644
index 240bf074..00000000
--- a/src/api/routes/guilds/templates/index.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { Request, Response, Router } from "express";
-import {
- Template,
- Guild,
- Role,
- Snowflake,
- Config,
- Member,
- GuildTemplateCreateSchema,
-} from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { DiscordApiErrors } from "@fosscord/util";
-import fetch from "node-fetch";
-const router: Router = Router();
-
-router.get("/:code", route({}), async (req: Request, res: Response) => {
- const { allowDiscordTemplates, allowRaws, enabled } =
- Config.get().templates;
- if (!enabled)
- res.json({
- code: 403,
- message: "Template creation & usage is disabled on this instance.",
- }).sendStatus(403);
-
- const { code } = req.params;
-
- if (code.startsWith("discord:")) {
- if (!allowDiscordTemplates)
- return res
- .json({
- code: 403,
- message:
- "Discord templates cannot be used on this instance.",
- })
- .sendStatus(403);
- const discordTemplateID = code.split("discord:", 2)[1];
-
- const discordTemplateData = await fetch(
- `https://discord.com/api/v9/guilds/templates/${discordTemplateID}`,
- {
- method: "get",
- headers: { "Content-Type": "application/json" },
- },
- );
- return res.json(await discordTemplateData.json());
- }
-
- if (code.startsWith("external:")) {
- if (!allowRaws)
- return res
- .json({
- code: 403,
- message: "Importing raws is disabled on this instance.",
- })
- .sendStatus(403);
-
- return res.json(code.split("external:", 2)[1]);
- }
-
- const template = await Template.findOneOrFail({ where: { code: code } });
- res.json(template);
-});
-
-router.post(
- "/:code",
- route({ body: "GuildTemplateCreateSchema" }),
- async (req: Request, res: Response) => {
- const {
- enabled,
- allowTemplateCreation,
- allowDiscordTemplates,
- allowRaws,
- } = Config.get().templates;
- if (!enabled)
- return res
- .json({
- code: 403,
- message:
- "Template creation & usage is disabled on this instance.",
- })
- .sendStatus(403);
- if (!allowTemplateCreation)
- return res
- .json({
- code: 403,
- message: "Template creation is disabled on this instance.",
- })
- .sendStatus(403);
-
- const { code } = req.params;
- const body = req.body as GuildTemplateCreateSchema;
-
- const { maxGuilds } = Config.get().limits.user;
-
- const guild_count = await Member.count({ where: { id: req.user_id } });
- if (guild_count >= maxGuilds) {
- throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
- }
-
- const template = await Template.findOneOrFail({
- where: { code: code },
- });
-
- const guild_id = Snowflake.generate();
-
- const [guild, role] = await Promise.all([
- Guild.create({
- ...body,
- ...template.serialized_source_guild,
- id: guild_id,
- owner_id: req.user_id,
- }).save(),
- Role.create({
- id: guild_id,
- guild_id: guild_id,
- color: 0,
- hoist: false,
- managed: true,
- mentionable: true,
- name: "@everyone",
- permissions: BigInt("2251804225").toString(), // TODO: where did this come from?
- position: 0,
- }).save(),
- ]);
-
- await Member.addToGuild(req.user_id, guild_id);
-
- res.status(201).json({ id: guild.id });
- },
-);
-
-export default router;
|