All files / app/api/admin/tenants route.ts

82.92% Statements 34/41
75% Branches 15/20
100% Functions 2/2
82.92% Lines 34/41

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 }
    );
  }
}