Skip to content

Comments

fix: Organization User Events' Spam#24468

Merged
alishaz-polymath merged 3 commits intomainfrom
fix-spam-user-event
Oct 15, 2025
Merged

fix: Organization User Events' Spam#24468
alishaz-polymath merged 3 commits intomainfrom
fix-spam-user-event

Conversation

@hariombalhara
Copy link
Member

@hariombalhara hariombalhara commented Oct 15, 2025

What does this PR do?

Fixes organization-level spam detection for user events by deriving the organization ID from the hostname instead of relying solely on team hierarchy or user profile data. This ensures spam checks use the correct organization context based on the domain/subdomain being accessed.

Key Changes

1. Hostname-based Organization Resolution

  • Before: Spam checks used team?.parentId ?? eventType.profile?.organizationId to determine the organization
  • After: First attempts to extract org slug from hostname and fetch the organization ID, falling back to the original logic if unavailable

2. Implementation Details

In handleNewBooking.ts:

  • Added hostname-based org resolution using getOrgSlug() and OrganizationRepository.findBySlug()
  • Dynamically imports org-related modules to avoid circular dependencies
  • Maintains backward compatibility by falling back to team/profile-based resolution
  • Organization ID is now correctly passed to spamCheckService.startCheck()

In getEventTypesFromDB.ts:

  • Updated to use withSelectedCalendars() for hosts and users
  • Improved organization team event detection using eventType.profile?.organizationId

In defaultEvents.ts:

  • Added profile: null to commons object for consistency

In orgDomains.ts:

  • Added defensive checks to handle edge cases in org slug extraction

3. Comprehensive Test Coverage

Added integration tests in spam-booking.integration-test.ts:

  • ✅ Verifies organization watchlist blocks bookings at org level
  • ✅ Ensures personal user events are NOT blocked by org-level watchlist
  • ✅ Tests fail-open behavior when SpamCheckService encounters errors

Why This Change?

In multi-tenant deployments where organizations use custom domains/subdomains:

  • Users can access the same event type via different organization domains
  • Spam detection must use the organization context of the domain being accessed
  • Previous logic could use the wrong organization for spam checks, allowing spam to bypass org-level blocks

Example Scenario

Before:

User books acme-org-event.cal.com/sales/demo
→ Spam check uses eventType.profile?.organizationId (might be null or wrong org)
→ Org-level spam blocks don't work correctly

After:

User books acme-org-event.cal.com/sales/demo
→ Extract "acme-org-event" from hostname
→ Fetch organization ID from slug
→ Spam check uses correct org context
→ Org-level spam blocks work as expected

Testing

  • Added integration tests for organization-level spam blocking
  • Added tests for personal event exemption from org blocks
  • Added fail-open error handling tests
  • Verified backward compatibility when hostname is not available
  • Lint and type checks pass

Related Issues

Fixes organization user event spam detection issues where domain-based spam blocks were not being applied correctly.

@hariombalhara hariombalhara requested a review from a team as a code owner October 15, 2025 06:15
@graphite-app graphite-app bot requested a review from a team October 15, 2025 06:16
@vercel
Copy link

vercel bot commented Oct 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Oct 15, 2025 10:52am
cal-eu Ignored Ignored Oct 15, 2025 10:52am

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Oct 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Walkthrough

Replaces direct extraction of eventOrganizationId in the new-booking flow with a new helper getEventOrganizationId that derives organizationId from event/team/parent hierarchy or falls back to the booker’s profile organizationId. Spam/watchlist initiation and blocked/decoy booking paths now use that helper. Adds use of WorkflowRepository for reschedule handling (deleting old reminders). Adds ProfileRepository.findFirstForUserId and an integration test asserting organization-level email watchlist blocking for user events without a team. orgDomains.getOrgSlug now logs and honors forced slugs in E2E and integration test modes.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly identifies that the change fixes spam detection for organization-level user events, matching the primary update in the pull request which derives the organization ID from the hostname for spam checks.
Description Check ✅ Passed The description clearly outlines the problem, the implemented hostname-based organization resolution logic, the related code changes and tests, and explains why the fix is necessary in a multi-tenant context.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-spam-user-event

📜 Recent 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 7ce1fd9 and 811796d.

📒 Files selected for processing (4)
  • packages/features/bookings/lib/handleNewBooking.ts (7 hunks)
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (2 hunks)
  • packages/features/ee/organizations/lib/orgDomains.ts (1 hunks)
  • packages/features/profile/repositories/ProfileRepository.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/features/profile/repositories/ProfileRepository.ts
  • packages/features/ee/organizations/lib/orgDomains.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
  • packages/features/bookings/lib/handleNewBooking.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). (2)
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build Web App

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot dosubot bot added bookings area: bookings, availability, timezones, double booking 🐛 bug Something isn't working labels Oct 15, 2025
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

Caution

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

⚠️ Outside diff range comments (1)
packages/features/bookings/lib/handleNewBooking.ts (1)

1227-1236: Use eventType.profile and precomputed eventOrganizationId; remove extra profile query

Current code fetches the first profile for the organizer (findFirst by userId) to derive organizerOrganizationId and usernameInOrg. If the user has multiple org profiles, this can pick the wrong org, producing incorrect bookerUrl and usernameInOrg for user events linked to a specific org profile.

You already computed eventOrganizationId earlier (Line 515) from team?.parentId or eventType.profile?.organizationId. Use that and the event’s profile to avoid mismatches and an extra DB call.

Apply these diffs:

  1. Replace the extra profile query and compute bookerUrl from eventOrganizationId:
-  const organizerOrganizationProfile = await prisma.profile.findFirst({
-    where: {
-      userId: organizerUser.id,
-    },
-  });
-
-  const organizerOrganizationId = organizerOrganizationProfile?.organizationId;
-  const bookerUrl = eventType.team
-    ? await getBookerBaseUrl(eventType.team.parentId)
-    : await getBookerBaseUrl(organizerOrganizationId ?? null);
+  const bookerUrl = await getBookerBaseUrl(eventOrganizationId);
  1. Use the event’s profile for usernameInOrg:
-      usernameInOrg: organizerOrganizationProfile?.username || undefined,
+      usernameInOrg: eventType.profile?.username || undefined,

To support this, ensure getEventTypesFromDB selects profile.username:
packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts

   profile: {
     select: {
-      organizationId: true,
+      organizationId: true,
+      username: true,
     },
   },

This removes an extra DB hit, aligns URLs/usernames with the correct org, and adheres to the “select only what you need” Prisma guideline. As per coding guidelines

Also applies to: 1284-1292, 515-516

🧹 Nitpick comments (3)
packages/features/eventtypes/lib/defaultEvents.ts (1)

217-217: Prefer named exports over default exports

Consider replacing default export with a named export for better tree-shaking and refactoring ergonomics.

As per coding guidelines

-export default defaultEvents;
+export { defaultEvents };
packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts (1)

35-39: Select profile.username to avoid extra queries and ensure correct org context

handleNewBooking reads organizer profile username for usernameInOrg and should use the event’s profile to avoid mismatches when users have multiple org profiles. Add username to the existing profile select so callers don’t need an extra query.

   profile: {
     select: {
-      organizationId: true,
+      organizationId: true,
+      username: true,
     },
   },

This also enables removing a redundant prisma.profile.findFirst in handleNewBooking.ts. As per coding guidelines

packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (1)

124-124: Remove debug logging from tests

console.log("watchlists", …) adds noise to CI logs. Please remove.

-        console.log("watchlists", await prisma.watchlist.findMany());
+        // Removed noisy debug log
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between b312955 and 8e4a25f.

📒 Files selected for processing (4)
  • packages/features/bookings/lib/handleNewBooking.ts (5 hunks)
  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts (2 hunks)
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (2 hunks)
  • packages/features/eventtypes/lib/defaultEvents.ts (1 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/eventtypes/lib/defaultEvents.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.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/eventtypes/lib/defaultEvents.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.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/eventtypes/lib/defaultEvents.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking.ts
📚 Learning: 2025-08-21T13:44:06.805Z
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.805Z
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/bookings/lib/handleNewBooking/getEventTypesFromDB.ts
📚 Learning: 2025-09-08T07:27:42.903Z
Learnt from: vijayraghav-io
PR: calcom/cal.com#16878
File: packages/app-store/feishucalendar/api/callback.ts:72-79
Timestamp: 2025-09-08T07:27:42.903Z
Learning: Four calendar integrations in Cal.com still use direct prisma.selectedCalendar.create instead of SelectedCalendarRepository.create: feishucalendar, zohocalendar, office365calendar, and larkcalendar. These bypass repository hooks and won't trigger reconnection logic for BookingReferences.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts
📚 Learning: 2025-09-08T07:27:42.903Z
Learnt from: vijayraghav-io
PR: calcom/cal.com#16878
File: packages/app-store/feishucalendar/api/callback.ts:72-79
Timestamp: 2025-09-08T07:27:42.903Z
Learning: In the Cal.com codebase, some calendar integrations like google-calendar already use SelectedCalendarRepository.create for selectedCalendar creation, which automatically triggers reconnection logic, while others like feishucalendar use direct prisma.selectedCalendar.create calls that bypass the repository hooks.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts
🧬 Code graph analysis (1)
packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (2)
packages/features/bookings/lib/handleNewBooking/test/getNewBookingHandler.ts (1)
  • getNewBookingHandler (15-17)
apps/web/test/utils/bookingScenario/bookingScenario.ts (8)
  • createOrganization (1040-1079)
  • getBooker (2250-2264)
  • getOrganizer (1539-1598)
  • TestData (1258-1530)
  • getGoogleCalendarCredential (1211-1219)
  • createBookingScenario (997-1028)
  • getScenarioData (1600-1688)
  • mockCalendarToHaveNoBusySlots (1989-2002)
⏰ 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). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (7)
packages/features/eventtypes/lib/defaultEvents.ts (1)

101-101: Good addition: ensure profile field exists on defaults

Adding profile: null keeps eventType.profile access safe downstream (org-aware flows). No further issues.

packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts (1)

198-201: isOrgTeamEvent computation looks correct

Using team presence and profile?.organizationId is a solid signal for org-scoped events, including managed and user-profiled events.

packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (2)

789-983: Great coverage for org watchlist behavior in user vs personal events

New tests clearly validate org-scoped blocking for user events, managed variants, and personal fail-open. Nicely done.


81-92: Ensure Prisma assertions use the same test mock

File: packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (lines 81–92)
bookingScenario helpers use prismock but expectNoBookingInDatabase calls prisma.booking.findMany — confirm setupAndTeardown remaps "@calcom/prisma" to that prismock; if it does not, change this assertion to use the same mock client (e.g., import/use prismock from tests/libs/mocks/prisma).

packages/features/bookings/lib/handleNewBooking.ts (3)

39-49: Import changes look correct

getBookerBaseUrl and WorkflowRepository imports align with new usage; DI type imports match IBookingServiceDependencies.


514-516: Org resolution for spam checks is correct

Fallback to eventType.profile?.organizationId covers user events associated with org profiles. Good fix.


1428-1496: Decoy response shape is safe

No sensitive organizer data is exposed; email is null. Property isShortCircuitedBooking is fine for internal consumers/tests.

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

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 8e4a25f and b448048.

📒 Files selected for processing (1)
  • packages/features/bookings/lib/handleNewBooking.ts (5 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/bookings/lib/handleNewBooking.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/bookings/lib/handleNewBooking.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/bookings/lib/handleNewBooking.ts
🧠 Learnings (1)
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking.ts
🧬 Code graph analysis (1)
packages/features/bookings/lib/handleNewBooking.ts (1)
packages/features/ee/organizations/lib/orgDomains.ts (1)
  • getOrgSlug (16-59)
🔇 Additional comments (1)
packages/features/bookings/lib/handleNewBooking.ts (1)

527-530: LGTM!

The fallback logic for resolving eventOrganizationId is clear and correctly prioritizes team.parentId before falling back to eventType.profile?.organizationId. Safe navigation operators prevent null reference errors.

Comment on lines 514 to 525
if (hostname) {
const { getOrgSlug } = await import("@calcom/features/ee/organizations/lib/orgDomains");
const { OrganizationRepository } = await import(
"@calcom/features/ee/organizations/repositories/OrganizationRepository"
);

const orgSlug = getOrgSlug(hostname, forcedSlug);
if (orgSlug) {
const organization = await OrganizationRepository.findBySlug({ slug: orgSlug });
eventOrganizationId = organization?.id ?? null;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling for organization resolution to prevent booking failures.

The organization resolution logic lacks error handling around the dynamic imports and database lookup. If getOrgSlug or OrganizationRepository.findBySlug throws an error, the entire booking process will crash. Since the spam check can function with a null organizationId, this code should fail gracefully.

Apply this diff to add error handling:

  let eventOrganizationId: number | null = null;

- if (hostname) {
-   const { getOrgSlug } = await import("@calcom/features/ee/organizations/lib/orgDomains");
-   const { OrganizationRepository } = await import(
-     "@calcom/features/ee/organizations/repositories/OrganizationRepository"
-   );
-
-   const orgSlug = getOrgSlug(hostname, forcedSlug);
-   if (orgSlug) {
-     const organization = await OrganizationRepository.findBySlug({ slug: orgSlug });
-     eventOrganizationId = organization?.id ?? null;
-   }
- }
+ if (hostname) {
+   try {
+     const { getOrgSlug } = await import("@calcom/features/ee/organizations/lib/orgDomains");
+     const { OrganizationRepository } = await import(
+       "@calcom/features/ee/organizations/repositories/OrganizationRepository"
+     );
+
+     const orgSlug = getOrgSlug(hostname, forcedSlug);
+     if (orgSlug) {
+       const organization = await OrganizationRepository.findBySlug({ slug: orgSlug });
+       eventOrganizationId = organization?.id ?? null;
+     }
+   } catch (error) {
+     loggerWithEventDetails.warn("Failed to resolve organization from hostname", { hostname, error });
+     // Continue with null organizationId - spam check can handle it
+   }
+ }
🤖 Prompt for AI Agents
In packages/features/bookings/lib/handleNewBooking.ts around lines 514 to 525,
the dynamic imports and OrganizationRepository.findBySlug call are not guarded;
any thrown error will crash booking creation. Wrap the entire hostname/orgSlug
resolution block in a try/catch, and on error set eventOrganizationId = null (do
not rethrow) so booking can continue; inside the catch log the error using the
module's logger (or console.error if none available) with context like "failed
to resolve organization for hostname" to aid debugging.


const createdBooking = await handleNewBooking({
bookingData: mockBookingData,
forcedSlug: org.slug,
Copy link
Member Author

Choose a reason for hiding this comment

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

Using forcedSlug approach to tell the slug instead of hostname as it is not easily possible to mock ALLOWED_HOSTNAMES right now

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: 2

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 0aa2c51 and 7ce1fd9.

📒 Files selected for processing (4)
  • packages/features/bookings/lib/handleNewBooking.ts (7 hunks)
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (2 hunks)
  • packages/features/ee/organizations/lib/orgDomains.ts (1 hunks)
  • packages/features/profile/repositories/ProfileRepository.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/ee/organizations/lib/orgDomains.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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/bookings/lib/handleNewBooking.ts
  • packages/features/profile/repositories/ProfileRepository.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.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/bookings/lib/handleNewBooking.ts
  • packages/features/profile/repositories/ProfileRepository.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.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/bookings/lib/handleNewBooking.ts
  • packages/features/profile/repositories/ProfileRepository.ts
  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
**/*Repository.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Repository files must include Repository suffix, prefix with technology if applicable (e.g., PrismaAppRepository.ts), and use PascalCase matching the exported class

Files:

  • packages/features/profile/repositories/ProfileRepository.ts
🧠 Learnings (2)
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking.ts
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts
🧬 Code graph analysis (2)
packages/features/bookings/lib/handleNewBooking.ts (1)
packages/features/profile/repositories/ProfileRepository.ts (1)
  • ProfileRepository (66-734)
packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (1)
apps/web/test/utils/bookingScenario/bookingScenario.ts (8)
  • createOrganization (1040-1079)
  • getBooker (2250-2264)
  • getOrganizer (1539-1598)
  • TestData (1258-1530)
  • getGoogleCalendarCredential (1211-1219)
  • createBookingScenario (997-1028)
  • getScenarioData (1600-1688)
  • mockCalendarToHaveNoBusySlots (1989-2002)
⏰ 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). (7)
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Linters / lint
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Type check / check-types
🔇 Additional comments (2)
packages/features/bookings/lib/handleNewBooking.ts (1)

551-555: LGTM! Organization ID derivation integrated correctly.

The call to getEventOrganizationId properly derives the organization ID before initiating the spam check, which aligns with the PR objective of fixing organization-level spam detection for user events.

However, ensure the underlying profile lookup is fixed (per separate comment on getEventOrganizationId) to prevent non-deterministic behavior.

packages/features/bookings/lib/handleNewBooking/test/spam-booking.integration-test.ts (1)

789-871: LGTM! Comprehensive test coverage for user events in organizations.

This test case properly validates that organization-level watchlist blocking works for user events (non-team events) when the user has a profile linking them to an organization. The test:

  • Correctly creates an organization without a team (withTeam: false)
  • Sets up a user event type with userId: 101 (no teamId)
  • Links the organizer to the organization via organizationId
  • Validates the decoy response and absence of database booking

This fills an important gap in test coverage for the organization spam detection feature.

Comment on lines +18 to +19
if (process.env.NEXT_PUBLIC_IS_E2E || process.env.INTEGRATION_TEST_MODE) {
log.debug("Using provided forcedSlug in E2E/Integration Test mode", {
Copy link
Member Author

Choose a reason for hiding this comment

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

I think it is better to keep it still(not needed right now though) because it could be useful while integration testing in future

@github-actions
Copy link
Contributor

github-actions bot commented Oct 15, 2025

E2E results are ready!

@alishaz-polymath alishaz-polymath merged commit 3076aca into main Oct 15, 2025
57 of 63 checks passed
@alishaz-polymath alishaz-polymath deleted the fix-spam-user-event branch October 15, 2025 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bookings area: bookings, availability, timezones, double booking 🐛 bug Something isn't working core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ready-for-e2e size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants