From 0d9b8fb4faf1e714143bc8b720253f70aa5af85e Mon Sep 17 00:00:00 2001 From: Dominic Ferrando Date: Sat, 26 Sep 2026 16:07:21 -0400 Subject: [PATCH] Refactor /me routes --- apps/api/src/server.ts | 173 +++++++++--------- .../src/lib/components/PlayersTable.svelte | 8 +- 2 files changed, 87 insertions(+), 94 deletions(-) diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index fc61ece..a2a10fd 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -458,6 +458,7 @@ export const app = new Elysia() // ACCOUNTS .group("/accounts", (app) => app + // TODO: for added security, could enforce bot or admin only access .get("/:id/stats", async ({ params: { id } }) => { const stats = await s.Accounts.stats(id); if (!stats) throw new NotFoundError("Account stats not found"); @@ -465,13 +466,6 @@ export const app = new Elysia() }, { params: t.Object({ id: t.String() }) }) - .guard({ auth: true }, (app) => app - .get("/me/stats", async ({ accountId }) => { - const stats = await s.Accounts.stats(accountId); - if (!stats) throw new NotFoundError("Account stats not found"); - return stats; - }) - ) .guard({ authAdmin: true }, (app) => app .get("/:id", async ({ params: { id } }) => { const account = await s.Accounts.get(id); @@ -481,12 +475,13 @@ export const app = new Elysia() params: t.Object({ id: t.String() }) }) ) - ) - - // ASSESSMENTS - .group("/assessments", (app) => app - .guard({ auth: true }, (app) => app - .post("/me", async ({ body: { player, activityPerformances }, accountId }) => { + .group("/me", { auth: true }, (app) => app + .get("/stats", async ({ accountId }) => { + const stats = await s.Accounts.stats(accountId); + if (!stats) throw new NotFoundError("Account stats not found"); + return stats; + }) + .post("/assessments", async ({ body: { player, activityPerformances }, accountId }) => { return await s.Assessments.create(player, activityPerformances, accountId); }, { body: t.Object({ @@ -494,43 +489,16 @@ export const app = new Elysia() activityPerformances: t.Array(ActivityPerformanceSchema) }) }) - .get("/me", async ({ accountId }) => { + .get("/assessments", async ({ accountId }) => { return await s.Assessments.list({ filter: { accountId } }); }) - .delete("/me/:id", async ({ params: { id }, accountId }) => { + .delete("/assessments/:id", async ({ params: { id }, accountId }) => { const deleted = await s.Assessments.delete(id, accountId); if (!deleted) throw new NotFoundError("Assessment not found"); }, { params: t.Object({ id: t.String() }) }) - ) - .guard({ authAdmin: true }, (app) => app - .post("/", async ({ body: { player, activityPerformances, id } }) => { - await s.Assessments.create(player, activityPerformances, id); - }, { - body: t.Object({ - player: PlayerSchema, - activityPerformances: t.Array(ActivityPerformanceSchema), - id: t.Optional(t.String()), - }) - }) - .put("/:id", async ({ body: { player, activityPerformances }, params: { id } }) => { - const updated = await s.Assessments.update(id, player, activityPerformances); - if (!updated) throw new NotFoundError("Assessment not found"); - }, { - params: t.Object({ id: t.String() }), - body: t.Object({ - player: PlayerSchema, - activityPerformances: t.Array(ActivityPerformanceSchema), - }) - }) - ) - ) - - // VERIFICATIONS - .group("/verifications", (app) => app - .guard({ auth: true }, (app) => app - .post("/me", async ({ body: { assessmentId, activityVideoUrls }, accountId }) => { + .post("/verifications", async ({ body: { assessmentId, activityVideoUrls }, accountId }) => { const requested = await s.Verifications.request(assessmentId, accountId, activityVideoUrls); if (!requested) throw new NotFoundError("Assessment not found"); return requested; @@ -541,57 +509,82 @@ export const app = new Elysia() }) }) ) - .guard({ authAdmin: true }, (app) => app - .get("/", async ({ query }) => { - return await s.Verifications.list({ - filter: { status: query.status }, - limit: query.limit, - offset: query.offset, - }); - }, { - query: t.Object({ - status: t.Optional(VerificationStatusSchema), - limit: t.Optional(t.Numeric()), - offset: t.Optional(t.Numeric()), - }) - }) - .get("/:id", async ({ params: { id } }) => { - const verification = await s.Verifications.get(id); - if (!verification) throw new NotFoundError("Verification not found"); - return verification; - }, { - params: t.Object({ id: t.String() }) - }) - .post("/:id/request-action", async ({ params: { id }, body: { reviewerNotes, activityVerifications } }) => { - const verification = await s.Verifications.get(id); - if (!verification) throw new NotFoundError("Verification not found"); - if (verification.status === "completed" || verification.status === "action_requested") - throw status(409, { error: "Cannot modify a completed or action-requested verification" }); + ) - const updated = await s.Verifications.requestAction(id, reviewerNotes ?? null, activityVerifications); - if (!updated) throw new NotFoundError("Verification not found"); - }, { - params: t.Object({ id: t.String() }), - body: t.Object({ - reviewerNotes: t.Optional(t.String()), - activityVerifications: ActivityVerificationsSchema, - }) + // ASSESSMENTS + .group("/assessments", { authAdmin: true }, (app) => app + .post("/", async ({ body: { player, activityPerformances, id } }) => { + await s.Assessments.create(player, activityPerformances, id); + }, { + body: t.Object({ + player: PlayerSchema, + activityPerformances: t.Array(ActivityPerformanceSchema), + id: t.Optional(t.String()), }) - .post("/:id/complete", async ({ params: { id }, body: { activityVerifications }, accountId }) => { - const verification = await s.Verifications.get(id); - if (!verification) throw new NotFoundError("Verification not found"); - if (verification.status === "completed" || verification.status === "action_requested") - throw status(409, { error: "Cannot modify a completed or action-requested verification" }); + }) + .put("/:id", async ({ body: { player, activityPerformances }, params: { id } }) => { + const updated = await s.Assessments.update(id, player, activityPerformances); + if (!updated) throw new NotFoundError("Assessment not found"); + }, { + params: t.Object({ id: t.String() }), + body: t.Object({ + player: PlayerSchema, + activityPerformances: t.Array(ActivityPerformanceSchema), + }) + }) + ) - const updated = await s.Verifications.complete(id, accountId, activityVerifications); - if (!updated) throw new NotFoundError("Verification not found"); - }, { - params: t.Object({ id: t.String() }), - body: t.Object({ - activityVerifications: ActivityVerificationsSchema, - }) + // VERIFICATIONS + .group("/verifications", { authAdmin: true }, (app) => app + .get("/", async ({ query }) => { + return await s.Verifications.list({ + filter: { status: query.status }, + limit: query.limit, + offset: query.offset, + }); + }, { + query: t.Object({ + status: t.Optional(VerificationStatusSchema), + limit: t.Optional(t.Numeric()), + offset: t.Optional(t.Numeric()), }) - ) + }) + .get("/:id", async ({ params: { id } }) => { + const verification = await s.Verifications.get(id); + if (!verification) throw new NotFoundError("Verification not found"); + return verification; + }, { + params: t.Object({ id: t.String() }) + }) + .post("/:id/request-action", async ({ params: { id }, body: { reviewerNotes, activityVerifications } }) => { + const verification = await s.Verifications.get(id); + if (!verification) throw new NotFoundError("Verification not found"); + if (verification.status === "completed" || verification.status === "action_requested") + throw status(409, { error: "Cannot modify a completed or action-requested verification" }); + + const updated = await s.Verifications.requestAction(id, reviewerNotes ?? null, activityVerifications); + if (!updated) throw new NotFoundError("Verification not found"); + }, { + params: t.Object({ id: t.String() }), + body: t.Object({ + reviewerNotes: t.Optional(t.String()), + activityVerifications: ActivityVerificationsSchema, + }) + }) + .post("/:id/complete", async ({ params: { id }, body: { activityVerifications }, accountId }) => { + const verification = await s.Verifications.get(id); + if (!verification) throw new NotFoundError("Verification not found"); + if (verification.status === "completed" || verification.status === "action_requested") + throw status(409, { error: "Cannot modify a completed or action-requested verification" }); + + const updated = await s.Verifications.complete(id, accountId, activityVerifications); + if (!updated) throw new NotFoundError("Verification not found"); + }, { + params: t.Object({ id: t.String() }), + body: t.Object({ + activityVerifications: ActivityVerificationsSchema, + }) + }) ) // WEBHOOKS diff --git a/apps/portal/src/lib/components/PlayersTable.svelte b/apps/portal/src/lib/components/PlayersTable.svelte index 099e60c..b779cac 100644 --- a/apps/portal/src/lib/components/PlayersTable.svelte +++ b/apps/portal/src/lib/components/PlayersTable.svelte @@ -18,7 +18,7 @@ import { api } from "$lib/api"; type AssessmentRow = NonNullable< - Awaited>["data"] + Awaited>["data"] >[number]; interface CalcData { @@ -112,7 +112,7 @@ loading = true; loadError = null; try { - const res = await api.assessments.me.get(); + const res = await api.accounts.me.assessments.get(); if (res.error) throw res.error; calculations = (res.data ?? []).map(assessmentToCalc); } catch (err) { @@ -135,7 +135,7 @@ }); if (res.error) throw res.error; } else { - const res = await api.assessments.me.post({ + const res = await api.accounts.me.assessments.post({ player: calculation.player, activityPerformances: calculation.activityPerformances, }); @@ -162,7 +162,7 @@ calculation.deleting = true; calculation.deleteError = undefined; try { - const res = await api.assessments.me({ id: calculation.id }).delete(); + const res = await api.accounts.me.assessments({ id: calculation.id }).delete(); if (res.error) throw res.error; calculations.splice(index, 1); } catch (err) {