(req: NextRequest)
| 15 | import { logger } from '@/util/logger' |
| 16 | |
| 17 | export async function POST(req: NextRequest) { |
| 18 | const session = await getServerSession(authOptions) |
| 19 | if (!session?.user?.id) { |
| 20 | return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
| 21 | } |
| 22 | |
| 23 | const userId = session.user.id |
| 24 | |
| 25 | const body = await req.json().catch(() => null) |
| 26 | const rawTier = Number(body?.tier) |
| 27 | if (!rawTier || !(rawTier in SUBSCRIPTION_TIERS)) { |
| 28 | return NextResponse.json( |
| 29 | { error: `Invalid tier. Must be one of: ${Object.keys(SUBSCRIPTION_TIERS).join(', ')}.` }, |
| 30 | { status: 400 }, |
| 31 | ) |
| 32 | } |
| 33 | const tier = rawTier as SubscriptionTierPrice |
| 34 | |
| 35 | const priceId = getPriceIdFromTier(tier) |
| 36 | if (!priceId) { |
| 37 | return NextResponse.json( |
| 38 | { error: 'Subscription tier not available' }, |
| 39 | { status: 503 }, |
| 40 | ) |
| 41 | } |
| 42 | |
| 43 | const user = await db.query.user.findFirst({ |
| 44 | where: eq(schema.user.id, userId), |
| 45 | columns: { stripe_customer_id: true, banned: true }, |
| 46 | }) |
| 47 | |
| 48 | if (user?.banned) { |
| 49 | logger.warn({ userId }, 'Banned user attempted to create subscription') |
| 50 | return NextResponse.json( |
| 51 | { error: 'Your account has been suspended. Please contact support.' }, |
| 52 | { status: 403 }, |
| 53 | ) |
| 54 | } |
| 55 | |
| 56 | if (!user?.stripe_customer_id) { |
| 57 | return NextResponse.json( |
| 58 | { error: 'Stripe customer not found.' }, |
| 59 | { status: 400 }, |
| 60 | ) |
| 61 | } |
| 62 | |
| 63 | const existing = await getActiveSubscription({ userId, logger }) |
| 64 | if (existing) { |
| 65 | return NextResponse.json( |
| 66 | { error: 'You already have an active subscription.' }, |
| 67 | { status: 409 }, |
| 68 | ) |
| 69 | } |
| 70 | |
| 71 | try { |
| 72 | const checkoutSession = await stripeServer.checkout.sessions.create({ |
| 73 | customer: user.stripe_customer_id, |
| 74 | mode: 'subscription', |
nothing calls this directly
no test coverage detected