feat: user blocking and content reporting/flagging
- user_blocks table (composite PK), Block/Unblock button on profiles. Blocking severs any existing follow relationship both ways and prevents the blocked party from following, commenting on the blocker's recipes, or the blocker from seeing their comments. - reports table (recipe/comment/user targets, pending/reviewed/ dismissed status). ReportButton on comments, admin review queue at /admin/reports with dismiss/mark-reviewed actions, audit-logged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { db, recipes, comments, users, eq, and } from "@epicure/db";
|
||||
import { db, recipes, comments, users, userBlocks, eq, and } from "@epicure/db";
|
||||
import { requireSession } from "@/lib/api-auth";
|
||||
import { applyRateLimit } from "@/lib/rate-limit";
|
||||
import { dispatchWebhook } from "@/lib/webhooks";
|
||||
import { sendPushNotification } from "@/lib/push";
|
||||
import { createNotification } from "@/lib/notifications";
|
||||
import { isBlockedEitherWay } from "@/lib/blocks";
|
||||
|
||||
const Schema = z.object({
|
||||
content: z.string().min(1).max(5000),
|
||||
@@ -21,6 +22,8 @@ export async function GET(_req: NextRequest, { params }: Params) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const { session } = await requireSession();
|
||||
|
||||
const rows = await db
|
||||
.select({
|
||||
id: comments.id,
|
||||
@@ -38,7 +41,15 @@ export async function GET(_req: NextRequest, { params }: Params) {
|
||||
.where(eq(comments.recipeId, id))
|
||||
.orderBy(comments.createdAt);
|
||||
|
||||
return NextResponse.json(rows);
|
||||
if (!session) return NextResponse.json(rows);
|
||||
|
||||
const blocked = await db
|
||||
.select({ blockedId: userBlocks.blockedId })
|
||||
.from(userBlocks)
|
||||
.where(eq(userBlocks.blockerId, session.user.id));
|
||||
const blockedIds = new Set(blocked.map((b) => b.blockedId));
|
||||
|
||||
return NextResponse.json(rows.filter((r) => !blockedIds.has(r.userId)));
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest, { params }: Params) {
|
||||
@@ -54,6 +65,10 @@ export async function POST(req: NextRequest, { params }: Params) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
if (recipe.authorId !== session!.user.id && await isBlockedEitherWay(session!.user.id, recipe.authorId)) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const body = await req.json() as unknown;
|
||||
const parsed = Schema.safeParse(body);
|
||||
if (!parsed.success) return NextResponse.json({ error: "Validation error" }, { status: 400 });
|
||||
|
||||
Reference in New Issue
Block a user