summary refs log tree commit diff
path: root/api/src/util/route.ts
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-09-12 23:32:55 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-09-12 23:32:55 +0200
commit33533fc183d3dce4abcb49d76c2d14bdb26e771a (patch)
tree388837320acfb6d0d04993b258207e1d814ba0d1 /api/src/util/route.ts
parentMerge pull request #353 from AlTech98/dummy-routes (diff)
parent:sparkles: #307 done (diff)
downloadserver-33533fc183d3dce4abcb49d76c2d14bdb26e771a.tar.xz
Merge branch 'typescript-interface-body-parser+autogenerate-unit-tests+documentation'
Diffstat (limited to 'api/src/util/route.ts')
-rw-r--r--api/src/util/route.ts76
1 files changed, 76 insertions, 0 deletions
diff --git a/api/src/util/route.ts b/api/src/util/route.ts
new file mode 100644

index 00000000..f618a630 --- /dev/null +++ b/api/src/util/route.ts
@@ -0,0 +1,76 @@ +import { DiscordApiErrors, Event, EventData, getPermission, PermissionResolvable, Permissions } from "@fosscord/util"; +import { NextFunction, Request, Response } from "express"; +import fs from "fs"; +import path from "path"; +import Ajv from "ajv"; +import { AnyValidateFunction } from "ajv/dist/core"; +import { FieldErrors } from ".."; +import addFormats from "ajv-formats"; + +const SchemaPath = path.join(__dirname, "..", "..", "assets", "schemas.json"); +const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" })); +export const ajv = new Ajv({ + allErrors: true, + parseDate: true, + allowDate: true, + schemas, + messages: true, + strict: true, + strictRequired: true +}); +addFormats(ajv); + +declare global { + namespace Express { + interface Request { + permission?: Permissions; + } + } +} + +export type RouteSchema = string; // typescript interface name +export type RouteResponse = { status?: number; body?: RouteSchema; headers?: Record<string, string> }; + +export interface RouteOptions { + permission?: PermissionResolvable; + body?: RouteSchema; + response?: RouteResponse; + example?: { + body?: any; + path?: string; + event?: EventData; + headers?: Record<string, string>; + }; +} + +export function route(opts: RouteOptions) { + var validate: AnyValidateFunction<any>; + if (opts.body) { + // @ts-ignore + validate = ajv.getSchema(opts.body); + if (!validate) throw new Error(`Body schema ${opts.body} not found`); + } + + return async (req: Request, res: Response, next: NextFunction) => { + if (opts.permission) { + const required = new Permissions(opts.permission); + const permission = await getPermission(req.user_id, req.params.guild_id, req.params.channel_id); + console.log(required.bitfield, permission.bitfield, permission.bitfield & required.bitfield); + + // bitfield comparison: check if user lacks certain permission + if (!permission.has(required)) { + throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(opts.permission as string); + } + + if (validate) { + const valid = validate(req.body); + if (!valid) { + const fields: Record<string, { code?: string; message: string }> = {}; + validate.errors?.forEach((x) => (fields[x.instancePath] = { code: x.keyword, message: x.message || "" })); + throw FieldErrors(fields); + } + } + } + next(); + }; +}