118 lines
2.9 KiB
TypeScript
118 lines
2.9 KiB
TypeScript
|
|
import { z } from 'zod'
|
||
|
|
import { TRPCError } from '@trpc/server'
|
||
|
|
import { router, adminProcedure, protectedProcedure, juryProcedure } from '../trpc'
|
||
|
|
import {
|
||
|
|
previewRoundAssignment,
|
||
|
|
executeRoundAssignment,
|
||
|
|
getRoundCoverageReport,
|
||
|
|
getUnassignedQueue,
|
||
|
|
} from '../services/round-assignment'
|
||
|
|
|
||
|
|
export const roundAssignmentRouter = router({
|
||
|
|
/**
|
||
|
|
* Preview round assignments without committing
|
||
|
|
*/
|
||
|
|
preview: adminProcedure
|
||
|
|
.input(
|
||
|
|
z.object({
|
||
|
|
roundId: z.string(),
|
||
|
|
honorIntents: z.boolean().default(true),
|
||
|
|
requiredReviews: z.number().int().min(1).max(20).default(3),
|
||
|
|
})
|
||
|
|
)
|
||
|
|
.query(async ({ ctx, input }) => {
|
||
|
|
return previewRoundAssignment(
|
||
|
|
input.roundId,
|
||
|
|
{
|
||
|
|
honorIntents: input.honorIntents,
|
||
|
|
requiredReviews: input.requiredReviews,
|
||
|
|
},
|
||
|
|
ctx.prisma,
|
||
|
|
)
|
||
|
|
}),
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Execute round assignments (create Assignment records)
|
||
|
|
*/
|
||
|
|
execute: adminProcedure
|
||
|
|
.input(
|
||
|
|
z.object({
|
||
|
|
roundId: z.string(),
|
||
|
|
assignments: z.array(
|
||
|
|
z.object({
|
||
|
|
userId: z.string(),
|
||
|
|
projectId: z.string(),
|
||
|
|
})
|
||
|
|
).min(1),
|
||
|
|
})
|
||
|
|
)
|
||
|
|
.mutation(async ({ ctx, input }) => {
|
||
|
|
const result = await executeRoundAssignment(
|
||
|
|
input.roundId,
|
||
|
|
input.assignments,
|
||
|
|
ctx.user.id,
|
||
|
|
ctx.prisma,
|
||
|
|
)
|
||
|
|
|
||
|
|
if (result.errors.length > 0 && result.created === 0) {
|
||
|
|
throw new TRPCError({
|
||
|
|
code: 'INTERNAL_SERVER_ERROR',
|
||
|
|
message: result.errors.join('; '),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
return result
|
||
|
|
}),
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get coverage report for a round
|
||
|
|
*/
|
||
|
|
coverageReport: protectedProcedure
|
||
|
|
.input(
|
||
|
|
z.object({
|
||
|
|
roundId: z.string(),
|
||
|
|
requiredReviews: z.number().int().min(1).max(20).default(3),
|
||
|
|
})
|
||
|
|
)
|
||
|
|
.query(async ({ ctx, input }) => {
|
||
|
|
return getRoundCoverageReport(input.roundId, input.requiredReviews, ctx.prisma)
|
||
|
|
}),
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get projects below required reviews threshold
|
||
|
|
*/
|
||
|
|
unassignedQueue: protectedProcedure
|
||
|
|
.input(
|
||
|
|
z.object({
|
||
|
|
roundId: z.string(),
|
||
|
|
requiredReviews: z.number().int().min(1).max(20).default(3),
|
||
|
|
})
|
||
|
|
)
|
||
|
|
.query(async ({ ctx, input }) => {
|
||
|
|
return getUnassignedQueue(input.roundId, input.requiredReviews, ctx.prisma)
|
||
|
|
}),
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get assignments for the current jury member in a specific round
|
||
|
|
*/
|
||
|
|
getMyAssignments: juryProcedure
|
||
|
|
.input(z.object({ roundId: z.string() }))
|
||
|
|
.query(async ({ ctx, input }) => {
|
||
|
|
return ctx.prisma.assignment.findMany({
|
||
|
|
where: {
|
||
|
|
roundId: input.roundId,
|
||
|
|
userId: ctx.user.id,
|
||
|
|
},
|
||
|
|
include: {
|
||
|
|
project: {
|
||
|
|
select: { id: true, title: true, competitionCategory: true },
|
||
|
|
},
|
||
|
|
evaluation: {
|
||
|
|
select: { id: true, status: true, globalScore: true },
|
||
|
|
},
|
||
|
|
},
|
||
|
|
orderBy: { createdAt: 'asc' },
|
||
|
|
})
|
||
|
|
}),
|
||
|
|
})
|