diff --git a/src/api/routes/users/@me/activities/statistics/applications.ts b/src/api/routes/users/@me/activities/statistics/applications.ts
index a9bc5961..b0119161 100644
--- a/src/api/routes/users/@me/activities/statistics/applications.ts
+++ b/src/api/routes/users/@me/activities/statistics/applications.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.json([]).status(200);
+ // TODO:
+ res.json([]).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/affinities/guilds.ts b/src/api/routes/users/@me/affinities/guilds.ts
index 30fe8879..8de9aa58 100644
--- a/src/api/routes/users/@me/affinities/guilds.ts
+++ b/src/api/routes/users/@me/affinities/guilds.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.status(200).send({ guild_affinities: [] });
+ // TODO:
+ res.status(200).send({ guild_affinities: [] });
});
export default router;
diff --git a/src/api/routes/users/@me/affinities/users.ts b/src/api/routes/users/@me/affinities/users.ts
index 038f4108..2f666252 100644
--- a/src/api/routes/users/@me/affinities/users.ts
+++ b/src/api/routes/users/@me/affinities/users.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.status(200).send({ user_affinities: [], inverse_user_affinities: [] });
+ // TODO:
+ res.status(200).send({ user_affinities: [], inverse_user_affinities: [] });
});
export default router;
diff --git a/src/api/routes/users/@me/applications/#application_id/entitlements.ts b/src/api/routes/users/@me/applications/#application_id/entitlements.ts
index f1f9a292..e8e6f657 100644
--- a/src/api/routes/users/@me/applications/#application_id/entitlements.ts
+++ b/src/api/routes/users/@me/applications/#application_id/entitlements.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router: Router = Router({ mergeParams: true });
router.get("/", route({}), async (req: Request, res: Response) => {
- //TODO
- res.json([]).status(200);
+ //TODO
+ res.json([]).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/billing/country-code.ts b/src/api/routes/users/@me/billing/country-code.ts
index 1907536a..8bddafc3 100644
--- a/src/api/routes/users/@me/billing/country-code.ts
+++ b/src/api/routes/users/@me/billing/country-code.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router: Router = Router({ mergeParams: true });
router.get("/", route({}), async (req: Request, res: Response) => {
- //TODO
- res.json({ country_code: "US" }).status(200);
+ //TODO
+ res.json({ country_code: "US" }).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/billing/location-info.ts b/src/api/routes/users/@me/billing/location-info.ts
index 3fe7f679..918ea913 100644
--- a/src/api/routes/users/@me/billing/location-info.ts
+++ b/src/api/routes/users/@me/billing/location-info.ts
@@ -22,9 +22,9 @@ import { route } from "@spacebar/api";
const router: Router = Router({ mergeParams: true });
router.get("/", route({}), async (req: Request, res: Response) => {
- //TODO
- // TODO: subdivision_code (optional)
- res.json({ country_code: "US" }).status(200);
+ //TODO
+ // TODO: subdivision_code (optional)
+ res.json({ country_code: "US" }).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/billing/payment-sources.ts b/src/api/routes/users/@me/billing/payment-sources.ts
index c2ebd3fe..1380ed52 100644
--- a/src/api/routes/users/@me/billing/payment-sources.ts
+++ b/src/api/routes/users/@me/billing/payment-sources.ts
@@ -23,59 +23,59 @@ const router = Router({ mergeParams: true });
// https://docs.discord.food/resources/billing#example-payment-source
const example = {
- id: "1422548914485198869",
- type: 1,
- invalid: false,
- flags: 2,
- deleted_at: null,
- brand: "visa",
- last_4: "4242",
- expires_month: 9,
- expires_year: 2077,
- billing_address: {
- name: "John Doe",
- line_1: "123 Main Street",
- line_2: "Apt 4B",
- city: "San Francisco",
- state: "CA",
- country: "US",
- postal_code: "94105",
- },
- country: "US",
- payment_gateway: 1,
- payment_gateway_source_id: "pm_DwiVlGlYwe1qxLzy4QWChQeo",
- default: false,
+ id: "1422548914485198869",
+ type: 1,
+ invalid: false,
+ flags: 2,
+ deleted_at: null,
+ brand: "visa",
+ last_4: "4242",
+ expires_month: 9,
+ expires_year: 2077,
+ billing_address: {
+ name: "John Doe",
+ line_1: "123 Main Street",
+ line_2: "Apt 4B",
+ city: "San Francisco",
+ state: "CA",
+ country: "US",
+ postal_code: "94105",
+ },
+ country: "US",
+ payment_gateway: 1,
+ payment_gateway_source_id: "pm_DwiVlGlYwe1qxLzy4QWChQeo",
+ default: false,
};
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json([example]).status(200);
+ // TODO: schema
+ res.json([example]).status(200);
});
router.post("/", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json([example]).status(200);
+ // TODO: schema
+ res.json([example]).status(200);
});
router.get("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json({
- ...example,
- id: req.route.payment_source_id,
- }).status(200);
+ // TODO: schema
+ res.json({
+ ...example,
+ id: req.route.payment_source_id,
+ }).status(200);
});
router.patch("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.json({
- ...example,
- id: req.route.payment_source_id,
- }).status(200);
+ // TODO: schema
+ res.json({
+ ...example,
+ id: req.route.payment_source_id,
+ }).status(200);
});
router.delete("/:payment_source_id", route({}), (req: Request, res: Response) => {
- // TODO: schema
- res.status(204);
+ // TODO: schema
+ res.status(204);
});
export default router;
diff --git a/src/api/routes/users/@me/billing/subscriptions.ts b/src/api/routes/users/@me/billing/subscriptions.ts
index f1f9a292..e8e6f657 100644
--- a/src/api/routes/users/@me/billing/subscriptions.ts
+++ b/src/api/routes/users/@me/billing/subscriptions.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router: Router = Router({ mergeParams: true });
router.get("/", route({}), async (req: Request, res: Response) => {
- //TODO
- res.json([]).status(200);
+ //TODO
+ res.json([]).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/channels.ts b/src/api/routes/users/@me/channels.ts
index 9411e72e..e13b874a 100644
--- a/src/api/routes/users/@me/channels.ts
+++ b/src/api/routes/users/@me/channels.ts
@@ -24,37 +24,37 @@ import { DmChannelCreateSchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "APIDMChannelArray",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const recipients = await Recipient.find({
- where: { user_id: req.user_id, closed: false },
- relations: ["channel", "channel.recipients"],
- });
- res.json(await Promise.all(recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id]))));
- },
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "APIDMChannelArray",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const recipients = await Recipient.find({
+ where: { user_id: req.user_id, closed: false },
+ relations: ["channel", "channel.recipients"],
+ });
+ res.json(await Promise.all(recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id]))));
+ },
);
router.post(
- "/",
- route({
- requestBody: "DmChannelCreateSchema",
- responses: {
- 200: {
- body: "DmChannelDTO",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as DmChannelCreateSchema;
- res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name));
- },
+ "/",
+ route({
+ requestBody: "DmChannelCreateSchema",
+ responses: {
+ 200: {
+ body: "DmChannelDTO",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as DmChannelCreateSchema;
+ res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name));
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/collectibles-marketing.ts b/src/api/routes/users/@me/collectibles-marketing.ts
index c9f1a1d1..a043a146 100644
--- a/src/api/routes/users/@me/collectibles-marketing.ts
+++ b/src/api/routes/users/@me/collectibles-marketing.ts
@@ -24,26 +24,26 @@ const router = Router({ mergeParams: true });
// Unsure what this endpoint does, it seems to only affect the visual style of the shop tab in home
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "CollectiblesMarketingResponse",
- },
- 204: {},
- 401: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- res.send({
- marketings: {},
- } as CollectiblesMarketingResponse);
- },
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "CollectiblesMarketingResponse",
+ },
+ 204: {},
+ 401: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ res.send({
+ marketings: {},
+ } as CollectiblesMarketingResponse);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/collectibles-purchases.ts b/src/api/routes/users/@me/collectibles-purchases.ts
index 9491e30a..1e6a08d0 100644
--- a/src/api/routes/users/@me/collectibles-purchases.ts
+++ b/src/api/routes/users/@me/collectibles-purchases.ts
@@ -23,24 +23,24 @@ const router = Router({ mergeParams: true });
// Unsure what this endpoint does, it seems to only affect the visual style of the shop tab in home
router.get(
- "/",
- route({
- responses: {
- 200: {
- // body: "CollectiblesPurchasesResponse",
- },
- 204: {},
- 401: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- res.send([]);
- },
+ "/",
+ route({
+ responses: {
+ 200: {
+ // body: "CollectiblesPurchasesResponse",
+ },
+ 204: {},
+ 401: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ res.send([]);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts
index fcab4321..8846efe4 100644
--- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts
+++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts
@@ -28,49 +28,49 @@ const ALLOWED_CONNECTIONS = ["twitch", "youtube"];
// NOTE: this route has not been extensively tested, as the required connections are not implemented as of writing
router.get("/", route({}), async (req: Request, res: Response) => {
- const { connection_name, connection_id } = req.params;
+ const { connection_name, connection_id } = req.params;
- const connection = ConnectionStore.connections.get(connection_name);
+ const connection = ConnectionStore.connections.get(connection_name);
- if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection)
- throw FieldErrors({
- provider_id: {
- code: "BASE_TYPE_CHOICES",
- message: req.t("common:field.BASE_TYPE_CHOICES", {
- types: ALLOWED_CONNECTIONS.join(", "),
- }),
- },
- });
+ if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection)
+ throw FieldErrors({
+ provider_id: {
+ code: "BASE_TYPE_CHOICES",
+ message: req.t("common:field.BASE_TYPE_CHOICES", {
+ types: ALLOWED_CONNECTIONS.join(", "),
+ }),
+ },
+ });
- if (!connection.settings.enabled)
- throw FieldErrors({
- provider_id: {
- message: "This connection has been disabled server-side.",
- },
- });
+ if (!connection.settings.enabled)
+ throw FieldErrors({
+ provider_id: {
+ message: "This connection has been disabled server-side.",
+ },
+ });
- const connectedAccount = await ConnectedAccount.findOne({
- where: {
- type: connection_name,
- external_id: connection_id,
- user_id: req.user_id,
- },
- select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "token_data", "friend_sync", "integrations"],
- });
- if (!connectedAccount) throw DiscordApiErrors.UNKNOWN_CONNECTION;
- if (connectedAccount.revoked) throw DiscordApiErrors.CONNECTION_REVOKED;
- if (!connectedAccount.token_data) throw new ApiError("No token data", 0, 400);
+ const connectedAccount = await ConnectedAccount.findOne({
+ where: {
+ type: connection_name,
+ external_id: connection_id,
+ user_id: req.user_id,
+ },
+ select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "token_data", "friend_sync", "integrations"],
+ });
+ if (!connectedAccount) throw DiscordApiErrors.UNKNOWN_CONNECTION;
+ if (connectedAccount.revoked) throw DiscordApiErrors.CONNECTION_REVOKED;
+ if (!connectedAccount.token_data) throw new ApiError("No token data", 0, 400);
- let access_token = connectedAccount.token_data.access_token;
- const { expires_at, expires_in, fetched_at } = connectedAccount.token_data;
+ let access_token = connectedAccount.token_data.access_token;
+ const { expires_at, expires_in, fetched_at } = connectedAccount.token_data;
- if ((expires_at && expires_at < Date.now()) || (expires_in && fetched_at + expires_in * 1000 < Date.now())) {
- if (!(connection instanceof RefreshableConnection)) throw new ApiError("Access token expired", 0, 400);
- const tokenData = await connection.refresh(connectedAccount);
- access_token = tokenData.access_token;
- }
+ if ((expires_at && expires_at < Date.now()) || (expires_in && fetched_at + expires_in * 1000 < Date.now())) {
+ if (!(connection instanceof RefreshableConnection)) throw new ApiError("Access token expired", 0, 400);
+ const tokenData = await connection.refresh(connectedAccount);
+ access_token = tokenData.access_token;
+ }
- res.json({ access_token });
+ res.json({ access_token });
});
export default router;
diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts
index 37deee38..111312ae 100644
--- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts
+++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts
@@ -24,65 +24,65 @@ const router = Router({ mergeParams: true });
// TODO: connection update schema
router.patch("/", route({ requestBody: "ConnectionUpdateSchema" }), async (req: Request, res: Response) => {
- const { connection_name, connection_id } = req.params;
- const body = req.body as ConnectionUpdateSchema;
+ const { connection_name, connection_id } = req.params;
+ const body = req.body as ConnectionUpdateSchema;
- const connection = await ConnectedAccount.findOne({
- where: {
- user_id: req.user_id,
- external_id: connection_id,
- type: connection_name,
- },
- select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "friend_sync", "integrations"],
- });
+ const connection = await ConnectedAccount.findOne({
+ where: {
+ user_id: req.user_id,
+ external_id: connection_id,
+ type: connection_name,
+ },
+ select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "friend_sync", "integrations"],
+ });
- if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION;
- // TODO: do we need to do anything if the connection is revoked?
+ if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION;
+ // TODO: do we need to do anything if the connection is revoked?
- if (typeof body.visibility === "boolean")
- //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
- body.visibility = body.visibility ? 1 : 0;
- if (typeof body.show_activity === "boolean")
- //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
- body.show_activity = body.show_activity ? 1 : 0;
- if (typeof body.metadata_visibility === "boolean")
- //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
- body.metadata_visibility = body.metadata_visibility ? 1 : 0;
+ if (typeof body.visibility === "boolean")
+ //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
+ body.visibility = body.visibility ? 1 : 0;
+ if (typeof body.show_activity === "boolean")
+ //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
+ body.show_activity = body.show_activity ? 1 : 0;
+ if (typeof body.metadata_visibility === "boolean")
+ //@ts-expect-error For some reason the client sends this as a boolean, even tho docs say its a number?
+ body.metadata_visibility = body.metadata_visibility ? 1 : 0;
- connection.assign(req.body);
+ connection.assign(req.body);
- await ConnectedAccount.update(
- {
- user_id: req.user_id,
- external_id: connection_id,
- type: connection_name,
- },
- connection,
- );
- res.json(connection.toJSON());
+ await ConnectedAccount.update(
+ {
+ user_id: req.user_id,
+ external_id: connection_id,
+ type: connection_name,
+ },
+ connection,
+ );
+ res.json(connection.toJSON());
});
router.delete("/", route({}), async (req: Request, res: Response) => {
- const { connection_name, connection_id } = req.params;
+ const { connection_name, connection_id } = req.params;
- const account = await ConnectedAccount.findOneOrFail({
- where: {
- user_id: req.user_id,
- external_id: connection_id,
- type: connection_name,
- },
- });
+ const account = await ConnectedAccount.findOneOrFail({
+ where: {
+ user_id: req.user_id,
+ external_id: connection_id,
+ type: connection_name,
+ },
+ });
- await Promise.all([
- ConnectedAccount.remove(account),
- emitEvent({
- event: "USER_CONNECTIONS_UPDATE",
- data: account,
- user_id: req.user_id,
- }),
- ]);
+ await Promise.all([
+ ConnectedAccount.remove(account),
+ emitEvent({
+ event: "USER_CONNECTIONS_UPDATE",
+ data: account,
+ user_id: req.user_id,
+ }),
+ ]);
- return res.sendStatus(200);
+ return res.sendStatus(200);
});
export default router;
diff --git a/src/api/routes/users/@me/connections/index.ts b/src/api/routes/users/@me/connections/index.ts
index 00625eea..a2d8b82a 100644
--- a/src/api/routes/users/@me/connections/index.ts
+++ b/src/api/routes/users/@me/connections/index.ts
@@ -23,14 +23,14 @@ import { ConnectedAccount, ConnectedAccountDTO } from "@spacebar/util";
const router: Router = Router({ mergeParams: true });
router.get("/", route({}), async (req: Request, res: Response) => {
- const connections = await ConnectedAccount.find({
- where: {
- user_id: req.user_id,
- },
- select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "token_data", "friend_sync", "integrations"],
- });
+ const connections = await ConnectedAccount.find({
+ where: {
+ user_id: req.user_id,
+ },
+ select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "token_data", "friend_sync", "integrations"],
+ });
- res.json(connections.map((x) => new ConnectedAccountDTO(x, true)));
+ res.json(connections.map((x) => new ConnectedAccountDTO(x, true)));
});
export default router;
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index 43861181..668f7c19 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -25,44 +25,44 @@ import { HTTPError } from "lambert-server";
const router = Router({ mergeParams: true });
router.post(
- "/",
- route({
- responses: {
- 204: {},
- 401: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: ["data"],
- }); //User object
- let correctpass = true;
+ "/",
+ route({
+ responses: {
+ 204: {},
+ 401: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
+ }); //User object
+ let correctpass = true;
- if (user.data.hash) {
- // guest accounts can delete accounts without password
- correctpass = await bcrypt.compare(req.body.password, user.data.hash);
- if (!correctpass) {
- throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
- }
- }
+ if (user.data.hash) {
+ // guest accounts can delete accounts without password
+ correctpass = await bcrypt.compare(req.body.password, user.data.hash);
+ if (!correctpass) {
+ throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+ }
+ }
- // TODO: decrement guild member count
+ // TODO: decrement guild member count
- if (correctpass) {
- const members = await Member.find({ where: { id: req.user_id } });
- await Promise.all([User.delete({ id: req.user_id }), ...members.map((member) => Member.removeFromGuild(member.id, member.guild_id))]);
+ if (correctpass) {
+ const members = await Member.find({ where: { id: req.user_id } });
+ await Promise.all([User.delete({ id: req.user_id }), ...members.map((member) => Member.removeFromGuild(member.id, member.guild_id))]);
- res.sendStatus(204);
- } else {
- res.sendStatus(401);
- }
- },
+ res.sendStatus(204);
+ } else {
+ res.sendStatus(401);
+ }
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/devices.ts b/src/api/routes/users/@me/devices.ts
index 644302cd..d3206138 100644
--- a/src/api/routes/users/@me/devices.ts
+++ b/src/api/routes/users/@me/devices.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.post("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.sendStatus(204);
+ // TODO:
+ res.sendStatus(204);
});
export default router;
diff --git a/src/api/routes/users/@me/disable.ts b/src/api/routes/users/@me/disable.ts
index 73de8395..95995e4b 100644
--- a/src/api/routes/users/@me/disable.ts
+++ b/src/api/routes/users/@me/disable.ts
@@ -24,41 +24,41 @@ import { Request, Response, Router } from "express";
const router = Router({ mergeParams: true });
router.post(
- "/",
- route({
- responses: {
- 204: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: ["data"],
- }); //User object
- let correctpass = true;
+ "/",
+ route({
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
+ }); //User object
+ let correctpass = true;
- if (user.data.hash) {
- // guest accounts can delete accounts without password
- correctpass = await bcrypt.compare(req.body.password, user.data.hash); //Not sure if user typed right password :/
- }
+ if (user.data.hash) {
+ // guest accounts can delete accounts without password
+ correctpass = await bcrypt.compare(req.body.password, user.data.hash); //Not sure if user typed right password :/
+ }
- if (correctpass) {
- await User.update({ id: req.user_id }, { disabled: true });
+ if (correctpass) {
+ await User.update({ id: req.user_id }, { disabled: true });
- res.sendStatus(204);
- } else {
- res.status(400).json({
- message: "Password does not match",
- code: 50018,
- });
- }
- },
+ res.sendStatus(204);
+ } else {
+ res.status(400).json({
+ message: "Password does not match",
+ code: 50018,
+ });
+ }
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/email-settings.ts b/src/api/routes/users/@me/email-settings.ts
index c5575009..ede73532 100644
--- a/src/api/routes/users/@me/email-settings.ts
+++ b/src/api/routes/users/@me/email-settings.ts
@@ -22,17 +22,17 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.json({
- categories: {
- social: true,
- communication: true,
- tips: false,
- updates_and_announcements: false,
- recommendations_and_events: false,
- },
- initialized: false,
- }).status(200);
+ // TODO:
+ res.json({
+ categories: {
+ social: true,
+ communication: true,
+ tips: false,
+ updates_and_announcements: false,
+ recommendations_and_events: false,
+ },
+ initialized: false,
+ }).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/entitlements.ts b/src/api/routes/users/@me/entitlements.ts
index fd953eee..ac73a12c 100644
--- a/src/api/routes/users/@me/entitlements.ts
+++ b/src/api/routes/users/@me/entitlements.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/gifts", route({}), (req: Request, res: Response) => {
- // TODO:
- res.json([]).status(200);
+ // TODO:
+ res.json([]).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/guilds.ts b/src/api/routes/users/@me/guilds.ts
index df71f46e..c06c39c4 100644
--- a/src/api/routes/users/@me/guilds.ts
+++ b/src/api/routes/users/@me/guilds.ts
@@ -24,62 +24,62 @@ import { HTTPError } from "lambert-server";
const router: Router = Router({ mergeParams: true });
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "APIGuildArray",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const members = await Member.find({
- relations: ["guild"],
- where: { id: req.user_id },
- });
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "APIGuildArray",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const members = await Member.find({
+ relations: ["guild"],
+ where: { id: req.user_id },
+ });
- let guild = members.map((x) => x.guild);
+ let guild = members.map((x) => x.guild);
- if ("with_counts" in req.query && req.query.with_counts == "true") {
- guild = []; // TODO: Load guilds with user role permissions number
- }
+ if ("with_counts" in req.query && req.query.with_counts == "true") {
+ guild = []; // TODO: Load guilds with user role permissions number
+ }
- res.json(guild);
- },
+ res.json(guild);
+ },
);
// user send to leave a certain guild
router.delete(
- "/:guild_id",
- route({
- responses: {
- 204: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { autoJoin } = Config.get().guild;
- const { guild_id } = req.params;
- const guild = await Guild.findOneOrFail({
- where: { id: guild_id },
- select: ["owner_id"],
- });
+ "/:guild_id",
+ route({
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { autoJoin } = Config.get().guild;
+ const { guild_id } = req.params;
+ const guild = await Guild.findOneOrFail({
+ where: { id: guild_id },
+ select: ["owner_id"],
+ });
- if (!guild) throw new HTTPError("Guild doesn't exist", 404);
- if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
- if (autoJoin.enabled && autoJoin.guilds.includes(guild_id) && !autoJoin.canLeave) {
- throw new HTTPError("You can't leave instance auto join guilds", 400);
- }
+ if (!guild) throw new HTTPError("Guild doesn't exist", 404);
+ if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
+ if (autoJoin.enabled && autoJoin.guilds.includes(guild_id) && !autoJoin.canLeave) {
+ throw new HTTPError("You can't leave instance auto join guilds", 400);
+ }
- await Member.removeFromGuild(req.user_id, guild_id);
+ await Member.removeFromGuild(req.user_id, guild_id);
- return res.sendStatus(204);
- },
+ return res.sendStatus(204);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/guilds/#guild_id/settings.ts b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
index 7fda9a90..16b64ec5 100644
--- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts
+++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
@@ -25,54 +25,54 @@ const router = Router({ mergeParams: true });
// GET doesn't exist on discord.com
router.get(
- "/",
- route({
- responses: {
- 200: {},
- 404: {},
- },
- }),
- async (req: Request, res: Response) => {
- const user = await Member.findOneOrFail({
- where: { id: req.user_id, guild_id: req.params.guild_id },
- select: ["settings"],
- });
- return res.json(user.settings);
- },
+ "/",
+ route({
+ responses: {
+ 200: {},
+ 404: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const user = await Member.findOneOrFail({
+ where: { id: req.user_id, guild_id: req.params.guild_id },
+ select: ["settings"],
+ });
+ return res.json(user.settings);
+ },
);
router.patch(
- "/",
- route({
- requestBody: "UserGuildSettingsSchema",
- responses: {
- 200: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UserGuildSettingsSchema;
+ "/",
+ route({
+ requestBody: "UserGuildSettingsSchema",
+ responses: {
+ 200: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserGuildSettingsSchema;
- if (body.channel_overrides) {
- for (const channel in body.channel_overrides) {
- Channel.findOneOrFail({ where: { id: channel } });
- }
- }
+ if (body.channel_overrides) {
+ for (const channel in body.channel_overrides) {
+ Channel.findOneOrFail({ where: { id: channel } });
+ }
+ }
- const user = await Member.findOneOrFail({
- where: { id: req.user_id, guild_id: req.params.guild_id },
- select: ["settings"],
- });
- OrmUtils.mergeDeep(user.settings || {}, body);
- Member.update({ id: req.user_id, guild_id: req.params.guild_id }, user);
+ const user = await Member.findOneOrFail({
+ where: { id: req.user_id, guild_id: req.params.guild_id },
+ select: ["settings"],
+ });
+ OrmUtils.mergeDeep(user.settings || {}, body);
+ Member.update({ id: req.user_id, guild_id: req.params.guild_id }, user);
- res.json(user.settings);
- },
+ res.json(user.settings);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/guilds/premium/subscription-slots.ts b/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
index a9bc5961..b0119161 100644
--- a/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
+++ b/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.json([]).status(200);
+ // TODO:
+ res.json([]).status(200);
});
export default router;
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index aba9f928..bd1fa077 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -25,182 +25,182 @@ import { PrivateUserProjection, UserModifySchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "APIPrivateUser",
- },
- },
- }),
- async (req: Request, res: Response) => {
- res.json(
- await User.findOne({
- select: PrivateUserProjection,
- where: { id: req.user_id },
- }),
- );
- },
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "APIPrivateUser",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ res.json(
+ await User.findOne({
+ select: PrivateUserProjection,
+ where: { id: req.user_id },
+ }),
+ );
+ },
);
router.patch(
- "/",
- route({
- requestBody: "UserModifySchema",
- responses: {
- 200: {
- body: "UserUpdateResponse",
- },
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UserModifySchema;
+ "/",
+ route({
+ requestBody: "UserModifySchema",
+ responses: {
+ 200: {
+ body: "UserUpdateResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserModifySchema;
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: [...PrivateUserProjection, "data"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: [...PrivateUserProjection, "data"],
+ });
- // Populated on password change
- let newToken: string | undefined;
+ // Populated on password change
+ let newToken: string | undefined;
- if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string);
- if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
+ if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string);
+ if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
- if (body.password) {
- if (user.data?.hash) {
- const same_password = await bcrypt.compare(body.password, user.data.hash || "");
- if (!same_password) {
- throw FieldErrors({
- password: {
- message: req.t("auth:login.INVALID_PASSWORD"),
- code: "INVALID_PASSWORD",
- },
- });
- }
- } else {
- user.data.hash = await bcrypt.hash(body.password, 12);
- }
- }
+ if (body.password) {
+ if (user.data?.hash) {
+ const same_password = await bcrypt.compare(body.password, user.data.hash || "");
+ if (!same_password) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
+ } else {
+ user.data.hash = await bcrypt.hash(body.password, 12);
+ }
+ }
- if (body.email) {
- if (!body.email && Config.get().register.email.required)
- throw FieldErrors({
- email: {
- message: req.t("auth:register.EMAIL_INVALID"),
- code: "EMAIL_INVALID",
- },
- });
- if (!body.password)
- throw FieldErrors({
- password: {
- message: req.t("auth:login.INVALID_PASSWORD"),
- code: "INVALID_PASSWORD",
- },
- });
- }
+ if (body.email) {
+ if (!body.email && Config.get().register.email.required)
+ throw FieldErrors({
+ email: {
+ message: req.t("auth:register.EMAIL_INVALID"),
+ code: "EMAIL_INVALID",
+ },
+ });
+ if (!body.password)
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
- if (body.new_password) {
- if (!body.password && user.email) {
- throw FieldErrors({
- password: {
- code: "BASE_TYPE_REQUIRED",
- message: req.t("common:field.BASE_TYPE_REQUIRED"),
- },
- });
- }
- user.data.hash = await bcrypt.hash(body.new_password, 12);
- user.data.valid_tokens_since = new Date();
- newToken = (await generateToken(user.id)) as string;
- }
+ if (body.new_password) {
+ if (!body.password && user.email) {
+ throw FieldErrors({
+ password: {
+ code: "BASE_TYPE_REQUIRED",
+ message: req.t("common:field.BASE_TYPE_REQUIRED"),
+ },
+ });
+ }
+ user.data.hash = await bcrypt.hash(body.new_password, 12);
+ user.data.valid_tokens_since = new Date();
+ newToken = (await generateToken(user.id)) as string;
+ }
- if (body.username) {
- const check_username = body?.username?.replace(/\s/g, "").trim();
- if (!check_username) {
- throw FieldErrors({
- username: {
- code: "BASE_TYPE_REQUIRED",
- message: req.t("common:field.BASE_TYPE_REQUIRED"),
- },
- });
- }
+ if (body.username) {
+ const check_username = body?.username?.replace(/\s/g, "").trim();
+ if (!check_username) {
+ throw FieldErrors({
+ username: {
+ code: "BASE_TYPE_REQUIRED",
+ message: req.t("common:field.BASE_TYPE_REQUIRED"),
+ },
+ });
+ }
- const { maxUsername } = Config.get().limits.user;
- if (check_username.length > maxUsername || check_username.length < 2) {
- throw FieldErrors({
- username: {
- code: "BASE_TYPE_BAD_LENGTH",
- message: `Must be between 2 and ${maxUsername} in length.`,
- },
- });
- }
+ const { maxUsername } = Config.get().limits.user;
+ if (check_username.length > maxUsername || check_username.length < 2) {
+ throw FieldErrors({
+ username: {
+ code: "BASE_TYPE_BAD_LENGTH",
+ message: `Must be between 2 and ${maxUsername} in length.`,
+ },
+ });
+ }
- if (!body.password) {
- throw FieldErrors({
- password: {
- message: req.t("auth:login.INVALID_PASSWORD"),
- code: "INVALID_PASSWORD",
- },
- });
- }
- }
+ if (!body.password) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
+ }
- if (body.discriminator) {
- if (
- await User.findOne({
- where: {
- discriminator: body.discriminator,
- username: body.username || user.username,
- },
- })
- ) {
- throw FieldErrors({
- discriminator: {
- code: "INVALID_DISCRIMINATOR",
- message: "This discriminator is already in use.",
- },
- });
- }
- }
+ if (body.discriminator) {
+ if (
+ await User.findOne({
+ where: {
+ discriminator: body.discriminator,
+ username: body.username || user.username,
+ },
+ })
+ ) {
+ throw FieldErrors({
+ discriminator: {
+ code: "INVALID_DISCRIMINATOR",
+ message: "This discriminator is already in use.",
+ },
+ });
+ }
+ }
- if (body.bio) {
- const { maxBio } = Config.get().limits.user;
- if (body.bio.length > maxBio) {
- throw FieldErrors({
- bio: {
- code: "BIO_INVALID",
- message: `Bio must be less than ${maxBio} in length`,
- },
- });
- }
- }
+ if (body.bio) {
+ const { maxBio } = Config.get().limits.user;
+ if (body.bio.length > maxBio) {
+ throw FieldErrors({
+ bio: {
+ code: "BIO_INVALID",
+ message: `Bio must be less than ${maxBio} in length`,
+ },
+ });
+ }
+ }
- user.assign(body);
- user.validate();
- await user.save();
+ user.assign(body);
+ user.validate();
+ await user.save();
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- //@ts-ignore
- delete user.data;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ //@ts-ignore
+ delete user.data;
- // TODO: send update member list event in gateway
- await emitEvent({
- event: "USER_UPDATE",
- user_id: req.user_id,
- data: user,
- } as UserUpdateEvent);
+ // TODO: send update member list event in gateway
+ await emitEvent({
+ event: "USER_UPDATE",
+ user_id: req.user_id,
+ data: user,
+ } as UserUpdateEvent);
- res.json({
- ...user,
- newToken,
- });
- },
+ res.json({
+ ...user,
+ newToken,
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/library.ts b/src/api/routes/users/@me/library.ts
index 845cd171..8d09b38d 100644
--- a/src/api/routes/users/@me/library.ts
+++ b/src/api/routes/users/@me/library.ts
@@ -22,8 +22,8 @@ import { route } from "@spacebar/api";
const router = Router({ mergeParams: true });
router.get("/", route({}), (req: Request, res: Response) => {
- // TODO:
- res.status(200).send([]);
+ // TODO:
+ res.status(200).send([]);
});
export default router;
diff --git a/src/api/routes/users/@me/mentions.ts b/src/api/routes/users/@me/mentions.ts
index 37a7abe1..2d631e90 100644
--- a/src/api/routes/users/@me/mentions.ts
+++ b/src/api/routes/users/@me/mentions.ts
@@ -24,139 +24,139 @@ import { In, LessThan, FindOptionsWhere } from "typeorm";
const router: Router = Router({ mergeParams: true });
router.get(
- "",
- route({
- responses: {
- 200: {
- body: "MessageListResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- // AFAICT this endpoint doesn't list DMs
- async (req: Request, res: Response) => {
- const limit = req.query.limit && !isNaN(Number(req.query.limit)) ? Number(req.query.limit) : 25;
- const everyone = req.query.everyone !== undefined ? Boolean(req.query.everyone) : true;
- const roles = req.query.roles !== undefined ? Boolean(req.query.roles) : true;
- const before = req.query.before !== undefined ? String(req.query.before as string) : undefined;
- const guild_id = req.query.guild_id !== undefined ? req.query.guild_id : undefined;
+ "",
+ route({
+ responses: {
+ 200: {
+ body: "MessageListResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ // AFAICT this endpoint doesn't list DMs
+ async (req: Request, res: Response) => {
+ const limit = req.query.limit && !isNaN(Number(req.query.limit)) ? Number(req.query.limit) : 25;
+ const everyone = req.query.everyone !== undefined ? Boolean(req.query.everyone) : true;
+ const roles = req.query.roles !== undefined ? Boolean(req.query.roles) : true;
+ const before = req.query.before !== undefined ? String(req.query.before as string) : undefined;
+ const guild_id = req.query.guild_id !== undefined ? req.query.guild_id : undefined;
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ });
- const memberships = await Member.find({
- where: { id: req.user_id, ...(guild_id === undefined ? {} : { guild_id: String(guild_id) }) },
- select: {
- guild_id: true,
- id: true,
- communication_disabled_until: true,
- roles: {
- // We don't want to include all guild roles, as this could cause a lot more explosive behavior
- id: true,
- position: true,
- permissions: true,
- mentionable: true, // cause we can skip querying for unmentionable roles
- },
- guild: {
- id: true,
- owner_id: true,
- },
- },
- relations: ["guild", "roles"],
- });
+ const memberships = await Member.find({
+ where: { id: req.user_id, ...(guild_id === undefined ? {} : { guild_id: String(guild_id) }) },
+ select: {
+ guild_id: true,
+ id: true,
+ communication_disabled_until: true,
+ roles: {
+ // We don't want to include all guild roles, as this could cause a lot more explosive behavior
+ id: true,
+ position: true,
+ permissions: true,
+ mentionable: true, // cause we can skip querying for unmentionable roles
+ },
+ guild: {
+ id: true,
+ owner_id: true,
+ },
+ },
+ relations: ["guild", "roles"],
+ });
- const channels = await Channel.find({
- where: {
- guild_id: In(memberships.map((m) => m.guild_id)),
- },
- select: { id: true, guild_id: true, permission_overwrites: true },
- });
+ const channels = await Channel.find({
+ where: {
+ guild_id: In(memberships.map((m) => m.guild_id)),
+ },
+ select: { id: true, guild_id: true, permission_overwrites: true },
+ });
- const visibleChannels = channels.filter((c) => {
- const member = memberships.find((m) => m.guild_id === c.guild_id)!;
- return Permissions.finalPermission({
- user: { id: member.id, roles: member.roles.map((r) => r.id), communication_disabled_until: member.communication_disabled_until, flags: 0 },
- guild: { id: member.guild.id, owner_id: member.guild.owner_id!, roles: member.roles },
- channel: c,
- }).has("VIEW_CHANNEL");
- });
+ const visibleChannels = channels.filter((c) => {
+ const member = memberships.find((m) => m.guild_id === c.guild_id)!;
+ return Permissions.finalPermission({
+ user: { id: member.id, roles: member.roles.map((r) => r.id), communication_disabled_until: member.communication_disabled_until, flags: 0 },
+ guild: { id: member.guild.id, owner_id: member.guild.owner_id!, roles: member.roles },
+ channel: c,
+ }).has("VIEW_CHANNEL");
+ });
- const visibleChannelIds = visibleChannels.map((c) => c.id);
- const ownedMentionableRoleIds = memberships.reduce((acc, m) => {
- acc.push(...m.roles.filter((r) => r.mentionable).map((r) => r.id));
- return acc;
- }, [] as Snowflake[]);
+ const visibleChannelIds = visibleChannels.map((c) => c.id);
+ const ownedMentionableRoleIds = memberships.reduce((acc, m) => {
+ acc.push(...m.roles.filter((r) => r.mentionable).map((r) => r.id));
+ return acc;
+ }, [] as Snowflake[]);
- const whereQuery: FindOptionsWhere<Message>[] = [
- {
- channel_id: In(visibleChannelIds),
- mentions: { id: user.id },
- id: before ? LessThan(before) : undefined,
- },
- ];
- if (everyone) {
- whereQuery.push({
- channel_id: In(visibleChannelIds),
- mention_everyone: true,
- id: before ? LessThan(before) : undefined,
- });
- }
- if (roles) {
- whereQuery.push({
- channel_id: In(visibleChannelIds),
- mention_roles: { id: In(ownedMentionableRoleIds) },
- id: before ? LessThan(before) : undefined,
- });
- }
+ const whereQuery: FindOptionsWhere<Message>[] = [
+ {
+ channel_id: In(visibleChannelIds),
+ mentions: { id: user.id },
+ id: before ? LessThan(before) : undefined,
+ },
+ ];
+ if (everyone) {
+ whereQuery.push({
+ channel_id: In(visibleChannelIds),
+ mention_everyone: true,
+ id: before ? LessThan(before) : undefined,
+ });
+ }
+ if (roles) {
+ whereQuery.push({
+ channel_id: In(visibleChannelIds),
+ mention_roles: { id: In(ownedMentionableRoleIds) },
+ id: before ? LessThan(before) : undefined,
+ });
+ }
- const sw = Stopwatch.startNew();
- const finalMessages = (
- await Message.find({
- where: whereQuery,
- order: { timestamp: "DESC" },
- relations: [
- "author",
- "webhook",
- "application",
- "mentions",
- "mention_roles",
- "mention_channels",
- "sticker_items",
- "attachments",
- "referenced_message",
- "referenced_message.author",
- "referenced_message.webhook",
- "referenced_message.application",
- "referenced_message.mentions",
- "referenced_message.mention_roles",
- "referenced_message.mention_channels",
- "referenced_message.sticker_items",
- "referenced_message.attachments",
- ],
- take: limit,
- })
- ).map((m) => {
- return {
- ...m.toJSON(),
- attachments: m.attachments?.map((attachment: Attachment) =>
- Attachment.prototype.signUrls.call(
- attachment,
- new NewUrlUserSignatureData({
- ip: req.ip,
- userAgent: req.headers["user-agent"] as string,
- }),
- ),
- ),
- };
- });
+ const sw = Stopwatch.startNew();
+ const finalMessages = (
+ await Message.find({
+ where: whereQuery,
+ order: { timestamp: "DESC" },
+ relations: [
+ "author",
+ "webhook",
+ "application",
+ "mentions",
+ "mention_roles",
+ "mention_channels",
+ "sticker_items",
+ "attachments",
+ "referenced_message",
+ "referenced_message.author",
+ "referenced_message.webhook",
+ "referenced_message.application",
+ "referenced_message.mentions",
+ "referenced_message.mention_roles",
+ "referenced_message.mention_channels",
+ "referenced_message.sticker_items",
+ "referenced_message.attachments",
+ ],
+ take: limit,
+ })
+ ).map((m) => {
+ return {
+ ...m.toJSON(),
+ attachments: m.attachments?.map((attachment: Attachment) =>
+ Attachment.prototype.signUrls.call(
+ attachment,
+ new NewUrlUserSignatureData({
+ ip: req.ip,
+ userAgent: req.headers["user-agent"] as string,
+ }),
+ ),
+ ),
+ };
+ });
- console.log(`[Inbox/mentions] User ${user.id} fetched full message data for ${finalMessages.length} messages in ${sw.elapsed().totalMilliseconds}ms`);
+ console.log(`[Inbox/mentions] User ${user.id} fetched full message data for ${finalMessages.length} messages in ${sw.elapsed().totalMilliseconds}ms`);
- return res.json(finalMessages);
- },
+ return res.json(finalMessages);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/codes-verification.ts b/src/api/routes/users/@me/mfa/codes-verification.ts
index c8995d83..4cc4c072 100644
--- a/src/api/routes/users/@me/mfa/codes-verification.ts
+++ b/src/api/routes/users/@me/mfa/codes-verification.ts
@@ -24,52 +24,52 @@ import { CodesVerificationSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(
- "/",
- route({
- requestBody: "CodesVerificationSchema",
- responses: {
- 200: {
- body: "APIBackupCodeArray",
- },
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- // const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
- const { regenerate } = req.body as CodesVerificationSchema;
+ "/",
+ route({
+ requestBody: "CodesVerificationSchema",
+ responses: {
+ 200: {
+ body: "APIBackupCodeArray",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ // const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
+ const { regenerate } = req.body as CodesVerificationSchema;
- // TODO: We don't have email/etc etc, so can't send a verification code.
- // Once that's done, this route can verify `key`
+ // TODO: We don't have email/etc etc, so can't send a verification code.
+ // Once that's done, this route can verify `key`
- // const user = await User.findOneOrFail({ where: { id: req.user_id } });
- if ((await User.count({ where: { id: req.user_id } })) === 0) throw DiscordApiErrors.UNKNOWN_USER;
+ // const user = await User.findOneOrFail({ where: { id: req.user_id } });
+ if ((await User.count({ where: { id: req.user_id } })) === 0) throw DiscordApiErrors.UNKNOWN_USER;
- let codes: BackupCode[];
- if (regenerate) {
- await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
+ let codes: BackupCode[];
+ if (regenerate) {
+ await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
- codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(codes.map((x) => x.save()));
- } else {
- codes = await BackupCode.find({
- where: {
- user: {
- id: req.user_id,
- },
- expired: false,
- },
- });
- }
+ codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(codes.map((x) => x.save()));
+ } else {
+ codes = await BackupCode.find({
+ where: {
+ user: {
+ id: req.user_id,
+ },
+ expired: false,
+ },
+ });
+ }
- return res.json({
- backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
- });
- },
+ return res.json({
+ backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts
index 579a106e..2eb1a3e3 100644
--- a/src/api/routes/users/@me/mfa/codes.ts
+++ b/src/api/routes/users/@me/mfa/codes.ts
@@ -27,61 +27,61 @@ const router = Router({ mergeParams: true });
// TODO: This route is replaced with users/@me/mfa/codes-verification in newer clients
router.post(
- "/",
- route({
- requestBody: "MfaCodesSchema",
- deprecated: true,
- description: "This route is replaced with users/@me/mfa/codes-verification in newer clients",
- responses: {
- 200: {
- body: "APIBackupCodeArray",
- },
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { password, regenerate } = req.body as MfaCodesSchema;
+ "/",
+ route({
+ requestBody: "MfaCodesSchema",
+ deprecated: true,
+ description: "This route is replaced with users/@me/mfa/codes-verification in newer clients",
+ responses: {
+ 200: {
+ body: "APIBackupCodeArray",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { password, regenerate } = req.body as MfaCodesSchema;
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: ["data"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
+ });
- if (!(await bcrypt.compare(password, user.data.hash || ""))) {
- throw FieldErrors({
- password: {
- message: req.t("auth:login.INVALID_PASSWORD"),
- code: "INVALID_PASSWORD",
- },
- });
- }
+ if (!(await bcrypt.compare(password, user.data.hash || ""))) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
- let codes: BackupCode[];
- if (regenerate) {
- await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
+ let codes: BackupCode[];
+ if (regenerate) {
+ await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
- codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(codes.map((x) => x.save()));
- } else {
- codes = await BackupCode.find({
- where: {
- user: {
- id: req.user_id,
- },
- expired: false,
- },
- });
- }
+ codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(codes.map((x) => x.save()));
+ } else {
+ codes = await BackupCode.find({
+ where: {
+ user: {
+ id: req.user_id,
+ },
+ expired: false,
+ },
+ });
+ }
- return res.json({
- backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
- });
- },
+ return res.json({
+ backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts
index 003dcb74..11c927e4 100644
--- a/src/api/routes/users/@me/mfa/totp/disable.ts
+++ b/src/api/routes/users/@me/mfa/totp/disable.ts
@@ -26,51 +26,51 @@ import { TotpDisableSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(
- "/",
- route({
- requestBody: "TotpDisableSchema",
- responses: {
- 200: {
- body: "TokenOnlyResponse",
- },
- 400: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as TotpDisableSchema;
+ "/",
+ route({
+ requestBody: "TotpDisableSchema",
+ responses: {
+ 200: {
+ body: "TokenOnlyResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as TotpDisableSchema;
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: ["totp_secret"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["totp_secret"],
+ });
- const backup = await BackupCode.findOne({ where: { code: body.code } });
- if (!backup) {
- const ret = verifyToken(user.totp_secret || "", body.code);
- if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
- }
+ const backup = await BackupCode.findOne({ where: { code: body.code } });
+ if (!backup) {
+ const ret = verifyToken(user.totp_secret || "", body.code);
+ if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+ }
- await User.update(
- { id: req.user_id },
- {
- mfa_enabled: false,
- totp_secret: "",
- },
- );
+ await User.update(
+ { id: req.user_id },
+ {
+ mfa_enabled: false,
+ totp_secret: "",
+ },
+ );
- await BackupCode.update(
- { user: { id: req.user_id } },
- {
- expired: true,
- },
- );
+ await BackupCode.update(
+ { user: { id: req.user_id } },
+ {
+ expired: true,
+ },
+ );
- return res.json({
- token: await generateToken(user.id),
- });
- },
+ return res.json({
+ token: await generateToken(user.id),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index f0563e30..a400c628 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -27,54 +27,54 @@ import { TotpEnableSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(
- "/",
- route({
- requestBody: "TotpEnableSchema",
- responses: {
- 200: {
- body: "TokenWithBackupCodesResponse",
- },
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as TotpEnableSchema;
+ "/",
+ route({
+ requestBody: "TotpEnableSchema",
+ responses: {
+ 200: {
+ body: "TokenWithBackupCodesResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as TotpEnableSchema;
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: ["data", "email"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data", "email"],
+ });
- // TODO: Are guests allowed to enable 2fa?
- if (user.data.hash) {
- if (!(await bcrypt.compare(body.password, user.data.hash))) {
- throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
- }
- }
+ // TODO: Are guests allowed to enable 2fa?
+ if (user.data.hash) {
+ if (!(await bcrypt.compare(body.password, user.data.hash))) {
+ throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+ }
+ }
- if (!body.secret) throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
+ if (!body.secret) throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
- if (!body.code) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+ if (!body.code) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
- if (verifyToken(body.secret, body.code)?.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+ if (verifyToken(body.secret, body.code)?.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
- const backup_codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(backup_codes.map((x) => x.save()));
- await User.update({ id: req.user_id }, { mfa_enabled: true, totp_secret: body.secret });
+ const backup_codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(backup_codes.map((x) => x.save()));
+ await User.update({ id: req.user_id }, { mfa_enabled: true, totp_secret: body.secret });
- res.send({
- token: await generateToken(user.id),
- backup_codes: backup_codes.map((x) => ({
- ...x,
- expired: undefined,
- })),
- });
- },
+ res.send({
+ token: await generateToken(user.id),
+ backup_codes: backup_codes.map((x) => ({
+ ...x,
+ expired: undefined,
+ })),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/webauthn/credentials/#key_id/index.ts b/src/api/routes/users/@me/mfa/webauthn/credentials/#key_id/index.ts
index 6dc06563..77180cac 100644
--- a/src/api/routes/users/@me/mfa/webauthn/credentials/#key_id/index.ts
+++ b/src/api/routes/users/@me/mfa/webauthn/credentials/#key_id/index.ts
@@ -22,29 +22,29 @@ import { Request, Response, Router } from "express";
const router = Router({ mergeParams: true });
router.delete(
- "/",
- route({
- responses: {
- 204: {},
- },
- }),
- async (req: Request, res: Response) => {
- const { key_id } = req.params;
+ "/",
+ route({
+ responses: {
+ 204: {},
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { key_id } = req.params;
- await SecurityKey.delete({
- id: key_id,
- user_id: req.user_id,
- });
+ await SecurityKey.delete({
+ id: key_id,
+ user_id: req.user_id,
+ });
- const keys = await SecurityKey.count({
- where: { user_id: req.user_id },
- });
+ const keys = await SecurityKey.count({
+ where: { user_id: req.user_id },
+ });
- // disable webauthn if there are no keys left
- if (keys === 0) await User.update({ id: req.user_id }, { webauthn_enabled: false });
+ // disable webauthn if there are no keys left
+ if (keys === 0) await User.update({ id: req.user_id }, { webauthn_enabled: false });
- res.sendStatus(204);
- },
+ res.sendStatus(204);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/mfa/webauthn/credentials/index.ts b/src/api/routes/users/@me/mfa/webauthn/credentials/index.ts
index 0c4b733d..7bd29a57 100644
--- a/src/api/routes/users/@me/mfa/webauthn/credentials/index.ts
+++ b/src/api/routes/users/@me/mfa/webauthn/credentials/index.ts
@@ -26,138 +26,138 @@ import { CreateWebAuthnCredentialSchema, GenerateWebAuthnCredentialsSchema, WebA
const router = Router({ mergeParams: true });
const isGenerateSchema = (body: WebAuthnPostSchema): body is GenerateWebAuthnCredentialsSchema => {
- return "password" in body;
+ return "password" in body;
};
const isCreateSchema = (body: WebAuthnPostSchema): body is CreateWebAuthnCredentialSchema => {
- return "credential" in body;
+ return "credential" in body;
};
function toArrayBuffer(buf: Buffer) {
- const ab = new ArrayBuffer(buf.length);
- const view = new Uint8Array(ab);
- for (let i = 0; i < buf.length; ++i) {
- view[i] = buf[i];
- }
- return ab;
+ const ab = new ArrayBuffer(buf.length);
+ const view = new Uint8Array(ab);
+ for (let i = 0; i < buf.length; ++i) {
+ view[i] = buf[i];
+ }
+ return ab;
}
router.get("/", route({}), async (req: Request, res: Response) => {
- const securityKeys = await SecurityKey.find({
- where: {
- user_id: req.user_id,
- },
- });
+ const securityKeys = await SecurityKey.find({
+ where: {
+ user_id: req.user_id,
+ },
+ });
- return res.json(
- securityKeys.map((key) => ({
- id: key.id,
- name: key.name,
- })),
- );
+ return res.json(
+ securityKeys.map((key) => ({
+ id: key.id,
+ name: key.name,
+ })),
+ );
});
router.post(
- "/",
- route({
- requestBody: "WebAuthnPostSchema",
- responses: {
- 200: {
- body: "WebAuthnCreateResponse",
- },
- 400: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- if (!WebAuthn.fido2) {
- // TODO: I did this for typescript and I can't use !
- throw new Error("WebAuthn not enabled");
- }
+ "/",
+ route({
+ requestBody: "WebAuthnPostSchema",
+ responses: {
+ 200: {
+ body: "WebAuthnCreateResponse",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ if (!WebAuthn.fido2) {
+ // TODO: I did this for typescript and I can't use !
+ throw new Error("WebAuthn not enabled");
+ }
- const user = await User.findOneOrFail({
- where: {
- id: req.user_id,
- },
- select: ["data", "id", "disabled", "deleted", "totp_secret", "mfa_enabled", "username"],
- relations: ["settings"],
- });
+ const user = await User.findOneOrFail({
+ where: {
+ id: req.user_id,
+ },
+ select: ["data", "id", "disabled", "deleted", "totp_secret", "mfa_enabled", "username"],
+ relations: ["settings"],
+ });
- if (isGenerateSchema(req.body)) {
- const { password } = req.body;
- const same_password = await bcrypt.compare(password, user.data.hash || "");
- if (!same_password) {
- throw FieldErrors({
- password: {
- message: req.t("auth:login.INVALID_PASSWORD"),
- code: "INVALID_PASSWORD",
- },
- });
- }
+ if (isGenerateSchema(req.body)) {
+ const { password } = req.body;
+ const same_password = await bcrypt.compare(password, user.data.hash || "");
+ if (!same_password) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
- const registrationOptions = await WebAuthn.fido2.attestationOptions();
- const challenge = JSON.stringify({
- publicKey: {
- ...registrationOptions,
- challenge: Buffer.from(registrationOptions.challenge).toString("base64"),
- user: {
- id: user.id,
- name: user.username,
- displayName: user.username,
- },
- },
- });
+ const registrationOptions = await WebAuthn.fido2.attestationOptions();
+ const challenge = JSON.stringify({
+ publicKey: {
+ ...registrationOptions,
+ challenge: Buffer.from(registrationOptions.challenge).toString("base64"),
+ user: {
+ id: user.id,
+ name: user.username,
+ displayName: user.username,
+ },
+ },
+ });
- const ticket = await generateWebAuthnTicket(challenge);
+ const ticket = await generateWebAuthnTicket(challenge);
- return res.json({
- ticket: ticket,
- challenge,
- });
- } else if (isCreateSchema(req.body)) {
- const { credential, name, ticket } = req.body;
+ return res.json({
+ ticket: ticket,
+ challenge,
+ });
+ } else if (isCreateSchema(req.body)) {
+ const { credential, name, ticket } = req.body;
- const verified = await verifyWebAuthnToken(ticket);
- if (!verified) throw new HTTPError("Invalid ticket", 400);
+ const verified = await verifyWebAuthnToken(ticket);
+ if (!verified) throw new HTTPError("Invalid ticket", 400);
- const clientAttestationResponse = JSON.parse(credential);
+ const clientAttestationResponse = JSON.parse(credential);
- if (!clientAttestationResponse.rawId) throw new HTTPError("Missing rawId", 400);
+ if (!clientAttestationResponse.rawId) throw new HTTPError("Missing rawId", 400);
- const rawIdBuffer = Buffer.from(clientAttestationResponse.rawId, "base64");
- clientAttestationResponse.rawId = toArrayBuffer(rawIdBuffer);
+ const rawIdBuffer = Buffer.from(clientAttestationResponse.rawId, "base64");
+ clientAttestationResponse.rawId = toArrayBuffer(rawIdBuffer);
- const attestationExpectations: ExpectedAttestationResult = JSON.parse(Buffer.from(clientAttestationResponse.response.clientDataJSON, "base64").toString());
+ const attestationExpectations: ExpectedAttestationResult = JSON.parse(Buffer.from(clientAttestationResponse.response.clientDataJSON, "base64").toString());
- const regResult = await WebAuthn.fido2.attestationResult(clientAttestationResponse, {
- ...attestationExpectations,
- factor: "second",
- });
+ const regResult = await WebAuthn.fido2.attestationResult(clientAttestationResponse, {
+ ...attestationExpectations,
+ factor: "second",
+ });
- const authnrData = regResult.authnrData;
- const keyId = Buffer.from(authnrData.get("credId")).toString("base64");
- const counter = authnrData.get("counter");
- const publicKey = authnrData.get("credentialPublicKeyPem");
+ const authnrData = regResult.authnrData;
+ const keyId = Buffer.from(authnrData.get("credId")).toString("base64");
+ const counter = authnrData.get("counter");
+ const publicKey = authnrData.get("credentialPublicKeyPem");
- const securityKey = SecurityKey.create({
- name,
- counter,
- public_key: publicKey,
- user_id: req.user_id,
- key_id: keyId,
- });
+ const securityKey = SecurityKey.create({
+ name,
+ counter,
+ public_key: publicKey,
+ user_id: req.user_id,
+ key_id: keyId,
+ });
- await Promise.all([securityKey.save(), User.update({ id: req.user_id }, { webauthn_enabled: true })]);
+ await Promise.all([securityKey.save(), User.update({ id: req.user_id }, { webauthn_enabled: true })]);
- return res.json({
- name,
- id: securityKey.id,
- });
- } else {
- throw DiscordApiErrors.INVALID_AUTHENTICATION_TOKEN;
- }
- },
+ return res.json({
+ name,
+ id: securityKey.id,
+ });
+ } else {
+ throw DiscordApiErrors.INVALID_AUTHENTICATION_TOKEN;
+ }
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/notes.ts b/src/api/routes/users/@me/notes.ts
index 4969fa75..8cd33304 100644
--- a/src/api/routes/users/@me/notes.ts
+++ b/src/api/routes/users/@me/notes.ts
@@ -23,89 +23,89 @@ import { Request, Response, Router } from "express";
const router: Router = Router({ mergeParams: true });
router.get(
- "/:user_id",
- route({
- responses: {
- 200: {
- body: "UserNoteResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { user_id } = req.params;
+ "/:user_id",
+ route({
+ responses: {
+ 200: {
+ body: "UserNoteResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { user_id } = req.params;
- const note = await Note.findOneOrFail({
- where: {
- owner: { id: req.user_id },
- target: { id: user_id },
- },
- });
+ const note = await Note.findOneOrFail({
+ where: {
+ owner: { id: req.user_id },
+ target: { id: user_id },
+ },
+ });
- return res.json({
- note: note?.content,
- note_user_id: user_id,
- user_id: req.user_id,
- });
- },
+ return res.json({
+ note: note?.content,
+ note_user_id: user_id,
+ user_id: req.user_id,
+ });
+ },
);
router.put(
- "/:user_id",
- route({
- requestBody: "UserNoteUpdateSchema",
- responses: {
- 204: {},
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { user_id } = req.params;
- const owner = await User.findOneOrFail({ where: { id: req.user_id } });
- const target = await User.findOneOrFail({ where: { id: user_id } }); //if noted user does not exist throw
- const { note } = req.body;
+ "/:user_id",
+ route({
+ requestBody: "UserNoteUpdateSchema",
+ responses: {
+ 204: {},
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { user_id } = req.params;
+ const owner = await User.findOneOrFail({ where: { id: req.user_id } });
+ const target = await User.findOneOrFail({ where: { id: user_id } }); //if noted user does not exist throw
+ const { note } = req.body;
- if (note && note.length) {
- // upsert a note
- if (
- await Note.findOne({
- where: {
- owner: { id: owner.id },
- target: { id: target.id },
- },
- })
- ) {
- Note.update({ owner: { id: owner.id }, target: { id: target.id } }, { owner, target, content: note });
- } else {
- Note.insert({
- id: Snowflake.generate(),
- owner,
- target,
- content: note,
- });
- }
- } else {
- await Note.delete({
- owner: { id: owner.id },
- target: { id: target.id },
- });
- }
+ if (note && note.length) {
+ // upsert a note
+ if (
+ await Note.findOne({
+ where: {
+ owner: { id: owner.id },
+ target: { id: target.id },
+ },
+ })
+ ) {
+ Note.update({ owner: { id: owner.id }, target: { id: target.id } }, { owner, target, content: note });
+ } else {
+ Note.insert({
+ id: Snowflake.generate(),
+ owner,
+ target,
+ content: note,
+ });
+ }
+ } else {
+ await Note.delete({
+ owner: { id: owner.id },
+ target: { id: target.id },
+ });
+ }
- await emitEvent({
- event: "USER_NOTE_UPDATE",
- data: {
- note: note,
- id: target.id,
- },
- user_id: owner.id,
- });
+ await emitEvent({
+ event: "USER_NOTE_UPDATE",
+ data: {
+ note: note,
+ id: target.id,
+ },
+ user_id: owner.id,
+ });
- return res.sendStatus(204);
- },
+ return res.sendStatus(204);
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts
index d3df9eb0..ef6c7798 100644
--- a/src/api/routes/users/@me/relationships.ts
+++ b/src/api/routes/users/@me/relationships.ts
@@ -27,255 +27,255 @@ const router = Router({ mergeParams: true });
const userProjection: (keyof User)[] = ["relationships", ...PublicUserProjection];
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "UserRelationshipsResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- relations: ["relationships", "relationships.to"],
- select: ["id", "relationships"],
- });
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "UserRelationshipsResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ relations: ["relationships", "relationships.to"],
+ select: ["id", "relationships"],
+ });
- const related_users = user.relationships.map((r) => r.toPublicRelationship());
- return res.json(related_users);
- },
+ const related_users = user.relationships.map((r) => r.toPublicRelationship());
+ return res.json(related_users);
+ },
);
router.put(
- "/:user_id",
- route({
- requestBody: "RelationshipPutSchema",
- responses: {
- 204: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- return await updateRelationship(
- req,
- res,
- await User.findOneOrFail({
- where: { id: req.params.user_id },
- relations: ["relationships", "relationships.to"],
- select: userProjection,
- }),
- req.body.type ?? RelationshipType.friends,
- );
- },
+ "/:user_id",
+ route({
+ requestBody: "RelationshipPutSchema",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ return await updateRelationship(
+ req,
+ res,
+ await User.findOneOrFail({
+ where: { id: req.params.user_id },
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
+ }),
+ req.body.type ?? RelationshipType.friends,
+ );
+ },
);
router.post(
- "/",
- route({
- requestBody: "RelationshipPostSchema",
- responses: {
- 204: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- return await updateRelationship(
- req,
- res,
- await User.findOneOrFail({
- relations: ["relationships", "relationships.to"],
- select: userProjection,
- where: {
- discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
- username: req.body.username,
- },
- }),
- req.body.type,
- );
- },
+ "/",
+ route({
+ requestBody: "RelationshipPostSchema",
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ return await updateRelationship(
+ req,
+ res,
+ await User.findOneOrFail({
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
+ where: {
+ discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
+ username: req.body.username,
+ },
+ }),
+ req.body.type,
+ );
+ },
);
router.delete(
- "/:user_id",
- route({
- responses: {
- 204: {},
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { user_id } = req.params;
- if (user_id === req.user_id) throw new HTTPError("You can't remove yourself as a friend");
+ "/:user_id",
+ route({
+ responses: {
+ 204: {},
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { user_id } = req.params;
+ if (user_id === req.user_id) throw new HTTPError("You can't remove yourself as a friend");
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: userProjection,
- relations: ["relationships"],
- });
- const friend = await User.findOneOrFail({
- where: { id: user_id },
- select: userProjection,
- relations: ["relationships"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: userProjection,
+ relations: ["relationships"],
+ });
+ const friend = await User.findOneOrFail({
+ where: { id: user_id },
+ select: userProjection,
+ relations: ["relationships"],
+ });
- const relationship = user.relationships.find((x) => x.to_id === user_id);
- const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+ const relationship = user.relationships.find((x) => x.to_id === user_id);
+ const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
- if (!relationship) throw new HTTPError("You are not friends with the user", 404);
+ if (!relationship) throw new HTTPError("You are not friends with the user", 404);
- if (relationship?.type === RelationshipType.blocked) {
- // unblock user
- await Promise.all([
- Relationship.delete({ id: relationship.id }),
- emitEvent({
- event: "RELATIONSHIP_REMOVE",
- user_id: req.user_id,
- data: relationship.toPublicRelationship(),
- } as RelationshipRemoveEvent),
- ]);
- return res.sendStatus(204);
- }
- if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
- await Promise.all([
- Relationship.delete({ id: friendRequest.id }),
- await emitEvent({
- event: "RELATIONSHIP_REMOVE",
- data: friendRequest.toPublicRelationship(),
- user_id: user_id,
- } as RelationshipRemoveEvent),
- ]);
- }
+ if (relationship?.type === RelationshipType.blocked) {
+ // unblock user
+ await Promise.all([
+ Relationship.delete({ id: relationship.id }),
+ emitEvent({
+ event: "RELATIONSHIP_REMOVE",
+ user_id: req.user_id,
+ data: relationship.toPublicRelationship(),
+ } as RelationshipRemoveEvent),
+ ]);
+ return res.sendStatus(204);
+ }
+ if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
+ await Promise.all([
+ Relationship.delete({ id: friendRequest.id }),
+ await emitEvent({
+ event: "RELATIONSHIP_REMOVE",
+ data: friendRequest.toPublicRelationship(),
+ user_id: user_id,
+ } as RelationshipRemoveEvent),
+ ]);
+ }
- await Promise.all([
- Relationship.delete({ id: relationship.id }),
- emitEvent({
- event: "RELATIONSHIP_REMOVE",
- data: relationship.toPublicRelationship(),
- user_id: req.user_id,
- } as RelationshipRemoveEvent),
- ]);
+ await Promise.all([
+ Relationship.delete({ id: relationship.id }),
+ emitEvent({
+ event: "RELATIONSHIP_REMOVE",
+ data: relationship.toPublicRelationship(),
+ user_id: req.user_id,
+ } as RelationshipRemoveEvent),
+ ]);
- return res.sendStatus(204);
- },
+ return res.sendStatus(204);
+ },
);
export default router;
async function updateRelationship(req: Request, res: Response, friend: User, type: RelationshipType) {
- const id = friend.id;
- if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
+ const id = friend.id;
+ if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- relations: ["relationships", "relationships.to"],
- select: userProjection,
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
+ });
- let relationship = user.relationships.find((x) => x.to_id === id);
- const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+ let relationship = user.relationships.find((x) => x.to_id === id);
+ const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
- // TODO: you can add infinitely many blocked users (should this be prevented?)
- if (type === RelationshipType.blocked) {
- if (relationship) {
- if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user");
- relationship.type = RelationshipType.blocked;
- await relationship.save();
- } else {
- relationship = await Relationship.create({
- to_id: id,
- type: RelationshipType.blocked,
- from_id: req.user_id,
- }).save();
- }
+ // TODO: you can add infinitely many blocked users (should this be prevented?)
+ if (type === RelationshipType.blocked) {
+ if (relationship) {
+ if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user");
+ relationship.type = RelationshipType.blocked;
+ await relationship.save();
+ } else {
+ relationship = await Relationship.create({
+ to_id: id,
+ type: RelationshipType.blocked,
+ from_id: req.user_id,
+ }).save();
+ }
- if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
- await Promise.all([
- Relationship.delete({ id: friendRequest.id }),
- emitEvent({
- event: "RELATIONSHIP_REMOVE",
- data: friendRequest.toPublicRelationship(),
- user_id: id,
- } as RelationshipRemoveEvent),
- ]);
- }
+ if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
+ await Promise.all([
+ Relationship.delete({ id: friendRequest.id }),
+ emitEvent({
+ event: "RELATIONSHIP_REMOVE",
+ data: friendRequest.toPublicRelationship(),
+ user_id: id,
+ } as RelationshipRemoveEvent),
+ ]);
+ }
- await emitEvent({
- event: "RELATIONSHIP_ADD",
- data: relationship.toPublicRelationship(),
- user_id: req.user_id,
- } as RelationshipAddEvent);
+ await emitEvent({
+ event: "RELATIONSHIP_ADD",
+ data: relationship.toPublicRelationship(),
+ user_id: req.user_id,
+ } as RelationshipAddEvent);
- return res.sendStatus(204);
- }
+ return res.sendStatus(204);
+ }
- const { maxFriends } = Config.get().limits.user;
- if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
+ const { maxFriends } = Config.get().limits.user;
+ if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
- let incoming_relationship = Relationship.create({
- nickname: undefined,
- type: RelationshipType.incoming,
- to: user,
- from: friend,
- });
- let outgoing_relationship = Relationship.create({
- nickname: undefined,
- type: RelationshipType.outgoing,
- to: friend,
- from: user,
- });
+ let incoming_relationship = Relationship.create({
+ nickname: undefined,
+ type: RelationshipType.incoming,
+ to: user,
+ from: friend,
+ });
+ let outgoing_relationship = Relationship.create({
+ nickname: undefined,
+ type: RelationshipType.outgoing,
+ to: friend,
+ from: user,
+ });
- if (friendRequest) {
- if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
- if (friendRequest.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
- // accept friend request
- incoming_relationship = friendRequest;
- incoming_relationship.type = RelationshipType.friends;
- }
+ if (friendRequest) {
+ if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
+ if (friendRequest.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+ // accept friend request
+ incoming_relationship = friendRequest;
+ incoming_relationship.type = RelationshipType.friends;
+ }
- if (relationship) {
- if (relationship.type === RelationshipType.outgoing) throw new HTTPError("You already sent a friend request");
- if (relationship.type === RelationshipType.blocked) throw new HTTPError("Unblock the user before sending a friend request");
- if (relationship.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
- outgoing_relationship = relationship;
- outgoing_relationship.type = RelationshipType.friends;
- }
+ if (relationship) {
+ if (relationship.type === RelationshipType.outgoing) throw new HTTPError("You already sent a friend request");
+ if (relationship.type === RelationshipType.blocked) throw new HTTPError("Unblock the user before sending a friend request");
+ if (relationship.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+ outgoing_relationship = relationship;
+ outgoing_relationship.type = RelationshipType.friends;
+ }
- await Promise.all([
- incoming_relationship.save(),
- outgoing_relationship.save(),
- emitEvent({
- event: "RELATIONSHIP_ADD",
- data: outgoing_relationship.toPublicRelationship(),
- user_id: req.user_id,
- } as RelationshipAddEvent),
- emitEvent({
- event: "RELATIONSHIP_ADD",
- data: {
- ...incoming_relationship.toPublicRelationship(),
- should_notify: true,
- },
- user_id: id,
- } as RelationshipAddEvent),
- ]);
+ await Promise.all([
+ incoming_relationship.save(),
+ outgoing_relationship.save(),
+ emitEvent({
+ event: "RELATIONSHIP_ADD",
+ data: outgoing_relationship.toPublicRelationship(),
+ user_id: req.user_id,
+ } as RelationshipAddEvent),
+ emitEvent({
+ event: "RELATIONSHIP_ADD",
+ data: {
+ ...incoming_relationship.toPublicRelationship(),
+ should_notify: true,
+ },
+ user_id: id,
+ } as RelationshipAddEvent),
+ ]);
- return res.sendStatus(204);
+ return res.sendStatus(204);
}
diff --git a/src/api/routes/users/@me/settings-proto/1.ts b/src/api/routes/users/@me/settings-proto/1.ts
index 6f58b422..d54bdf36 100644
--- a/src/api/routes/users/@me/settings-proto/1.ts
+++ b/src/api/routes/users/@me/settings-proto/1.ts
@@ -27,159 +27,159 @@ const router: Router = Router({ mergeParams: true });
//#region Protobuf
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "SettingsProtoResponse",
- },
- },
- query: {
- atomic: {
- type: "boolean",
- description: "Whether to try to apply the settings update atomically (default false)",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description: "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
- res.json({
- settings: PreloadedUserSettings.toBase64(userSettings.userSettings!),
- } as SettingsProtoResponse);
- },
+ res.json({
+ settings: PreloadedUserSettings.toBase64(userSettings.userSettings!),
+ } as SettingsProtoResponse);
+ },
);
router.patch(
- "/",
- route({
- requestBody: "SettingsProtoUpdateSchema",
- responses: {
- 200: {
- body: "SettingsProtoUpdateResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
- const { atomic } = req.query;
- const updatedSettings = PreloadedUserSettings.fromBase64(settings);
+ "/",
+ route({
+ requestBody: "SettingsProtoUpdateSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
+ const { atomic } = req.query;
+ const updatedSettings = PreloadedUserSettings.fromBase64(settings);
- const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
+ const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
- res.json({
- settings: PreloadedUserSettings.toBase64(resultObj.settings),
- out_of_date: resultObj.out_of_date,
- });
- },
+ res.json({
+ settings: PreloadedUserSettings.toBase64(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
);
//#endregion
//#region JSON
router.get(
- "/json",
- route({
- responses: {
- 200: {
- body: "SettingsProtoJsonResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
+ "/json",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoJsonResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
- res.json({
- settings: PreloadedUserSettings.toJson(userSettings.userSettings!),
- } as SettingsProtoJsonResponse);
- },
+ res.json({
+ settings: PreloadedUserSettings.toJson(userSettings.userSettings!),
+ } as SettingsProtoJsonResponse);
+ },
);
router.patch(
- "/json",
- route({
- requestBody: "SettingsProtoUpdateJsonSchema",
- responses: {
- 200: {
- body: "SettingsProtoUpdateJsonResponse",
- },
- },
- query: {
- atomic: {
- type: "boolean",
- description: "Whether to try to apply the settings update atomically (default false)",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
- const { atomic } = req.query;
- const updatedSettings = PreloadedUserSettings.fromJson(settings);
+ "/json",
+ route({
+ requestBody: "SettingsProtoUpdateJsonSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateJsonResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description: "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
+ const { atomic } = req.query;
+ const updatedSettings = PreloadedUserSettings.fromJson(settings);
- const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
+ const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
- res.json({
- settings: PreloadedUserSettings.toJson(resultObj.settings),
- out_of_date: resultObj.out_of_date,
- });
- },
+ res.json({
+ settings: PreloadedUserSettings.toJson(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
);
//#endregion
async function patchUserSettings(userId: string, updatedSettings: PreloadedUserSettings, required_data_version: number | undefined, atomic: boolean = false) {
- const userSettings = await UserSettingsProtos.getOrDefault(userId);
- let settings = userSettings.userSettings!;
+ const userSettings = await UserSettingsProtos.getOrDefault(userId);
+ let settings = userSettings.userSettings!;
- if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
- return {
- settings: settings,
- out_of_date: true,
- };
- }
+ if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
+ return {
+ settings: settings,
+ out_of_date: true,
+ };
+ }
- if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_SETTINGS_UPDATES) && process.env.LOG_PROTO_SETTINGS_UPDATES !== "false")
- console.log(`Updating user settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
+ if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_SETTINGS_UPDATES) && process.env.LOG_PROTO_SETTINGS_UPDATES !== "false")
+ console.log(`Updating user settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
- if (!atomic) {
- settings = PreloadedUserSettings.fromJson(
- Object.assign(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
- );
- } else {
- settings = PreloadedUserSettings.fromJson(
- OrmUtils.mergeDeep(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
- );
- }
+ if (!atomic) {
+ settings = PreloadedUserSettings.fromJson(
+ Object.assign(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
+ );
+ } else {
+ settings = PreloadedUserSettings.fromJson(
+ OrmUtils.mergeDeep(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
+ );
+ }
- settings.versions = {
- clientVersion: updatedSettings.versions?.clientVersion ?? settings.versions?.clientVersion ?? 0,
- serverVersion: settings.versions?.serverVersion ?? 0,
- dataVersion: (settings.versions?.dataVersion ?? 0) + 1,
- };
- userSettings.userSettings = settings;
- await userSettings.save();
+ settings.versions = {
+ clientVersion: updatedSettings.versions?.clientVersion ?? settings.versions?.clientVersion ?? 0,
+ serverVersion: settings.versions?.serverVersion ?? 0,
+ dataVersion: (settings.versions?.dataVersion ?? 0) + 1,
+ };
+ userSettings.userSettings = settings;
+ await userSettings.save();
- await emitEvent({
- user_id: userId,
- event: "USER_SETTINGS_PROTO_UPDATE",
- data: {
- settings: {
- proto: PreloadedUserSettings.toBase64(settings),
- type: 1,
- },
- json_settings: {
- proto: PreloadedUserSettings.toJson(settings),
- type: "user_settings",
- },
- partial: false, // Unsure how this should behave
- },
- });
- // This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
- // when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
+ await emitEvent({
+ user_id: userId,
+ event: "USER_SETTINGS_PROTO_UPDATE",
+ data: {
+ settings: {
+ proto: PreloadedUserSettings.toBase64(settings),
+ type: 1,
+ },
+ json_settings: {
+ proto: PreloadedUserSettings.toJson(settings),
+ type: "user_settings",
+ },
+ partial: false, // Unsure how this should behave
+ },
+ });
+ // This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
+ // when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
- return {
- settings: settings,
- out_of_date: false,
- };
+ return {
+ settings: settings,
+ out_of_date: false,
+ };
}
export default router;
diff --git a/src/api/routes/users/@me/settings-proto/2.ts b/src/api/routes/users/@me/settings-proto/2.ts
index b37805fd..809db848 100644
--- a/src/api/routes/users/@me/settings-proto/2.ts
+++ b/src/api/routes/users/@me/settings-proto/2.ts
@@ -27,159 +27,159 @@ const router: Router = Router({ mergeParams: true });
//#region Protobuf
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "SettingsProtoResponse",
- },
- },
- query: {
- atomic: {
- type: "boolean",
- description: "Whether to try to apply the settings update atomically (default false)",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description: "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
- res.json({
- settings: FrecencyUserSettings.toBase64(userSettings.frecencySettings!),
- } as SettingsProtoResponse);
- },
+ res.json({
+ settings: FrecencyUserSettings.toBase64(userSettings.frecencySettings!),
+ } as SettingsProtoResponse);
+ },
);
router.patch(
- "/",
- route({
- requestBody: "SettingsProtoUpdateSchema",
- responses: {
- 200: {
- body: "SettingsProtoUpdateResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
- const { atomic } = req.query;
- const updatedSettings = FrecencyUserSettings.fromBase64(settings);
+ "/",
+ route({
+ requestBody: "SettingsProtoUpdateSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
+ const { atomic } = req.query;
+ const updatedSettings = FrecencyUserSettings.fromBase64(settings);
- const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
+ const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
- res.json({
- settings: FrecencyUserSettings.toBase64(resultObj.settings),
- out_of_date: resultObj.out_of_date,
- });
- },
+ res.json({
+ settings: FrecencyUserSettings.toBase64(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
);
//#endregion
//#region JSON
router.get(
- "/json",
- route({
- responses: {
- 200: {
- body: "SettingsProtoJsonResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
+ "/json",
+ route({
+ responses: {
+ 200: {
+ body: "SettingsProtoJsonResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
- res.json({
- settings: FrecencyUserSettings.toJson(userSettings.frecencySettings!),
- } as SettingsProtoJsonResponse);
- },
+ res.json({
+ settings: FrecencyUserSettings.toJson(userSettings.frecencySettings!),
+ } as SettingsProtoJsonResponse);
+ },
);
router.patch(
- "/json",
- route({
- requestBody: "SettingsProtoUpdateJsonSchema",
- responses: {
- 200: {
- body: "SettingsProtoUpdateJsonResponse",
- },
- },
- query: {
- atomic: {
- type: "boolean",
- description: "Whether to try to apply the settings update atomically (default false)",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
- const { atomic } = req.query;
- const updatedSettings = FrecencyUserSettings.fromJson(settings);
+ "/json",
+ route({
+ requestBody: "SettingsProtoUpdateJsonSchema",
+ responses: {
+ 200: {
+ body: "SettingsProtoUpdateJsonResponse",
+ },
+ },
+ query: {
+ atomic: {
+ type: "boolean",
+ description: "Whether to try to apply the settings update atomically (default false)",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
+ const { atomic } = req.query;
+ const updatedSettings = FrecencyUserSettings.fromJson(settings);
- const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
+ const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
- res.json({
- settings: FrecencyUserSettings.toJson(resultObj.settings),
- out_of_date: resultObj.out_of_date,
- });
- },
+ res.json({
+ settings: FrecencyUserSettings.toJson(resultObj.settings),
+ out_of_date: resultObj.out_of_date,
+ });
+ },
);
//#endregion
async function patchUserSettings(userId: string, updatedSettings: FrecencyUserSettings, required_data_version: number | undefined, atomic: boolean = false) {
- const userSettings = await UserSettingsProtos.getOrDefault(userId);
- let settings = userSettings.frecencySettings!;
+ const userSettings = await UserSettingsProtos.getOrDefault(userId);
+ let settings = userSettings.frecencySettings!;
- if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
- return {
- settings: settings,
- out_of_date: true,
- };
- }
+ if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
+ return {
+ settings: settings,
+ out_of_date: true,
+ };
+ }
- if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_FRECENCY_UPDATES) && process.env.LOG_PROTO_FRECENCY_UPDATES !== "false")
- console.log(`Updating frecency settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
+ if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_FRECENCY_UPDATES) && process.env.LOG_PROTO_FRECENCY_UPDATES !== "false")
+ console.log(`Updating frecency settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
- if (!atomic) {
- settings = FrecencyUserSettings.fromJson(
- Object.assign(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
- );
- } else {
- settings = FrecencyUserSettings.fromJson(
- OrmUtils.mergeDeep(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
- );
- }
+ if (!atomic) {
+ settings = FrecencyUserSettings.fromJson(
+ Object.assign(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
+ );
+ } else {
+ settings = FrecencyUserSettings.fromJson(
+ OrmUtils.mergeDeep(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
+ );
+ }
- settings.versions = {
- clientVersion: updatedSettings.versions?.clientVersion ?? settings.versions?.clientVersion ?? 0,
- serverVersion: settings.versions?.serverVersion ?? 0,
- dataVersion: (settings.versions?.dataVersion ?? 0) + 1,
- };
- userSettings.frecencySettings = settings;
- await userSettings.save();
+ settings.versions = {
+ clientVersion: updatedSettings.versions?.clientVersion ?? settings.versions?.clientVersion ?? 0,
+ serverVersion: settings.versions?.serverVersion ?? 0,
+ dataVersion: (settings.versions?.dataVersion ?? 0) + 1,
+ };
+ userSettings.frecencySettings = settings;
+ await userSettings.save();
- await emitEvent({
- user_id: userId,
- event: "USER_SETTINGS_PROTO_UPDATE",
- data: {
- settings: {
- proto: FrecencyUserSettings.toBase64(settings),
- type: 2,
- },
- json_settings: {
- proto: FrecencyUserSettings.toJson(settings),
- type: "frecency_settings",
- },
- partial: false, // Unsure how this should behave
- },
- });
- // This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
- // when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
+ await emitEvent({
+ user_id: userId,
+ event: "USER_SETTINGS_PROTO_UPDATE",
+ data: {
+ settings: {
+ proto: FrecencyUserSettings.toBase64(settings),
+ type: 2,
+ },
+ json_settings: {
+ proto: FrecencyUserSettings.toJson(settings),
+ type: "frecency_settings",
+ },
+ partial: false, // Unsure how this should behave
+ },
+ });
+ // This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
+ // when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
- return {
- settings: settings,
- out_of_date: false,
- };
+ return {
+ settings: settings,
+ out_of_date: false,
+ };
}
export default router;
diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts
index d220b859..57ffba14 100644
--- a/src/api/routes/users/@me/settings.ts
+++ b/src/api/routes/users/@me/settings.ts
@@ -24,81 +24,81 @@ import { UserSettingsUpdateSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.get(
- "/",
- route({
- responses: {
- 200: {
- body: "UserSettings",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const settings = await UserSettings.getOrDefault(req.user_id);
- return res.json(settings);
- },
+ "/",
+ route({
+ responses: {
+ 200: {
+ body: "UserSettings",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const settings = await UserSettings.getOrDefault(req.user_id);
+ return res.json(settings);
+ },
);
router.patch(
- "/",
- route({
- requestBody: "UserSettingsUpdateSchema",
- responses: {
- 200: {
- body: "UserSettings",
- },
- 400: {
- body: "APIErrorResponse",
- },
- 404: {
- body: "APIErrorResponse",
- },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UserSettingsUpdateSchema;
- if (!body) return res.status(400).json({ code: 400, message: "Invalid request body" });
- if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unknown locale
+ "/",
+ route({
+ requestBody: "UserSettingsUpdateSchema",
+ responses: {
+ 200: {
+ body: "UserSettings",
+ },
+ 400: {
+ body: "APIErrorResponse",
+ },
+ 404: {
+ body: "APIErrorResponse",
+ },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserSettingsUpdateSchema;
+ if (!body) return res.status(400).json({ code: 400, message: "Invalid request body" });
+ if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unknown locale
- const user = await User.findOneOrFail({
- where: { id: req.user_id, bot: false },
- relations: ["settings"],
- });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id, bot: false },
+ relations: ["settings"],
+ });
- if (!user.settings) user.settings = UserSettings.create<UserSettings>(body);
- else user.settings.assign(body);
+ if (!user.settings) user.settings = UserSettings.create<UserSettings>(body);
+ else user.settings.assign(body);
- if (body.guild_folders) user.settings.guild_folders = body.guild_folders;
+ if (body.guild_folders) user.settings.guild_folders = body.guild_folders;
- await user.settings.save();
- await user.save();
- if (body.status) {
- const [session] = (await Session.find({
- where: { user_id: user.id },
- })) as [Session | undefined];
- if (session) {
- session.status = body.status;
+ await user.settings.save();
+ await user.save();
+ if (body.status) {
+ const [session] = (await Session.find({
+ where: { user_id: user.id },
+ })) as [Session | undefined];
+ if (session) {
+ session.status = body.status;
- await Promise.all([
- emitEvent({
- event: "PRESENCE_UPDATE",
- user_id: user.id,
- data: {
- user: user.toPublicUser(),
- activities: session.activities,
- client_status: session?.client_status,
- status: session.getPublicStatus(),
- },
- } as PresenceUpdateEvent),
- session.save(),
- ]);
- }
- }
+ await Promise.all([
+ emitEvent({
+ event: "PRESENCE_UPDATE",
+ user_id: user.id,
+ data: {
+ user: user.toPublicUser(),
+ activities: session.activities,
+ client_status: session?.client_status,
+ status: session.getPublicStatus(),
+ },
+ } as PresenceUpdateEvent),
+ session.save(),
+ ]);
+ }
+ }
- res.json({ ...user.settings, index: undefined });
- },
+ res.json({ ...user.settings, index: undefined });
+ },
);
export default router;
|