Vervang productAccessFilter in de WHERE clause door een expliciete toegangscheck na het ophalen. findFirst haalt de taak op met product en members (gefilterd op auth.userId); daarna wordt eigenaarschap of teamlidmaatschap gecontroleerd en 403 teruggegeven bij geen toegang. Dit herstelt het onderscheid 404 (taak bestaat niet) vs 403 (taak bestaat maar geen toegang), zoals de beveiligingstest verwacht. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
import { authenticateApiRequest } from '@/lib/api-auth'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { z } from 'zod'
|
|
|
|
const patchSchema = z
|
|
.object({
|
|
status: z.enum(['TO_DO', 'IN_PROGRESS', 'DONE']).optional(),
|
|
implementation_plan: z.string().optional(),
|
|
})
|
|
.refine((data) => data.status !== undefined || data.implementation_plan !== undefined, {
|
|
message: 'Geef minimaal status of implementation_plan mee',
|
|
})
|
|
|
|
export async function PATCH(
|
|
request: Request,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
const auth = await authenticateApiRequest(request)
|
|
if ('error' in auth) {
|
|
return Response.json({ error: auth.error }, { status: auth.status })
|
|
}
|
|
if (auth.isDemo) {
|
|
return Response.json({ error: 'Niet beschikbaar in demo-modus' }, { status: 403 })
|
|
}
|
|
|
|
const { id } = await params
|
|
|
|
const task = await prisma.task.findFirst({
|
|
where: { id },
|
|
include: {
|
|
story: {
|
|
include: {
|
|
product: {
|
|
include: {
|
|
members: {
|
|
where: { user_id: auth.userId },
|
|
select: { id: true },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if (!task) {
|
|
return Response.json({ error: 'Taak niet gevonden' }, { status: 404 })
|
|
}
|
|
|
|
const hasAccess =
|
|
task.story.product.user_id === auth.userId ||
|
|
(task.story.product.members?.length ?? 0) > 0
|
|
if (!hasAccess) {
|
|
return Response.json({ error: 'Geen toegang' }, { status: 403 })
|
|
}
|
|
|
|
const body = await request.json().catch(() => null)
|
|
const parsed = patchSchema.safeParse(body)
|
|
if (!parsed.success) {
|
|
return Response.json({ error: parsed.error.flatten() }, { status: 400 })
|
|
}
|
|
|
|
const updated = await prisma.task.update({
|
|
where: { id },
|
|
data: {
|
|
...(parsed.data.status !== undefined && { status: parsed.data.status }),
|
|
...(parsed.data.implementation_plan !== undefined && {
|
|
implementation_plan: parsed.data.implementation_plan,
|
|
}),
|
|
},
|
|
})
|
|
|
|
return Response.json({
|
|
id: updated.id,
|
|
status: updated.status,
|
|
implementation_plan: updated.implementation_plan,
|
|
})
|
|
}
|