src/app/api/admin/auth/username/route.ts

route·app·2.5 KB · 87 lignes· Voir l'itinéraire
Annotation non disponible

Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.

2 exports

POSTdynamic

Code source· typescript

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";
import { isValidCodeFormat, normalizeCode } from "@/lib/admin/code-acces";

export const dynamic = "force-dynamic";

const USERNAME_REGEX = /^[a-z0-9_-]{3,30}$/;

// POST /api/admin/auth/username
// Body: { code: "WARI-XXXX-XXXX", username: "..." }
// Check unicité globale + format, passe à onboardingStep=PWD.
export async function POST(req: NextRequest) {
  let body: { code?: string; username?: string };
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: "Body invalide" }, { status: 400 });
  }

  const code = normalizeCode(body.code ?? "");
  const usernameRaw = (body.username ?? "").trim().toLowerCase();

  if (!isValidCodeFormat(code)) {
    return NextResponse.json({ error: "Code d'accès invalide" }, { status: 400 });
  }
  if (!USERNAME_REGEX.test(usernameRaw)) {
    return NextResponse.json(
      {
        error:
          "Username invalide. 3 à 30 caractères, lettres minuscules, chiffres, tirets et underscores uniquement.",
      },
      { status: 400 }
    );
  }

  const tenant = await prisma.tenant.findUnique({
    where: { codeAcces: code },
    select: {
      id: true,
      onboardingStep: true,
      actif: true,
      users: {
        where: { isPrimary: true },
        select: { id: true, emailVerifiedAt: true },
        take: 1,
      },
    },
  });
  if (!tenant) {
    return NextResponse.json({ error: "Code invalide" }, { status: 404 });
  }
  if (!tenant.actif || tenant.onboardingStep === "DONE") {
    return NextResponse.json({ error: "Setup non disponible" }, { status: 422 });
  }

  const primary = tenant.users[0];
  if (!primary || !primary.emailVerifiedAt) {
    return NextResponse.json(
      { error: "Vérifie d'abord ton email avant de choisir un username." },
      { status: 422 }
    );
  }

  // Check unicité username globale (exclut le user courant si c'est le même)
  const existant = await prisma.user.findFirst({
    where: { username: usernameRaw, NOT: { id: primary.id } },
    select: { id: true },
  });
  if (existant) {
    return NextResponse.json(
      { error: "Ce nom d'utilisateur est déjà pris. Essaie une variante." },
      { status: 409 }
    );
  }

  await prisma.user.update({
    where: { id: primary.id },
    data: { username: usernameRaw },
  });
  await prisma.tenant.update({
    where: { id: tenant.id },
    data: { onboardingStep: "PWD" },
  });

  return NextResponse.json({ ok: true, username: usernameRaw });
}