pummmp.fun/app/api/tip/route.ts
2026-07-04 12:49:09 -07:00

124 lines
4.4 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'
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { recipientUsername, amount } = await request.json()
const tipAmount = parseFloat(amount);
if (isNaN(tipAmount) || tipAmount <= 0) {
return NextResponse.json({ error: 'Invalid amount' }, { status: 400 })
}
// you cant tip urself brotato i msorry
if (session.user.name === recipientUsername) {
return NextResponse.json({ error: 'You cannot tip yourself' }, { status: 400 })
}
const { db } = await connectToDatabase()
const sender = await db.collection('users').findOne({ _id: new ObjectId(session.user.id) })
if (!sender) {
return NextResponse.json({ error: 'Sender not found' }, { status: 404 })
}
if ((sender.balance || 0) < tipAmount) {
return NextResponse.json({ error: 'Insufficient funds' }, { status: 400 })
}
// Check if sender is tip banned
if (sender.tipBannedUntil) {
const banExpiry = new Date(sender.tipBannedUntil);
const nowCheck = new Date();
if (banExpiry > nowCheck) {
const isPermanent = (typeof banExpiry.getFullYear === 'function' && banExpiry.getFullYear() === 9999);
const remaining = isPermanent ? 'permanently' : `${Math.ceil((banExpiry.getTime() - Date.now()) / (1000 * 60))} minutes`;
return NextResponse.json({ error: `You are tip banned ${isPermanent ? 'permanently' : `for ${remaining} more minutes`}.` }, { status: 403 })
} else {
// Ban expired, remove it
try {
await db.collection('users').updateOne(
{ _id: sender._id },
{ $unset: { tipBannedUntil: 1 } }
)
} catch (e) {}
}
}
//? only 1 tip/30min
const now = new Date();
if (sender.lastTipAt) {
const lastTip = new Date(sender.lastTipAt);
const diffMs = now.getTime() - lastTip.getTime();
const diffMins = diffMs / 60000;
if (diffMins < 30) {
const minutesLeft = Math.ceil(30 - diffMins);
return NextResponse.json({ error: `You can tip again in ${minutesLeft} minutes` }, { status: 429 })
}
}
//? get recipient
//! note: assuming username is unique enough or we trust the passed username
//! ideally we should tip by id, but the chat command uses username and im lazy asf
const recipient = await db.collection('users').findOne({ name: recipientUsername })
if (!recipient) {
return NextResponse.json({ error: `User '${recipientUsername}' not found` }, { status: 404 })
}
// Check if recipient is tip banned
if (recipient.tipBannedUntil) {
const banExpiry = new Date(recipient.tipBannedUntil);
const nowCheck = new Date();
if (banExpiry > nowCheck) {
return NextResponse.json({ error: 'Cannot tip this user - they are tip banned.' }, { status: 400 })
} else {
// Ban expired, remove it
try {
await db.collection('users').updateOne(
{ _id: recipient._id },
{ $unset: { tipBannedUntil: 1 } }
)
} catch (e) {}
}
}
// tip!
await db.collection('users').updateOne( // sender
{ _id: new ObjectId(session.user.id) },
{
$inc: { balance: -tipAmount },
$set: { lastTipAt: now }
}
)
await db.collection('users').updateOne( // reciever
{ _id: recipient._id },
{ $inc: { balance: tipAmount } }
)
let solPrice = 0;
try {
const priceDoc = await db.collection('settings').findOne({ _id: 'sol_price' as any });
if (priceDoc) solPrice = priceDoc.price;
} catch {}
return NextResponse.json({
success: true,
message: `Successfully sent ${tipAmount} SOL to ${recipientUsername}`,
newBalance: (sender.balance || 0) - tipAmount
})
} catch (error) {
console.error('Tip error:', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}