-
Notifications
You must be signed in to change notification settings - Fork 10.8k
refactor(teams): Use UserRepository for new user invitation #24423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
refactor(teams): Use UserRepository for new user invitation #24423
Conversation
Fixes calcom#14869 Fixes CAL-3632
@AyushMukkanwar is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughConstructor for UserRepository now accepts Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (1)
340-356
: Drop the double cast when wiring the repository.Inside interactive transactions we get a
Prisma.TransactionClient
, and force-casting it toPrismaClient
hides the mismatch—ifUserRepository
ever calls aPrismaClient
-only helper (e.g.$transaction
,$connect
), we’ll hit a runtime failure. Prefer widening the repository constructor to accept aTransactionClient
and passtx
straight through; the cast and extra import then disappear.- const userRepository = new UserRepository(tx as unknown as PrismaClient); + const userRepository = new UserRepository(tx);- constructor(private prismaClient: PrismaClient) {} + constructor(private prismaClient: PrismaClient | Prisma.TransactionClient) {}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
packages/lib/server/repository/user.ts
(3 hunks)packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
(4 hunks)packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-09-16T08:59:45.884Z
Learning: anglerfishlyy's PR #23467 demonstrates excellent software architecture with proper email validation (regex + zod), secure token generation using randomBytes, comprehensive host type system using discriminated unions (userId OR email), and smart reuse of existing team invitation infrastructure. The implementation includes robust error handling, type safety, and maintains backward compatibility while adding CreatableSelect-based email invitation functionality.
🧬 Code graph analysis (3)
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.ts (2)
packages/platform/libraries/index.ts (1)
MembershipRole
(32-32)packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.ts (1)
inviteMemberHandler
(297-303)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (2)
packages/lib/server/repository/user.ts (1)
UserRepository
(126-1153)packages/prisma/index.ts (1)
PrismaClient
(84-84)
packages/lib/server/repository/user.ts (2)
packages/platform/libraries/index.ts (1)
CreationSource
(28-28)packages/lib/server/repository/profile.ts (1)
ProfileRepository
(67-726)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Tests / Unit
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: Install dependencies / Yarn install & cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/lib/server/repository/user.ts (1)
717-762
: Consider adding aselect
clause to limit returned fields.The create operation returns all user fields. As per coding guidelines, "only select data you need" for Prisma queries. While create operations may legitimately return the full record, consider whether all fields are needed by callers or if a more focused selection would be appropriate.
As per coding guidelines.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/lib/server/repository/user.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/lib/server/repository/user.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/lib/server/repository/user.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/lib/server/repository/user.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-09-16T08:59:45.884Z
Learning: anglerfishlyy's PR #23467 demonstrates excellent software architecture with proper email validation (regex + zod), secure token generation using randomBytes, comprehensive host type system using discriminated unions (userId OR email), and smart reuse of existing team invitation infrastructure. The implementation includes robust error handling, type safety, and maintains backward compatibility while adding CreatableSelect-based email invitation functionality.
🧬 Code graph analysis (1)
packages/lib/server/repository/user.ts (1)
packages/lib/server/repository/profile.ts (1)
ProfileRepository
(67-726)
🔇 Additional comments (1)
packages/lib/server/repository/user.ts (1)
688-765
: Well-structured invitation flow with clear conditional logic.The method properly centralizes user creation logic for invitation scenarios, with appropriate conditional handling for:
- Profile creation when organizationId and username are both provided
- Default schedule creation for non-platform-managed users
The logging and translation setup are also handled correctly.
Fixes calcom#14869 Fixes CAL-3632
861b0fb
to
41f4bce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all the AI generated comments
My initial commit had no comments but code rabbit insisted on commenting. Should i remove the comments then? |
role: invitation.role, | ||
accepted: autoAccept, // If the user is invited to a child team, they are automatically accepted | ||
}, | ||
const userRepository = new UserRepository(tx as unknown as PrismaClient); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should try to avoid type assertions maybe we should change the type to PrismaClient | PrismaTransactionClient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this feedback, I will make the appropriate change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/lib/server/repository/user.ts (1)
688-761
: Consider extracting shared user creation logic.Both
create
(lines 625-680) andcreateFromInvitation
duplicate logic for:
- Getting translated schedule names
- Computing default availability
- Creating profiles when
organizationId
exists- Creating schedules with identical structure
While some duplication is acceptable for distinct flows, extracting shared helpers (e.g.,
buildDefaultScheduleData
,buildProfileData
) could improve maintainability and reduce the risk of drift between the two methods.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/lib/server/repository/user.ts
(4 hunks)packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
packages/lib/server/repository/user.ts
🧠 Learnings (3)
📚 Learning: 2025-09-09T03:29:43.025Z
Learnt from: emrysal
PR: calcom/cal.com#23692
File: packages/lib/server/service/InsightsBookingBaseService.ts:16-16
Timestamp: 2025-09-09T03:29:43.025Z
Learning: In the Cal.com codebase, readonlyPrisma is still an instance of PrismaClient, making type changes from `typeof readonlyPrisma` to `PrismaClient` less critical since they are fundamentally compatible types.
Applied to files:
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts
📚 Learning: 2025-08-27T16:39:38.192Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Applied to files:
packages/lib/server/repository/user.ts
📚 Learning: 2025-09-16T08:59:45.884Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-09-16T08:59:45.884Z
Learning: anglerfishlyy's PR #23467 demonstrates excellent software architecture with proper email validation (regex + zod), secure token generation using randomBytes, comprehensive host type system using discriminated unions (userId OR email), and smart reuse of existing team invitation infrastructure. The implementation includes robust error handling, type safety, and maintains backward compatibility while adding CreatableSelect-based email invitation functionality.
Applied to files:
packages/lib/server/repository/user.ts
🧬 Code graph analysis (2)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (1)
packages/lib/server/repository/user.ts (1)
UserRepository
(123-1152)
packages/lib/server/repository/user.ts (2)
packages/platform/libraries/index.ts (1)
CreationSource
(28-28)packages/lib/server/repository/profile.ts (1)
ProfileRepository
(67-726)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Linters / lint
- GitHub Check: Type check / check-types
- GitHub Check: Tests / Unit
🔇 Additional comments (5)
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts (1)
340-359
: LGTM! Successful refactor to repository pattern.The refactor successfully centralizes user creation logic into
UserRepository.createFromInvitation
, improving maintainability and following the repository pattern. The transaction handling is correct, and all required parameters (email, username, language, isPlatformManaged, organizationId, invitedTo, teams) are properly passed.packages/lib/server/repository/user.ts (4)
124-124
: LGTM: Transaction support added.Accepting
PrismaClient | PrismaTransaction
enables using this repository within database transactions, which is essential for atomic multi-step operations like user creation with related records.
688-700
: Well-documented method signature.The method signature clearly defines all required parameters for invitation-based user creation. The JSDoc comment provides helpful context about the method's purpose.
739-756
: Schedule creation correctly gated by platform management.Platform-managed users don't need default schedules since their availability is managed externally. This conditional logic appropriately skips schedule creation for such users.
728-738
: Confirm intentional stricter profile creation condition
Profile creation now requires bothorganizationId
andusername
; in the invitation floworgMemberUsername
andorgId
are only set for org invites and both are falsy for regular team members, so this change is intentional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/lib/server/repository/user.ts (1)
682-686
: Consider enriching JSDoc with parameter descriptions.The comments explain the method's purpose well. For better maintainability, consider adding
@param
tags describing each parameter and an@returns
tag.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/lib/server/repository/user.ts
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/lib/server/repository/user.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/lib/server/repository/user.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/lib/server/repository/user.ts
🧠 Learnings (2)
📚 Learning: 2025-08-27T16:39:38.192Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Applied to files:
packages/lib/server/repository/user.ts
📚 Learning: 2025-09-16T08:59:45.884Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-09-16T08:59:45.884Z
Learning: anglerfishlyy's PR #23467 demonstrates excellent software architecture with proper email validation (regex + zod), secure token generation using randomBytes, comprehensive host type system using discriminated unions (userId OR email), and smart reuse of existing team invitation infrastructure. The implementation includes robust error handling, type safety, and maintains backward compatibility while adding CreatableSelect-based email invitation functionality.
Applied to files:
packages/lib/server/repository/user.ts
🧬 Code graph analysis (1)
packages/lib/server/repository/user.ts (1)
packages/lib/server/repository/profile.ts (1)
ProfileRepository
(67-726)
🔇 Additional comments (2)
packages/lib/server/repository/user.ts (2)
124-124
: LGTM! Constructor now supports transactions.Accepting
PrismaClient | PrismaTransaction
allows the repository to be used within transaction contexts, improving flexibility and enabling atomic operations across multiple repository calls.
688-761
: Verify preconditions and password flow for invitation-based user creation
- In
packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts:341
, confirm there’s a uniqueness check forinvitation.usernameOrEmail
before callingcreateFromInvitation
to avoid DB constraint errors.- Ensure invited users set their password in the invitation acceptance/signup flow, since
createFromInvitation
doesn’t handle password assignment.
What does this PR do?
This PR refactors the user creation logic within the team member invitation flow, as requested by the issue. It replaces a direct prisma.user.create call with a new, safer UserRepository.createFromInvitation method.
This change centralizes the business logic for creating a new user (including the conditional creation of default schedules and profiles) within the repository. This improves maintainability and adheres to the project's established repository pattern. An integration test was also added to verify the behavior is correct.
Fixes #14869
Fixes CAL-3632
Visual Demo (For contributors especially)
N/A - This is a backend refactoring and has no visual changes.
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
The new integration test added in packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.test.ts specifically covers the new user creation path and passes.
Manual testing:
As a team owner, invite a brand new email address that has never been used on the platform.
Confirm that the invitation is sent.
Check the database to ensure the new User record has been created with a pending Membership for that team.