fix: 评论流程两个断点(mock 登录 cookie 透传 + 评论后 ISR 缓存失效)
- mock-social 500:route handler 里 headers() 不可写,session cookie 无法落浏览器。
改为 auth.api.signInEmail({ asResponse: true }) 并把 Set-Cookie 显式透传给响应。
浏览器验证:mock 登录后有 session cookie,get-session 返回演示用户。
- 评论提交后详情页仍显示旧评分(ISR 1h):submitReview/deleteMyReview/setReviewStatus
增加 revalidatePath(tools/[slug] + rankings + 首页)。
浏览器验证:提交评论后 'Based on N reviews' 即时 2→3。
- 全链路回归:登录→写评论(星级/正文/优缺点)→提交出现→聚合更新→Helpful 计数 全部 PASS
This commit is contained in:
@@ -134,7 +134,10 @@ export async function submitReview(
|
||||
metadata: { rating: data.rating },
|
||||
});
|
||||
|
||||
// 失效详情页 ISR 缓存(评分/评论数即时反映)+ 榜单页
|
||||
revalidatePath("/[locale]/tools/[slug]", "page");
|
||||
revalidatePath("/[locale]/rankings", "page");
|
||||
revalidatePath("/[locale]", "page");
|
||||
return { success: true, reviewId };
|
||||
}
|
||||
|
||||
@@ -314,6 +317,7 @@ export async function deleteMyReview(toolId: string) {
|
||||
.where(and(eq(review.userId, user.id), eq(review.toolId, toolId)));
|
||||
await recalcToolRating(toolId);
|
||||
revalidatePath("/[locale]/tools/[slug]", "page");
|
||||
revalidatePath("/[locale]/rankings", "page");
|
||||
return { success: true as const };
|
||||
}
|
||||
|
||||
@@ -335,6 +339,7 @@ export async function setReviewStatus(reviewId: string, status: ReviewStatus) {
|
||||
if (row) {
|
||||
await recalcToolRating(row.toolId);
|
||||
revalidatePath("/[locale]/tools/[slug]", "page");
|
||||
revalidatePath("/[locale]/rankings", "page");
|
||||
}
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { db } from "@/lib/db";
|
||||
import { user, account } from "@/lib/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { nanoid } from "nanoid";
|
||||
import { hashPassword } from "better-auth/crypto";
|
||||
|
||||
/**
|
||||
* POST /api/auth/mock-social { provider: "google" | "github" }
|
||||
* 说明:开发/演示环境的第三方登录 Mock。
|
||||
* 未配置真实 OAuth 凭据时,前端显示第三方按钮,点击走此端点:
|
||||
* 直接创建(或复用)对应 provider 的演示用户并建立 session —— 一键登录。
|
||||
* 生产环境配置了 AUTH_GOOGLE_ID / AUTH_GITHUB_ID 后此端点自动禁用(403)。
|
||||
* - 未配置真实 OAuth 凭据时启用;生产配置 AUTH_GOOGLE_ID/AUTH_GITHUB_ID 后自动 403。
|
||||
* - 复用/创建对应 provider 的演示用户,然后通过 better-auth 的 signInEmail 建立 session,
|
||||
* 并把 Set-Cookie 头显式透传给浏览器(route handler 里 headers() 不可写,必须走 response)。
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
// 双保险:配置了真实凭据时拒绝 mock
|
||||
if (process.env.AUTH_GOOGLE_ID || process.env.AUTH_GITHUB_ID) {
|
||||
return NextResponse.json({ error: "MOCK_DISABLED" }, { status: 403 });
|
||||
}
|
||||
@@ -27,7 +26,6 @@ export async function POST(req: NextRequest) {
|
||||
const email = `${provider}-user@demo.dev`;
|
||||
const name = provider === "google" ? "Google Demo User" : "GitHub Demo User";
|
||||
|
||||
// 复用或创建演示用户
|
||||
let [u] = await db.select().from(user).where(eq(user.email, email)).limit(1);
|
||||
if (!u) {
|
||||
[u] = await db
|
||||
@@ -42,11 +40,10 @@ export async function POST(req: NextRequest) {
|
||||
.returning();
|
||||
}
|
||||
|
||||
// 确保 credential 密码存在(一键登录用)
|
||||
await db
|
||||
.insert(account)
|
||||
.values({
|
||||
id: `acc_mock_${provider}`,
|
||||
id: nanoid(),
|
||||
accountId: u.id,
|
||||
providerId: "credential",
|
||||
userId: u.id,
|
||||
@@ -54,11 +51,32 @@ export async function POST(req: NextRequest) {
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
|
||||
// 建立 session
|
||||
const session = await auth.api.signInEmail({
|
||||
// 用一个模拟请求头调用 signInEmail;返回的 set-cookie 需要透传
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
requestHeaders.set("cookie", req.headers.get("cookie") || "");
|
||||
|
||||
const res = await auth.api.signInEmail({
|
||||
body: { email, password: "password123" },
|
||||
headers: await headers(),
|
||||
headers: requestHeaders,
|
||||
asResponse: true,
|
||||
});
|
||||
|
||||
return NextResponse.json({ ok: true, user: session?.user ?? null });
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
return NextResponse.json(
|
||||
{ error: "MOCK_SIGNIN_FAILED", detail: text.slice(0, 200) },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await res.json();
|
||||
const out = NextResponse.json({ ok: true, user: body.user ?? null });
|
||||
|
||||
// 透传全部 Set-Cookie(session token)
|
||||
const setCookies = res.headers.getSetCookie?.() ?? [];
|
||||
for (const c of setCookies) {
|
||||
out.headers.append("set-cookie", c);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user