(request: NextRequest, { params }: RouteParams)
| 22 | const ORG_MIN_PURCHASE_CREDITS = 5000 // $50 minimum for organizations |
| 23 | |
| 24 | export async function POST(request: NextRequest, { params }: RouteParams) { |
| 25 | if (!ORG_BILLING_ENABLED) { |
| 26 | return NextResponse.json({ error: 'Organization billing is temporarily disabled' }, { status: 503 }) |
| 27 | } |
| 28 | |
| 29 | const session = await getServerSession(authOptions) |
| 30 | if (!session?.user?.id) { |
| 31 | return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
| 32 | } |
| 33 | |
| 34 | const { orgId } = await params |
| 35 | |
| 36 | try { |
| 37 | const body = await request.json() |
| 38 | const { amount: credits } = body // Frontend sends 'amount' which is actually credits |
| 39 | |
| 40 | if (!credits || credits < ORG_MIN_PURCHASE_CREDITS) { |
| 41 | return NextResponse.json( |
| 42 | { |
| 43 | error: `Minimum purchase is ${ORG_MIN_PURCHASE_CREDITS.toLocaleString()} credits`, |
| 44 | }, |
| 45 | { status: 400 }, |
| 46 | ) |
| 47 | } |
| 48 | |
| 49 | // Check if user is banned |
| 50 | const user = await db.query.user.findFirst({ |
| 51 | where: eq(schema.user.id, session.user.id), |
| 52 | columns: { banned: true }, |
| 53 | }) |
| 54 | |
| 55 | if (user?.banned) { |
| 56 | logger.warn( |
| 57 | { userId: session.user.id, orgId }, |
| 58 | 'Banned user attempted to purchase organization credits', |
| 59 | ) |
| 60 | return NextResponse.json( |
| 61 | { error: 'Your account has been suspended. Please contact support.' }, |
| 62 | { status: 403 }, |
| 63 | ) |
| 64 | } |
| 65 | |
| 66 | // Verify user has permission to purchase credits for this organization |
| 67 | const membership = await db.query.orgMember.findFirst({ |
| 68 | where: and( |
| 69 | eq(schema.orgMember.org_id, orgId), |
| 70 | eq(schema.orgMember.user_id, session.user.id), |
| 71 | // Only owners can purchase credits for now |
| 72 | eq(schema.orgMember.role, 'owner'), |
| 73 | ), |
| 74 | }) |
| 75 | |
| 76 | if (!membership) { |
| 77 | return NextResponse.json( |
| 78 | { error: 'Forbidden or Organization not found' }, |
| 79 | { status: 403 }, |
| 80 | ) |
| 81 | } |
nothing calls this directly
no test coverage detected