11import { AuditAction , AuditResourceType , recordAudit } from '@sim/audit'
22import { db } from '@sim/db'
3- import { permissions , settings , type WorkspaceMode , workflow , workspace } from '@sim/db/schema'
3+ import { permissions , type WorkspaceMode , workflow , workspace } from '@sim/db/schema'
44import { createLogger } from '@sim/logger'
55import { generateId } from '@sim/utils/id'
66import { and , eq , isNull } from 'drizzle-orm'
@@ -9,24 +9,20 @@ import { listWorkspacesQuerySchema } from '@/lib/api/contracts'
99import { createWorkspaceContract } from '@/lib/api/contracts/workspaces'
1010import { parseRequest } from '@/lib/api/server'
1111import { getSession } from '@/lib/auth'
12- import type { PlanCategory } from '@/lib/billing/plan-helpers '
12+ import { getActiveOrganizationId } from '@/lib/auth/session-response '
1313import { PlatformEvents } from '@/lib/core/telemetry'
1414import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1515import { captureServerEvent } from '@/lib/posthog/server'
1616import { buildDefaultWorkflowArtifacts } from '@/lib/workflows/defaults'
1717import { saveWorkflowToNormalizedTables } from '@/lib/workflows/persistence/utils'
1818import { getRandomWorkspaceColor } from '@/lib/workspaces/colors'
19+ import { listWorkspacesForViewer } from '@/lib/workspaces/list'
1920import {
20- CONTACT_OWNER_TO_UPGRADE_REASON ,
21- evaluateWorkspaceInvitePolicy ,
22- getInvitePlanCategoryForOrganization ,
23- getInvitePlanCategoryForUser ,
2421 getWorkspaceCreationPolicy ,
2522 getWorkspaceInvitePolicy ,
26- UPGRADE_TO_INVITE_REASON ,
23+ resolveInviteFlags ,
2724 WORKSPACE_MODE ,
2825} from '@/lib/workspaces/policy'
29- import { listAccessibleWorkspaceRowsForUser } from '@/lib/workspaces/utils'
3026
3127const logger = createLogger ( 'Workspaces' )
3228
@@ -38,13 +34,6 @@ export const GET = withRouteHandler(async (request: Request) => {
3834 return NextResponse . json ( { error : 'Unauthorized' } , { status : 401 } )
3935 }
4036
41- const activeOrganizationId =
42- ( session . session as { activeOrganizationId ?: string } | null ) ?. activeOrganizationId ?? null
43- const creationPolicy = await getWorkspaceCreationPolicy ( {
44- userId : session . user . id ,
45- activeOrganizationId,
46- } )
47-
4837 const scopeResult = listWorkspacesQuerySchema . safeParse (
4938 Object . fromEntries ( new URL ( request . url ) . searchParams . entries ( ) )
5039 )
@@ -56,20 +45,15 @@ export const GET = withRouteHandler(async (request: Request) => {
5645 }
5746 const { scope } = scopeResult . data
5847
59- const settingsQuery = db
60- . select ( { lastActiveWorkspaceId : settings . lastActiveWorkspaceId } )
61- . from ( settings )
62- . where ( eq ( settings . userId , session . user . id ) )
63- . limit ( 1 )
64-
65- const [ userWorkspaces , userSettings ] = await Promise . all ( [
66- listAccessibleWorkspaceRowsForUser ( session . user . id , scope ) ,
67- settingsQuery ,
68- ] )
69-
70- const lastActiveWorkspaceId = userSettings [ 0 ] ?. lastActiveWorkspaceId ?? null
48+ const activeOrganizationId = getActiveOrganizationId ( session )
49+ const payload = await listWorkspacesForViewer ( {
50+ userId : session . user . id ,
51+ activeOrganizationId,
52+ scope,
53+ } )
54+ const { lastActiveWorkspaceId, creationPolicy } = payload
7155
72- if ( scope === 'active' && userWorkspaces . length === 0 ) {
56+ if ( scope === 'active' && payload . workspaces . length === 0 ) {
7357 if ( ! creationPolicy . canCreate ) {
7458 return NextResponse . json ( { workspaces : [ ] , lastActiveWorkspaceId, creationPolicy } )
7559 }
@@ -95,76 +79,10 @@ export const GET = withRouteHandler(async (request: Request) => {
9579 }
9680
9781 if ( scope === 'active' ) {
98- await ensureWorkflowsHaveWorkspace ( session . user . id , userWorkspaces [ 0 ] . workspace . id )
82+ await ensureWorkflowsHaveWorkspace ( session . user . id , payload . workspaces [ 0 ] . id )
9983 }
10084
101- const nonOrgBilledUserIds = [
102- ...new Set (
103- userWorkspaces
104- . filter ( ( { workspace : ws } ) => ws . workspaceMode !== WORKSPACE_MODE . ORGANIZATION )
105- . map ( ( { workspace : ws } ) => ws . billedAccountUserId )
106- ) ,
107- ]
108- const orgIds = [
109- ...new Set (
110- userWorkspaces
111- . filter (
112- ( { workspace : ws } ) =>
113- ws . workspaceMode === WORKSPACE_MODE . ORGANIZATION && ws . organizationId
114- )
115- . map ( ( { workspace : ws } ) => ws . organizationId as string )
116- ) ,
117- ]
118- const planCategoryByBilledUser = new Map < string , PlanCategory > ( )
119- const planCategoryByOrg = new Map < string , PlanCategory > ( )
120- await Promise . all ( [
121- ...nonOrgBilledUserIds . map ( async ( userId ) => {
122- planCategoryByBilledUser . set ( userId , await getInvitePlanCategoryForUser ( userId ) )
123- } ) ,
124- ...orgIds . map ( async ( orgId ) => {
125- planCategoryByOrg . set ( orgId , await getInvitePlanCategoryForOrganization ( orgId ) )
126- } ) ,
127- ] )
128-
129- const workspacesWithPermissions = userWorkspaces . map (
130- ( { workspace : workspaceDetails , permissionType } ) => {
131- const billedPlanCategory : PlanCategory =
132- workspaceDetails . workspaceMode === WORKSPACE_MODE . ORGANIZATION
133- ? workspaceDetails . organizationId
134- ? ( planCategoryByOrg . get ( workspaceDetails . organizationId ) ?? 'free' )
135- : 'free'
136- : ( planCategoryByBilledUser . get ( workspaceDetails . billedAccountUserId ) ?? 'free' )
137- const invitePolicy = evaluateWorkspaceInvitePolicy ( workspaceDetails , { billedPlanCategory } )
138- const callerIsBilledUser = workspaceDetails . billedAccountUserId === session . user . id
139-
140- const canActOnUpgrade = invitePolicy . upgradeRequired && callerIsBilledUser
141- const inviteDisabledReason = invitePolicy . allowed
142- ? null
143- : callerIsBilledUser
144- ? ( invitePolicy . reason ?? UPGRADE_TO_INVITE_REASON )
145- : CONTACT_OWNER_TO_UPGRADE_REASON
146-
147- return {
148- ...workspaceDetails ,
149- role :
150- workspaceDetails . ownerId === session . user . id
151- ? 'owner'
152- : permissionType === 'admin'
153- ? 'admin'
154- : 'member' ,
155- permissions : permissionType ,
156- inviteMembersEnabled : invitePolicy . allowed ,
157- inviteDisabledReason,
158- inviteUpgradeRequired : canActOnUpgrade ,
159- }
160- }
161- )
162-
163- return NextResponse . json ( {
164- workspaces : workspacesWithPermissions ,
165- lastActiveWorkspaceId,
166- creationPolicy,
167- } )
85+ return NextResponse . json ( payload )
16886} )
16987
17088// POST /api/workspaces - Create a new workspace
@@ -179,8 +97,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
17997 const parsed = await parseRequest ( createWorkspaceContract , req , { } )
18098 if ( ! parsed . success ) return parsed . response
18199 const { name, color, skipDefaultWorkflow } = parsed . data . body
182- const activeOrganizationId =
183- ( session . session as { activeOrganizationId ?: string } | null ) ?. activeOrganizationId ?? null
100+ const activeOrganizationId = getActiveOrganizationId ( session )
184101 const creationPolicy = await getWorkspaceCreationPolicy ( {
185102 userId : session . user . id ,
186103 activeOrganizationId,
@@ -380,13 +297,6 @@ async function createWorkspace({
380297 billedAccountUserId,
381298 ownerId : userId ,
382299 } )
383- const callerIsBilledUser = billedAccountUserId === userId
384- const canActOnUpgrade = invitePolicy . upgradeRequired && callerIsBilledUser
385- const inviteDisabledReason = invitePolicy . allowed
386- ? null
387- : callerIsBilledUser
388- ? ( invitePolicy . reason ?? UPGRADE_TO_INVITE_REASON )
389- : CONTACT_OWNER_TO_UPGRADE_REASON
390300
391301 return {
392302 id : workspaceId ,
@@ -401,9 +311,7 @@ async function createWorkspace({
401311 updatedAt : now ,
402312 role : 'owner' ,
403313 permissions : 'admin' ,
404- inviteMembersEnabled : invitePolicy . allowed ,
405- inviteDisabledReason,
406- inviteUpgradeRequired : canActOnUpgrade ,
314+ ...resolveInviteFlags ( invitePolicy , billedAccountUserId === userId ) ,
407315 }
408316}
409317
0 commit comments