From 99e0b81233b7bfdbb1f754334200253010797577 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Mon, 8 Dec 2025 15:38:08 -0800 Subject: [PATCH] improvement(org): remove dead seats get endpoint (#2247) * improvement(org): remove dead seats get endpoint * remove more dead code * remove fallback limit --- .../app/api/organizations/[id]/seats/route.ts | 71 ----------------- apps/sim/lib/auth/auth.ts | 76 +------------------ bun.lock | 1 - 3 files changed, 1 insertion(+), 147 deletions(-) diff --git a/apps/sim/app/api/organizations/[id]/seats/route.ts b/apps/sim/app/api/organizations/[id]/seats/route.ts index c107b42a8..f084dded5 100644 --- a/apps/sim/app/api/organizations/[id]/seats/route.ts +++ b/apps/sim/app/api/organizations/[id]/seats/route.ts @@ -224,74 +224,3 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{ return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) } } - -/** - * GET /api/organizations/[id]/seats - * Get current seat information for an organization - */ -export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { - try { - const session = await getSession() - - if (!session?.user?.id) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) - } - - const { id: organizationId } = await params - - // Verify user has access to this organization - const memberEntry = await db - .select() - .from(member) - .where(and(eq(member.organizationId, organizationId), eq(member.userId, session.user.id))) - .limit(1) - - if (memberEntry.length === 0) { - return NextResponse.json( - { error: 'Forbidden - Not a member of this organization' }, - { status: 403 } - ) - } - - // Get subscription data - const subscriptionRecord = await db - .select() - .from(subscription) - .where(and(eq(subscription.referenceId, organizationId), eq(subscription.status, 'active'))) - .limit(1) - - if (subscriptionRecord.length === 0) { - return NextResponse.json({ error: 'No active subscription found' }, { status: 404 }) - } - - // Get member count - const memberCount = await db - .select({ userId: member.userId }) - .from(member) - .where(eq(member.organizationId, organizationId)) - - const orgSubscription = subscriptionRecord[0] - const maxSeats = orgSubscription.seats || 1 - const usedSeats = memberCount.length - const availableSeats = Math.max(0, maxSeats - usedSeats) - - return NextResponse.json({ - success: true, - data: { - maxSeats, - usedSeats, - availableSeats, - plan: orgSubscription.plan, - canModifySeats: orgSubscription.plan === 'team', - }, - }) - } catch (error) { - const { id: organizationId } = await params - logger.error('Failed to get organization seats', { - organizationId, - error, - }) - - return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) - } -} diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 9e2d6fa63..9daa10efe 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -13,12 +13,11 @@ import { oneTimeToken, organization, } from 'better-auth/plugins' -import { and, eq } from 'drizzle-orm' +import { eq } from 'drizzle-orm' import { headers } from 'next/headers' import Stripe from 'stripe' import { getEmailSubject, - renderInvitationEmail, renderOTPEmail, renderPasswordResetEmail, } from '@/components/emails/render-email' @@ -2068,79 +2067,6 @@ export const auth = betterAuth({ return hasTeamPlan }, - // Set a fixed membership limit of 50, but the actual limit will be enforced in the invitation flow - membershipLimit: 50, - // Validate seat limits before sending invitations - beforeInvite: async ({ organization }: { organization: { id: string } }) => { - const subscriptions = await db - .select() - .from(schema.subscription) - .where( - and( - eq(schema.subscription.referenceId, organization.id), - eq(schema.subscription.status, 'active') - ) - ) - - const teamOrEnterpriseSubscription = subscriptions.find( - (sub) => sub.plan === 'team' || sub.plan === 'enterprise' - ) - - if (!teamOrEnterpriseSubscription) { - throw new Error('No active team or enterprise subscription for this organization') - } - - const members = await db - .select() - .from(schema.member) - .where(eq(schema.member.organizationId, organization.id)) - - const pendingInvites = await db - .select() - .from(schema.invitation) - .where( - and( - eq(schema.invitation.organizationId, organization.id), - eq(schema.invitation.status, 'pending') - ) - ) - - const totalCount = members.length + pendingInvites.length - const seatLimit = teamOrEnterpriseSubscription.seats || 1 - - if (totalCount >= seatLimit) { - throw new Error(`Organization has reached its seat limit of ${seatLimit}`) - } - }, - sendInvitationEmail: async (data: any) => { - try { - const { invitation, organization, inviter } = data - - const inviteUrl = `${getBaseUrl()}/invite/${invitation.id}` - const inviterName = inviter.user?.name || 'A team member' - - const html = await renderInvitationEmail( - inviterName, - organization.name, - inviteUrl, - invitation.email - ) - - const result = await sendEmail({ - to: invitation.email, - subject: `${inviterName} has invited you to join ${organization.name} on Sim`, - html, - from: getFromEmailAddress(), - emailType: 'transactional', - }) - - if (!result.success) { - logger.error('Failed to send organization invitation email:', result.message) - } - } catch (error) { - logger.error('Error sending invitation email', { error }) - } - }, organizationCreation: { afterCreate: async ({ organization, user }) => { logger.info('[organizationCreation.afterCreate] Organization created', { diff --git a/bun.lock b/bun.lock index 3727ab54d..6d5d53b5a 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "simstudio",