( input: AcceptInvitationInput )
| 264 | } |
| 265 | |
| 266 | export async function acceptInvitation( |
| 267 | input: AcceptInvitationInput |
| 268 | ): Promise<AcceptInvitationResult> { |
| 269 | const inv = await getInvitationById(input.invitationId) |
| 270 | |
| 271 | if (!inv) { |
| 272 | return { success: false, kind: 'not-found' } |
| 273 | } |
| 274 | |
| 275 | if (input.token && inv.token !== input.token) { |
| 276 | return { success: false, kind: 'invalid-token' } |
| 277 | } |
| 278 | |
| 279 | if (inv.status !== 'pending') { |
| 280 | return { success: false, kind: 'already-processed' } |
| 281 | } |
| 282 | |
| 283 | if (isInvitationExpired(inv)) { |
| 284 | await db |
| 285 | .update(invitation) |
| 286 | .set({ status: 'expired', updatedAt: new Date() }) |
| 287 | .where(and(eq(invitation.id, inv.id), eq(invitation.status, 'pending'))) |
| 288 | return { success: false, kind: 'expired' } |
| 289 | } |
| 290 | |
| 291 | if (normalizeEmail(input.userEmail) !== normalizeEmail(inv.email)) { |
| 292 | return { success: false, kind: 'email-mismatch' } |
| 293 | } |
| 294 | |
| 295 | let membershipAlreadyExists = false |
| 296 | let acceptedMembershipIntent = inv.membershipIntent |
| 297 | let shouldJoinOrganization = inv.membershipIntent !== 'external' |
| 298 | |
| 299 | const primaryGrant = inv.grants[0] |
| 300 | let billingOwnerUserId = inv.inviterId |
| 301 | let workspaceOrganizationId = inv.organizationId |
| 302 | if (primaryGrant) { |
| 303 | const grantWorkspace = await getWorkspaceWithOwner(primaryGrant.workspaceId) |
| 304 | if (grantWorkspace) { |
| 305 | billingOwnerUserId = grantWorkspace.billedAccountUserId |
| 306 | workspaceOrganizationId = grantWorkspace.organizationId ?? inv.organizationId |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | const existingMembership = await getUserOrganization(input.userId) |
| 311 | const inviteeAlreadyInDifferentOrg = |
| 312 | !!existingMembership && |
| 313 | (workspaceOrganizationId ? existingMembership.organizationId !== workspaceOrganizationId : true) |
| 314 | |
| 315 | if (shouldJoinOrganization && inviteeAlreadyInDifferentOrg) { |
| 316 | if (await downgradeOrRejectCrossOrgInvite(inv)) { |
| 317 | acceptedMembershipIntent = 'external' |
| 318 | shouldJoinOrganization = false |
| 319 | } else { |
| 320 | return { success: false, kind: 'already-in-organization' } |
| 321 | } |
| 322 | } |
| 323 |
no test coverage detected