From 3335f16ad1a6ec114058a8b7e6e71c2cae33c33d Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 23 Mar 2023 11:01:38 -0400 Subject: [PATCH] applications --- assets/schemas.json | Bin 2417674 -> 3951834 bytes src/api/routes/applications/#id/bot/index.ts | 124 +++++++++++------- .../routes/applications/#id/entitlements.ts | 22 +++- src/api/routes/applications/#id/index.ts | 91 +++++++++---- src/api/routes/applications/#id/skus.ts | 18 ++- src/api/routes/applications/detectable.ts | 20 ++- src/api/routes/applications/index.ts | 37 ++++-- src/api/util/handlers/route.ts | 3 +- .../ApplicationDetectableResponse.ts | 1 + .../ApplicationEntitlementsResponse.ts | 1 + .../responses/ApplicationSkusResponse.ts | 1 + .../schemas/responses/ApplicationsResponse.ts | 3 + src/util/schemas/responses/index.ts | 4 + 13 files changed, 227 insertions(+), 98 deletions(-) create mode 100644 src/util/schemas/responses/ApplicationDetectableResponse.ts create mode 100644 src/util/schemas/responses/ApplicationEntitlementsResponse.ts create mode 100644 src/util/schemas/responses/ApplicationSkusResponse.ts create mode 100644 src/util/schemas/responses/ApplicationsResponse.ts diff --git a/assets/schemas.json b/assets/schemas.json index 923ddd89ef9303f52b0592603972e85944a9df80..db47e1fc5544fc8a7f6039b32e61a86c5a683ca4 100644 GIT binary patch delta 214904 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 Osr4MN_$gB+u37*B=!F6R diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts index e3f1832c..1df7fba0 100644 --- a/src/api/routes/applications/#id/bot/index.ts +++ b/src/api/routes/applications/#id/bot/index.ts @@ -16,78 +16,114 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; import { Application, - generateToken, - User, BotModifySchema, - handleFile, DiscordApiErrors, + User, + generateToken, + handleFile, } from "@spacebar/util"; +import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; import { verifyToken } from "node-2fa"; const router: Router = Router(); -router.post("/", route({}), async (req: Request, res: Response) => { - const app = await Application.findOneOrFail({ - where: { id: req.params.id }, - relations: ["owner"], - }); +router.post( + "/", + route({ + responses: { + 200: { + body: "TokenResponse", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const app = await Application.findOneOrFail({ + where: { id: req.params.id }, + relations: ["owner"], + }); - if (app.owner.id != req.user_id) - throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; - const user = await User.register({ - username: app.name, - password: undefined, - id: app.id, - req, - }); + const user = await User.register({ + username: app.name, + password: undefined, + id: app.id, + req, + }); - user.id = app.id; - user.premium_since = new Date(); - user.bot = true; + user.id = app.id; + user.premium_since = new Date(); + user.bot = true; - await user.save(); + await user.save(); - // flags is NaN here? - app.assign({ bot: user, flags: app.flags || 0 }); + // flags is NaN here? + app.assign({ bot: user, flags: app.flags || 0 }); - await app.save(); + await app.save(); - res.send({ - token: await generateToken(user.id), - }).status(204); -}); + res.send({ + token: await generateToken(user.id), + }).status(204); + }, +); -router.post("/reset", route({}), async (req: Request, res: Response) => { - const bot = await User.findOneOrFail({ where: { id: req.params.id } }); - const owner = await User.findOneOrFail({ where: { id: req.user_id } }); +router.post( + "/reset", + route({ + responses: { + 200: { + body: "TokenResponse", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const bot = await User.findOneOrFail({ where: { id: req.params.id } }); + const owner = await User.findOneOrFail({ where: { id: req.user_id } }); - if (owner.id != req.user_id) - throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + if (owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; - if ( - owner.totp_secret && - (!req.body.code || verifyToken(owner.totp_secret, req.body.code)) - ) - throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); + if ( + owner.totp_secret && + (!req.body.code || verifyToken(owner.totp_secret, req.body.code)) + ) + throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); - bot.data = { hash: undefined, valid_tokens_since: new Date() }; + bot.data = { hash: undefined, valid_tokens_since: new Date() }; - await bot.save(); + await bot.save(); - const token = await generateToken(bot.id); + const token = await generateToken(bot.id); - res.json({ token }).status(200); -}); + res.json({ token }).status(200); + }, +); router.patch( "/", - route({ body: "BotModifySchema" }), + route({ + body: "BotModifySchema", + responses: { + 200: { + body: "Application", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), async (req: Request, res: Response) => { const body = req.body as BotModifySchema; if (!body.avatar?.trim()) delete body.avatar; diff --git a/src/api/routes/applications/#id/entitlements.ts b/src/api/routes/applications/#id/entitlements.ts index e88fb7f7..6388e6b3 100644 --- a/src/api/routes/applications/#id/entitlements.ts +++ b/src/api/routes/applications/#id/entitlements.ts @@ -16,15 +16,25 @@ along with this program. If not, see . */ -import { Router, Response, Request } from "express"; import { route } from "@spacebar/api"; +import { Request, Response, Router } from "express"; const router = Router(); -router.get("/", route({}), (req: Request, res: Response) => { - // TODO: - //const { exclude_consumed } = req.query; - res.status(200).send([]); -}); +router.get( + "/", + route({ + responses: { + 200: { + body: "ApplicationEntitlementsResponse", + }, + }, + }), + (req: Request, res: Response) => { + // TODO: + //const { exclude_consumed } = req.query; + res.status(200).send([]); + }, +); export default router; diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts index 067f5dad..dec2a9b1 100644 --- a/src/api/routes/applications/#id/index.ts +++ b/src/api/routes/applications/#id/index.ts @@ -16,32 +16,55 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; import { Application, - DiscordApiErrors, ApplicationModifySchema, + DiscordApiErrors, } from "@spacebar/util"; -import { verifyToken } from "node-2fa"; +import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; +import { verifyToken } from "node-2fa"; const router: Router = Router(); -router.get("/", route({}), async (req: Request, res: Response) => { - const app = await Application.findOneOrFail({ - where: { id: req.params.id }, - relations: ["owner", "bot"], - }); - if (app.owner.id != req.user_id) - throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; +router.get( + "/", + route({ + responses: { + 200: { + body: "Application", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const app = await Application.findOneOrFail({ + where: { id: req.params.id }, + relations: ["owner", "bot"], + }); + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; - return res.json(app); -}); + return res.json(app); + }, +); router.patch( "/", - route({ body: "ApplicationModifySchema" }), + route({ + body: "ApplicationModifySchema", + responses: { + 200: { + body: "Application", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), async (req: Request, res: Response) => { const body = req.body as ApplicationModifySchema; @@ -73,23 +96,35 @@ router.patch( }, ); -router.post("/delete", route({}), async (req: Request, res: Response) => { - const app = await Application.findOneOrFail({ - where: { id: req.params.id }, - relations: ["bot", "owner"], - }); - if (app.owner.id != req.user_id) - throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; +router.post( + "/delete", + route({ + responses: { + 200: {}, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const app = await Application.findOneOrFail({ + where: { id: req.params.id }, + relations: ["bot", "owner"], + }); + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; - if ( - app.owner.totp_secret && - (!req.body.code || verifyToken(app.owner.totp_secret, req.body.code)) - ) - throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); + if ( + app.owner.totp_secret && + (!req.body.code || + verifyToken(app.owner.totp_secret, req.body.code)) + ) + throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); - await Application.delete({ id: app.id }); + await Application.delete({ id: app.id }); - res.send().status(200); -}); + res.send().status(200); + }, +); export default router; diff --git a/src/api/routes/applications/#id/skus.ts b/src/api/routes/applications/#id/skus.ts index fcb75423..dc4fad23 100644 --- a/src/api/routes/applications/#id/skus.ts +++ b/src/api/routes/applications/#id/skus.ts @@ -16,13 +16,23 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; +import { Request, Response, Router } from "express"; const router: Router = Router(); -router.get("/", route({}), async (req: Request, res: Response) => { - res.json([]).status(200); -}); +router.get( + "/", + route({ + responses: { + 200: { + body: "ApplicationSkusResponse", + }, + }, + }), + async (req: Request, res: Response) => { + res.json([]).status(200); + }, +); export default router; diff --git a/src/api/routes/applications/detectable.ts b/src/api/routes/applications/detectable.ts index a8e30894..5cf9d171 100644 --- a/src/api/routes/applications/detectable.ts +++ b/src/api/routes/applications/detectable.ts @@ -16,14 +16,24 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; +import { Request, Response, Router } from "express"; const router: Router = Router(); -router.get("/", route({}), async (req: Request, res: Response) => { - //TODO - res.send([]).status(200); -}); +router.get( + "/", + route({ + responses: { + 200: { + body: "ApplicationDetectableResponse", + }, + }, + }), + async (req: Request, res: Response) => { + //TODO + res.send([]).status(200); + }, +); export default router; diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts index 80a19aa8..2290414c 100644 --- a/src/api/routes/applications/index.ts +++ b/src/api/routes/applications/index.ts @@ -16,28 +16,45 @@ along with this program. If not, see . */ -import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; import { Application, ApplicationCreateSchema, - trimSpecial, User, + trimSpecial, } from "@spacebar/util"; +import { Request, Response, Router } from "express"; const router: Router = Router(); -router.get("/", route({}), async (req: Request, res: Response) => { - const results = await Application.find({ - where: { owner: { id: req.user_id } }, - relations: ["owner", "bot"], - }); - res.json(results).status(200); -}); +router.get( + "/", + route({ + responses: { + 200: { + body: "ApplicationsResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const results = await Application.find({ + where: { owner: { id: req.user_id } }, + relations: ["owner", "bot"], + }); + res.json(results).status(200); + }, +); router.post( "/", - route({ body: "ApplicationCreateSchema" }), + route({ + body: "ApplicationCreateSchema", + responses: { + 200: { + body: "Application", + }, + }, + }), async (req: Request, res: Response) => { const body = req.body as ApplicationCreateSchema; const user = await User.findOneOrFail({ where: { id: req.user_id } }); diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts index 66bd2890..04910ed4 100644 --- a/src/api/util/handlers/route.ts +++ b/src/api/util/handlers/route.ts @@ -55,7 +55,8 @@ export interface RouteOptions { body?: `${string}Schema`; // typescript interface name responses?: { [status: number]: { - body?: `${string}Response`; + // body?: `${string}Response`; + body?: string; }; }; test?: { diff --git a/src/util/schemas/responses/ApplicationDetectableResponse.ts b/src/util/schemas/responses/ApplicationDetectableResponse.ts new file mode 100644 index 00000000..958b8d43 --- /dev/null +++ b/src/util/schemas/responses/ApplicationDetectableResponse.ts @@ -0,0 +1 @@ +export type ApplicationDetectableResponse = unknown[]; diff --git a/src/util/schemas/responses/ApplicationEntitlementsResponse.ts b/src/util/schemas/responses/ApplicationEntitlementsResponse.ts new file mode 100644 index 00000000..1d2b349e --- /dev/null +++ b/src/util/schemas/responses/ApplicationEntitlementsResponse.ts @@ -0,0 +1 @@ +export type ApplicationEntitlementsResponse = unknown[]; diff --git a/src/util/schemas/responses/ApplicationSkusResponse.ts b/src/util/schemas/responses/ApplicationSkusResponse.ts new file mode 100644 index 00000000..8d577c92 --- /dev/null +++ b/src/util/schemas/responses/ApplicationSkusResponse.ts @@ -0,0 +1 @@ +export type ApplicationSkusResponse = unknown[]; diff --git a/src/util/schemas/responses/ApplicationsResponse.ts b/src/util/schemas/responses/ApplicationsResponse.ts new file mode 100644 index 00000000..fef3fbde --- /dev/null +++ b/src/util/schemas/responses/ApplicationsResponse.ts @@ -0,0 +1,3 @@ +import { Application } from "../../entities"; + +export type ApplicationsResponse = Application[]; diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts index ed91b866..6dde4d24 100644 --- a/src/util/schemas/responses/index.ts +++ b/src/util/schemas/responses/index.ts @@ -1,5 +1,9 @@ export * from "./APIErrorOrCaptchaResponse"; export * from "./APIErrorResponse"; +export * from "./ApplicationDetectableResponse"; +export * from "./ApplicationEntitlementsResponse"; +export * from "./ApplicationSkusResponse"; +export * from "./ApplicationsResponse"; export * from "./BackupCodesChallengeResponse"; export * from "./CaptchaRequiredResponse"; export * from "./GenerateRegistrationTokensResponse";