feat: external lunch attendees CRUD
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,102 @@ export const lunchRouter = router({
|
||||
return { ok: true as const }
|
||||
}),
|
||||
|
||||
// ─── External attendees CRUD ─────────────────────────────────────────────
|
||||
|
||||
listExternals: adminProcedure
|
||||
.input(z.object({ lunchEventId: z.string() }))
|
||||
.query(({ ctx, input }) =>
|
||||
ctx.prisma.externalAttendee.findMany({
|
||||
where: { lunchEventId: input.lunchEventId },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
include: { project: { select: { id: true, title: true } } },
|
||||
}),
|
||||
),
|
||||
|
||||
createExternal: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
lunchEventId: z.string(),
|
||||
name: z.string().min(1).max(200),
|
||||
email: z.string().email().optional(),
|
||||
projectId: z.string().nullable().optional(),
|
||||
roleNote: z.string().max(500).optional(),
|
||||
dishId: z.string().nullable().optional(),
|
||||
allergens: allergens.optional(),
|
||||
allergenOther: z.string().max(500).optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const ext = await ctx.prisma.externalAttendee.create({
|
||||
data: {
|
||||
lunchEventId: input.lunchEventId,
|
||||
name: input.name,
|
||||
email: input.email,
|
||||
projectId: input.projectId ?? null,
|
||||
roleNote: input.roleNote,
|
||||
dishId: input.dishId ?? null,
|
||||
allergens: input.allergens ?? [],
|
||||
allergenOther: input.allergenOther,
|
||||
},
|
||||
})
|
||||
await logAudit({
|
||||
prisma: ctx.prisma,
|
||||
userId: ctx.user.id,
|
||||
action: 'LUNCH_EXTERNAL_CREATED',
|
||||
entityType: 'ExternalAttendee',
|
||||
entityId: ext.id,
|
||||
detailsJson: { name: ext.name, projectId: ext.projectId },
|
||||
})
|
||||
return ext
|
||||
}),
|
||||
|
||||
updateExternal: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
externalId: z.string(),
|
||||
name: z.string().min(1).max(200).optional(),
|
||||
email: z.string().email().nullable().optional(),
|
||||
projectId: z.string().nullable().optional(),
|
||||
roleNote: z.string().max(500).nullable().optional(),
|
||||
dishId: z.string().nullable().optional(),
|
||||
allergens: allergens.optional(),
|
||||
allergenOther: z.string().max(500).nullable().optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { externalId, ...patch } = input
|
||||
const ext = await ctx.prisma.externalAttendee.update({
|
||||
where: { id: externalId },
|
||||
data: patch,
|
||||
})
|
||||
await logAudit({
|
||||
prisma: ctx.prisma,
|
||||
userId: ctx.user.id,
|
||||
action: 'LUNCH_EXTERNAL_UPDATED',
|
||||
entityType: 'ExternalAttendee',
|
||||
entityId: ext.id,
|
||||
detailsJson: patch as Record<string, unknown>,
|
||||
})
|
||||
return ext
|
||||
}),
|
||||
|
||||
deleteExternal: adminProcedure
|
||||
.input(z.object({ externalId: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const ext = await ctx.prisma.externalAttendee.delete({
|
||||
where: { id: input.externalId },
|
||||
})
|
||||
await logAudit({
|
||||
prisma: ctx.prisma,
|
||||
userId: ctx.user.id,
|
||||
action: 'LUNCH_EXTERNAL_DELETED',
|
||||
entityType: 'ExternalAttendee',
|
||||
entityId: ext.id,
|
||||
detailsJson: { name: ext.name },
|
||||
})
|
||||
return { ok: true as const }
|
||||
}),
|
||||
|
||||
/** Patch any subset of LunchEvent config fields. Audit-logged. */
|
||||
updateEvent: adminProcedure
|
||||
.input(
|
||||
|
||||
Reference in New Issue
Block a user