169 lines
4.6 KiB
TypeScript
169 lines
4.6 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import { z } from 'zod';
|
||
import { nanoid } from 'nanoid';
|
||
import { db } from '@/drizzle/db';
|
||
import { users, verificationCodes, userSettings } from '@/drizzle/schema';
|
||
import { eq, and, gt } from 'drizzle-orm';
|
||
import { hashPassword, validatePassword, validateEmail, validateNickname } from '@/lib/password';
|
||
import { generateToken, setAuthCookie } from '@/lib/auth';
|
||
|
||
// 请求体验证
|
||
const registerSchema = z.object({
|
||
email: z.string().email('邮箱格式不正确'),
|
||
password: z.string().min(8, '密码长度不能少于8位'),
|
||
confirmPassword: z.string(),
|
||
nickname: z.string().min(2, '昵称长度不能少于2位').max(20, '昵称长度不能超过20位'),
|
||
code: z.string().length(6, '验证码必须是6位'),
|
||
}).refine((data) => data.password === data.confirmPassword, {
|
||
message: '两次输入的密码不一致',
|
||
path: ['confirmPassword'],
|
||
});
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json();
|
||
|
||
// 验证请求体
|
||
const result = registerSchema.safeParse(body);
|
||
if (!result.success) {
|
||
return NextResponse.json(
|
||
{ success: false, error: result.error.issues[0].message },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
const { email, password, nickname, code } = result.data;
|
||
|
||
// 验证邮箱格式
|
||
if (!validateEmail(email)) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '邮箱格式不正确' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 验证密码格式
|
||
const passwordValidation = validatePassword(password);
|
||
if (!passwordValidation.valid) {
|
||
return NextResponse.json(
|
||
{ success: false, error: passwordValidation.errors[0] },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 验证昵称格式
|
||
const nicknameValidation = validateNickname(nickname);
|
||
if (!nicknameValidation.valid) {
|
||
return NextResponse.json(
|
||
{ success: false, error: nicknameValidation.error },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 检查邮箱是否已注册
|
||
const existingUser = await db
|
||
.select()
|
||
.from(users)
|
||
.where(eq(users.email, email))
|
||
.limit(1);
|
||
|
||
if (existingUser.length > 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '该邮箱已被注册' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 验证验证码
|
||
const now = new Date();
|
||
const validCode = await db
|
||
.select()
|
||
.from(verificationCodes)
|
||
.where(
|
||
and(
|
||
eq(verificationCodes.email, email),
|
||
eq(verificationCodes.code, code),
|
||
eq(verificationCodes.type, 'register'),
|
||
eq(verificationCodes.used, false),
|
||
gt(verificationCodes.expiresAt, now)
|
||
)
|
||
)
|
||
.limit(1);
|
||
|
||
if (validCode.length === 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '验证码无效或已过期' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 标记验证码为已使用
|
||
await db
|
||
.update(verificationCodes)
|
||
.set({ used: true })
|
||
.where(eq(verificationCodes.id, validCode[0].id));
|
||
|
||
// 加密密码
|
||
const hashedPassword = await hashPassword(password);
|
||
|
||
// 生成用户ID
|
||
const userId = nanoid();
|
||
|
||
// 创建用户
|
||
const [newUser] = await db
|
||
.insert(users)
|
||
.values({
|
||
userId,
|
||
email,
|
||
password: hashedPassword,
|
||
nickname,
|
||
emailVerified: true, // 已通过邮箱验证
|
||
lastLoginAt: now,
|
||
})
|
||
.returning();
|
||
|
||
// 创建默认用户设置(API Key 为空,需要用户自行配置)
|
||
await db.insert(userSettings).values({
|
||
userId,
|
||
cchUrl: process.env.CCH_DEFAULT_URL || 'https://claude.leocoder.cn/',
|
||
cchApiKey: null,
|
||
cchApiKeyConfigured: false,
|
||
defaultModel: 'claude-sonnet-4-20250514',
|
||
defaultTools: ['web_search', 'code_execution', 'web_fetch'],
|
||
theme: 'light',
|
||
language: 'zh-CN',
|
||
fontSize: 15,
|
||
enableThinking: false,
|
||
saveChatHistory: true,
|
||
});
|
||
|
||
// 生成 JWT Token
|
||
const token = await generateToken({
|
||
userId: newUser.userId,
|
||
email: newUser.email,
|
||
nickname: newUser.nickname,
|
||
plan: newUser.plan || 'free',
|
||
});
|
||
|
||
// 设置认证 Cookie
|
||
await setAuthCookie(token);
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
user: {
|
||
id: newUser.userId,
|
||
email: newUser.email,
|
||
nickname: newUser.nickname,
|
||
plan: newUser.plan,
|
||
},
|
||
message: '注册成功',
|
||
});
|
||
} catch (error) {
|
||
console.error('注册失败:', error);
|
||
return NextResponse.json(
|
||
{ success: false, error: '服务器错误' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|