Files
CICD/src/app/(auth)/register/page.tsx
2026-02-24 15:50:38 +08:00

123 lines
3.8 KiB
TypeScript

import { Metadata } from "next"
import { hash } from "bcryptjs"
import { createId } from "@paralleldrive/cuid2"
import { eq } from "drizzle-orm"
import type { ActionState } from "@/shared/types/action-state"
import { RegisterForm } from "@/modules/auth/components/register-form"
export const metadata: Metadata = {
title: "Register - Next_Edu",
description: "Create an account",
}
const normalizeBcryptHash = (value: string) => {
if (value.startsWith("$2")) return value
if (value.startsWith("$")) return `$2b${value}`
return `$2b$${value}`
}
export default function RegisterPage() {
async function registerAction(formData: FormData): Promise<ActionState> {
"use server"
const databaseUrl = process.env.DATABASE_URL
if (!databaseUrl) return { success: false, message: "DATABASE_URL 未配置" }
try {
const [{ db }, { users }] = await Promise.all([
import("@/shared/db"),
import("@/shared/db/schema"),
])
const name = String(formData.get("name") ?? "").trim()
const email = String(formData.get("email") ?? "").trim().toLowerCase()
const password = String(formData.get("password") ?? "")
if (!email) return { success: false, message: "请输入邮箱" }
if (!password) return { success: false, message: "请输入密码" }
if (password.length < 6) return { success: false, message: "密码至少 6 位" }
const existing = await db.query.users.findFirst({
where: eq(users.email, email),
columns: { id: true },
})
if (existing) return { success: false, message: "该邮箱已注册" }
const hashedPassword = normalizeBcryptHash(await hash(password, 10))
await db.insert(users).values({
id: createId(),
name: name.length ? name : null,
email,
password: hashedPassword,
role: "student",
})
return { success: true, message: "账户创建成功" }
} catch (error) {
const isProd = process.env.NODE_ENV === "production"
const anyErr = error as unknown as {
code?: string
message?: string
sqlMessage?: string
cause?: unknown
}
const cause1 = anyErr?.cause as
| { code?: string; message?: string; sqlMessage?: string; cause?: unknown }
| undefined
const cause2 = (cause1?.cause ?? undefined) as
| { code?: string; message?: string; sqlMessage?: string }
| undefined
const code = String(cause2?.code ?? cause1?.code ?? anyErr?.code ?? "").trim()
const msg = String(
cause2?.sqlMessage ??
cause1?.sqlMessage ??
anyErr?.sqlMessage ??
cause2?.message ??
cause1?.message ??
anyErr?.message ??
""
).trim()
const msgLower = msg.toLowerCase()
if (
code === "ER_DUP_ENTRY" ||
msgLower.includes("duplicate") ||
msgLower.includes("unique")
) {
return { success: false, message: "该邮箱已注册" }
}
if (
code === "ER_NO_SUCH_TABLE" ||
msgLower.includes("doesn't exist") ||
msgLower.includes("unknown column")
) {
return {
success: false,
message: "数据库未初始化或未迁移,请先运行 npm run db:migrate",
}
}
if (code === "ER_ACCESS_DENIED_ERROR") {
return { success: false, message: "数据库账号/权限错误,请检查 DATABASE_URL" }
}
if (code === "ECONNREFUSED" || code === "ENOTFOUND") {
return { success: false, message: "数据库连接失败,请检查 DATABASE_URL 与网络" }
}
if (!isProd && msg) {
return { success: false, message: `创建账户失败:${msg}` }
}
return { success: false, message: "创建账户失败,请稍后重试" }
}
}
return <RegisterForm registerAction={registerAction} />
}