96 lines
2.5 KiB
TypeScript
96 lines
2.5 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { COOKIE_NAME } from "@/app/lib/auth-cookie";
|
|
import {
|
|
findVipEmailLinkByUserId,
|
|
getActiveSiteVipRecord,
|
|
getAdminToken,
|
|
hasVipByUserId,
|
|
isAnonymousUserId,
|
|
} from "@/app/api/vip/_helpers";
|
|
|
|
type SessionPayload = {
|
|
userId?: string;
|
|
anonymousUserId?: string;
|
|
};
|
|
|
|
function readSessionPayload(request: NextRequest): SessionPayload | null {
|
|
const raw = request.cookies.get(COOKIE_NAME)?.value;
|
|
if (!raw) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(Buffer.from(raw, "base64url").toString("utf-8"));
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const payload = readSessionPayload(request);
|
|
const userId =
|
|
typeof payload?.userId === "string" ? payload.userId.trim() : "";
|
|
const anonymousUserId =
|
|
typeof payload?.anonymousUserId === "string"
|
|
? payload.anonymousUserId.trim()
|
|
: "";
|
|
|
|
if (!userId) {
|
|
return NextResponse.json({ ok: true, vip: false });
|
|
}
|
|
|
|
try {
|
|
const adminToken = await getAdminToken();
|
|
if (!adminToken) {
|
|
// 未配置 POCKETBASE_EMAIL/PASSWORD 等时无法校验;前端勿据此清空本地已登录态
|
|
return NextResponse.json({
|
|
ok: true,
|
|
vip: false,
|
|
adminUnavailable: true,
|
|
});
|
|
}
|
|
|
|
const userRecord = await getActiveSiteVipRecord(adminToken, userId);
|
|
if (userRecord) {
|
|
return NextResponse.json({
|
|
ok: true,
|
|
vip: true,
|
|
expires_at:
|
|
typeof userRecord.expires_at === "string" ? userRecord.expires_at : null,
|
|
});
|
|
}
|
|
|
|
if (await hasVipByUserId(adminToken, userId)) {
|
|
return NextResponse.json({ ok: true, vip: true, expires_at: null });
|
|
}
|
|
|
|
const candidates = isAnonymousUserId(anonymousUserId)
|
|
? [anonymousUserId]
|
|
: [];
|
|
if (!isAnonymousUserId(userId)) {
|
|
const linkRecord = await findVipEmailLinkByUserId(adminToken, userId);
|
|
const linkedAnonymousUserId =
|
|
typeof linkRecord?.anonymous_user_id === "string"
|
|
? linkRecord.anonymous_user_id.trim()
|
|
: "";
|
|
if (isAnonymousUserId(linkedAnonymousUserId)) {
|
|
candidates.push(linkedAnonymousUserId);
|
|
}
|
|
}
|
|
|
|
for (const candidate of candidates) {
|
|
if (await hasVipByUserId(adminToken, candidate)) {
|
|
return NextResponse.json({ ok: true, vip: true, expires_at: null });
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ ok: true, vip: false });
|
|
} catch {
|
|
return NextResponse.json({
|
|
ok: true,
|
|
vip: false,
|
|
uncertain: true,
|
|
});
|
|
}
|
|
}
|