mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
improvement(org): remove dead seats get endpoint (#2247)
* improvement(org): remove dead seats get endpoint * remove more dead code * remove fallback limit
This commit is contained in:
committed by
GitHub
parent
c197b04bcc
commit
99e0b81233
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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', {
|
||||
|
||||
Reference in New Issue
Block a user