/** * File: route.ts * Created by: AI Assistant * Date: 2025-11-29 * Purpose: Comments API with file attachment support and privacy controls * Part of: kreatiVortex - Platform Pembelajaran Tari Online */ import { NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; import { auth } from '@/lib/auth'; import { headers } from 'next/headers'; import { getOrCreateUserProfile } from '@/lib/profile'; // Helper function to check if user can view private comment async function canViewComment(comment: any, currentUser: any, postAuthor: any, classEducator: any) { if (!comment.isPrivate) return true; if (currentUser.role === 'PENDIDIK' && currentUser.id === classEducator?.id) return true; if (currentUser.id === postAuthor?.id) return true; return false; } // Helper function to check if user can create private comment async function canCreatePrivateComment(currentUser: any, classEducator: any) { return currentUser.role === 'PENDIDIK' && currentUser.id === classEducator?.id; } // Helper function to get class educator and post author async function getForumPostContext(forumPostId: string) { const forumPost = await prisma.forumPost.findUnique({ where: { id: forumPostId }, include: { forum: { include: { class: { include: { educator: true } } } }, author: true } }); return { classEducator: forumPost?.forum?.class?.educator, postAuthor: forumPost?.author }; } export async function POST(request: Request) { try { const session = await auth.api.getSession({ headers: await headers() }); if (!session?.user) { return NextResponse.json( { success: false, message: 'Unauthorized' }, { status: 401 } ); } // Get or create user profile const userProfile = await getOrCreateUserProfile(session.user.id); const body = await request.json(); const { content, videoId, forumPostId, parentId, attachments, isPrivate } = body; // Validation if (!content && (!attachments || attachments.length === 0)) { return NextResponse.json( { success: false, message: 'Content or attachment is required' }, { status: 400 } ); } if (!videoId && !forumPostId) { return NextResponse.json( { success: false, message: 'Video ID or Forum Post ID is required' }, { status: 400 } ); } // Check privacy permissions for forum posts let classEducator = null; let postAuthor = null; let privateForId = null; if (forumPostId) { const context = await getForumPostContext(forumPostId); classEducator = context.classEducator; postAuthor = context.postAuthor; // Check if user can create private comment if (isPrivate && !await canCreatePrivateComment(userProfile, classEducator)) { return NextResponse.json( { success: false, message: 'Only educators can create private comments' }, { status: 403 } ); } // Set privateForId to post author if comment is private if (isPrivate && postAuthor) { privateForId = postAuthor.id; } } const comment = await prisma.comment.create({ data: { content: content || '', videoId: videoId || null, forumPostId: forumPostId || null, parentId: parentId || null, authorId: userProfile.id, updatedBy: userProfile.id, attachments: attachments || [], isPrivate: isPrivate || false, privateForId: privateForId, }, include: { author: { include: { user: { select: { name: true, image: true, }, }, }, }, }, }); return NextResponse.json({ success: true, data: comment }); } catch (error) { console.error('Error creating comment:', error); return NextResponse.json( { success: false, message: 'Failed to create comment' }, { status: 500 } ); } } export async function GET(request: Request) { try { const session = await auth.api.getSession({ headers: await headers() }); const { searchParams } = new URL(request.url); const videoId = searchParams.get('videoId'); const forumPostId = searchParams.get('forumPostId'); const whereClause: any = { isActive: true }; if (videoId) { whereClause.videoId = videoId; } if (forumPostId) { whereClause.forumPostId = forumPostId; } const comments = await prisma.comment.findMany({ where: whereClause, include: { author: { include: { user: { select: { name: true, image: true, }, }, }, }, replies: { include: { author: { include: { user: { select: { name: true, image: true, }, }, }, }, }, orderBy: { createdAt: 'asc', }, }, }, orderBy: { createdAt: 'asc', }, }); // Filter comments based on privacy if user is authenticated let filteredComments = comments; if (session?.user) { const userProfile = await getOrCreateUserProfile(session.user.id); // Get context for forum posts let context = null; if (forumPostId) { context = await getForumPostContext(forumPostId); } // Filter comments based on privacy filteredComments = []; for (const comment of comments) { const canView = await canViewComment( comment, userProfile, context?.postAuthor, context?.classEducator ); if (canView) { // Filter replies as well const filteredReplies = []; for (const reply of comment.replies) { const canViewReply = await canViewComment( reply, userProfile, context?.postAuthor, context?.classEducator ); if (canViewReply) { filteredReplies.push(reply); } } filteredComments.push({ ...comment, replies: filteredReplies }); } } } return NextResponse.json({ success: true, data: filteredComments }); } catch (error) { console.error('Error fetching comments:', error); return NextResponse.json( { success: false, message: 'Failed to fetch comments' }, { status: 500 } ); } }