124 lines
4.4 KiB
TypeScript
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 })
|
|
}
|
|
}
|