131 lines
3.8 KiB
TypeScript
131 lines
3.8 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getPocketBaseConfig } from "@/config/services.config";
|
|
import { getThemeConfig } from "@/config";
|
|
|
|
const COOKIE_NAME = "pb_session";
|
|
|
|
function getOrCreateUserId(request: NextRequest): string {
|
|
const cookie = request.cookies.get(COOKIE_NAME)?.value;
|
|
if (cookie) {
|
|
try {
|
|
const payload = JSON.parse(Buffer.from(cookie, "base64url").toString("utf-8"));
|
|
if (payload?.userId) return payload.userId;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
return `user${Date.now()}`;
|
|
}
|
|
|
|
async function getAdminToken(): Promise<string | null> {
|
|
const email = process.env.POCKETBASE_EMAIL;
|
|
const password = process.env.POCKETBASE_PASSWORD;
|
|
if (!email || !password) return null;
|
|
|
|
const pb = getPocketBaseConfig();
|
|
const res = await fetch(`${pb.url}/api/admins/auth-with-password`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ identity: email, password }),
|
|
});
|
|
if (!res.ok) return null;
|
|
const data = await res.json();
|
|
return data?.token ?? null;
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const userId = getOrCreateUserId(request);
|
|
const body = await request.json();
|
|
const formData = body && typeof body === "object" ? body : {};
|
|
|
|
const {
|
|
nickname,
|
|
gender,
|
|
single,
|
|
profession,
|
|
intro,
|
|
wechat,
|
|
education,
|
|
graduationYear,
|
|
phone,
|
|
media: mediaUrl,
|
|
} = formData;
|
|
|
|
// reason=自我介绍, single=感情状态, media=MinIO 上传后的 URL
|
|
const record: Record<string, string | number> = {
|
|
nickname: nickname || "",
|
|
occupation: profession || "",
|
|
reason: intro || "",
|
|
single: single || "",
|
|
wechatId: wechat || "",
|
|
gender: gender || "",
|
|
education: education || "",
|
|
gradYear: graduationYear || "",
|
|
phone: phone || "",
|
|
user_id: userId,
|
|
amount: 0,
|
|
order_id: "",
|
|
type: "",
|
|
};
|
|
|
|
if (mediaUrl && typeof mediaUrl === "string") {
|
|
(record as Record<string, string>)["media"] = mediaUrl;
|
|
}
|
|
|
|
const theme = getThemeConfig();
|
|
const pb = getPocketBaseConfig({
|
|
joinCollection: theme.services?.pocketbaseJoinCollection,
|
|
});
|
|
const collection = pb.joinCollection;
|
|
|
|
const doCreate = async (authToken?: string) => {
|
|
const headers: Record<string, string> = {
|
|
"Content-Type": "application/json",
|
|
};
|
|
if (authToken) headers["Authorization"] = authToken;
|
|
|
|
return fetch(`${pb.url}/api/collections/${collection}/records`, {
|
|
method: "POST",
|
|
headers,
|
|
body: JSON.stringify(record),
|
|
});
|
|
};
|
|
|
|
let res = await doCreate();
|
|
|
|
if (res.status === 403) {
|
|
const token = await getAdminToken();
|
|
if (token) res = await doCreate(token);
|
|
}
|
|
|
|
if (!res.ok) {
|
|
const errText = await res.text();
|
|
console.error("PocketBase create error:", res.status, errText);
|
|
let errMsg = "提交失败,请稍后重试";
|
|
try {
|
|
const errJson = JSON.parse(errText);
|
|
if (errJson?.message) errMsg = errJson.message;
|
|
if (errJson?.data && typeof errJson.data === "object") {
|
|
const details = Object.entries(errJson.data)
|
|
.map(([k, v]) => `${k}: ${(v as { message?: string })?.message || v}`)
|
|
.join("; ");
|
|
if (details) errMsg += ` (${details})`;
|
|
}
|
|
} catch {
|
|
if (errText.length < 200) errMsg = errText;
|
|
}
|
|
return NextResponse.json({ ok: false, error: errMsg }, { status: 500 });
|
|
}
|
|
|
|
return NextResponse.json({ ok: true, user_id: userId });
|
|
} catch (e) {
|
|
const msg = e instanceof Error ? e.message : String(e);
|
|
console.error("Join API error:", e);
|
|
return NextResponse.json(
|
|
{ ok: false, error: `提交失败: ${msg}` },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|