83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { requirePlatformRole } from "@/lib/session";
|
|
import { getTenantRequestById, updateTenantRequestStatus } from "@/lib/db";
|
|
import { createTenant } from "@/lib/k8s";
|
|
|
|
/**
|
|
* POST /api/admin/requests/[id]/approve
|
|
* Approve a tenant request: create the PiecedTenant CR and update status.
|
|
* Also supports re-approving a previously rejected request.
|
|
*/
|
|
export async function POST(
|
|
request: Request,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
try {
|
|
await requirePlatformRole();
|
|
} catch {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const { id } = await params;
|
|
const body = await request.json().catch(() => ({}));
|
|
const adminNotes = body.adminNotes as string | undefined;
|
|
|
|
const tenantRequest = await getTenantRequestById(id);
|
|
if (!tenantRequest) {
|
|
return NextResponse.json(
|
|
{ error: "Request not found" },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
if (tenantRequest.status !== "pending" && tenantRequest.status !== "rejected") {
|
|
return NextResponse.json(
|
|
{ error: `Request is already ${tenantRequest.status}` },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Derive tenant name from company name: lowercase, alphanumeric + hyphens
|
|
const tenantName = tenantRequest.companyName
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, "-")
|
|
.replace(/^-|-$/g, "")
|
|
.slice(0, 63) || `tenant-${tenantRequest.id.slice(0, 8)}`;
|
|
|
|
try {
|
|
// Create the PiecedTenant CR
|
|
await createTenant(
|
|
tenantName,
|
|
{
|
|
displayName: tenantRequest.companyName,
|
|
agentName: tenantRequest.agentName,
|
|
packages: tenantRequest.packages,
|
|
workspaceFiles: tenantRequest.soulMd
|
|
? { "SOUL.md": tenantRequest.soulMd }
|
|
: undefined,
|
|
},
|
|
{
|
|
"pieced.ch/zitadel-org-id": tenantRequest.zitadelOrgId,
|
|
}
|
|
);
|
|
|
|
// Update request status
|
|
const updated = await updateTenantRequestStatus(id, "provisioning", {
|
|
adminNotes,
|
|
tenantName,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
message: "Tenant approved and provisioning started.",
|
|
request: updated,
|
|
tenantName,
|
|
});
|
|
} catch (e: any) {
|
|
console.error("Failed to create tenant:", e);
|
|
return NextResponse.json(
|
|
{ error: `Failed to create tenant: ${e.message}` },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|