refactor(teams): Use UserRepository for new user invitation#24423
refactor(teams): Use UserRepository for new user invitation#24423AyushMukkanwar wants to merge 5 commits intocalcom:mainfrom
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.
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 toPrismaClienthides the mismatch—ifUserRepositoryever calls aPrismaClient-only helper (e.g.$transaction,$connect), we’ll hit a runtime failure. Prefer widening the repository constructor to accept aTransactionClientand passtxstraight 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.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/inviteMember.handler.integration-test.tspackages/trpc/server/routers/viewer/teams/inviteMember/utils.tspackages/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.tspackages/trpc/server/routers/viewer/teams/inviteMember/utils.tspackages/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.tspackages/trpc/server/routers/viewer/teams/inviteMember/utils.tspackages/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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/lib/server/repository/user.ts (1)
717-762: Consider adding aselectclause 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.keyfield 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
Udit-takkar
left a comment
There was a problem hiding this comment.
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.
We should try to avoid type assertions maybe we should change the type to PrismaClient | PrismaTransactionClient
There was a problem hiding this comment.
Thank you for this feedback, I will make the appropriate change.
There was a problem hiding this comment.
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) andcreateFromInvitationduplicate logic for:
- Getting translated schedule names
- Computing default availability
- Creating profiles when
organizationIdexists- 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.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/trpc/server/routers/viewer/teams/inviteMember/utils.tspackages/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.tspackages/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.tspackages/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 | PrismaTransactionenables 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 bothorganizationIdandusername; in the invitation floworgMemberUsernameandorgIdare 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.
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
@paramtags describing each parameter and an@returnstag.
📜 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.keyfield 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 | PrismaTransactionallows 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.usernameOrEmailbefore callingcreateFromInvitationto avoid DB constraint errors.- Ensure invited users set their password in the invitation acceptance/signup flow, since
createFromInvitationdoesn’t handle password assignment.
|
Hey @AyushMukkanwar, what happened? why did you close this PR? |
The main branch of cal.com had got many changes in the recent commits which were causing too many conflicts with my pr. So i though to close this pr and start a new one fresh. Also due to these changes refactoring also needs to change according to it. |
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.