MOPC-App/src/server/routers/roundTemplate.ts

210 lines
5.8 KiB
TypeScript

import { z } from 'zod'
import { RoundType } from '@prisma/client'
import { router, adminProcedure } from '../trpc'
import { logAudit } from '@/server/utils/audit'
export const roundTemplateRouter = router({
/**
* List all round templates, optionally filtered by programId.
*/
list: adminProcedure
.input(
z.object({
programId: z.string().optional(),
}).optional()
)
.query(async ({ ctx, input }) => {
return ctx.prisma.roundTemplate.findMany({
where: {
...(input?.programId ? { programId: input.programId } : {}),
},
orderBy: { createdAt: 'desc' },
})
}),
/**
* Get a single template by ID.
*/
getById: adminProcedure
.input(z.object({ id: z.string() }))
.query(async ({ ctx, input }) => {
const template = await ctx.prisma.roundTemplate.findUnique({
where: { id: input.id },
})
if (!template) {
throw new Error('Template not found')
}
return template
}),
/**
* Create a new round template from scratch.
*/
create: adminProcedure
.input(
z.object({
name: z.string().min(1).max(200),
description: z.string().optional(),
programId: z.string().optional(),
roundType: z.nativeEnum(RoundType).default('EVALUATION'),
criteriaJson: z.any(),
settingsJson: z.any().optional(),
assignmentConfig: z.any().optional(),
})
)
.mutation(async ({ ctx, input }) => {
const template = await ctx.prisma.roundTemplate.create({
data: {
name: input.name,
description: input.description,
programId: input.programId,
roundType: input.roundType,
criteriaJson: input.criteriaJson,
settingsJson: input.settingsJson ?? undefined,
assignmentConfig: input.assignmentConfig ?? undefined,
createdBy: ctx.user.id,
},
})
try {
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'CREATE_ROUND_TEMPLATE',
entityType: 'RoundTemplate',
entityId: template.id,
detailsJson: { name: input.name },
})
} catch {}
return template
}),
/**
* Create a template from an existing round (snapshot).
*/
createFromRound: adminProcedure
.input(
z.object({
roundId: z.string(),
name: z.string().min(1).max(200),
description: z.string().optional(),
})
)
.mutation(async ({ ctx, input }) => {
// Fetch the round and its active evaluation form
const round = await ctx.prisma.round.findUnique({
where: { id: input.roundId },
include: {
evaluationForms: {
where: { isActive: true },
take: 1,
},
},
})
if (!round) {
throw new Error('Round not found')
}
const form = round.evaluationForms[0]
const criteriaJson = form?.criteriaJson ?? []
const template = await ctx.prisma.roundTemplate.create({
data: {
name: input.name,
description: input.description || `Snapshot of ${round.name}`,
programId: round.programId,
roundType: round.roundType,
criteriaJson,
settingsJson: round.settingsJson ?? undefined,
createdBy: ctx.user.id,
},
})
try {
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'CREATE_ROUND_TEMPLATE_FROM_ROUND',
entityType: 'RoundTemplate',
entityId: template.id,
detailsJson: { name: input.name, sourceRoundId: input.roundId },
})
} catch {}
return template
}),
/**
* Update a template.
*/
update: adminProcedure
.input(
z.object({
id: z.string(),
name: z.string().min(1).max(200).optional(),
description: z.string().optional(),
programId: z.string().nullable().optional(),
roundType: z.nativeEnum(RoundType).optional(),
criteriaJson: z.any().optional(),
settingsJson: z.any().optional(),
assignmentConfig: z.any().optional(),
})
)
.mutation(async ({ ctx, input }) => {
const { id, ...data } = input
const template = await ctx.prisma.roundTemplate.update({
where: { id },
data: {
...(data.name !== undefined ? { name: data.name } : {}),
...(data.description !== undefined ? { description: data.description } : {}),
...(data.programId !== undefined ? { programId: data.programId } : {}),
...(data.roundType !== undefined ? { roundType: data.roundType } : {}),
...(data.criteriaJson !== undefined ? { criteriaJson: data.criteriaJson } : {}),
...(data.settingsJson !== undefined ? { settingsJson: data.settingsJson } : {}),
...(data.assignmentConfig !== undefined ? { assignmentConfig: data.assignmentConfig } : {}),
},
})
try {
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'UPDATE_ROUND_TEMPLATE',
entityType: 'RoundTemplate',
entityId: id,
detailsJson: { updatedFields: Object.keys(data) },
})
} catch {}
return template
}),
/**
* Delete a template.
*/
delete: adminProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ ctx, input }) => {
await ctx.prisma.roundTemplate.delete({
where: { id: input.id },
})
try {
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'DELETE_ROUND_TEMPLATE',
entityType: 'RoundTemplate',
entityId: input.id,
})
} catch {}
return { success: true }
}),
})