121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getServerSession } from 'next-auth'
|
|
import { authOptions } from '@/lib/auth'
|
|
import { connectToDatabase } from '@/lib/mongodb'
|
|
import { ObjectId } from 'mongodb'
|
|
import { commentSchema } from '@/lib/validations'
|
|
import { checkRateLimit } from '@/lib/rate-limit'
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(request.url)
|
|
const coinId = searchParams.get('coinId')
|
|
|
|
if (!coinId) {
|
|
return NextResponse.json({ error: 'Coin ID required' }, { status: 400 })
|
|
}
|
|
|
|
const { db } = await connectToDatabase()
|
|
const comments = await db.collection('comments')
|
|
.find({ coinId })
|
|
.sort({ createdAt: -1 })
|
|
.limit(50)
|
|
.toArray()
|
|
|
|
return NextResponse.json(comments)
|
|
} catch (error) {
|
|
return NextResponse.json({ error: 'Failed to fetch comments' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const session = await getServerSession(authOptions)
|
|
if (!session) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
}
|
|
|
|
//! rate limiting: 5 comments per minute per user
|
|
if (checkRateLimit(session.user.id, 'comment', 5, 60000)) {
|
|
return NextResponse.json({ error: 'Rate limit exceeded. Please wait.' }, { status: 429 })
|
|
}
|
|
|
|
const body = await request.json()
|
|
const validationResult = commentSchema.safeParse(body)
|
|
|
|
if (!validationResult.success) {
|
|
return NextResponse.json({ error: validationResult.error.errors[0].message }, { status: 400 })
|
|
}
|
|
|
|
const { coinId, text } = validationResult.data
|
|
|
|
if ((text.match(/\n/g) || []).length > 2) {
|
|
return NextResponse.json({ error: 'Comment is too tall (max 2 new lines)' }, { status: 400 })
|
|
}
|
|
|
|
const { db } = await connectToDatabase()
|
|
|
|
|
|
//? owns % of coin? (holder)
|
|
const user = await db.collection('users').findOne({ _id: new ObjectId(session.user.id) })
|
|
const isHolder = user?.portfolio?.some((p: any) => p.coinId === coinId && p.amount > 0)
|
|
|
|
const comment = {
|
|
coinId,
|
|
userId: session.user.id,
|
|
userName: session.user.name || 'Anonymous',
|
|
userImage: session.user.image,
|
|
userVerified: !!user?.verified,
|
|
userIsAdmin: !!user?.isAdmin,
|
|
userIsBetaTester: !!user?.isBetaTester,
|
|
userIsBugHunter: !!user?.isBugHunter,
|
|
text,
|
|
isHolder,
|
|
createdAt: new Date(),
|
|
}
|
|
|
|
await db.collection('comments').insertOne(comment)
|
|
|
|
return NextResponse.json(comment)
|
|
} catch (error) {
|
|
return NextResponse.json({ error: 'Failed to post comment' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest) {
|
|
try {
|
|
const session = await getServerSession(authOptions)
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
}
|
|
|
|
const { searchParams } = new URL(request.url)
|
|
const commentId = searchParams.get('id')
|
|
|
|
if (!commentId) {
|
|
return NextResponse.json({ error: 'Comment ID required' }, { status: 400 })
|
|
}
|
|
|
|
const { db } = await connectToDatabase()
|
|
const comment = await db.collection('comments').findOne({ _id: new ObjectId(commentId) })
|
|
if (!comment) {
|
|
return NextResponse.json({ error: 'Comment not found' }, { status: 404 })
|
|
}
|
|
const coin = await db.collection('coins').findOne({ _id: new ObjectId(comment.coinId) })
|
|
|
|
const isOwner = comment.userId === session.user.id
|
|
const isCoinCreator = coin && coin.creatorId === session.user.id
|
|
const isAdmin = session.user.isAdmin
|
|
|
|
if (!isOwner && !isCoinCreator && !isAdmin) {
|
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
|
|
}
|
|
|
|
await db.collection('comments').deleteOne({ _id: new ObjectId(commentId) })
|
|
|
|
return NextResponse.json({ success: true })
|
|
} catch (error) {
|
|
console.error('Delete comment error:', error)
|
|
return NextResponse.json({ error: 'Failed to delete comment' }, { status: 500 })
|
|
}
|
|
}
|