Skip to content

Conversation

@SinghaAnirban005
Copy link
Contributor

@SinghaAnirban005 SinghaAnirban005 commented Aug 25, 2025

What does this PR do?

This PR ensures that the personal users event types are listed when the "All" context is set

Visual Demo (For contributors especially)

Screencast.from.2025-08-25.22-45-01.webm

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Are there environment variables that should be set?
  • What are the minimal test data to have?
  • What is expected (happy path) to have (input and output)?
  • Any other important info that could help to test that PR

@vercel
Copy link

vercel bot commented Aug 25, 2025

@SinghaAnirban005 is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 25, 2025

Walkthrough

Refactors getEventTypeList in packages/features/insights/server/trpc-router.ts: function is exported and now accepts a user param; adds early-return when no scope provided; adds a user-centric early branch returning personal event types when userId is provided without teamId/isAll; changes the org-admin (isAll) branch to query event types where teamId is the org or its child teams OR user-owned personal event types; updates non-admin membership filtering to OR together ownership and membership; expands selected fields to include userId and team.name; returns prisma query results from each branch.

Assessment against linked issues

Objective Addressed Explanation
Include personal (user-owned, no team) event types in the Event Type filter for relevant queries ([#23257], [CAL-6297])

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Export and signature change of getEventTypeList to include user and export (packages/features/insights/server/trpc-router.ts) Public API/signature was changed (now exported and requires a user object). This is not required by the linked issues which only requested inclusion of personal event types.
Selection expanded to include userId and team.name in query results (packages/features/insights/server/trpc-router.ts) Return shape was extended to include additional fields (userId, team.name), which is not specified in the linked issues' objective.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Aug 25, 2025
@graphite-app graphite-app bot requested a review from a team August 25, 2025 17:36
@github-actions github-actions bot added consumer event-types area: event types, event-types 🐛 bug Something isn't working labels Aug 25, 2025
@graphite-app
Copy link

graphite-app bot commented Aug 25, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (08/25/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add community label" took an action on this PR • (08/25/25)

1 label was added to this PR based on Keith Williams's automation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/features/insights/server/trpc-router.ts (1)

1073-1104: Fix short-circuit that prevents the isAll branch from ever running

When isAll is true (org “All” context), callers commonly pass no teamId and no userId. The early-return guard returns [] before the isAll branch (Line 1103) is evaluated, breaking the PR objective.

Apply this minimal fix so org-wide queries can flow through:

-  if (!teamId && !userId) {
+  // Allow org-wide "All" queries to continue even when both teamId and userId are absent
+  if (!teamId && !userId && !isAll) {
     return [];
   }
🧹 Nitpick comments (3)
packages/features/insights/server/trpc-router.ts (3)

1080-1101: Clarify/validate userId semantics in the “personal-only” branch

This branch ignores the input userId and always uses the authed user.id. If that’s intentional (security), make it explicit and guard against attempts to fetch someone else’s personal event types; otherwise, honor the provided userId with proper authorization.

Option A (make intent explicit and reject mismatched userIds):

-  if (userId && !teamId && !isAll) {
+  if (userId && !teamId && !isAll) {
+    if (userId !== user.id) {
+      throw new TRPCError({ code: "UNAUTHORIZED" });
+    }
     const eventTypeResult = await prisma.eventType.findMany({
       select: {
         id: true,
         slug: true,
         title: true,
         teamId: true,
         userId: true,
         team: {
           select: {
             name: true,
           },
         },
       },
       where: {
-        userId: user.id,
+        userId: user.id,
         teamId: null,
       },
     });
     return eventTypeResult;
   }

Option B (drop dependency on input userId entirely in this branch, since you already scope to the authed user):

-  if (userId && !teamId && !isAll) {
+  if (!teamId && !isAll) {
     const eventTypeResult = await prisma.eventType.findMany({
       ...

Please confirm which behavior product expects.


1103-1146: “All” scope likely needs all org members’ personal event types, not just the current user’s

Your org-wide (isAll) query adds only the authed user’s personal event types. Upstream, org-level booking filters (see buildBaseWhereCondition Lines 79–127) include personal bookings from all org users via usersFromOrg. If we don’t mirror that here, the Event Type filter won’t list many personal event types that actually show up in org analytics, limiting drill-down/filtering.

If product requirements confirm parity with booking scope, extend the OR to include personal event types of all accepted org members.

Proposed change:

   if (isAll && user.organizationId && user.isOwnerAdminOfParentTeam) {
     const childTeams = await prisma.team.findMany({
       where: {
         parentId: user.organizationId,
       },
       select: {
         id: true,
       },
     });

     if (childTeams.length > 0) {
       childrenTeamIds = childTeams.map((team) => team.id);
     }

+    const teamIds = [user.organizationId, ...childrenTeamIds];
+    const usersFromOrg =
+      teamIds.length > 0
+        ? await prisma.membership.findMany({
+            where: {
+              team: { id: { in: teamIds } },
+              accepted: true,
+            },
+            select: { userId: true },
+            distinct: ["userId"],
+          })
+        : [];

     const eventTypeResult = await prisma.eventType.findMany({
       select: {
         id: true,
         slug: true,
         title: true,
         teamId: true,
         userId: true,
         team: {
           select: {
             name: true,
           },
         },
       },
       where: {
         OR: [
           {
             teamId: {
-              in: [user.organizationId, ...childrenTeamIds],
+              in: teamIds,
             },
           },
-          {
-            userId: user.id,
-            teamId: null,
-          },
+          ...(usersFromOrg.length > 0
+            ? [
+                {
+                  teamId: null,
+                  userId: { in: usersFromOrg.map((u) => u.userId) },
+                },
+              ]
+            : []),
         ],
       },
     });

     return eventTypeResult;
   }

Note: If privacy policy restricts listing other users’ personal event types to admins only, keep the admin check (already present) and proceed.


1081-1099: Add deterministic ordering to eventType lists

UI filters benefit from stable ordering. Ordering by title (and optionally teamId) reduces flicker and improves UX.

Add orderBy to the three queries:

 // personal-only branch
 const eventTypeResult = await prisma.eventType.findMany({
   select: { ... },
   where: { ... },
+  orderBy: [{ title: "asc" }],
 });

 // org-wide branch
 const eventTypeResult = await prisma.eventType.findMany({
   select: { ... },
   where: { ... },
+  orderBy: [{ title: "asc" }],
 });

 // fallback/member branch
 const eventTypeResult = await prisma.eventType.findMany({
   select: {
     id: true,
     slug: true,
     title: true,
     teamId: true,
     userId: true,
     team: { select: { name: true } },
   },
   where: eventTypeWhereConditional,
+  orderBy: [{ title: "asc" }],
 });

Also applies to: 1117-1143, 1181-1194

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8d2a072 and eb437ac.

📒 Files selected for processing (1)
  • packages/features/insights/server/trpc-router.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 use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/insights/server/trpc-router.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/features/insights/server/trpc-router.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/features/insights/server/trpc-router.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
📚 Learning: 2025-08-21T13:44:06.784Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-23T13:45:16.490Z
Learnt from: shaun-ak
PR: calcom/cal.com#23233
File: packages/features/users/components/UserTable/EditSheet/EditUserForm.tsx:100-101
Timestamp: 2025-08-23T13:45:16.490Z
Learning: In Cal.com's team structure, the organization team (root team) is identified by having no parentId (!team.parentId), while sub-teams within an organization have a parentId. Use selectedUser?.teams?.find((team) => !team.parentId) to get the organization team, not by matching org?.id.

Applied to files:

  • packages/features/insights/server/trpc-router.ts

Copy link
Contributor

@kart1ka kart1ka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good to me. Could you also add some tests to verify the fix?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/features/insights/server/trpc-router.ts (1)

1103-1146: All context should respect selected user filter for personal events

In the org-admin “isAll” path, OR currently includes personal events for the authenticated user only. If a user filter is active, include that selected member’s personal event types instead.

Apply this diff:

-  if (isAll && user.organizationId && user.isOwnerAdminOfParentTeam) {
+  if (isAll && user.organizationId && user.isOwnerAdminOfParentTeam) {
     const childTeams = await prisma.team.findMany({
       where: {
         parentId: user.organizationId,
       },
       select: {
         id: true,
       },
     });

     if (childTeams.length > 0) {
       childrenTeamIds = childTeams.map((team) => team.id);
     }

     const eventTypeResult = await prisma.eventType.findMany({
       select: {
         id: true,
         slug: true,
         title: true,
         teamId: true,
         userId: true,
         team: {
           select: {
             name: true,
           },
         },
       },
       where: {
         OR: [
           {
             teamId: {
               in: [user.organizationId, ...childrenTeamIds],
             },
           },
           {
-            userId: user.id,
+            userId: userId ?? user.id,
             teamId: null,
           },
         ],
       },
     });

     return eventTypeResult;
   }
♻️ Duplicate comments (1)
packages/features/insights/server/trpc-router.ts (1)

1174-1178: Include hosted event types and remove stale TODO (use hosts.some.userId)

Event visibility for members should also include event types where the user is a host. This was raised earlier; the TODO should be resolved now.

Apply this diff:

   if (isMember) {
-    eventTypeWhereConditional["OR"] = [{ userId: user.id }, { users: { some: { id: user.id } } }];
-    // @TODO this is not working as expected
-    // hosts: { some: { id: user.id } },
+    eventTypeWhereConditional["OR"] = [
+      { userId: user.id },
+      { users: { some: { id: user.id } } },
+      { hosts: { some: { userId: user.id } } },
+    ];
   }

If you want, I can run a verification script to confirm the relation path on EventType/Host.

#!/bin/bash
# Verify EventType relations for 'users' and 'hosts', and Host fields
rg -n -C2 -g '!**/node_modules/**' -P 'model\s+EventType\b' --type-add 'prisma:*.prisma' --type prisma
rg -n -C2 -g '!**/node_modules/**' -P 'model\s+Host\b' --type prisma
rg -n -C2 -g '!**/node_modules/**' -P '\bhosts\s*:' --type ts --type tsx
🧹 Nitpick comments (5)
packages/features/insights/server/trpc-router.ts (3)

1153-1158: Avoid querying membership with an empty where (could return arbitrary row)

findFirst({}) may return an unrelated membership. Guard the call and also select only what you need.

Apply this diff:

-  const membership = await prisma.membership.findFirst({
-    where: membershipWhereConditional,
-  });
+  const hasMembershipFilter = Object.keys(membershipWhereConditional).length > 0;
+  const membership = hasMembershipFilter
+    ? await prisma.membership.findFirst({
+        where: { ...membershipWhereConditional, accepted: true },
+        select: { role: true },
+      })
+    : null;

1180-1194: Deterministic ordering for stable UI (optional)

Add an orderBy to stabilize the list for users; e.g., by team then title.

Apply this diff:

   const eventTypeResult = await prisma.eventType.findMany({
     select: {
       id: true,
       slug: true,
       title: true,
       teamId: true,
       userId: true,
       team: {
         select: {
           name: true,
         },
       },
     },
+    orderBy: [{ teamId: "asc" }, { title: "asc" }],
     where: eventTypeWhereConditional,
   });

1056-1072: Minor: clarify the db type/name for readability

The parameter is typed as typeof readonlyPrisma but the caller passes ctx.prisma (writable). Consider renaming the argument to db and typing it to the minimal surface used (eventType, team, membership) to avoid confusion.

Example:

type Db = Pick<typeof readonlyPrisma, "eventType" | "team" | "membership">;
export async function getEventTypeList({ prisma: db, ... }: { prisma: Db; ... }) { ... }
packages/features/insights/server/__tests__/trpc-router.test.ts (2)

101-148: Add assertion for userId precedence in isAll=true path

To cover the updated behavior, add a case where isAll is true and a different userId is provided; assert that the OR includes that selected userId for personal events.

Here’s a test you can append after the existing “Organization-wide view” test:

+    it("should include selected user's personal events when isAll=true and userId is provided", async () => {
+      const childTeams = [{ id: 11 }, { id: 12 }];
+      vi.mocked(readonlyPrisma.team.findMany).mockResolvedValue(childTeams);
+      vi.mocked(readonlyPrisma.eventType.findMany).mockResolvedValue(mockEventTypes);
+
+      const ownerUser = { ...mockUser, isOwnerAdminOfParentTeam: true };
+      const result = await getEventTypeList({
+        prisma: readonlyPrisma,
+        teamId: null,
+        userId: 999,
+        isAll: true,
+        user: ownerUser,
+      });
+
+      expect(readonlyPrisma.eventType.findMany).toHaveBeenCalledWith({
+        select: {
+          id: true,
+          slug: true,
+          title: true,
+          teamId: true,
+          userId: true,
+          team: { select: { name: true } },
+        },
+        where: {
+          OR: [
+            { teamId: { in: [10, 11, 12] } },
+            { userId: 999, teamId: null },
+          ],
+        },
+      });
+      expect(result).toEqual(mockEventTypes);
+    });

21-25: Optional: verify membership is not queried in contexts that don’t need it

Add expectations like expect(readonlyPrisma.membership.findFirst).not.toHaveBeenCalled() in “Organization-wide view” and the personal-events branch to prevent regressions where membership is queried with an empty where.

I can draft the exact expectations if you confirm the intended behavior.

Also applies to: 185-199

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c164352 and 0448774.

📒 Files selected for processing (2)
  • packages/features/insights/server/__tests__/trpc-router.test.ts (1 hunks)
  • packages/features/insights/server/trpc-router.ts (4 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 use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/insights/server/__tests__/trpc-router.test.ts
  • packages/features/insights/server/trpc-router.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/features/insights/server/__tests__/trpc-router.test.ts
  • packages/features/insights/server/trpc-router.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/features/insights/server/__tests__/trpc-router.test.ts
  • packages/features/insights/server/trpc-router.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
📚 Learning: 2025-08-21T13:44:06.784Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-23T13:45:16.490Z
Learnt from: shaun-ak
PR: calcom/cal.com#23233
File: packages/features/users/components/UserTable/EditSheet/EditUserForm.tsx:100-101
Timestamp: 2025-08-23T13:45:16.490Z
Learning: In Cal.com's team structure, the organization team (root team) is identified by having no parentId (!team.parentId), while sub-teams within an organization have a parentId. Use selectedUser?.teams?.find((team) => !team.parentId) to get the organization team, not by matching org?.id.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
🧬 Code graph analysis (1)
packages/features/insights/server/__tests__/trpc-router.test.ts (2)
packages/features/insights/server/trpc-router.ts (1)
  • getEventTypeList (1056-1197)
packages/prisma/index.ts (1)
  • readonlyPrisma (71-75)
⏰ 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). (2)
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types
🔇 Additional comments (1)
packages/features/insights/server/trpc-router.ts (1)

1118-1130: Good: using select over include and minimizing fields

Nice adherence to the guideline of selecting only required fields from Prisma. Keeps payloads lean and avoids accidental leakage.

Also applies to: 1181-1192

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

♻️ Duplicate comments (1)
packages/features/insights/server/trpc-router.ts (1)

1174-1178: Include host-linked event types in member view and remove stale TODO

Event types where the user is a host are currently excluded. Add the hosts condition using userId (not id) and remove the TODO.

Apply:

-  if (isMember) {
-    eventTypeWhereConditional["OR"] = [{ userId: user.id }, { users: { some: { id: user.id } } }];
-    // @TODO this is not working as expected
-    // hosts: { some: { id: user.id } },
-  }
+  if (isMember) {
+    eventTypeWhereConditional["OR"] = [
+      { userId: user.id },
+      { users: { some: { id: user.id } } },
+      { hosts: { some: { userId: user.id } } },
+    ];
+  }
🧹 Nitpick comments (3)
packages/features/insights/server/trpc-router.ts (3)

1155-1161: Avoid findFirst() with an empty where; it can return unrelated memberships

When teamId is undefined and you’re not in the org-admin branch (future edits could make this reachable), membershipWhereConditional is {}. Prisma.findFirst({ where: {} }) returns the first row in the table, which is risky and wastes a query. Guard it.

-  const membership = await prisma.membership.findFirst({
-    where: membershipWhereConditional,
-  });
+  const hasMembershipFilter = Object.keys(membershipWhereConditional).length > 0;
+  const membership = hasMembershipFilter
+    ? await prisma.membership.findFirst({ where: membershipWhereConditional })
+    : null;

Optionally, replace the generic Error with a TRPCError for consistency with the rest of this module:

-  if (!membership && !user.isOwnerAdminOfParentTeam) {
-    throw new Error("User is not part of a team/org");
-  }
+  if (!membership && !user.isOwnerAdminOfParentTeam) {
+    throw new TRPCError({ code: "UNAUTHORIZED" });
+  }

1082-1093: DRY up the repeated select blocks

Three identical select shapes are inlined. Extracting a shared constant reduces drift risk and eases future additions (e.g., adding team.slug later).

Add once (above the first query in this function):

+ const eventTypeSelect = {
+   id: true,
+   slug: true,
+   title: true,
+   teamId: true,
+   userId: true,
+   team: { select: { name: true } },
+ } satisfies Prisma.EventTypeSelect;

Then replace each inline select:

- select: {
-   id: true,
-   slug: true,
-   title: true,
-   teamId: true,
-   userId: true,
-   team: { select: { name: true } },
- },
+ select: eventTypeSelect,

Also applies to: 1119-1129, 1181-1192


1080-1101: Add a guard or test for userId ≠ ctx.user.id to avoid UX confusion

Today you ignore the input userId for personal events (by design). If a caller passes a different userId, they’ll still get the current user’s personal event types. Consider either:

  • returning [] when userId !== user.id, or
  • documenting/typing the param to indicate it applies only to “current user.”

Do you want me to add a unit test asserting that passing a different userId still returns only the caller’s personal event types?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0448774 and 8d3c15e.

📒 Files selected for processing (2)
  • packages/features/insights/server/__tests__/trpc-router.test.ts (1 hunks)
  • packages/features/insights/server/trpc-router.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/insights/server/tests/trpc-router.test.ts
🧰 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 use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/insights/server/trpc-router.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/features/insights/server/trpc-router.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/features/insights/server/trpc-router.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.383Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
📚 Learning: 2025-08-26T08:08:23.383Z
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.383Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-21T13:44:06.784Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.784Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-23T13:45:16.490Z
Learnt from: shaun-ak
PR: calcom/cal.com#23233
File: packages/features/users/components/UserTable/EditSheet/EditUserForm.tsx:100-101
Timestamp: 2025-08-23T13:45:16.490Z
Learning: In Cal.com's team structure, the organization team (root team) is identified by having no parentId (!team.parentId), while sub-teams within an organization have a parentId. Use selectedUser?.teams?.find((team) => !team.parentId) to get the organization team, not by matching org?.id.

Applied to files:

  • packages/features/insights/server/trpc-router.ts
⏰ 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: Linters / lint
  • GitHub Check: Type check / check-types
🔇 Additional comments (5)
packages/features/insights/server/trpc-router.ts (5)

1056-1072: Good extraction and clear, minimal surface for getEventTypeList()

Exporting this helper with an explicit param shape (id, organizationId, isOwnerAdminOfParentTeam) keeps the contract tight and avoids over-exposing ctx.user. Nice.


1073-1075: Early-return guard prevents accidental “full-scan” calls

The empty-scope fast return avoids unnecessary DB hits and ambiguous behavior when no target is provided. Good defensive pattern.


1080-1101: Personal events branch correctly clamps to the authenticated user

Using ctx.user.id (not the input userId) for personal event types is the right security posture here. This aligns with our prior learning and prevents privilege escalation via arbitrary userId injection.

Note: I used the “retrieved learnings” you shared to validate this behavior.


1117-1146: Org “All” scope now includes current user’s personal event types — matches the issue intent

The OR combining org/child team event types with the caller’s personal event types addresses CAL-6297. Select clauses remain minimal and use select (not include), complying with Prisma guidelines.


1180-1196: Prisma usage: minimal select and no include — compliant

The final findMany adheres to our “select-only” guidance and returns just what the UI needs. Looks good.

@SinghaAnirban005
Copy link
Contributor Author

@kart1ka Necessary tests have been added
Kindly review it
Thank You

Copy link
Contributor

@kart1ka kart1ka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for your contribution 🙏.

@github-actions
Copy link
Contributor

E2E results are ready!

return eventTypeResult;
}

if (isAll && user.organizationId && user.isOwnerAdminOfParentTeam) {
Copy link
Contributor

@eunjae-lee eunjae-lee Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason we don't check teamId here? (compared to the previous code)

never mind. it was not used before.

@eunjae-lee eunjae-lee merged commit f1d7d7f into calcom:main Aug 28, 2025
58 of 63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working community Created by Linear-GitHub Sync consumer event-types area: event types, event-types ready-for-e2e

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Event Type filter is missing personal event types

3 participants