1
1
import { Prisma } from "@prisma/client" ;
2
2
3
3
import { getAppFromSlug } from "@calcom/app-store/utils" ;
4
- import { getOrgFullOrigin , getSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains" ;
4
+ import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains" ;
5
5
import prisma , { baseEventTypeSelect } from "@calcom/prisma" ;
6
6
import { SchedulingType } from "@calcom/prisma/enums" ;
7
- import { EventTypeMetaDataSchema , teamMetadataSchema } from "@calcom/prisma/zod-utils" ;
7
+ import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils" ;
8
8
9
9
import { WEBAPP_URL } from "../../../constants" ;
10
- import logger from "../../../logger " ;
10
+ import { getTeam , getOrg } from "../../repository/team " ;
11
11
12
12
export type TeamWithMembers = Awaited < ReturnType < typeof getTeamWithMembers > > ;
13
13
@@ -24,6 +24,9 @@ export async function getTeamWithMembers(args: {
24
24
isOrgView ?: boolean ;
25
25
} ) {
26
26
const { id, slug, userId, orgSlug, isTeamView, isOrgView, includeTeamLogo } = args ;
27
+
28
+ // This should improve performance saving already app data found.
29
+ const appDataMap = new Map ( ) ;
27
30
const userSelect = Prisma . validator < Prisma . UserSelect > ( ) ( {
28
31
username : true ,
29
32
email : true ,
@@ -61,115 +64,100 @@ export async function getTeamWithMembers(args: {
61
64
} ,
62
65
} ,
63
66
} ) ;
64
- const teamSelect = Prisma . validator < Prisma . TeamSelect > ( ) ( {
65
- id : true ,
66
- name : true ,
67
- slug : true ,
68
- ...( ! ! includeTeamLogo ? { logo : true } : { } ) ,
69
- bio : true ,
70
- hideBranding : true ,
71
- hideBookATeamMember : true ,
72
- isPrivate : true ,
73
- metadata : true ,
74
- parent : {
75
- select : {
76
- id : true ,
77
- slug : true ,
78
- name : true ,
79
- } ,
80
- } ,
81
- children : {
82
- select : {
83
- name : true ,
84
- slug : true ,
67
+ let lookupBy ;
68
+
69
+ if ( id ) {
70
+ lookupBy = { id, havingMemberWithId : userId } ;
71
+ } else if ( slug ) {
72
+ lookupBy = { slug, havingMemberWithId : userId } ;
73
+ } else {
74
+ throw new Error ( "Must provide either id or slug" ) ;
75
+ }
76
+
77
+ const arg = {
78
+ lookupBy,
79
+ forOrgWithSlug : orgSlug ?? null ,
80
+ isOrg : ! ! isOrgView ,
81
+ teamSelect : {
82
+ id : true ,
83
+ name : true ,
84
+ slug : true ,
85
+ ...( ! ! includeTeamLogo ? { logo : true } : { } ) ,
86
+ bio : true ,
87
+ hideBranding : true ,
88
+ hideBookATeamMember : true ,
89
+ isPrivate : true ,
90
+ metadata : true ,
91
+ parent : {
92
+ select : {
93
+ id : true ,
94
+ slug : true ,
95
+ name : true ,
96
+ } ,
85
97
} ,
86
- } ,
87
- members : {
88
- select : {
89
- accepted : true ,
90
- role : true ,
91
- disableImpersonation : true ,
92
- user : {
93
- select : userSelect ,
98
+ children : {
99
+ select : {
100
+ name : true ,
101
+ slug : true ,
94
102
} ,
95
103
} ,
96
- } ,
97
- theme : true ,
98
- brandColor : true ,
99
- darkBrandColor : true ,
100
- eventTypes : {
101
- where : {
102
- hidden : false ,
103
- schedulingType : {
104
- not : SchedulingType . MANAGED ,
104
+ members : {
105
+ select : {
106
+ accepted : true ,
107
+ role : true ,
108
+ disableImpersonation : true ,
109
+ user : {
110
+ select : userSelect ,
111
+ } ,
105
112
} ,
106
113
} ,
107
- select : {
108
- users : {
109
- select : userSelect ,
114
+ theme : true ,
115
+ brandColor : true ,
116
+ darkBrandColor : true ,
117
+ eventTypes : {
118
+ where : {
119
+ hidden : false ,
120
+ schedulingType : {
121
+ not : SchedulingType . MANAGED ,
122
+ } ,
123
+ } ,
124
+ select : {
125
+ users : {
126
+ select : userSelect ,
127
+ } ,
128
+ metadata : true ,
129
+ ...baseEventTypeSelect ,
110
130
} ,
111
- metadata : true ,
112
- ...baseEventTypeSelect ,
113
131
} ,
114
- } ,
115
- inviteTokens : {
116
- select : {
117
- token : true ,
118
- expires : true ,
119
- expiresInDays : true ,
120
- identifier : true ,
132
+ inviteTokens : {
133
+ select : {
134
+ token : true ,
135
+ expires : true ,
136
+ expiresInDays : true ,
137
+ identifier : true ,
138
+ } ,
121
139
} ,
122
140
} ,
123
- } ) ;
141
+ } as const ;
124
142
125
- const where : Prisma . TeamFindFirstArgs [ "where" ] = { } ;
143
+ const teamOrOrg = isOrgView ? await getOrg ( arg ) : await getTeam ( arg ) ;
126
144
127
- if ( userId ) where . members = { some : { userId } } ;
128
- if ( orgSlug && orgSlug !== slug ) {
129
- where . parent = getSlugOrRequestedSlug ( orgSlug ) ;
130
- }
131
- if ( id ) where . id = id ;
132
- if ( slug ) where . slug = slug ;
133
- if ( isOrgView ) {
134
- // We must fetch only the organization here.
135
- // Note that an organization and a team that doesn't belong to an organization, both have parentId null
136
- // If the organization has null slug(but requestedSlug is 'test') and the team also has slug 'test', we can't distinguish them without explicitly checking the metadata.isOrganization
137
- // Note that, this isn't possible now to have same requestedSlug as the slug of a team not part of an organization. This is legacy teams handling mostly. But it is still safer to be sure that you are fetching an Organization only in case of isOrgView
138
- where . metadata = {
139
- path : [ "isOrganization" ] ,
140
- equals : true ,
141
- } ;
142
- }
145
+ if ( ! teamOrOrg ) return null ;
143
146
144
- const teams = await prisma . team . findMany ( {
145
- where,
146
- select : teamSelect ,
147
- } ) ;
148
-
149
- if ( teams . length > 1 ) {
150
- logger . error ( "Found more than one team/Org. We should be doing something wrong." , {
151
- where,
152
- teams : teams . map ( ( team ) => ( { id : team . id , slug : team . slug } ) ) ,
153
- } ) ;
154
- }
155
-
156
- const team = teams [ 0 ] ;
157
- if ( ! team ) return null ;
158
-
159
- // This should improve performance saving already app data found.
160
- const appDataMap = new Map ( ) ;
161
- const members = team . members . map ( ( obj ) => {
162
- const { credentials, ...restUser } = obj . user ;
147
+ const members = teamOrOrg . members . map ( ( m ) => {
148
+ const { credentials, ...restUser } = m . user ;
163
149
return {
164
150
...restUser ,
165
- role : obj . role ,
166
- accepted : obj . accepted ,
167
- disableImpersonation : obj . disableImpersonation ,
151
+ role : m . role ,
152
+ accepted : m . accepted ,
153
+ disableImpersonation : m . disableImpersonation ,
168
154
subteams : orgSlug
169
- ? obj . user . teams . filter ( ( obj ) => obj . team . slug !== orgSlug ) . map ( ( obj ) => obj . team . slug )
155
+ ? m . user . teams
156
+ . filter ( ( membership ) => membership . team . slug !== orgSlug )
157
+ . map ( ( membership ) => membership . team . slug )
170
158
: null ,
171
- avatar : `${ WEBAPP_URL } /${ obj . user . username } /avatar.png` ,
172
- orgOrigin : getOrgFullOrigin ( obj . user . organization ?. slug || "" ) ,
159
+ avatar : `${ WEBAPP_URL } /${ m . user . username } /avatar.png` ,
160
+ orgOrigin : getOrgFullOrigin ( m . user . organization ?. slug || "" ) ,
173
161
connectedApps : ! isTeamView
174
162
? credentials ?. map ( ( cred ) => {
175
163
const appSlug = cred . app ?. slug ;
@@ -193,15 +181,15 @@ export async function getTeamWithMembers(args: {
193
181
} ;
194
182
} ) ;
195
183
196
- const eventTypes = team . eventTypes . map ( ( eventType ) => ( {
184
+ const eventTypes = teamOrOrg . eventTypes . map ( ( eventType ) => ( {
197
185
...eventType ,
198
186
metadata : EventTypeMetaDataSchema . parse ( eventType . metadata ) ,
199
187
} ) ) ;
200
188
// Don't leak invite tokens to the frontend
201
- const { inviteTokens, ...teamWithoutInviteTokens } = team ;
189
+ const { inviteTokens, ...teamWithoutInviteTokens } = teamOrOrg ;
202
190
203
191
// Don't leak stripe payment ids
204
- const teamMetadata = teamMetadataSchema . parse ( team . metadata ) ;
192
+ const teamMetadata = teamOrOrg . metadata ;
205
193
const {
206
194
paymentId : _ ,
207
195
subscriptionId : __ ,
@@ -214,7 +202,7 @@ export async function getTeamWithMembers(args: {
214
202
/** To prevent breaking we only return non-email attached token here, if we have one */
215
203
inviteToken : inviteTokens . find (
216
204
( token ) =>
217
- token . identifier === `invite-link-for-teamId-${ team . id } ` &&
205
+ token . identifier === `invite-link-for-teamId-${ teamOrOrg . id } ` &&
218
206
token . expires > new Date ( new Date ( ) . setHours ( 24 ) )
219
207
) ,
220
208
metadata : restTeamMetadata ,
0 commit comments