import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; import { requireAuth } from "@/lib/auth"; import { getUserTier, FORUM_LIMITS } from "@/lib/tiers"; import { moderateContent } from "@/lib/shariah-moderation"; export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const categoryId = searchParams.get("categoryId"); const where: Record = {}; if (categoryId) { where.categoryId = categoryId; } // For group-scoped visibility: if user is authenticated, find which group IDs // they are a member of, so we can include public threads (groupId: null) plus // private threads where they are a member. const auth = await requireAuth(request); let userGroupIds: string[] = []; if (auth) { const memberships = await prisma.groupMember.findMany({ where: { userId: auth.userId }, select: { groupId: true }, }); userGroupIds = memberships.map((m) => m.groupId); } const threads = await prisma.forumThread.findMany({ where: { ...where, OR: [ { groupId: null }, { groupId: { in: userGroupIds } }, ], }, include: { author: { select: { id: true, name: true, isPremium: true, isPro: true }, }, category: { select: { id: true, name: true, icon: true }, }, group: { select: { id: true, name: true }, }, _count: { select: { posts: true }, }, }, orderBy: [ { pinned: "desc" }, { createdAt: "desc" }, ], }); return NextResponse.json({ threads }); } catch (error) { console.error("GET /api/forum/threads error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } } export async function POST(request: NextRequest) { try { const auth = await requireAuth(request); if (!auth) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const user = await prisma.user.findUnique({ where: { id: auth.userId } }); if (!user) { return NextResponse.json({ error: "User not found" }, { status: 404 }); } const tier = getUserTier(user.isPremium, user.isPro); const limits = FORUM_LIMITS[tier]; if (!limits.canPost) { return NextResponse.json( { error: "Your tier does not support posting. Upgrade to Premium or Pro to create threads." }, { status: 403 } ); } const { title, content, categoryId, groupId } = await request.json(); if (!title || !content || !categoryId) { return NextResponse.json( { error: "Missing required fields: title, content, categoryId" }, { status: 400 } ); } // Verify category exists const category = await prisma.forumCategory.findUnique({ where: { id: categoryId }, }); if (!category) { return NextResponse.json( { error: "Invalid category" }, { status: 400 } ); } // If groupId is provided, verify user is a member of that group if (groupId) { const membership = await prisma.groupMember.findUnique({ where: { groupId_userId: { groupId, userId: user.id }, }, }); if (!membership) { return NextResponse.json( { error: "You are not a member of this group" }, { status: 403 } ); } } const thread = await prisma.forumThread.create({ data: { title, content, categoryId, authorId: user.id, groupId: groupId || null, shariahStatus: groupId ? "private" : "pending", }, include: { author: { select: { id: true, name: true, isPremium: true, isPro: true }, }, category: { select: { id: true, name: true, icon: true }, }, group: { select: { id: true, name: true }, }, _count: { select: { posts: true }, }, }, }); // ── Auto-moderation for public threads ─────────────────────────── if (!groupId) { const result = moderateContent(content, title); if (result.status === "approved") { await prisma.forumThread.update({ where: { id: thread.id }, data: { shariahStatus: "approved" }, }); thread.shariahStatus = "approved"; } else { await prisma.forumThread.update({ where: { id: thread.id }, data: { shariahFlags: JSON.stringify(result.flags) }, }); thread.shariahFlags = JSON.stringify(result.flags); } } return NextResponse.json({ thread }, { status: 201 }); } catch (error) { console.error("POST /api/forum/threads error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }