Add VerificationsService with some basic methods
This commit is contained in:
@@ -3,8 +3,8 @@ import { Kysely, sql } from 'kysely'
|
|||||||
import { addDefaultColumns } from '../db';
|
import { addDefaultColumns } from '../db';
|
||||||
|
|
||||||
export async function up(db: Kysely<any>): Promise<void> {
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
// TABLE: ASSESSMENT_VERIFICATIONS
|
// TABLE: VERIFICATIONS
|
||||||
await db.schema.createTable("assessment_verifications")
|
await db.schema.createTable("verifications")
|
||||||
.$call(addDefaultColumns)
|
.$call(addDefaultColumns)
|
||||||
.addColumn("assessment_id", "bigint", (cb) => cb.notNull().unique())
|
.addColumn("assessment_id", "bigint", (cb) => cb.notNull().unique())
|
||||||
.addColumn("status", "text", (cb) => cb.notNull().defaultTo("request")) // request | in_review | action_required | completed
|
.addColumn("status", "text", (cb) => cb.notNull().defaultTo("request")) // request | in_review | action_required | completed
|
||||||
@@ -24,27 +24,27 @@ export async function up(db: Kysely<any>): Promise<void> {
|
|||||||
.addColumn("verf_cone_drill", "boolean")
|
.addColumn("verf_cone_drill", "boolean")
|
||||||
.addColumn("reviewer_notes", "text") // can be structured in the future, for now keep simple
|
.addColumn("reviewer_notes", "text") // can be structured in the future, for now keep simple
|
||||||
.addForeignKeyConstraint(
|
.addForeignKeyConstraint(
|
||||||
"fk_assessment_verifications_assessment_id",
|
"fk_verifications_assessment_id",
|
||||||
["assessment_id"],
|
["assessment_id"],
|
||||||
"assessments",
|
"assessments",
|
||||||
["id"],
|
["id"],
|
||||||
(cb) => cb.onDelete("cascade")
|
(cb) => cb.onDelete("cascade")
|
||||||
)
|
)
|
||||||
.addForeignKeyConstraint(
|
.addForeignKeyConstraint(
|
||||||
"fk_assessment_verifications_completed_by",
|
"fk_verifications_completed_by",
|
||||||
["completed_by"],
|
["completed_by"],
|
||||||
"accounts",
|
"accounts",
|
||||||
["id"],
|
["id"],
|
||||||
(cb) => cb.onDelete("restrict")
|
(cb) => cb.onDelete("restrict")
|
||||||
)
|
)
|
||||||
.addCheckConstraint(
|
.addCheckConstraint(
|
||||||
"chk_assessment_verifications_completed_fields",
|
"chk_verifications_completed_fields",
|
||||||
sql`status != 'completed' OR (completed_at IS NOT NULL AND completed_by IS NOT NULL)`
|
sql`status != 'completed' OR (completed_at IS NOT NULL AND completed_by IS NOT NULL)`
|
||||||
)
|
)
|
||||||
.execute()
|
.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(db: Kysely<any>): Promise<void> {
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
// TABLE: ASSESSMENT_VERIFICATIONS
|
// TABLE: VERIFICATIONS
|
||||||
await db.schema.dropTable("assessment_verifications").ifExists().execute()
|
await db.schema.dropTable("verifications").ifExists().execute()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { Activity, type ActivityVideoUrls } from "@blade-and-brawn/domain";
|
||||||
|
import { db } from "../database/db";
|
||||||
|
|
||||||
|
export type VerificationStatus = "request" | "in_review" | "action_required" | "completed";
|
||||||
|
|
||||||
|
export class VerificationsService {
|
||||||
|
async request(assessmentId: string, activityVideoUrls: ActivityVideoUrls) {
|
||||||
|
return await db.insertInto("verifications")
|
||||||
|
.values({
|
||||||
|
assessment_id: assessmentId,
|
||||||
|
status: "request" satisfies VerificationStatus,
|
||||||
|
url_back_squat: activityVideoUrls[Activity.BackSquat] ?? null,
|
||||||
|
url_deadlift: activityVideoUrls[Activity.Deadlift] ?? null,
|
||||||
|
url_bench_press: activityVideoUrls[Activity.BenchPress] ?? null,
|
||||||
|
url_broad_jump: activityVideoUrls[Activity.BroadJump] ?? null,
|
||||||
|
url_run: activityVideoUrls[Activity.Run] ?? null,
|
||||||
|
url_cone_drill: activityVideoUrls[Activity.ConeDrill] ?? null,
|
||||||
|
})
|
||||||
|
.onConflict((oc) => oc
|
||||||
|
.column("assessment_id")
|
||||||
|
.doUpdateSet((eb) => ({
|
||||||
|
status: "request" satisfies VerificationStatus,
|
||||||
|
url_back_squat: eb.ref("excluded.url_back_squat"),
|
||||||
|
url_deadlift: eb.ref("excluded.url_deadlift"),
|
||||||
|
url_bench_press: eb.ref("excluded.url_bench_press"),
|
||||||
|
url_broad_jump: eb.ref("excluded.url_broad_jump"),
|
||||||
|
url_run: eb.ref("excluded.url_run"),
|
||||||
|
url_cone_drill: eb.ref("excluded.url_cone_drill"),
|
||||||
|
// Re-requesting means new videos are under review, so the
|
||||||
|
// previous cycle's per-activity judgments and completion
|
||||||
|
// info no longer apply.
|
||||||
|
verf_back_squat: null,
|
||||||
|
verf_deadlift: null,
|
||||||
|
verf_bench_press: null,
|
||||||
|
verf_broad_jump: null,
|
||||||
|
verf_run: null,
|
||||||
|
verf_cone_drill: null,
|
||||||
|
completed_at: null,
|
||||||
|
completed_by: null,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.returning("id")
|
||||||
|
.executeTakeFirstOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(opt: {
|
||||||
|
filter?: { status?: VerificationStatus },
|
||||||
|
limit?: number,
|
||||||
|
offset?: number,
|
||||||
|
} = {}) {
|
||||||
|
return await db.selectFrom("verifications")
|
||||||
|
.selectAll()
|
||||||
|
.$if(opt.filter?.status !== undefined, (qb) => qb
|
||||||
|
.where("status", "=", opt.filter!.status!)
|
||||||
|
)
|
||||||
|
.orderBy("created_at", "desc")
|
||||||
|
.$if(opt.limit !== undefined, (qb) => qb.limit(opt.limit!))
|
||||||
|
.$if(opt.offset !== undefined, (qb) => qb.offset(opt.offset!))
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,3 +42,6 @@ export const ActivityPerformanceSchema = t.Object({
|
|||||||
performance: t.Number(),
|
performance: t.Number(),
|
||||||
});
|
});
|
||||||
export type ActivityPerformance = Static<typeof ActivityPerformanceSchema>;
|
export type ActivityPerformance = Static<typeof ActivityPerformanceSchema>;
|
||||||
|
|
||||||
|
export const ActivityVideosSchema = t.Partial(t.Record(t.Enum(Activity), t.String()));
|
||||||
|
export type ActivityVideoUrls = Static<typeof ActivityVideosSchema>;
|
||||||
|
|||||||
Reference in New Issue
Block a user