Merge pull request #101 from madhura68/feat/story-abeu63oz

ST-1207: Admin: productenbeheer & ledenbeheer (/admin/products)
This commit is contained in:
Janpeter Visser 2026-05-05 14:55:19 +02:00 committed by GitHub
commit 881ee007e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

86
actions/admin/products.ts Normal file
View file

@ -0,0 +1,86 @@
'use server'
import { revalidatePath } from 'next/cache'
import { z } from 'zod'
import { prisma } from '@/lib/prisma'
import { requireAdmin } from '@/lib/auth-guard'
const adminProductSchema = z.object({
name: z.string().min(1).max(100),
description: z.string().optional(),
repo_url: z.string().url().optional().or(z.literal('')),
definition_of_done: z.string().min(1),
auto_pr: z.boolean().default(false),
owner_user_id: z.string().cuid(),
})
const adminProductUpdateSchema = adminProductSchema.omit({ owner_user_id: true })
export async function adminCreateProductAction(data: unknown) {
await requireAdmin()
const parsed = adminProductSchema.safeParse(data)
if (!parsed.success) throw new Error(parsed.error.message)
const owner = await prisma.user.findUnique({ where: { id: parsed.data.owner_user_id } })
if (!owner) throw new Error('Eigenaar niet gevonden')
await prisma.product.create({
data: {
user_id: parsed.data.owner_user_id,
name: parsed.data.name,
description: parsed.data.description,
repo_url: parsed.data.repo_url || null,
definition_of_done: parsed.data.definition_of_done,
auto_pr: parsed.data.auto_pr,
},
})
revalidatePath('/admin/products')
}
export async function adminUpdateProductAction(productId: string, data: unknown) {
await requireAdmin()
const parsed = adminProductUpdateSchema.safeParse(data)
if (!parsed.success) throw new Error(parsed.error.message)
await prisma.product.update({
where: { id: productId },
data: {
name: parsed.data.name,
description: parsed.data.description,
repo_url: parsed.data.repo_url || null,
definition_of_done: parsed.data.definition_of_done,
auto_pr: parsed.data.auto_pr,
},
})
revalidatePath('/admin/products')
}
export async function adminArchiveProductAction(productId: string, archived: boolean) {
await requireAdmin()
await prisma.product.update({ where: { id: productId }, data: { archived } })
revalidatePath('/admin/products')
}
export async function adminDeleteProductAction(productId: string) {
await requireAdmin()
await prisma.product.delete({ where: { id: productId } })
revalidatePath('/admin/products')
}
export async function adminAddMemberAction(productId: string, userId: string) {
await requireAdmin()
await prisma.productMember.upsert({
where: { product_id_user_id: { product_id: productId, user_id: userId } },
create: { product_id: productId, user_id: userId },
update: {},
})
revalidatePath(`/admin/products/${productId}`)
}
export async function adminRemoveMemberAction(productId: string, userId: string) {
await requireAdmin()
await prisma.productMember.deleteMany({ where: { product_id: productId, user_id: userId } })
revalidatePath(`/admin/products/${productId}`)
}