This commit is contained in:
eric
2026-03-26 10:57:26 -05:00
parent a94e801a95
commit eaa92ddf36
3 changed files with 171 additions and 36 deletions

View File

@@ -21,8 +21,11 @@ type PBAuthRecord = {
type PayjsVipEmailResult = {
vip: boolean;
error?: string;
effectiveUserId?: string;
anonymousUserId?: string;
token?: string;
record?: PBAuthRecord;
};
type RecoveryResult = {
@@ -69,7 +72,13 @@ async function checkVipByEmailFromPayjsapi(
const data = await res.json().catch(() => ({}));
if (!data?.vip) {
return null;
return {
vip: false,
error:
typeof data?.error === "string" && data.error.trim()
? data.error.trim()
: undefined,
};
}
return {
@@ -82,6 +91,8 @@ async function checkVipByEmailFromPayjsapi(
typeof data?.anonymousUserId === "string"
? data.anonymousUserId.trim()
: undefined,
token: typeof data?.token === "string" ? data.token : undefined,
record: data?.record?.id ? data.record : undefined,
};
} catch (error) {
console.log("[check-by-email] payjsapi request failed:", error);
@@ -246,18 +257,74 @@ export async function POST(request: NextRequest) {
}
try {
const [authData, adminToken] = await Promise.all([
loginPocketBaseUser(email, password),
getAdminToken(),
]);
if (!adminToken) {
let authData: { token: string; record: PBAuthRecord } | null = null;
let loginError: string | null = null;
try {
authData = await loginPocketBaseUser(email, password);
} catch (error) {
loginError = error instanceof Error ? error.message : "登录失败";
}
let payjsResult: PayjsVipEmailResult | null = await checkVipByEmailFromPayjsapi(
request,
email,
password,
requestedAnonymousUserId || undefined
);
// PB 登录失败时,尝试使用 payjsapi 返回的 token/record 兜底恢复
if (!authData && payjsResult?.vip && payjsResult.token && payjsResult.record?.id) {
console.log("[check-by-email] fallback by payjsapi token email=%s", email);
return NextResponse.json({
ok: true,
vip: true,
token: payjsResult.token,
record: payjsResult.record,
effectiveUserId: payjsResult.record.id,
anonymousUserId: payjsResult.anonymousUserId ?? null,
memosAccount: payjsResult.anonymousUserId ?? null,
source: "payjsapi_token_fallback",
});
}
if (!authData) {
const msg = loginError || "登录失败";
return NextResponse.json(
{ ok: false, vip: false, error: "PocketBase 管理员认证失败" },
{ status: 500 }
{ ok: false, vip: false, error: msg },
{ status: msg.includes("密码") || msg.includes("邮箱") ? 401 : 503 }
);
}
const adminToken = await getAdminToken().catch((error) => {
console.error("[check-by-email] getAdminToken failed:", error);
return null;
});
if (!adminToken) {
// 管理员 token 获取失败时,降级到 payjsapi 结果,避免直接 500
if (payjsResult?.vip) {
return NextResponse.json({
ok: true,
vip: true,
token: authData.token,
record: authData.record,
effectiveUserId: authData.record.id,
anonymousUserId: payjsResult.anonymousUserId ?? null,
memosAccount: payjsResult.anonymousUserId ?? null,
source: "payjsapi_degraded",
});
}
return NextResponse.json(
{
ok: false,
vip: false,
error:
payjsResult?.error ||
"服务繁忙,请稍后重试",
},
{ status: 503 }
);
}
let payjsResult: PayjsVipEmailResult | null = null;
let recovery = await resolveRecovery(
adminToken,
email,
@@ -267,12 +334,14 @@ export async function POST(request: NextRequest) {
);
if (!recovery.vip) {
payjsResult = await checkVipByEmailFromPayjsapi(
request,
email,
password,
requestedAnonymousUserId || undefined
);
if (!payjsResult) {
payjsResult = await checkVipByEmailFromPayjsapi(
request,
email,
password,
requestedAnonymousUserId || undefined
);
}
recovery = await resolveRecovery(
adminToken,
email,
@@ -291,18 +360,25 @@ export async function POST(request: NextRequest) {
return NextResponse.json({
ok: false,
vip: false,
error:
error: payjsResult?.error ||
"未找到关联的会员记录,请确认已支付并绑定邮箱;如为历史匿名订单,可填写支付时的 user_id 再登录",
});
}
const fallbackAnonymousUserId = isAnonymousUserId(requestedAnonymousUserId)
? requestedAnonymousUserId
: (await findAnonymousUserIdForUser(adminToken, authData.record.id)) ||
let fallbackAnonymousUserId: string | undefined;
if (
isAnonymousUserId(requestedAnonymousUserId) &&
(await hasVipByUserId(adminToken, requestedAnonymousUserId))
) {
fallbackAnonymousUserId = requestedAnonymousUserId;
} else {
fallbackAnonymousUserId =
(await findAnonymousUserIdForUser(adminToken, authData.record.id)) ||
(typeof payjsResult?.anonymousUserId === "string" &&
isAnonymousUserId(payjsResult.anonymousUserId.trim())
? payjsResult.anonymousUserId.trim()
: undefined);
}
const anonymousUserId =
recovery.anonymousUserId || fallbackAnonymousUserId;