import { NextResponse } from 'next/server' import { db } from '@/lib/db' import { z } from 'zod' export const dynamic = 'force-dynamic' const patchSchema = z.object({ displayName: z.string().optional(), description: z.string().optional(), isPublic: z.boolean().optional(), isActive: z.boolean().optional(), envTemplate: z.string().optional(), // Assign to a specific company (or remove assignment) assignToCompany: z.string().optional(), unassignFromCompany: z.string().optional(), }) // PATCH /api/aos/repos/[id] — update repo settings + assign/unassign export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) { try { const { id } = await params const parsed = patchSchema.safeParse(await req.json()) if (!parsed.success) { return NextResponse.json({ error: 'validation failed', details: parsed.error.flatten() }, { status: 400 }) } const { displayName, description, isPublic, isActive, envTemplate, assignToCompany, unassignFromCompany } = parsed.data const repo = await db.allowedRepo.findUnique({ where: { id } }) if (!repo) { return NextResponse.json({ error: 'repo not found' }, { status: 404 }) } // Update fields const updateData: Record = {} if (displayName !== undefined) updateData.displayName = displayName if (description !== undefined) updateData.description = description if (isPublic !== undefined) updateData.isPublic = isPublic if (isActive !== undefined) updateData.isActive = isActive if (envTemplate !== undefined) updateData.envTemplate = envTemplate if (Object.keys(updateData).length > 0) { await db.allowedRepo.update({ where: { id }, data: updateData }) } // Assign to company if (assignToCompany) { await db.repoAssignment.upsert({ where: { allowedRepoId_companyId: { allowedRepoId: id, companyId: assignToCompany } }, create: { allowedRepoId: id, companyId: assignToCompany }, update: {}, }) } // Unassign from company if (unassignFromCompany) { await db.repoAssignment.deleteMany({ where: { allowedRepoId: id, companyId: unassignFromCompany }, }) } await db.auditLog.create({ data: { actor: 'admin:ui', action: 'repo.update', entity: 'AllowedRepo', entityId: id, after: JSON.stringify({ updateData, assignToCompany, unassignFromCompany }), hash: 'sha256:' + Math.random().toString(36).slice(2), }, }) return NextResponse.json({ ok: true }) } catch (err) { const msg = err instanceof Error ? err.message : 'internal server error' return NextResponse.json({ error: msg }, { status: 500 }) } } // DELETE /api/aos/repos/[id] — remove repo from allowed list export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) { try { const { id } = await params const repo = await db.allowedRepo.findUnique({ where: { id }, include: { _count: { select: { instances: true } } }, }) if (!repo) { return NextResponse.json({ error: 'repo not found' }, { status: 404 }) } if (repo._count.instances > 0) { return NextResponse.json({ error: 'cannot delete repo with active instances', instances: repo._count.instances, }, { status: 409 }) } await db.allowedRepo.delete({ where: { id } }) await db.auditLog.create({ data: { actor: 'admin:ui', action: 'repo.delete', entity: 'AllowedRepo', entityId: id, after: JSON.stringify({ giteaOwner: repo.giteaOwner, giteaRepo: repo.giteaRepo }), hash: 'sha256:' + Math.random().toString(36).slice(2), }, }) return NextResponse.json({ ok: true }) } catch (err) { const msg = err instanceof Error ? err.message : 'internal server error' return NextResponse.json({ error: msg }, { status: 500 }) } }