Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 2x 2x 2x 2x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 1x 3x 1x 2x 1x 1x 1x 1x 1x | /**
* GET /api/admin/tenants - List all tenants
* POST /api/admin/tenants - Create a new tenant
* Only accessible by Super Admins
*/
import { NextRequest, NextResponse } from "next/server";
import { generateClient } from "aws-amplify/data";
import { Amplify } from "aws-amplify";
import outputs from "../../../../../amplify_outputs.json";
import { type Schema } from "../../../../../amplify/data/resource";
import { TenantType } from "@/types/tenant";
import { requireSuperAdmin, forbiddenResponse, unauthorizedResponse } from "@/lib/amplify-server-utils";
// Valid tenant types for runtime validation
const VALID_TENANT_TYPES: TenantType[] = ["personal", "organisation", "charity", "business", "nonprofit"];
// Configure Amplify for server-side
Amplify.configure(outputs, { ssr: true });
export async function GET() {
try {
// Check super admin authorization
const auth = await requireSuperAdmin();
if (!auth.authorized) {
return auth.error === "Not authenticated"
? unauthorizedResponse(auth.error)
: forbiddenResponse(auth.error);
}
// Fetch tenants using API key auth
const client = generateClient<Schema>();
const { data: tenants, errors } = await client.models.Tenant.list({
authMode: "apiKey",
});
if (errors) {
console.error("Error fetching tenants:", errors);
return NextResponse.json(
{ error: "Failed to fetch tenants" },
{ status: 500 }
);
}
return NextResponse.json({
tenants: tenants || [],
});
} catch (error) {
console.error("Error listing tenants:", error);
return NextResponse.json(
{ error: "Failed to list tenants" },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
// Check super admin authorization
const auth = await requireSuperAdmin();
Iif (!auth.authorized) {
return auth.error === "Not authenticated"
? unauthorizedResponse(auth.error)
: forbiddenResponse(auth.error);
}
const body = await request.json();
const { name, type } = body as { name: string; type: string };
// Validate required fields
if (!name) {
return NextResponse.json({ error: "Name is required" }, { status: 400 });
}
if (!type) {
return NextResponse.json({ error: "Type is required" }, { status: 400 });
}
// Runtime validation for TenantType (JCN-32)
if (!VALID_TENANT_TYPES.includes(type as TenantType)) {
return NextResponse.json(
{ error: `Invalid tenant type. Must be one of: ${VALID_TENANT_TYPES.join(", ")}` },
{ status: 400 }
);
}
// Create tenant using API key auth
const client = generateClient<Schema>();
const { data: tenant, errors } = await client.models.Tenant.create(
{
name,
type: type as TenantType, // Safe cast after runtime validation
status: "pending_owner",
createdAt: new Date().toISOString(),
},
{
authMode: "apiKey",
}
);
Iif (errors) {
console.error("Error creating tenant:", errors);
return NextResponse.json(
{ error: "Failed to create tenant" },
{ status: 500 }
);
}
return NextResponse.json({
success: true,
tenant,
}, { status: 201 });
} catch (error) {
console.error("Error creating tenant:", error);
return NextResponse.json(
{ error: "Failed to create tenant" },
{ status: 500 }
);
}
}
|