Phase B polish: revalidatePath on approve, reject empty submissions
src/app/api/admin/review-queue/[id]/route.ts
- Call revalidatePath on /news, /news/<slug>, /articles/<slug>, /home-page,
section pages, and /sitemap.xml on approve/reject. The /news listing is
ISR-cached (revalidate=1800) so approval would otherwise be invisible
for up to 30 minutes; this flushes the cache immediately.
src/app/api/ai/submit/route.ts
- Reject submissions where rawTitle/title is whitespace or rawContent/body
is empty after stripping HTML. Previously empty bodies fell through into
the LLM and Claude dutifully wrote a 400-word piece about the empty
submission. Hard-cap at the gate to avoid the spend.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { revalidatePath, revalidateTag } from "next/cache";
|
||||
import { createClient } from "@/lib/supabase/server";
|
||||
import { createAdminClient } from "@/lib/supabase/admin";
|
||||
|
||||
@@ -55,7 +56,7 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
...extras,
|
||||
})
|
||||
.eq("id", id)
|
||||
.select("id, original_submission_id")
|
||||
.select("id, slug, original_submission_id")
|
||||
.single();
|
||||
|
||||
if (error || !data) return NextResponse.json({ error: error?.message || "Not found" }, { status: 500 });
|
||||
@@ -67,5 +68,20 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
.eq("id", (data as any).original_submission_id);
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: true, id: (data as any).id, status: nextStatus });
|
||||
const slug = (data as any).slug as string;
|
||||
for (const path of [
|
||||
"/news",
|
||||
`/news/${slug}`,
|
||||
`/articles/${slug}`,
|
||||
"/home-page",
|
||||
"/technology",
|
||||
"/gear",
|
||||
"/show-coverage",
|
||||
"/sitemap.xml",
|
||||
]) {
|
||||
try { revalidatePath(path); } catch {}
|
||||
}
|
||||
try { revalidateTag("articles"); } catch {}
|
||||
|
||||
return NextResponse.json({ ok: true, id: (data as any).id, status: nextStatus, slug });
|
||||
}
|
||||
|
||||
@@ -52,10 +52,12 @@ function normalize(raw: any): NativePayload | null {
|
||||
if (!raw || typeof raw !== "object") return null;
|
||||
// Native shape: { rawTitle, rawContent, ... }
|
||||
if (typeof raw.rawTitle === "string" && typeof raw.rawContent === "string") {
|
||||
if (!raw.rawTitle.trim() || !raw.rawContent.trim()) return null;
|
||||
return raw as NativePayload;
|
||||
}
|
||||
// Distribute-rmp shape: { title, body, contributor: {...} }
|
||||
if (typeof raw.title === "string" && typeof raw.body === "string") {
|
||||
if (!raw.title.trim() || !raw.body.replace(/<[^>]*>/g, "").trim()) return null;
|
||||
const d = raw as DistributePayload;
|
||||
const contributorName = d.contributor?.contact_name || d.contributor?.firm_name || undefined;
|
||||
const contributorEmail = d.contributor?.email || undefined;
|
||||
|
||||
Reference in New Issue
Block a user