diff --git a/src/api/routes/guilds/#guild_id/audit-logs.ts b/src/api/routes/guilds/#guild_id/audit-logs.ts
index b54835fc..76a11f6b 100644
--- a/src/api/routes/guilds/#guild_id/audit-logs.ts
+++ b/src/api/routes/guilds/#guild_id/audit-logs.ts
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
webhooks: [],
guild_scheduled_events: [],
threads: [],
- application_commands: []
+ 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
index ed00f9c0..930985d7 100644
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ b/src/api/routes/guilds/#guild_id/bans.ts
@@ -1,5 +1,15 @@
import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, GuildBanAddEvent, GuildBanRemoveEvent, Ban, User, Member, BanRegistrySchema, BanModeratorSchema } from "@fosscord/util";
+import {
+ DiscordApiErrors,
+ emitEvent,
+ GuildBanAddEvent,
+ GuildBanRemoveEvent,
+ Ban,
+ User,
+ Member,
+ BanRegistrySchema,
+ BanModeratorSchema,
+} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { getIpAdress, route } from "@fosscord/api";
@@ -7,150 +17,184 @@ 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;
+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[] = [];
+ 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.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));
- });
+ bans.forEach((ban) => {
+ promisesToAwait.push(User.getPublicUser(ban.user_id));
+ });
- const bannedUsers: object[] = await Promise.all(promisesToAwait);
+ 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
- }
+ 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);
-});
+ 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;
+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;
+ 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
+ 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. */
+ /* Filter secret from registry. */
- ban = ban as BanModeratorSchema;
+ ban = ban as BanModeratorSchema;
- delete ban.ip;
+ delete ban.ip;
- return res.json(ban);
-});
+ 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;
+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.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);
+ 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 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
- });
+ 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: {
+ 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,
- user: banned_user
- },
- guild_id: guild_id
- } as GuildBanAddEvent)
- ]);
+ } as GuildBanAddEvent),
+ ]);
- return res.json(ban);
-});
+ return res.json(ban);
+ },
+);
-router.put("/@me", route({ body: "BanCreateSchema" }), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
+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);
+ 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);
+ 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
- });
+ 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: {
+ 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,
- user: banned_user
- },
- guild_id: guild_id
- } as GuildBanAddEvent)
- ]);
+ } as GuildBanAddEvent),
+ ]);
- return res.json(ban);
-});
+ return res.json(ban);
+ },
+);
-router.delete("/:user_id", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => {
- const { guild_id, user_id } = req.params;
+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 } });
+ 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
+ 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);
+ const banned_user = await User.getPublicUser(user_id);
- await Promise.all([
- Ban.delete({
- user_id: user_id,
- guild_id
- }),
+ await Promise.all([
+ Ban.delete({
+ user_id: user_id,
+ guild_id,
+ }),
- emitEvent({
- event: "GUILD_BAN_REMOVE",
- data: {
+ emitEvent({
+ event: "GUILD_BAN_REMOVE",
+ data: {
+ guild_id,
+ user: banned_user,
+ },
guild_id,
- user: banned_user
- },
- guild_id
- } as GuildBanRemoveEvent)
- ]);
+ } as GuildBanRemoveEvent),
+ ]);
- return res.status(204).send();
-});
+ 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
index 7a5b50d1..af17465d 100644
--- a/src/api/routes/guilds/#guild_id/channels.ts
+++ b/src/api/routes/guilds/#guild_id/channels.ts
@@ -1,5 +1,10 @@
import { Router, Response, Request } from "express";
-import { Channel, ChannelUpdateEvent, emitEvent, ChannelModifySchema } from "@fosscord/util";
+import {
+ Channel,
+ ChannelUpdateEvent,
+ emitEvent,
+ ChannelModifySchema,
+} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { route } from "@fosscord/api";
const router = Router();
@@ -11,49 +16,77 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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;
+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);
+ const channel = await Channel.createChannel(
+ { ...body, guild_id },
+ req.user_id,
+ );
- res.status(201).json(channel);
-});
+ res.status(201).json(channel);
+ },
+);
-export type ChannelReorderSchema = { id: string; position?: number; lock_permissions?: boolean; parent_id?: string; }[];
+export type ChannelReorderSchema = {
+ id: string;
+ position?: number;
+ lock_permissions?: boolean;
+ parent_id?: string;
+}[];
-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;
+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);
+ 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;
+ 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;
+ 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 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);
- })
- ]);
+ await emitEvent({
+ event: "CHANNEL_UPDATE",
+ data: channel,
+ channel_id: x.id,
+ guild_id,
+ } as ChannelUpdateEvent);
+ }),
+ ]);
- res.sendStatus(204);
-});
+ 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
index bd158c56..b951e4f4 100644
--- a/src/api/routes/guilds/#guild_id/delete.ts
+++ b/src/api/routes/guilds/#guild_id/delete.ts
@@ -1,4 +1,14 @@
-import { Channel, emitEvent, GuildDeleteEvent, Guild, Member, Message, Role, Invite, Emoji } from "@fosscord/util";
+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";
@@ -10,18 +20,22 @@ const router = Router();
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);
+ 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
+ id: guild_id,
},
- guild_id: guild_id
- } as GuildDeleteEvent)
+ guild_id: guild_id,
+ } as GuildDeleteEvent),
]);
return res.sendStatus(204);
diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
index ad20633f..7e63c06b 100644
--- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts
+++ b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
@@ -6,33 +6,33 @@ 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
+ 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
+ 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,
});
});
diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts
index cf9d742a..6e8570eb 100644
--- a/src/api/routes/guilds/#guild_id/emojis.ts
+++ b/src/api/routes/guilds/#guild_id/emojis.ts
@@ -1,5 +1,17 @@
import { Router, Request, Response } from "express";
-import { Config, DiscordApiErrors, emitEvent, Emoji, GuildEmojisUpdateEvent, handleFile, Member, Snowflake, User, EmojiCreateSchema, EmojiModifySchema } from "@fosscord/util";
+import {
+ Config,
+ DiscordApiErrors,
+ emitEvent,
+ Emoji,
+ GuildEmojisUpdateEvent,
+ handleFile,
+ Member,
+ Snowflake,
+ User,
+ EmojiCreateSchema,
+ EmojiModifySchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
const router = Router();
@@ -9,7 +21,10 @@ router.get("/", route({}), async (req: Request, res: Response) => {
await Member.IsInGuildOrFail(req.user_id, guild_id);
- const emojis = await Emoji.find({ where: { guild_id: guild_id }, relations: ["user"] });
+ const emojis = await Emoji.find({
+ where: { guild_id: guild_id },
+ relations: ["user"],
+ });
return res.json(emojis);
});
@@ -19,89 +34,115 @@ router.get("/:emoji_id", route({}), async (req: Request, res: Response) => {
await Member.IsInGuildOrFail(req.user_id, guild_id);
- const emoji = await Emoji.findOneOrFail({ where: { guild_id: guild_id, id: emoji_id }, relations: ["user"] });
+ 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;
+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;
+ 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;
+ 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 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();
+ 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: {
+ await emitEvent({
+ event: "GUILD_EMOJIS_UPDATE",
guild_id: guild_id,
- emojis: await Emoji.find({ where: { guild_id: guild_id } })
- }
- } as GuildEmojisUpdateEvent);
+ data: {
+ guild_id: guild_id,
+ emojis: await Emoji.find({ where: { guild_id: guild_id } }),
+ },
+ } as GuildEmojisUpdateEvent);
- return res.status(201).json(emoji);
-});
+ return res.status(201).json(emoji);
+ },
+);
router.patch(
"/:emoji_id",
- route({ body: "EmojiModifySchema", permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+ 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();
+ 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 } })
- }
+ 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;
+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 Emoji.delete({
+ id: emoji_id,
+ guild_id: guild_id,
+ });
- await emitEvent({
- event: "GUILD_EMOJIS_UPDATE",
- guild_id: guild_id,
- data: {
+ await emitEvent({
+ event: "GUILD_EMOJIS_UPDATE",
guild_id: guild_id,
- emojis: await Emoji.find({ where: { guild_id: guild_id } })
- }
- } as GuildEmojisUpdateEvent);
+ data: {
+ guild_id: guild_id,
+ emojis: await Emoji.find({ where: { guild_id: guild_id } }),
+ },
+ } as GuildEmojisUpdateEvent);
- res.sendStatus(204);
-});
+ 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
index afeb0938..715a3835 100644
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/index.ts
@@ -1,5 +1,15 @@
import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, getPermission, getRights, Guild, GuildUpdateEvent, handleFile, Member, GuildCreateSchema } from "@fosscord/util";
+import {
+ DiscordApiErrors,
+ emitEvent,
+ getPermission,
+ getRights,
+ Guild,
+ GuildUpdateEvent,
+ handleFile,
+ Member,
+ GuildCreateSchema,
+} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { route } from "@fosscord/api";
@@ -26,9 +36,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
const [guild, member] = await Promise.all([
Guild.findOneOrFail({ where: { id: guild_id } }),
- Member.findOne({ where: { guild_id: guild_id, id: req.user_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);
+ 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;
@@ -36,39 +50,57 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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;
-
+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);
+ 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_GUILD");
+ if (!rights.has("MANAGE_GUILDS") || !permission.has("MANAGE_GUILD"))
+ throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(
+ "MANAGE_GUILD",
+ );
- // TODO: guild update check image
+ // TODO: guild update check image
- if (body.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
- if (body.banner) body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
- if (body.splash) body.splash = await handleFile(`/splashes/${guild_id}`, body.splash);
+ if (body.icon)
+ body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
+ if (body.banner)
+ body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
+ if (body.splash)
+ body.splash = await handleFile(
+ `/splashes/${guild_id}`,
+ body.splash,
+ );
- var guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- relations: ["emojis", "roles", "stickers"]
- });
- // TODO: check if body ids are valid
- guild.assign(body);
+ var guild = await Guild.findOneOrFail({
+ where: { id: guild_id },
+ relations: ["emojis", "roles", "stickers"],
+ });
+ // 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;
+ 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)]);
+ await Promise.all([
+ guild.save(),
+ emitEvent({
+ event: "GUILD_UPDATE",
+ data,
+ guild_id,
+ } as GuildUpdateEvent),
+ ]);
- return res.json(data);
-});
+ return res.json(data);
+ },
+);
export default router;
diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts
index b7534e31..4d033e9c 100644
--- a/src/api/routes/guilds/#guild_id/invites.ts
+++ b/src/api/routes/guilds/#guild_id/invites.ts
@@ -4,12 +4,19 @@ 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;
+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 });
+ const invites = await Invite.find({
+ where: { guild_id },
+ relations: PublicInviteRelation,
+ });
- return res.json(invites);
-});
+ 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
index 265a1b35..c2f946b2 100644
--- a/src/api/routes/guilds/#guild_id/member-verification.ts
+++ b/src/api/routes/guilds/#guild_id/member-verification.ts
@@ -2,12 +2,12 @@ import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
const router = Router();
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
// TODO: member verification
res.status(404).json({
message: "Unknown Guild Member Verification Form",
- code: 10068
+ code: 10068,
});
});
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
index 407619d3..2d867920 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
@@ -1,5 +1,16 @@
import { Request, Response, Router } from "express";
-import { Member, getPermission, getRights, Role, GuildMemberUpdateEvent, emitEvent, Sticker, Emoji, Guild, MemberChangeSchema } from "@fosscord/util";
+import {
+ Member,
+ getPermission,
+ getRights,
+ Role,
+ GuildMemberUpdateEvent,
+ emitEvent,
+ Sticker,
+ Emoji,
+ Guild,
+ MemberChangeSchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
const router = Router();
@@ -8,48 +19,63 @@ 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 } });
+ 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;
+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;
- const 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 } });
+ const 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.roles) {
- permission.hasThrow("MANAGE_ROLES");
+ if (body.roles) {
+ permission.hasThrow("MANAGE_ROLES");
- 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
- }
+ 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
+ }
- if ('nick' in body) {
- permission.hasThrow(req.user_id == member.user.id ? "CHANGE_NICKNAME" : "MANAGE_NICKNAMES");
- member.nick = body.nick?.trim() || undefined;
- }
+ if ("nick" in body) {
+ permission.hasThrow(
+ req.user_id == member.user.id
+ ? "CHANGE_NICKNAME"
+ : "MANAGE_NICKNAMES",
+ );
+ member.nick = body.nick?.trim() || undefined;
+ }
- await member.save();
+ await member.save();
- member.roles = member.roles.filter((x) => x.id !== everyone.id);
+ 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);
+ // 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);
-});
+ res.json(member);
+ },
+);
router.put("/", route({}), async (req: Request, res: Response) => {
-
// TODO: Lurker mode
const rights = await getRights(req.user_id);
@@ -59,23 +85,23 @@ router.put("/", route({}), async (req: Request, res: Response) => {
member_id = req.user_id;
rights.hasThrow("JOIN_GUILDS");
} else {
- // TODO: join others by controller
+ // TODO: join others by controller
}
var guild = await Guild.findOneOrFail({
- where: { id: guild_id }
+ where: { id: guild_id },
});
var emoji = await Emoji.find({
- where: { guild_id: guild_id }
+ where: { guild_id: guild_id },
});
var roles = await Role.find({
- where: { guild_id: guild_id }
+ where: { guild_id: guild_id },
});
var stickers = await Sticker.find({
- where: { guild_id: guild_id }
+ where: { guild_id: guild_id },
});
await Member.addToGuild(member_id, guild_id);
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
index edd47605..20443821 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
@@ -4,19 +4,23 @@ 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";
- }
+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);
+ 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();
-});
+ 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
index 8f5ca7ba..c0383912 100644
--- 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
@@ -4,18 +4,26 @@ 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;
+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);
-});
+ 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;
+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);
-});
+ 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
index b730a4e7..b516b9e9 100644
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/index.ts
@@ -12,7 +12,8 @@ const router = Router();
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");
+ 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) } : {};
@@ -22,7 +23,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
where: { guild_id, ...query },
select: PublicMemberProjection,
take: limit,
- order: { id: "ASC" }
+ order: { id: "ASC" },
});
return res.json(members);
diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts
index a7516ebd..f2d8087e 100644
--- a/src/api/routes/guilds/#guild_id/messages/search.ts
+++ b/src/api/routes/guilds/#guild_id/messages/search.ts
@@ -10,36 +10,62 @@ router.get("/", route({}), async (req: Request, res: Response) => {
const {
channel_id,
content,
- include_nsfw, // TODO
+ include_nsfw, // TODO
offset,
sort_order,
- sort_by, // TODO: Handle 'relevance'
+ 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 (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
+ 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);
+ const permissions = await getPermission(
+ req.user_id,
+ req.params.guild_id,
+ channel_id as string,
+ );
permissions.hasThrow("VIEW_CHANNEL");
- if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 });
+ 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" },
+ 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"],
+ relations: [
+ "author",
+ "webhook",
+ "application",
+ "mentions",
+ "mention_roles",
+ "mention_channels",
+ "sticker_items",
+ "attachments",
+ ],
skip: offset ? Number(offset) : 0,
};
//@ts-ignore
@@ -51,32 +77,34 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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,
+ 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,
},
- 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,
@@ -84,4 +112,4 @@ router.get("/", route({}), async (req: Request, res: Response) => {
});
});
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
index 2e674349..d11244b1 100644
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ b/src/api/routes/guilds/#guild_id/prune.ts
@@ -5,7 +5,12 @@ 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[] = []) => {
+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?
@@ -19,21 +24,27 @@ export const inactiveMembers = async (guild_id: string, user_id: string, days: n
where: [
{
guild_id,
- last_message_id: LessThan(minId.toString())
+ last_message_id: LessThan(minId.toString()),
},
{
- last_message_id: IsNull()
- }
+ last_message_id: IsNull(),
+ },
],
- relations: ["roles"]
+ relations: ["roles"],
});
console.log(members);
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)));
+ 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 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 } });
@@ -44,8 +55,8 @@ export const inactiveMembers = async (guild_id: string, user_id: string, days: n
member.roles?.some(
(role) =>
role.position < myHighestRole || //roles higher than me can't be kicked
- me.id === guild.owner_id //owner can kick anyone
- )
+ me.id === guild.owner_id, //owner can kick anyone
+ ),
);
return members;
@@ -57,23 +68,39 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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[]);
+ 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);
+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];
+ 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[]);
+ 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)));
+ await Promise.all(
+ members.map((x) => Member.removeFromGuild(x.id, guild_id)),
+ );
- res.send({ purged: members.length });
-});
+ 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
index 308d5ee5..0b275ea4 100644
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ b/src/api/routes/guilds/#guild_id/regions.ts
@@ -9,7 +9,12 @@ 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")));
+ 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
index 87cf5261..e274e3d0 100644
--- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
@@ -1,5 +1,13 @@
import { Router, Request, Response } from "express";
-import { Role, Member, GuildRoleUpdateEvent, GuildRoleDeleteEvent, emitEvent, handleFile, RoleModifySchema } from "@fosscord/util";
+import {
+ Role,
+ Member,
+ GuildRoleUpdateEvent,
+ GuildRoleDeleteEvent,
+ emitEvent,
+ handleFile,
+ RoleModifySchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
import { HTTPError } from "lambert-server";
@@ -12,57 +20,72 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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");
+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: {
+ await Promise.all([
+ Role.delete({
+ id: role_id,
+ guild_id: guild_id,
+ }),
+ emitEvent({
+ event: "GUILD_ROLE_DELETE",
guild_id,
- role_id
- }
- } as GuildRoleDeleteEvent)
- ]);
+ data: {
+ guild_id,
+ role_id,
+ },
+ } as GuildRoleDeleteEvent),
+ ]);
- res.sendStatus(204);
-});
+ 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;
+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;
+ if (body.icon && body.icon.length)
+ body.icon = await handleFile(
+ `/role-icons/${role_id}`,
+ body.icon as string,
+ );
+ else body.icon = undefined;
- const role = Role.create({
- ...body,
- id: role_id,
- guild_id,
- permissions: String(req.permission!.bitfield & BigInt(body.permissions || "0"))
- });
-
- await Promise.all([
- role.save(),
- emitEvent({
- event: "GUILD_ROLE_UPDATE",
+ const role = Role.create({
+ ...body,
+ id: role_id,
guild_id,
- data: {
+ permissions: String(
+ req.permission!.bitfield & BigInt(body.permissions || "0"),
+ ),
+ });
+
+ await Promise.all([
+ role.save(),
+ emitEvent({
+ event: "GUILD_ROLE_UPDATE",
guild_id,
- role
- }
- } as GuildRoleUpdateEvent)
- ]);
+ data: {
+ guild_id,
+ role,
+ },
+ } as GuildRoleUpdateEvent),
+ ]);
- res.json(role);
-});
+ 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
index c5a86400..e3c7373e 100644
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/index.ts
@@ -29,70 +29,87 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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;
+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;
+ 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);
+ if (role_count > maxRoles)
+ throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
- const role = Role.create({
- // values before ...body are default and can be overriden
- position: 0,
- 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
- });
+ const role = Role.create({
+ // values before ...body are default and can be overriden
+ position: 0,
+ 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,
+ });
- await Promise.all([
- role.save(),
- emitEvent({
- event: "GUILD_ROLE_CREATE",
- guild_id,
- data: {
+ await Promise.all([
+ role.save(),
+ emitEvent({
+ event: "GUILD_ROLE_CREATE",
guild_id,
- role: role
- }
- } as GuildRoleCreateEvent)
- ]);
+ data: {
+ guild_id,
+ role: role,
+ },
+ } as GuildRoleCreateEvent),
+ ]);
- res.json(role);
-});
+ res.json(role);
+ },
+);
-router.patch("/", route({ body: "RolePositionUpdateSchema" }), async (req: Request, res: Response) => {
- const { guild_id } = req.params;
- const body = req.body as RolePositionUpdateSchema;
+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");
+ 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 })));
+ 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 })) });
+ 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: {
+ await Promise.all(
+ roles.map((x) =>
+ emitEvent({
+ event: "GUILD_ROLE_UPDATE",
guild_id,
- role: x
- }
- } as GuildRoleUpdateEvent)
- )
- );
+ data: {
+ guild_id,
+ role: x,
+ },
+ } as GuildRoleUpdateEvent),
+ ),
+ );
- res.json(roles);
-});
+ 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
index fc0f49ab..3b1f5f8e 100644
--- a/src/api/routes/guilds/#guild_id/stickers.ts
+++ b/src/api/routes/guilds/#guild_id/stickers.ts
@@ -26,15 +26,18 @@ const bodyParser = multer({
limits: {
fileSize: 1024 * 1024 * 100,
fields: 10,
- files: 1
+ files: 1,
},
- storage: multer.memoryStorage()
+ storage: multer.memoryStorage(),
}).single("file");
router.post(
"/",
bodyParser,
- route({ permission: "MANAGE_EMOJIS_AND_STICKERS", body: "ModifyGuildStickerSchema" }),
+ route({
+ permission: "MANAGE_EMOJIS_AND_STICKERS",
+ body: "ModifyGuildStickerSchema",
+ }),
async (req: Request, res: Response) => {
if (!req.file) throw new HTTPError("missing file");
@@ -49,15 +52,15 @@ router.post(
id,
type: StickerType.GUILD,
format_type: getStickerFormat(req.file.mimetype),
- available: true
+ available: true,
}).save(),
- uploadFile(`/stickers/${id}`, req.file)
+ uploadFile(`/stickers/${id}`, req.file),
]);
await sendStickerUpdateEvent(guild_id);
res.json(sticker);
- }
+ },
);
export function getStickerFormat(mime_type: string) {
@@ -71,7 +74,9 @@ export function getStickerFormat(mime_type: string) {
case "image/gif":
return StickerFormatType.GIF;
default:
- throw new HTTPError("invalid sticker format: must be png, apng or lottie");
+ throw new HTTPError(
+ "invalid sticker format: must be png, apng or lottie",
+ );
}
}
@@ -79,21 +84,30 @@ 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 } }));
+ res.json(
+ await Sticker.findOneOrFail({ where: { guild_id, id: sticker_id } }),
+ );
});
router.patch(
"/:sticker_id",
- route({ body: "ModifyGuildStickerSchema", permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+ 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();
+ 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) {
@@ -102,18 +116,22 @@ async function sendStickerUpdateEvent(guild_id: string) {
guild_id: guild_id,
data: {
guild_id: guild_id,
- stickers: await Sticker.find({ where: { 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;
+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);
+ await Sticker.delete({ guild_id, id: sticker_id });
+ await sendStickerUpdateEvent(guild_id);
- return res.sendStatus(204);
-});
+ 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
index 628321f5..3b5eddaa 100644
--- a/src/api/routes/guilds/#guild_id/templates.ts
+++ b/src/api/routes/guilds/#guild_id/templates.ts
@@ -20,63 +20,97 @@ const TemplateGuildProjection: (keyof Guild)[] = [
"afk_channel_id",
"system_channel_id",
"system_channel_flags",
- "icon"
+ "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 } });
+ 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);
+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();
+ 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);
-});
+ res.json(template);
+ },
+);
-router.delete("/:code", route({ permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
- const { code, guild_id } = req.params;
+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
- });
+ const template = await Template.delete({
+ code,
+ source_guild_id: guild_id,
+ });
- res.json(template);
-});
+ 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 });
+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();
+ const template = await Template.create({
+ code,
+ serialized_source_guild: guild,
+ }).save();
- res.json(template);
-});
+ 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;
+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();
+ const template = await Template.create({
+ code,
+ name: name,
+ description: description,
+ source_guild_id: guild_id,
+ }).save();
- res.json(template);
-});
+ 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
index d1fe4726..9a96b066 100644
--- a/src/api/routes/guilds/#guild_id/vanity-url.ts
+++ b/src/api/routes/guilds/#guild_id/vanity-url.ts
@@ -1,4 +1,10 @@
-import { Channel, ChannelType, Guild, Invite, VanityUrlSchema } from "@fosscord/util";
+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";
@@ -7,52 +13,70 @@ 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 } });
+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 });
+ 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({ 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 })));
- }
-});
+ 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, "");
+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");
+ 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");
+ 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 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 } });
+ 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();
+ 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 });
-});
+ 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
index 006e997f..af03a07e 100644
--- 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
@@ -1,52 +1,71 @@
-import { Channel, ChannelType, DiscordApiErrors, emitEvent, getPermission, VoiceState, VoiceStateUpdateEvent, VoiceStateUpdateSchema } from "@fosscord/util";
+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;
+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);
+ 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 (body.suppress && user_id !== req.user_id) {
+ perms.hasThrow("MUTE_MEMBERS");
}
- });
- if (!voice_state) throw DiscordApiErrors.UNKNOWN_VOICE_STATE;
+ if (!body.suppress) body.request_to_speak_timestamp = new Date();
+ if (body.request_to_speak_timestamp) perms.hasThrow("REQUEST_TO_SPEAK");
- 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;
- }
+ 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);
-});
+ 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/welcome-screen.ts b/src/api/routes/guilds/#guild_id/welcome-screen.ts
index 57da062d..80ab138b 100644
--- a/src/api/routes/guilds/#guild_id/welcome-screen.ts
+++ b/src/api/routes/guilds/#guild_id/welcome-screen.ts
@@ -14,20 +14,30 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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;
+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 } });
+ 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;
+ 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();
+ await guild.save();
- res.sendStatus(204);
-});
+ 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
index be5bf23f..2c3124a2 100644
--- a/src/api/routes/guilds/#guild_id/widget.json.ts
+++ b/src/api/routes/guilds/#guild_id/widget.json.ts
@@ -1,5 +1,12 @@
import { Request, Response, Router } from "express";
-import { Config, Permissions, Guild, Invite, Channel, Member } from "@fosscord/util";
+import {
+ Config,
+ Permissions,
+ Guild,
+ Invite,
+ Channel,
+ Member,
+} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { random, route } from "@fosscord/api";
@@ -21,7 +28,9 @@ router.get("/", route({}), async (req: Request, res: Response) => {
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 } });
+ 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
@@ -45,16 +54,24 @@ router.get("/", route({}), async (req: Request, res: Response) => {
// 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) => {
+ (
+ 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
+ Permissions.channelPermission(
+ doc.permission_overwrites,
+ Permissions.FLAGS.CONNECT,
+ ) === Permissions.FLAGS.CONNECT
) {
channels.push({
id: doc.id,
name: doc.name,
- position: doc.position
+ position: doc.position,
});
}
});
@@ -70,7 +87,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
instant_invite: invite?.code,
channels: channels,
members: members,
- presence_count: guild.presence_count
+ presence_count: guild.presence_count,
};
res.set("Cache-Control", "public, max-age=300");
diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts
index c17d511e..eaec8f07 100644
--- a/src/api/routes/guilds/#guild_id/widget.png.ts
+++ b/src/api/routes/guilds/#guild_id/widget.png.ts
@@ -24,8 +24,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
// 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);
+ if (
+ !["shield", "banner1", "banner2", "banner3", "banner4"].includes(style)
+ ) {
+ throw new HTTPError(
+ "Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
+ 400,
+ );
}
// Setup canvas
@@ -34,7 +39,17 @@ router.get("/", route({}), async (req: Request, res: Response) => {
const sizeOf = require("image-size");
// TODO: Widget style templates need Fosscord branding
- const source = path.join(__dirname, "..", "..", "..", "..", "..", "assets", "widget", `${style}.png`);
+ const source = path.join(
+ __dirname,
+ "..",
+ "..",
+ "..",
+ "..",
+ "..",
+ "assets",
+ "widget",
+ `${style}.png`,
+ );
if (!fs.existsSync(source)) {
throw new HTTPError("Widget template does not exist.", 400);
}
@@ -50,30 +65,68 @@ router.get("/", route({}), async (req: Request, res: Response) => {
switch (style) {
case "shield":
ctx.textAlign = "center";
- await drawText(ctx, 73, 13, "#FFFFFF", "thin 10px Verdana", presence);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ throw new HTTPError(
+ "Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
+ 400,
+ );
}
// Return final image
@@ -83,7 +136,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
return res.send(buffer);
});
-async function drawIcon(canvas: any, x: number, y: number, scale: number, icon: string) {
+async function drawIcon(
+ canvas: any,
+ x: number,
+ y: number,
+ scale: number,
+ icon: string,
+) {
// @ts-ignore
const img = new require("canvas").Image();
img.src = icon;
@@ -101,10 +160,19 @@ async function drawIcon(canvas: any, x: number, y: number, scale: number, icon:
canvas.restore();
}
-async function drawText(canvas: any, x: number, y: number, color: string, font: string, text: string, maxcharacters?: number) {
+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) + "...";
+ if (text.length > (maxcharacters || 0) && maxcharacters)
+ text = text.slice(0, maxcharacters) + "...";
canvas.fillText(text, x, y);
}
diff --git a/src/api/routes/guilds/#guild_id/widget.ts b/src/api/routes/guilds/#guild_id/widget.ts
index dbb4cc0c..108339e1 100644
--- a/src/api/routes/guilds/#guild_id/widget.ts
+++ b/src/api/routes/guilds/#guild_id/widget.ts
@@ -10,18 +10,31 @@ router.get("/", route({}), async (req: Request, res: Response) => {
const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
- return res.json({ enabled: guild.widget_enabled || false, channel_id: guild.widget_channel_id || null });
+ 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;
+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
+ 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);
-});
+ return res.json(body);
+ },
+);
export default router;
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
index 0807cb96..69575aea 100644
--- a/src/api/routes/guilds/index.ts
+++ b/src/api/routes/guilds/index.ts
@@ -1,32 +1,47 @@
import { Router, Request, Response } from "express";
-import { Role, Guild, Config, getRights, Member, DiscordApiErrors, GuildCreateSchema } from "@fosscord/util";
+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;
+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 { 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 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] } } });
- }
+ 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);
+ await Member.addToGuild(req.user_id, guild.id);
- res.status(201).json({ 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
index 4e7abcc5..240bf074 100644
--- a/src/api/routes/guilds/templates/index.ts
+++ b/src/api/routes/guilds/templates/index.ts
@@ -1,29 +1,58 @@
import { Request, Response, Router } from "express";
-import { Template, Guild, Role, Snowflake, Config, Member, GuildTemplateCreateSchema } from "@fosscord/util";
+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 { 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);
+ 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" }
- });
+ 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);
+ 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]);
}
@@ -32,48 +61,72 @@ router.get("/:code", route({}), async (req: Request, res: Response) => {
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);
+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 { code } = req.params;
+ const body = req.body as GuildTemplateCreateSchema;
- const { maxGuilds } = Config.get().limits.user;
+ 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 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 template = await Template.findOneOrFail({
+ where: { code: code },
+ });
- const guild_id = Snowflake.generate();
+ 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()
- ]);
+ 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);
+ await Member.addToGuild(req.user_id, guild_id);
- res.status(201).json({ id: guild.id });
-});
+ res.status(201).json({ id: guild.id });
+ },
+);
export default router;
|