diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index 9fbbfd1..ea8c7bd 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; import bcrypt from "bcryptjs"; import { apiHandler, ApiError } from "@/lib/api"; import { validateUsername, validatePassword } from "@/lib/validation"; @@ -12,22 +13,26 @@ export const POST = apiHandler(async (req) => { const trimmedUsername = validateUsername(username); validatePassword(password); - const existing = await prisma.user.findUnique({ where: { username: trimmedUsername } }); - if (existing) throw new ApiError("用户名已被注册", 409); - const passwordHash = await bcrypt.hash(password, 10); - const user = await prisma.user.create({ - data: { - username: trimmedUsername, - passwordHash, - avatar: avatar || "🐱", - }, - }); + try { + const user = await prisma.user.create({ + data: { + username: trimmedUsername, + passwordHash, + avatar: avatar || "🐱", + }, + }); - return NextResponse.json({ - id: user.id, - username: user.username, - avatar: user.avatar, - }); + return NextResponse.json({ + id: user.id, + username: user.username, + avatar: user.avatar, + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { + throw new ApiError("用户名已被注册", 409); + } + throw e; + } }); diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index 6f07c9e..d9a0a2d 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; import bcrypt from "bcryptjs"; import { apiHandler, ApiError, requireUserId, requireUser } from "@/lib/api"; import { validateUsername, validatePassword, validateEmail } from "@/lib/validation"; @@ -13,12 +14,15 @@ export const GET = apiHandler(async (req) => { const decisionCount = await prisma.decision.count({ where: { userId } }); + let preferences = {}; + try { preferences = JSON.parse(user.preferences); } catch { /* fallback */ } + return NextResponse.json({ id: user.id, username: user.username, avatar: user.avatar, email: user.email, - preferences: JSON.parse(user.preferences), + preferences, createdAt: user.createdAt.toISOString(), decisionCount, }); @@ -63,16 +67,23 @@ export const PUT = apiHandler(async (req) => { updateData.preferences = JSON.stringify(body.preferences); } - const user = await prisma.user.update({ - where: { id: userId }, - data: updateData, - }); + try { + const user = await prisma.user.update({ + where: { id: userId }, + data: updateData, + }); - return NextResponse.json({ - id: user.id, - username: user.username, - avatar: user.avatar, - email: user.email, - preferences: JSON.parse(user.preferences), - }); + return NextResponse.json({ + id: user.id, + username: user.username, + avatar: user.avatar, + email: user.email, + preferences: JSON.parse(user.preferences), + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { + throw new ApiError("用户名已被占用", 409); + } + throw e; + } }); diff --git a/src/lib/api.ts b/src/lib/api.ts index 33d1e46..f3879dc 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,4 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; +import { Prisma } from "@prisma/client"; import { prisma } from "@/lib/prisma"; export class ApiError extends Error { @@ -7,6 +8,7 @@ export class ApiError extends Error { public status: number = 400, ) { super(message); + this.name = "ApiError"; } } @@ -45,6 +47,15 @@ export function apiHandler(handler: RouteHandler): RouteHandler { if (e instanceof ApiError) { return NextResponse.json({ error: e.message }, { status: e.status }); } + if ( + e instanceof Prisma.PrismaClientKnownRequestError && + e.code === "P2002" + ) { + return NextResponse.json( + { error: "该记录已存在或值已被占用" }, + { status: 409 }, + ); + } console.error(`[API ${req.method} ${req.nextUrl.pathname}]`, e); return NextResponse.json({ error: "操作失败" }, { status: 500 }); } diff --git a/src/lib/validation.ts b/src/lib/validation.ts index c9f5b5b..f400757 100644 --- a/src/lib/validation.ts +++ b/src/lib/validation.ts @@ -12,6 +12,9 @@ export function validatePassword(password: string, label = "密码"): void { if (password.length < 6) { throw new ApiError(`${label}至少 6 个字符`); } + if (password.length > 128) { + throw new ApiError(`${label}不能超过 128 个字符`); + } } export function validateEmail(email: string): void {