From 1cc42244af23b6d3c4934d6c44026244485481fa Mon Sep 17 00:00:00 2001 From: Dlurak <84224239+Dlurak@users.noreply.github.com> Date: Sat, 30 Mar 2024 21:31:27 +0100 Subject: [PATCH] Add an endpoint to get a list of requests or the own request --- src/routes/moderation/index.ts | 9 +++-- src/routes/moderation/list.ts | 67 +++++++++++++++++++++++++++++++++ src/routes/moderation/own.ts | 57 ++++++++++++++++++++++++++++ src/utils/objects/transform.ts | 18 ++++++--- tests/objects/transform.test.ts | 20 ++++++++++ 5 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 src/routes/moderation/list.ts create mode 100644 src/routes/moderation/own.ts diff --git a/src/routes/moderation/index.ts b/src/routes/moderation/index.ts index 931be93..7a3bab6 100644 --- a/src/routes/moderation/index.ts +++ b/src/routes/moderation/index.ts @@ -1,6 +1,9 @@ import Elysia from "elysia"; import { createJoinRequest } from "./create"; +import { listJoinRequests } from "./list"; +import { ownJoinRequest } from "./own"; -export const moderationRouter = new Elysia({ prefix: "/mod" }).use( - createJoinRequest, -); +export const moderationRouter = new Elysia({ prefix: "/mod" }) + .use(ownJoinRequest("/own")) + .use(createJoinRequest) + .use(listJoinRequests); diff --git a/src/routes/moderation/list.ts b/src/routes/moderation/list.ts new file mode 100644 index 0000000..eca4789 --- /dev/null +++ b/src/routes/moderation/list.ts @@ -0,0 +1,67 @@ +import e from "@edgedb"; +import { DATABASE_READ_FAILED, UNAUTHORIZED } from "constants/responses"; +import Elysia, { t } from "elysia"; +import { HttpStatusCode } from "elysia-http-status-code"; +import { client } from "index"; +import { auth } from "plugins/auth"; +import { promiseResult } from "utils/errors"; +import { replaceDateWithTimestamp } from "utils/objects/transform"; +import { responseBuilder } from "utils/response"; + +export const listJoinRequests = new Elysia() + .use(HttpStatusCode()) + .use(auth) + .get("/", async ({ set, auth, httpStatus }) => { + if (!auth.isAuthorized) { + set.status = httpStatus.HTTP_401_UNAUTHORIZED; + return UNAUTHORIZED; + } + + const joinRequestsQuery = e.select(e.JoinRequest, (jr) => { + const classMatches = e.op( + jr.wantsToJoin.students.username, + "=", + auth.username, + ); + + return { + filter: classMatches, + + user: () => ({ + username: true, + displayname: true, + created: true, + classes: () => ({ + name: true, + school: () => ({ name: true }), + }), + }), + wantsToJoin: () => ({ + name: true, + school: () => ({ name: true }), + }), + status: true, + created: true, + reviewedAt: true, + reviewedBy: () => ({ + username: true, + displayname: true, + }), + id: true, + }; + }); + const joinRequests = await promiseResult(() => + joinRequestsQuery.run(client), + ); + + if (joinRequests.isError) { + set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR; + return DATABASE_READ_FAILED; + } + + const responseData = joinRequests.data.map(replaceDateWithTimestamp); + return responseBuilder("success", { + message: `Successfully retrieved join requests ${auth.username} can review`, + data: responseData, + }); + }); diff --git a/src/routes/moderation/own.ts b/src/routes/moderation/own.ts new file mode 100644 index 0000000..555d9c6 --- /dev/null +++ b/src/routes/moderation/own.ts @@ -0,0 +1,57 @@ +import e from "@edgedb"; +import { DATABASE_READ_FAILED, UNAUTHORIZED } from "constants/responses"; +import Elysia from "elysia"; +import { HttpStatusCode } from "elysia-http-status-code"; +import { client } from "index"; +import { auth } from "plugins/auth"; +import { promiseResult } from "utils/errors"; +import { replaceDateWithTimestamp } from "utils/objects/transform"; +import { responseBuilder } from "utils/response"; + +export const ownJoinRequest = (path: string) => + new Elysia() + .use(auth) + .use(HttpStatusCode()) + .get(path, async ({ auth, httpStatus, set }) => { + if (!auth.isAuthorized) { + set.status = httpStatus.HTTP_401_UNAUTHORIZED; + return UNAUTHORIZED; + } + + const joinRequestQuery = e.select(e.JoinRequest, (jr) => ({ + filter: e.op(jr.user.username, "=", auth.username), + + status: true, + created: true, + reviewedAt: true, + reviewedBy: () => ({ + username: true, + displayname: true, + }), + wantsToJoin: () => ({ + name: true, + school: () => ({ name: true }), + }), + })); + + const joinRequest = await promiseResult(() => + joinRequestQuery.run(client), + ); + + if (joinRequest.isError) { + set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR; + return DATABASE_READ_FAILED; + } + if (!joinRequest.data) { + set.status = httpStatus.HTTP_404_NOT_FOUND; + return responseBuilder("error", { + error: `No join request found for user ${auth.username}`, + }); + } + + const responseData = joinRequest.data.map(replaceDateWithTimestamp); + return responseBuilder("success", { + message: `Successfully retrieved join request for ${auth.username}`, + data: responseData, + }); + }); diff --git a/src/utils/objects/transform.ts b/src/utils/objects/transform.ts index 1e8447d..bb47b59 100644 --- a/src/utils/objects/transform.ts +++ b/src/utils/objects/transform.ts @@ -1,27 +1,33 @@ type Object = Record; -type ConvertDatesOther = { - [K in keyof T]: T[K] extends Date ? R : T[K]; +type ConverDatesDeep = { + [K in keyof T]: T[K] extends Date + ? R + : T[K] extends Object + ? ConverDatesDeep + : T[K]; }; type DateCallback = (val: Date) => T; -export const replaceDate = ( +export const replaceDateDeep = ( obj: T, callback: DateCallback, -): ConvertDatesOther => { +): ConverDatesDeep => { const pairs = Object.entries(obj); const newPairs: [string, unknown][] = []; for (const [key, val] of pairs) { if (val instanceof Date) newPairs.push([key, callback(val)]); + else if (typeof val === "object" && val) + newPairs.push([key, replaceDateDeep(val as Object, callback)]); else newPairs.push([key, val]); } - return Object.fromEntries(newPairs) as ConvertDatesOther; + return Object.fromEntries(newPairs) as ConverDatesDeep; }; /** * Replaces all Date objects in an object with their timestamp */ export const replaceDateWithTimestamp = (obj: T) => - replaceDate(obj, (val) => val.getTime()); + replaceDateDeep(obj, (val) => val.getTime()); diff --git a/tests/objects/transform.test.ts b/tests/objects/transform.test.ts index 87048b7..be83a9e 100644 --- a/tests/objects/transform.test.ts +++ b/tests/objects/transform.test.ts @@ -16,4 +16,24 @@ describe("transform", () => { string: "hello", }); }); + + it("works recursively", () => { + const obj = { + date: new Date("2021-01-01"), + inner: { + date: new Date("2021-01-01"), + number: 1, + string: "hello", + }, + }; + + expect(replaceDateWithTimestamp(obj)).toEqual({ + date: 1609459200000, + inner: { + date: 1609459200000, + number: 1, + string: "hello", + }, + }); + }); });