ingestion: reject submissions containing disallowed phrases
/api/ai/submit and /api/submission-receive now scan incoming payload title + body against the bb.disallowed_phrases allowlist (cached 3 min) and return 422 with the matching phrases if any are found. Stops competitor mentions from re-entering the pipeline after the bulk purge.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ingestRawSubmission, rewriteSubmission } from "@/lib/ai/rewrite-pipeline";
|
||||
import { findViolations } from "@/lib/disallowed-phrases-guard";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const maxDuration = 300;
|
||||
@@ -98,6 +99,21 @@ export async function POST(req: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// Reject submissions whose title or body contains a disallowed phrase
|
||||
// (competitor publications, banned exhibitors, etc.). Logged with the
|
||||
// violation list so the sender knows what to remove.
|
||||
const scanText = `${payload.rawTitle}\n${payload.rawContent}\n${payload.rawHtml || ""}`;
|
||||
const violations = await findViolations(scanText);
|
||||
if (violations.length > 0) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Submission rejected: contains disallowed phrases",
|
||||
violations,
|
||||
},
|
||||
{ status: 422 },
|
||||
);
|
||||
}
|
||||
|
||||
const submissionId = await ingestRawSubmission(payload);
|
||||
const outcome = await rewriteSubmission({ submissionId, personaSlug: payload.personaSlug });
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextResponse, type NextRequest } from 'next/server';
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { findViolations } from '@/lib/disallowed-phrases-guard';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -36,6 +37,17 @@ export async function POST(request: NextRequest) {
|
||||
const content = (body?.body || '').toString();
|
||||
if (!title || !content) return NextResponse.json({ error: 'title and body are required' }, { status: 400 });
|
||||
|
||||
// Editorial guardrail: reject anything mentioning a disallowed phrase
|
||||
// (competitor publications, banned exhibitors, etc.) before it ever lands
|
||||
// in bb.native_articles.
|
||||
const violations = await findViolations(`${title}\n${content}`);
|
||||
if (violations.length > 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Submission rejected: contains disallowed phrases', violations },
|
||||
{ status: 422 },
|
||||
);
|
||||
}
|
||||
|
||||
const contributor = body?.contributor || {};
|
||||
const featuredImage = body?.featured_image_url || null;
|
||||
const attachments = Array.isArray(body?.attachments) ? body.attachments : [];
|
||||
|
||||
Reference in New Issue
Block a user