Implementation of verification action endpoints

This commit is contained in:
Dominic Ferrando
2026-09-26 17:59:34 -04:00
parent 5101bd3259
commit b66980c0fb
8 changed files with 222 additions and 119 deletions
+70 -16
View File
@@ -1,7 +1,7 @@
import {
ActivityPerformanceSchema,
ActivityVerificationsSchema,
ActivityVideosSchema,
ActivityMediaKeysSchema,
PlayerSchema,
} from "@blade-and-brawn/domain"
import { cors } from "@elysiajs/cors";
@@ -488,6 +488,7 @@ export const app = new Elysia()
activityPerformances: t.Array(ActivityPerformanceSchema)
})
})
// TODO: handle @ formatted accountIds
.get("/assessments", async ({ accountId }) => {
return await s.Assessments.list({ filter: { accountId } });
})
@@ -497,16 +498,71 @@ export const app = new Elysia()
}, {
params: t.Object({ id: t.String() })
})
.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;
.post("/verifications", async ({ body: { assessmentId, activityMediaKeys }, accountId }) => {
const assessment = await s.Assessments.get(assessmentId);
if (!assessment || assessment.account_id !== accountId) throw new NotFoundError("Assessment not found");
// TODO: only allow a single active non-completed verification at a time
// TODO: return R2 POST urls for the media
const created = await s.Verifications.create(assessmentId, activityMediaKeys);
if (!created) throw status(409, { error: "This assessment already has a verification" });
return created;
}, {
body: t.Object({
assessmentId: t.String(),
activityVideoUrls: ActivityVideosSchema,
activityMediaKeys: ActivityMediaKeysSchema,
})
})
.patch("/verifications/:id", async ({ params: { id }, body: { assessmentId, activityMediaKeys }, accountId }) => {
const verification = await s.Verifications.get(id);
if (!verification || verification.account_id !== accountId) throw new NotFoundError("Verification not found");
if (assessmentId === undefined && Object.keys(activityMediaKeys ?? {}).length === 0)
throw status(400, { error: "Nothing to update" });
if (assessmentId !== undefined) {
const assessment = await s.Assessments.get(assessmentId);
if (!assessment || assessment.account_id !== accountId) throw new NotFoundError("Assessment not found");
}
const updated = await s.Verifications.update(id, { assessmentId, activityMediaKeys })
.catch((err) => {
if (err?.code === "23505") throw status(409, { error: "That assessment already has a verification" });
throw err;
});
if (!updated) throw status(409, { error: `Cannot update a ${verification.status} verification` });
return updated;
}, {
params: t.Object({ id: t.String() }),
body: t.Object({
assessmentId: t.Optional(t.String()),
activityMediaKeys: t.Optional(ActivityMediaKeysSchema),
})
})
.post("/verifications/:id/submit", async ({ params: { id }, accountId }) => {
const verification = await s.Verifications.get(id);
if (!verification || verification.account_id !== accountId) throw new NotFoundError("Verification not found");
const submitted = await s.Verifications.submit(id);
if (submitted) {
// TODO: trigger discord webhook here
return submitted;
}
const current = await s.Verifications.get(id);
if (!current) throw new NotFoundError("Verification not found");
if (current.status === "submitted") return { id: current.id, status: current.status };
const missingActivityMediaKeys = VerificationsService.missingActivityMediaKeys(current);
throw status(409, {
error: current.status === "draft" && missingActivityMediaKeys.length > 0
? `Missing media for: ${missingActivityMediaKeys.join(", ")}`
: `Cannot submit a ${current.status} verification`
});
}, {
params: t.Object({ id: t.String() })
})
)
)
@@ -556,13 +612,12 @@ export const app = new Elysia()
params: t.Object({ id: t.String() })
})
.post("/:id/request-action", async ({ params: { id }, body: { reviewerNotes, activityVerifications } }) => {
const updated = await s.Verifications.requestAction(id, reviewerNotes ?? null, activityVerifications);
if (updated) return updated;
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");
throw status(409, { error: `Cannot request action on a ${verification.status} verification` });
}, {
params: t.Object({ id: t.String() }),
body: t.Object({
@@ -571,13 +626,12 @@ export const app = new Elysia()
})
})
.post("/:id/complete", async ({ params: { id }, body: { activityVerifications }, accountId }) => {
const updated = await s.Verifications.complete(id, accountId, activityVerifications);
if (updated) return updated;
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");
throw status(409, { error: `Cannot complete a ${verification.status} verification` });
}, {
params: t.Object({ id: t.String() }),
body: t.Object({