Catalyst / admin/Synapse-Sonar 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Synapse-Sonar

public

Attack Surface Simulation

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Synapse-Sonar / synapse-sonar / app / api / tenant / settings / route.ts 2123 B · main
 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
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { requireTenantContext, HttpError } from "@/lib/auth";
import { assertCan } from "@/lib/rbac";
import { prisma } from "@/lib/prisma";

export const runtime = "nodejs";

/** GET — tenant settings (any member may read). */
export async function GET() {
  try {
    const ctx = await requireTenantContext();
    assertCan(ctx.role, "user:read");
    const tenant = await prisma.tenant.findUnique({
      where: { id: ctx.tenantId },
      select: { name: true, mfaRequired: true },
    });
    return NextResponse.json({
      name: tenant?.name ?? "",
      mfaRequired: tenant?.mfaRequired ?? false,
    });
  } catch (err) {
    return errorResponse(err);
  }
}

const SettingsSchema = z
  .object({
    name: z.string().min(1).max(80).optional(),
    mfaRequired: z.boolean().optional(),
  })
  .refine((v) => v.name !== undefined || v.mfaRequired !== undefined, {
    message: "Nothing to update",
  });

/** PATCH — update org name and/or MFA policy (Tenant Admin only). */
export async function PATCH(req: NextRequest) {
  try {
    const ctx = await requireTenantContext();
    assertCan(ctx.role, "user:manage");
    const body = SettingsSchema.parse(await req.json());

    const tenant = await prisma.tenant.update({
      where: { id: ctx.tenantId },
      data: {
        ...(body.name !== undefined ? { name: body.name } : {}),
        ...(body.mfaRequired !== undefined ? { mfaRequired: body.mfaRequired } : {}),
      },
      select: { name: true, mfaRequired: true },
    });
    return NextResponse.json({ ok: true, ...tenant });
  } catch (err) {
    return errorResponse(err);
  }
}

function errorResponse(err: unknown) {
  if (err instanceof HttpError) {
    return NextResponse.json({ error: err.message }, { status: err.status });
  }
  if (err instanceof z.ZodError) {
    return NextResponse.json({ error: "Invalid input", details: err.issues }, { status: 422 });
  }
  const status = (err as { status?: number }).status ?? 500;
  return NextResponse.json({ error: (err as Error).message }, { status });
}