Skip to content

Comments

feat: authentication secured event types#23217

Merged
supalarry merged 18 commits intomainfrom
lauris/cal-6281-feat-admin-only-booking
Aug 22, 2025
Merged

feat: authentication secured event types#23217
supalarry merged 18 commits intomainfrom
lauris/cal-6281-feat-admin-only-booking

Conversation

@supalarry
Copy link
Contributor

Linear CAL-6281

@supalarry supalarry requested review from a team August 20, 2025 14:08
@supalarry supalarry requested a review from a team as a code owner August 20, 2025 14:08
@linear
Copy link

linear bot commented Aug 20, 2025

@github-actions github-actions bot added the ❗️ migrations contains migration files label Aug 20, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 20, 2025

Walkthrough

The PR adds a bookingRequiresAuthentication boolean across the stack (Prisma schema + migration, defaults, types, inputs/outputs, transformers, and OpenAPI docs). BookingsController now accepts optional auth and forwards an optional user to BookingsService. BookingsService injects memberships deps and adds checkBookingRequiresAuthenticationSetting to enforce multi-path authorization before booking creation. EventTypesRepository gained host/assigned-user checks. MembershipsRepository/Service gained methods to evaluate org/team admin/owner relationships. E2E tests were added for managed-user booking behavior (one suite is duplicated).

Assessment against linked issues

Objective Addressed Explanation
Add new EventType property bookingRequiresAuthentication in schema/prisma [CAL-6281]
Allow toggling this property via API (create/update inputs, outputs, docs) [CAL-6281]
Enforce booking-time check and pass optional auth through controller→service; allowed principals: owner, system admin, host, team admin/owner, org admin/owner [CAL-6281]
Add tests verifying restricted booking behavior for managed users (owner allowed, unrelated managed user denied, org admin allowed) [CAL-6281] Test suite exists but is duplicated in the file; duplication makes coverage/uniqueness unclear.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
reserveSlot parameter typing changed to AuthOptionalUser (apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts) Typing/export change in slots controller unrelated to CAL-6281 (bookingRequiresAuthentication is about event-type booking flow).
Added orgId/teamId unused params for Swagger (apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.ts) Signature edits solely for Swagger route param exposure; not required by CAL-6281.
Large OpenAPI/swagger additions (apps/api/v2/swagger/documentation.json & docs/api-reference/v2/openapi.json) Extensive new schemas and endpoints (schedules, workflows, calendars, webhooks, etc.) are beyond the single-field booking auth scope in CAL-6281.

Possibly related PRs

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.


📜 Recent 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 01f85d3 and eb7602d.

📒 Files selected for processing (1)
  • apps/api/v2/src/modules/memberships/memberships.repository.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/v2/src/modules/memberships/memberships.repository.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: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch lauris/cal-6281-feat-admin-only-booking

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 requested a review from a team August 20, 2025 14:08
@keithwillcode keithwillcode added core area: core, team members only platform Anything related to our platform plan labels Aug 20, 2025
@vercel
Copy link

vercel bot commented Aug 20, 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 Aug 22, 2025 11:14am
cal-eu Ignored Ignored Aug 22, 2025 11:14am

@dosubot dosubot bot added the event-types area: event types, event-types label Aug 20, 2025
@graphite-app
Copy link

graphite-app bot commented Aug 20, 2025

Graphite Automations

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

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

"Add ready-for-e2e label" took an action on this PR • (08/22/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: 30

Caution

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

⚠️ Outside diff range comments (1)
apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts (1)

2195-2195: Fix stray unary + causing runtime error in test

The leading + before expect coerces the matcher to NaN, making .toBe undefined at runtime.

Apply this diff:

-        +expect(updatedEventType.hidden).toBe(false);
+        expect(updatedEventType.hidden).toBe(false);
🧹 Nitpick comments (7)
apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts (1)

261-264: Remove duplicate ApiHeader decorator

OPTIONAL_X_CAL_CLIENT_ID_HEADER is declared twice. Keep a single declaration.

Apply this diff:

   @ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
-  @ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
   @ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts (1)

448-454: Mark bookingRequiresAuthentication as optional in OpenAPI

The field is optional in the type, but using ApiProperty (DocsProperty) without required: false will mark it as required in the Swagger schema. Use ApiPropertyOptional for consistency with other optional fields.

Apply this diff:

   @IsOptional()
   @IsBoolean()
-  @DocsProperty({
+  @ApiPropertyOptional({
     description:
       "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type.",
   })
   bookingRequiresAuthentication?: boolean;
apps/api/v2/src/modules/memberships/services/memberships.service.ts (1)

25-47: Clear, sequential authorization check; consider clarifying intent via naming/docs

The flow is correct and efficient (early return when no admin/owner orgs; then org membership check, then teams within those orgs). Two minor polish items:

  • The parameter name anotherUserId is a bit vague; targetUserId or subjectUserId would be clearer.
  • A short JSDoc would help future readers understand that “of another user” means “admin/owner in any org where that user is a member or a member via a team”.
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (1)

781-804: Add an explicit unauthenticated booking test for the “requires authentication” path

You validate owner and org-admin tokens, and a non-owner managed user. Missing is the “no Authorization header” case, which is the core of this flag. Add a test to assert 401 when booking without any credentials.

Apply this diff to add the missing test right after the first case:

@@
     beforeAll(async () => {
@@
     });
 
     it("can't be booked with managed user credentials who is not admin and not event type owner", async () => {
@@
     });
 
+    it("can't be booked without authentication", async () => {
+      await request(app.getHttpServer())
+        .post(`/v2/bookings`)
+        .send(body)
+        .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
+        .expect(401);
+    });
+
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (1)

102-138: Document optional auth and gated access in Swagger.

Consider adding explicit 401/403 responses and a note that when eventType.bookingRequiresAuthentication is true, valid credentials of an authorized user are required.

Apply this diff to annotate responses:

   @Post("/")
   @UseGuards(OptionalApiAuthGuard)
   @ApiOperation({
     summary: "Create a booking",
@@
   })
+  @ApiUnauthorizedResponse({ description: "Missing or invalid credentials" })
+  @ApiForbiddenResponse({ description: "Authenticated but not permitted to book this event type" })

And add imports at the top of this file:

import { ApiForbiddenResponse, ApiUnauthorizedResponse } from "@nestjs/swagger";
docs/api-reference/v2/openapi.json (2)

5326-5349: Tighten parameter typings and fix header description capitalization

  • teamId, take, and skip should be integers (paging/IDs are not fractional).
  • Capitalize “API key” and start the sentence with “Value” for consistency.

Apply this diff:

-            "description": "For non-platform customers - value must be `Bearer <token>` where `<token>` is api key prefixed with cal_",
+            "description": "For non-platform customers - Value must be `Bearer <token>`, where `<token>` is an API key prefixed with `cal_`",
...
-            "schema": {
-              "type": "number"
-            }
+            "schema": {
+              "type": "integer"
+            }
...
-            "schema": {
-              "minimum": 1,
-              "maximum": 250,
-              "default": 250,
-              "type": "number"
-            }
+            "schema": {
+              "minimum": 1,
+              "maximum": 250,
+              "default": 250,
+              "type": "integer"
+            }
...
-            "schema": {
-              "minimum": 0,
-              "default": 0,
-              "type": "number"
-            }
+            "schema": {
+              "minimum": 0,
+              "default": 0,
+              "type": "integer"
+            }

Also applies to: 5351-5357, 5359-5369, 5371-5382


12721-12726: Tighten parameter typings and fix header description capitalization

  • teamId, take, and skip should be integers.
  • Capitalize and clarify Authorization header text.

Apply this diff:

-            "description": "value must be `Bearer <token>` where `<token>` is api key prefixed with cal_ or managed user access token",
+            "description": "Value must be `Bearer <token>`, where `<token>` is an API key prefixed with `cal_` or a managed-user access token",
...
-            "schema": {
-              "type": "number"
-            }
+            "schema": {
+              "type": "integer"
+            }
...
-            "schema": {
-              "minimum": 1,
-              "maximum": 250,
-              "default": 250,
-              "type": "number"
-            }
+            "schema": {
+              "minimum": 1,
+              "maximum": 250,
+              "default": 250,
+              "type": "integer"
+            }
...
-            "schema": {
-              "minimum": 0,
-              "default": 0,
-              "type": "number"
-            }
+            "schema": {
+              "minimum": 0,
+              "default": 0,
+              "type": "integer"
+            }

Also applies to: 12728-12734, 12736-12746, 12749-12758

📜 Review details

Configuration used: CodeRabbit UI
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 48aa6bf and 3fb0f52.

📒 Files selected for processing (20)
  • apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts (2 hunks)
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (3 hunks)
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (3 hunks)
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (5 hunks)
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts (4 hunks)
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts (1 hunks)
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts (3 hunks)
  • apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1 hunks)
  • apps/api/v2/src/modules/memberships/memberships.repository.ts (3 hunks)
  • apps/api/v2/src/modules/memberships/services/memberships.service.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts (1 hunks)
  • apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts (2 hunks)
  • apps/api/v2/swagger/documentation.json (18 hunks)
  • docs/api-reference/v2/openapi.json (18 hunks)
  • packages/lib/defaultEvents.ts (1 hunks)
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts (1 hunks)
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts (1 hunks)
  • packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts (1 hunks)
  • packages/prisma/migrations/20250820094118_add_event_type_booking_requires_auth_column/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
🧰 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:

  • apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts
  • packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts
  • apps/api/v2/src/modules/memberships/services/memberships.service.ts
  • packages/lib/defaultEvents.ts
  • apps/api/v2/src/modules/memberships/memberships.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
  • apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.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:

  • apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts
  • packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts
  • apps/api/v2/src/modules/memberships/services/memberships.service.ts
  • packages/lib/defaultEvents.ts
  • apps/api/v2/src/modules/memberships/memberships.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
  • apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts
docs/api-reference/v2/openapi.json

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

When docs changes are made in /docs/api-reference/v2/openapi.json, ensure 'summary' fields are short, concise, do not end with a period, and are written in proper American English

Files:

  • docs/api-reference/v2/openapi.json
**/*.{service,repository}.ts

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

Avoid dot-suffixes like .service.ts or .repository.ts for new files; reserve .test.ts, .spec.ts, .types.ts for their specific purposes

Files:

  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/modules/memberships/services/memberships.service.ts
  • apps/api/v2/src/modules/memberships/memberships.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts
🧬 Code Graph Analysis (5)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts (1)
  • ApiAuthGuardUser (25-25)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (2)
apps/api/v2/test/utils/randomString.ts (1)
  • randomString (3-6)
packages/platform/constants/api.ts (2)
  • CAL_API_VERSION_HEADER (72-72)
  • VERSION_2024_08_13 (59-59)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
  • AuthOptionalUser (5-5)
apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts (1)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (2)
  • GetOptionalUser (7-32)
  • AuthOptionalUser (5-5)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (2)
apps/api/v2/src/modules/auth/guards/optional-api-auth/optional-api-auth.guard.ts (1)
  • OptionalApiAuthGuard (4-14)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (2)
  • GetOptionalUser (7-32)
  • AuthOptionalUser (5-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tests / Unit
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (38)
packages/prisma/schema.prisma (1)

231-232: Field addition looks correct and non-breaking

Adding bookingRequiresAuthentication with a false default is safe for existing rows and aligns with the migration.

apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)

5-6: Good: clear, reusable alias for optional auth

AuthOptionalUser = ApiAuthGuardUser | null provides a concise shared type for optional auth flows.

apps/api/v2/src/modules/slots/slots-2024-09-04/controllers/slots.controller.ts (2)

3-6: LGTM: imports updated to optional-auth pattern

Importing AuthOptionalUser alongside GetOptionalUser keeps signatures precise without leaking Prisma types into controllers.


266-266: Signature change is correct

Accepting AuthOptionalUser and passing user?.id down maintains behavior while allowing unauthenticated usage.

apps/api/v2/src/modules/organizations/event-types/services/output.service.ts (1)

78-79: Type surface aligned

Including bookingRequiresAuthentication in Input keeps org event-type outputs in sync with DB and shared types.

packages/prisma/migrations/20250820094118_add_event_type_booking_requires_auth_column/migration.sql (1)

2-2: Migration adds bookingRequiresAuthentication column with sane defaults — LGTM

Non-null with default false is appropriate and backward-compatible for existing rows.

apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts (1)

25-25: Wiring MembershipsModule into BookingsModule is correct

This enables DI for membership checks during booking authorization. No issues spotted.

Also applies to: 57-58

packages/lib/defaultEvents.ts (1)

149-150: Default event shape updated with bookingRequiresAuthentication — LGTM

Adding the flag to commons ensures downstream defaults are consistent with the new schema.

apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts (2)

501-502: E2E coverage for bookingRequiresAuthentication on create — LGTM

Payload includes bookingRequiresAuthentication: true and asserts it in the response. This validates output mapping as expected.

Also applies to: 574-575


1031-1032: E2E coverage for bookingRequiresAuthentication on update — LGTM

The update payload sets bookingRequiresAuthentication: false and the assertion verifies it. Good coverage for both create and update flows.

Also applies to: 1127-1128

apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (4)

6-6: Wiring MembershipsModule into the test app looks good

Ensures the membership-based authorization paths are available for these e2e tests.


84-84: Including MembershipsModule in Test.createTestingModule imports is appropriate

This aligns the test container with production wiring for membership checks.


805-812: Confirm semantics: 401 vs 403 for authenticated-but-insufficient role

Here you expect 401 for a user who is authenticated but lacks permission (not owner/host/assigned/admin). Typical REST semantics would be 403 Forbidden for authenticated users without sufficient authorization, reserving 401 for unauthenticated requests. If the service intentionally returns 401 for both, consider documenting this; otherwise, adjust expectation to 403.

Do you want me to open a follow-up to align status codes (401 unauthenticated, 403 forbidden) and update tests accordingly?


814-836: Positive coverage for owner and org-admin paths

These assertions exercise two allowed roles and clean up created bookings. LGTM.

apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts (1)

93-94: End-to-end propagation of bookingRequiresAuthentication in outputs looks correct

  • Included in Input pick, destructured in getResponseEventType, and returned in the output shape. This keeps API responses in sync with the new schema.

Also applies to: 133-134, 211-212

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (4)

16-19: Imports for optional auth user decorator look correct.

The new GetOptionalUser/AuthOptionalUser imports are aligned with the optional-auth flow introduced in the PR.


23-23: OptionalApiAuthGuard import aligns with the new endpoint behavior.

This correctly enables optional authentication on POST /v2/bookings.


146-149: Parameter wiring matches service signature.

createBooking(request, body, user) aligns with the service’s new signature.


103-103: PermissionsGuard No-Op Behavior Confirmed

PermissionsGuard’s canActivate returns true whenever no @Permissions metadata is found, so controller-level @UseGuards(PermissionsGuard) will not block methods (such as the @Post("/") handler at line 103) that only use @UseGuards(OptionalApiAuthGuard) without any @Permissions. No further changes are needed.

apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)

120-123: Potential null-dereference if errors handler doesn’t throw.

If this.errorsBookingsService.handleEventTypeToBeBookedNotFound(body) does not throw, eventType may be null, and checkBookingRequiresAuthenticationSetting(eventType, ...) will crash accessing eventType.bookingRequiresAuthentication.

Please confirm handleEventTypeToBeBookedNotFound always throws. If not, add an explicit throw/return after the call.

       if (!eventType) {
         this.errorsBookingsService.handleEventTypeToBeBookedNotFound(body);
+        return;
       }

107-110: BookingsModule_2024_08_13 correctly imports MembershipsModule
The BookingsModule_2024_08_13 decorator includes MembershipsModule, which exports both MembershipsRepository and MembershipsService. No further wiring is needed.


112-112: Signature change ripple-check complete

The only call site for bookingsService.createBooking is in
• apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts
– Invoked as this.bookingsService.createBooking(request, body, user)

No other references to the service method were found; tests and library functions use a different createBooking.

docs/api-reference/v2/openapi.json (9)

5321-5321: Summary format looks good

Summary is concise, American English, and has no trailing period.


12716-12716: Summary format looks good

Summary is concise, American English, and has no trailing period.


21053-21059: Per-DTO discriminators look fine

Using a single-value enum for the type discriminator in each DTO is acceptable and keeps the schema explicit.


21074-21080: Per-DTO discriminators look fine

Consistent with the other trigger DTOs.


21087-21093: Per-DTO discriminators look fine


21099-21105: Per-DTO discriminators look fine


21111-21117: Per-DTO discriminators look fine


21131-21137: Per-DTO discriminators look fine


21152-21158: Per-DTO discriminators look fine

apps/api/v2/swagger/documentation.json (7)

22812-22814: LGTM: specific trigger enum is correctly constrained

This schema intentionally constrains the trigger to beforeEvent only. Type and enum align.


22838-22840: LGTM: specific trigger enum is correctly constrained

afterEvent trigger enum looks correct.


22856-22858: LGTM: specific trigger enum is correctly constrained

eventCancelled trigger enum looks correct.


22872-22874: LGTM: specific trigger enum is correctly constrained

newEvent trigger enum looks correct.


22888-22890: LGTM: specific trigger enum is correctly constrained

rescheduleEvent trigger enum looks correct.


22912-22914: LGTM: specific trigger enum is correctly constrained

afterGuestsCalVideoNoShow trigger enum looks correct.


22938-22940: LGTM: specific trigger enum is correctly constrained

afterHostsCalVideoNoShow trigger enum looks correct.

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: CodeRabbit UI
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 3fb0f52 and 5537e7a.

📒 Files selected for processing (1)
  • packages/lib/test/builder.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/lib/test/builder.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/test/builder.ts

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

♻️ Duplicate comments (2)
apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts (1)

136-145: Prefer O(1) existence check via Host composite key; also add explicit return type

Using eventType.findFirst with hosts.some performs an extra join. If the Host model has a composite unique key (userId_eventTypeId), query Host directly for an O(1) existence check and return a boolean. Also add an explicit return type for stronger typing.

-  async isUserHostOfEventType(userId: number, eventTypeId: number) {
-    const eventType = await this.dbRead.prisma.eventType.findFirst({
-      where: {
-        id: eventTypeId,
-        hosts: { some: { userId: userId } },
-      },
-      select: { id: true },
-    });
-    return !!eventType;
-  }
+  async isUserHostOfEventType(userId: number, eventTypeId: number): Promise<boolean> {
+    const host = await this.dbRead.prisma.host.findUnique({
+      where: { userId_eventTypeId: { userId, eventTypeId } },
+      select: { userId: true },
+    });
+    return !!host;
+  }

If the composite unique is not available, fall back to host.findFirst({ where: { userId, eventTypeId }, select: { id: true } }).

apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)

24-31: LGTM: Use ForbiddenException for authenticated-but-not-authorized

The switch to ForbiddenException aligns with correct HTTP semantics for authenticated callers lacking permission. Good catch.

🧹 Nitpick comments (3)
apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts (1)

147-156: Add explicit return type; minor nit on object shorthand

The implementation looks good and adheres to “select-only.” Add an explicit return type, and consider property shorthand for readability.

-  async isUserAssignedToEventType(userId: number, eventTypeId: number) {
+  async isUserAssignedToEventType(userId: number, eventTypeId: number): Promise<boolean> {
     const eventType = await this.dbRead.prisma.eventType.findFirst({
       where: {
-        id: eventTypeId,
-        users: { some: { id: userId } },
+        id: eventTypeId,
+        users: { some: { id: userId } },
       },
       select: { id: true },
     });
     return !!eventType;
   }
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)

120-124: Return early when event type is not found to aid control-flow and types

If handleEventTypeToBeBookedNotFound throws (as expected), return explicitly so TS narrows eventType and future lines don't rely on a potentially null value.

-      if (!eventType) {
-        this.errorsBookingsService.handleEventTypeToBeBookedNotFound(body);
-      }
+      if (!eventType) {
+        return this.errorsBookingsService.handleEventTypeToBeBookedNotFound(body);
+      }

If handleEventTypeToBeBookedNotFound indeed always throws, consider annotating its return type as never for even stronger type narrowing.


158-206: Normalize checkBookingRequiresAuthenticationSetting to return void and remove boolean returns

This method is used for gating and throws on failure. Returning a boolean is unused and slightly muddles intent. Prefer a Promise signature with early returns only for the allowed paths. Also trim internal function names from error messages to avoid leaking implementation details.

-  async checkBookingRequiresAuthenticationSetting(
-    eventType: EventTypeWithOwnerAndTeam,
-    authUser: AuthOptionalUser
-  ) {
-    if (!eventType.bookingRequiresAuthentication) return true;
+  async checkBookingRequiresAuthenticationSetting(
+    eventType: EventTypeWithOwnerAndTeam,
+    authUser: AuthOptionalUser
+  ): Promise<void> {
+    if (!eventType.bookingRequiresAuthentication) return;
@@
-      throw new UnauthorizedException(
-        "checkBookingRequiresAuthentication - request must be authenticated by passing credentials belonging to event type owner, host or team or org admin or owner."
-      );
+      throw new UnauthorizedException(
+        "Authentication required: provide credentials for the event type owner/host, or a team/org admin/owner."
+      );
@@
-    const eventTypeId = eventType.id;
+    const eventTypeId = eventType.id;
@@
-    if (eventTypeId) {
-      const [isUserHost, isUserAssigned] = await Promise.all([
-        this.eventTypesRepository.isUserHostOfEventType(authUserId, eventTypeId),
-        this.eventTypesRepository.isUserAssignedToEventType(authUserId, eventTypeId),
-      ]);
-
-      if (isUserHost || isUserAssigned) return;
-    }
+    const [isUserHost, isUserAssigned] = await Promise.all([
+      this.eventTypesRepository.isUserHostOfEventType(authUserId, eventTypeId),
+      this.eventTypesRepository.isUserAssignedToEventType(authUserId, eventTypeId),
+    ]);
+    if (isUserHost || isUserAssigned) return;
@@
-    throw new ForbiddenException(
-      "checkBookingRequiresAuthentication - user is not authorized to access this event type. User has to be either event type owner, host, team admin or owner or org admin or owner."
-    );
+    throw new ForbiddenException(
+      "Not authorized to book this event type. Allowed roles: event type owner/host, team admin/owner, or org admin/owner."
+    );
📜 Review details

Configuration used: CodeRabbit UI
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 5537e7a and 89fbd78.

📒 Files selected for processing (2)
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (5 hunks)
  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{service,repository}.ts

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

Avoid dot-suffixes like .service.ts or .repository.ts for new files; reserve .test.ts, .spec.ts, .types.ts for their specific purposes

Files:

  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.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:

  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.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:

  • apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
  • AuthOptionalUser (5-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (3)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)

9-9: LGTM: Optional auth type import is correct and matches controller changes

Importing AuthOptionalUser cleanly communicates the optional-credentials contract for public booking endpoints.


13-14: LGTM: Memberships dependencies are properly injected

MembershipsRepository and MembershipsService DI looks consistent with the new authorization path.

Also applies to: 108-110


113-113: All createBooking call sites updated to include authUser

The rg search shows only two occurrences of createBooking( in the API code:

  • The service definition itself in apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (accepts three parameters).
  • The controller invocation in apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts at line 149, which now correctly passes (request, body, user).

No invocations with fewer than three arguments were found.

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

♻️ Duplicate comments (13)
docs/api-reference/v2/openapi.json (4)

17224-17230: Clarify bookingRequiresAuthentication wording; capitalize API

Same clarification as above for Update input. Keep schema neutral and point to service-level enforcement.

           "bookingRequiresAuthentication": {
             "type": "boolean",
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },

17257-17264: Don’t mark hidden and bookingRequiresAuthentication as required

These are optional fields with server-side defaults. Listing them in required breaks clients.

           "successRedirectUrl",
           "isInstantEvent",
           "scheduleId",
-          "hidden",
-          "bookingRequiresAuthentication",
           "ownerId",
           "users"

21061-21066: Invalid OpenAPI typing: string enum declared as object

This property is a scalar enum; type must be string.

           "unit": {
-            "type": "object",
+            "type": "string",
             "enum": ["hour", "minute", "day"],
             "description": "Unit for the offset time",
             "example": "hour"
           }

21652-21668: Fix nested enum array and incorrect type; use flat string enum

“type” is currently declared as object with enum nested array, which will fail validation and codegen.

         "properties": {
           "type": {
-            "type": "object",
-            "enum": [
-              [
-                "beforeEvent",
-                "eventCancelled",
-                "newEvent",
-                "afterEvent",
-                "rescheduleEvent",
-                "afterHostsCalVideoNoShow",
-                "afterGuestsCalVideoNoShow"
-              ]
-            ],
+            "type": "string",
+            "enum": [
+              "beforeEvent",
+              "eventCancelled",
+              "newEvent",
+              "afterEvent",
+              "rescheduleEvent",
+              "afterHostsCalVideoNoShow",
+              "afterGuestsCalVideoNoShow"
+            ],
             "description": "Trigger type for the workflow"
           }
         },
apps/api/v2/swagger/documentation.json (9)

20985-20991: Team event-type output: fix wording to authorization-based gating

Repeat of the same semantics issue; please harmonize.

           "bookingRequiresAuthentication": {
             "type": "boolean",
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "When true, API bookings are restricted to callers with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner)."
           },

5814-5829: Use integer for orgId/teamId path params

Same issue as above in this route: path params should be integer (ids), not number.

           {
             "name": "orgId",
             "required": true,
             "in": "path",
             "schema": {
-              "type": "number"
+              "type": "integer",
+              "format": "int64"
             }
           },
           {
             "name": "teamId",
             "required": true,
             "in": "path",
             "schema": {
-              "type": "number"
+              "type": "integer",
+              "format": "int64"
             }
           },

13325-13389: Team schedules: change teamId/take/skip to integer (repeat of earlier feedback)

These parameters are still typed as number. Please update to integer (int64 for IDs). This prevents float inputs and matches API semantics.

           {
             "name": "teamId",
             "required": true,
             "in": "path",
             "schema": {
-              "type": "number"
+              "type": "integer",
+              "format": "int64"
             }
           },
           {
             "name": "take",
             "required": false,
             "in": "query",
             "description": "Maximum number of items to return",
             "example": 25,
             "schema": {
               "minimum": 1,
               "maximum": 250,
               "default": 250,
-              "type": "number"
+              "type": "integer"
             }
           },
           {
             "name": "skip",
             "required": false,
             "in": "query",
             "description": "Number of items to skip",
             "example": 0,
             "schema": {
               "minimum": 0,
               "default": 0,
-              "type": "number"
+              "type": "integer"
             }
           }

18349-18355: Update input: align bookingRequiresAuthentication wording and add explicit default=false

Mirror the semantics used by the service (privileged authorization) and declare the default for consistency with other inputs.

           "bookingRequiresAuthentication": {
             "type": "boolean",
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "default": false,
+            "description": "If true, bookings via API require a caller with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner). Anonymous or unauthorized callers are rejected."
           },

22811-22816: Invalid enum schema for unit: type must be string, not object

Declaring type: object with a string enum will break client generation.

           "unit": {
-            "type": "object",
-            "enum": [
+            "type": "string",
+            "enum": [
               "hour",
               "minute",
               "day"
             ],
             "description": "Unit for the offset time",
             "example": "hour"
           }

23560-23576: Invalid nested enum array and object type (workflow trigger): flatten and use string

Enum is wrapped as a nested array and the schema type is object, which is invalid OpenAPI.

         "properties": {
           "type": {
-            "type": "object",
-            "enum": [
-              [
-                "beforeEvent",
-                "eventCancelled",
-                "newEvent",
-                "afterEvent",
-                "rescheduleEvent",
-                "afterHostsCalVideoNoShow",
-                "afterGuestsCalVideoNoShow"
-              ]
-            ],
+            "type": "string",
+            "enum": [
+              "beforeEvent",
+              "eventCancelled",
+              "newEvent",
+              "afterEvent",
+              "rescheduleEvent",
+              "afterHostsCalVideoNoShow",
+              "afterGuestsCalVideoNoShow"
+            ],
             "description": "Trigger type for the workflow"
           }
         },

18382-18389: Do not make hidden/bookingRequiresAuthentication required (breaking change)

These are feature flags with sensible defaults. Making them required will break existing clients and is unnecessary.

           "scheduleId",
-          "hidden",
-          "bookingRequiresAuthentication",
           "ownerId",
           "users"

5550-5640: IDs and pagination params must be integer-typed (not number) for client correctness

Path/query schemas here use "type": "number". Use integer types to avoid floats slipping into IDs/pagination and to align with prior endpoints.

Apply:

           {
             "name": "orgId",
             "required": true,
             "in": "path",
             "schema": {
-              "type": "number"
+              "type": "integer",
+              "format": "int64"
             }
           },
           {
             "name": "teamId",
             "required": true,
             "in": "path",
             "schema": {
-              "type": "number"
+              "type": "integer",
+              "format": "int64"
             }
           },
           {
             "name": "take",
             "required": false,
             "in": "query",
             "description": "Maximum number of items to return",
             "example": 25,
             "schema": {
               "minimum": 1,
               "maximum": 250,
               "default": 250,
-              "type": "number"
+              "type": "integer"
             }
           },
           {
             "name": "skip",
             "required": false,
             "in": "query",
             "description": "Number of items to skip",
             "example": 0,
             "schema": {
               "minimum": 0,
               "default": 0,
-              "type": "number"
+              "type": "integer"
             }
           }

16679-16686: Clarify authorization semantics of bookingRequiresAuthentication (create input)

Description implies “any authenticated user,” but the implementation enforces privileged roles (owner/host/team admin/org admin). Keep inputs explicit and consistent.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "If true, bookings via API require a caller with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner). Anonymous or unauthorized callers are rejected."
           },
🧹 Nitpick comments (9)
docs/api-reference/v2/openapi.json (5)

15737-15744: Clarify bookingRequiresAuthentication to reflect service-enforced authorization (not “any authenticated user”)

Per the implementation, this is an indicator; enforcement/role checks happen in service logic. Avoid implying that any authenticated user can book.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },

17560-17567: Align description with service-enforced authorization and capitalize API

Repeat of clarification for org create input.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },

19131-19138: Clarify authorization semantics; avoid implying “any authenticated user”

Same fix for team event type output.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },

19542-19548: Clarify authorization semantics; capitalize API

Same as above for team update input.

           "bookingRequiresAuthentication": {
             "type": "boolean",
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },

19958-19965: Clarify authorization semantics; capitalize API

Same as above for user create input (hosts variant).

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "Indicates booking this event type via the API requires authorized access; enforcement is handled by the booking service"
           },
apps/api/v2/swagger/documentation.json (4)

18707-18714: Team create input: clarify bookingRequiresAuthentication semantics (authZ vs. authN)

Same wording fix as above to avoid implying “any authenticated user.”

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "If true, API bookings are restricted to callers with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner)."
           },

20543-20550: Event-type output: reflect authorization semantics in description

Outputs should describe what the flag means operationally; keep wording consistent across all variants.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "When true, API bookings are restricted to callers with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner)."
           },

21438-21445: Org-scoped event-type input: unify description and default

Keep this variant consistent with others: default=false and authorization semantics.

           "bookingRequiresAuthentication": {
             "type": "boolean",
             "default": false,
-            "description": "Boolean to require authentication for booking this event type via api. If true, only authenticated users can book this event type."
+            "description": "If true, API bookings are restricted to callers with sufficient permissions (e.g., event owner/host, team admin/owner, or org admin/owner)."
           },

22840-22971: Workflow trigger single-value enums: consider $ref to a shared enum to reduce duplication

These schemas constrain "type" to a single literal via enum of one value. That’s valid but verbose and diverges from the shared trigger enum used elsewhere. Prefer referencing a single components schema (e.g., components/schemas/WorkflowTriggerType) or at least centralize allowed values to avoid drift.

Example:

-          "type": {
-            "type": "string",
-            "default": "beforeEvent",
-            "enum": ["beforeEvent"],
-            "description": "Trigger type for the workflow",
-            "example": "beforeEvent"
-          }
+          "type": {
+            "$ref": "#/components/schemas/WorkflowTriggerType"
+          }

If literals are intentional per-DTO, keep, but ensure a single source of truth exists for the enum.

📜 Review details

Configuration used: .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 a8eed2d and cd9cd7b.

📒 Files selected for processing (7)
  • apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.ts (2 hunks)
  • apps/api/v2/swagger/documentation.json (19 hunks)
  • docs/api-reference/v2/openapi.json (19 hunks)
  • packages/lib/defaultEvents.ts (1 hunks)
  • packages/lib/test/builder.ts (1 hunks)
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts (1 hunks)
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts (1 hunks)
🔥 Files not summarized due to errors (1)
  • docs/api-reference/v2/openapi.json: Error: Server error: no LLM provider could handle the message
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/lib/defaultEvents.ts
  • packages/lib/test/builder.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts
  • packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts
🧰 Additional context used
📓 Path-based instructions (4)
docs/api-reference/v2/openapi.json

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

When docs changes are made in /docs/api-reference/v2/openapi.json, ensure 'summary' fields are short, concise, do not end with a period, and are written in proper American English

Files:

  • docs/api-reference/v2/openapi.json
**/*.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:

  • apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.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:

  • apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.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:

  • apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23217
File: docs/api-reference/v2/openapi.json:17226-17229
Timestamp: 2025-08-21T13:59:04.198Z
Learning: In the cal.com codebase, permission logic is handled by business logic in specific endpoints/services rather than being enforced at the API schema level. The schema fields like `bookingRequiresAuthentication` serve as indicators, but the actual permission decisions are made by the individual services.
📚 Learning: 2025-08-21T13:59:04.198Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: docs/api-reference/v2/openapi.json:17226-17229
Timestamp: 2025-08-21T13:59:04.198Z
Learning: In the cal.com codebase, permission logic is handled by business logic in specific endpoints/services rather than being enforced at the API schema level. The schema fields like `bookingRequiresAuthentication` serve as indicators, but the actual permission decisions are made by the individual services.

Applied to files:

  • apps/api/v2/swagger/documentation.json
  • docs/api-reference/v2/openapi.json
📚 Learning: 2025-08-21T12:28:42.000Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/factory/WebhookPayloadFactory.ts:274-282
Timestamp: 2025-08-21T12:28:42.000Z
Learning: In webhook DTOs in packages/features/webhooks/lib/dto/types.ts, the booking fields are restricted structures containing only specific fields (id, eventTypeId, userId, and sometimes additional fields like startTime or smsReminderNumber) rather than full database booking objects, so there are no security or PII leakage concerns when using these booking objects in webhook payloads.

Applied to files:

  • apps/api/v2/swagger/documentation.json
  • docs/api-reference/v2/openapi.json
⏰ 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: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (11)
docs/api-reference/v2/openapi.json (7)

21081-21087: LGTM on string enum for trigger “beforeEvent”

This matches correct scalar enum typing and is consistent with examples.


21102-21108: LGTM on string enum for trigger “afterEvent”

Consistent with the above.


21115-21121: LGTM on string enum for trigger “eventCancelled”

Consistent scalar enum typing.


21127-21133: LGTM on string enum for trigger “newEvent”

Looks good.


21139-21145: LGTM on string enum for trigger “rescheduleEvent”

Looks good.


21159-21165: LGTM on string enum for trigger “afterGuestsCalVideoNoShow”

Looks good.


21180-21186: LGTM on string enum for trigger “afterHostsCalVideoNoShow”

Looks good.

apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.ts (2)

70-73: Fix typo and clarify Swagger path params comment

Confirmed that the Swagger documentation for /v2/organizations/{orgId}/teams/{teamId}/users/{userId}/schedules includes orgId, teamId, and userId as path parameters, and the IsUserInOrgTeam guard reads those exact param names. Applying the diff below corrects the typo and makes the intent explicit:

-    // note(Lauirs): putting orgId and teamId so swagger is generacted correctly
+    // note(Lauris): include orgId and teamId params so Swagger generates path params correctly (intentionally unused)

46-48: Fix typos in inline note and clarify Swagger intent

The inline comment on lines 46–48 has two typos (“Lauirs” and “generacted”) and could more clearly state that the parameter is only included to generate the path param in Swagger (and isn’t used at runtime).

• File: apps/api/v2/src/modules/organizations/teams/schedules/organizations-teams-schedules.controller.ts
• Lines: 46–48

Proposed diff:

-    // note(Lauirs): putting orgId so swagger is generacted correctly
+    // note(Lauris): include orgId param so Swagger generates path params correctly (intentionally unused)

Optional: If you’d rather be explicit in your OpenAPI spec instead of relying on inference, you can add @ApiParam decorators for both orgId and teamId.

apps/api/v2/swagger/documentation.json (2)

16679-16686: No changes needed for bookingRequiresAuthentication consistency

Confirmed that across all schema variants:

  • Input definitions (lines 16682–16686, 18710–18714, 20546–20550, 21441–21445) include "default": false and share the identical, concise description.
  • Output definitions (lines 18352–18355, 20988–20991) omit the default as per convention and use the same description text.

All six occurrences are already aligned with the intended authorization‐centric wording and default placement.


5550-5640: Review parameter types for common IDs and pagination fields

I’ve scanned all path/query parameters named orgId, teamId, userId, take, and skip that are currently defined with "type": "number". Please manually verify each occurrence and confirm whether the parameter should indeed be a number or be changed to a string for consistency with the API’s design.

• File: apps/api/v2/swagger/documentation.json
– Sections around lines 5550–5640 (e.g. /v2/organizations/{orgId}/teams/{teamId}/schedules)
– Sections around lines 13325–13389 (other endpoints)

• To regenerate the full list of matches, run:

rg -z -n -P '"in":\s*"(path|query)".*?"name":\s*"(orgId|teamId|userId|take|skip)".*?"schema":\s*\{[^}]*"type":\s*"number"' apps/api/v2/swagger/documentation.json

ThyMinimalDev
ThyMinimalDev previously approved these changes Aug 22, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 22, 2025

E2E results are ready!

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

💡 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 d033500 and 5e8258f.

📒 Files selected for processing (1)
  • packages/prisma/zod-utils.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/prisma/zod-utils.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/prisma/zod-utils.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/prisma/zod-utils.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23217
File: docs/api-reference/v2/openapi.json:17226-17229
Timestamp: 2025-08-21T13:59:04.198Z
Learning: In the cal.com codebase, permission logic is handled by business logic in specific endpoints/services rather than being enforced at the API schema level. The schema fields like `bookingRequiresAuthentication` serve as indicators, but the actual permission decisions are made by the individual services.
📚 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/prisma/zod-utils.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: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E 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: 0

🧹 Nitpick comments (4)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (4)

782-793: Isolate the variable under test: drop requiresConfirmation for the auth-gated event type

This suite validates bookingRequiresAuthentication. Setting requiresConfirmation here mixes concerns and can obscure failures (e.g., booking flows that return 201 but PENDING status). Recommend disabling requiresConfirmation in this describe to keep assertions targeted.

           length: 60,
-          requiresConfirmation: true,
+          requiresConfirmation: false,
           bookingRequiresAuthentication: true,

822-833: Assert response shape and semantics on successful booking (owner path)

Minor: Assert SUCCESS_STATUS and sanity-check the eventTypeId to catch regressions in output mapping. Also re-use the parsed typed body for cleanup.

       const response = await request(app.getHttpServer())
         .post(`/v2/bookings`)
         .send(body)
         .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
         .set("Authorization", `Bearer ${secondManagedUser.accessToken}`)
         .expect(201);

-      const bookingId = response.body.data.id;
+      const responseBody: ApiSuccessResponse<BookingOutput_2024_08_13> = response.body;
+      expect(responseBody.status).toEqual(SUCCESS_STATUS);
+      expect(responseBody.data.eventTypeId).toEqual(eventTypeRequiringAuthenticationId);
+      const bookingId = responseBody.data.id;
       await bookingsRepositoryFixture.deleteById(bookingId);

834-845: Mirror the success assertions for the admin path as well

Same reasoning as above for the admin-allowed path.

       const response = await request(app.getHttpServer())
         .post(`/v2/bookings`)
         .send(body)
         .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
         .set("Authorization", `Bearer ${orgAdminManagedUser.accessToken}`)
         .expect(201);

-      const bookingId = response.body.data.id;
+      const responseBody: ApiSuccessResponse<BookingOutput_2024_08_13> = response.body;
+      expect(responseBody.status).toEqual(SUCCESS_STATUS);
+      expect(responseBody.data.eventTypeId).toEqual(eventTypeRequiringAuthenticationId);
+      const bookingId = responseBody.data.id;
       await bookingsRepositoryFixture.deleteById(bookingId);

847-856: Optional cleanup: delete the auth-gated event type created in this suite

You delete the created bookings, but not the event type introduced in this describe. It will likely be cascaded by later cleanup, but an explicit delete makes the suite self-contained.

   afterAll(async () => {
+    // If not cascaded automatically:
+    // await eventTypesRepositoryFixture.delete(eventTypeRequiringAuthenticationId);
     await userRepositoryFixture.delete(firstManagedUser.user.id);
     await userRepositoryFixture.delete(secondManagedUser.user.id);
     await userRepositoryFixture.delete(thirdManagedUser.user.id);
     await userRepositoryFixture.delete(orgAdminManagedUser.user.id);
     await userRepositoryFixture.delete(platformAdmin.id);
     await oauthClientRepositoryFixture.delete(oAuthClient.id);
     await teamRepositoryFixture.delete(organization.id);
     await app.close();
   });
📜 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 5e8258f and 01f85d3.

📒 Files selected for processing (1)
  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.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:

  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.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:

  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.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:

  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: supalarry
PR: calcom/cal.com#23217
File: docs/api-reference/v2/openapi.json:17226-17229
Timestamp: 2025-08-21T13:59:04.198Z
Learning: In the cal.com codebase, permission logic is handled by business logic in specific endpoints/services rather than being enforced at the API schema level. The schema fields like `bookingRequiresAuthentication` serve as indicators, but the actual permission decisions are made by the individual services.
📚 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:

  • apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts
🧬 Code graph analysis (1)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (2)
apps/api/v2/test/utils/randomString.ts (1)
  • randomString (3-6)
packages/platform/constants/api.ts (2)
  • CAL_API_VERSION_HEADER (72-72)
  • VERSION_2024_08_13 (59-59)
⏰ 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: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (3)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (3)

805-812: Good distinction between 401 (no credentials) and 403 (insufficient privileges)

The expected status codes align with the contract introduced in this PR. Nice coverage of the unauthenticated vs. unauthorized paths.

Also applies to: 813-821


6-6: MembershipsModule import is required in this spec; AppModule does not include it
AppModule’s decorator includes SentryModule, ConfigModule, RedisModule, BullModule, ThrottlerModule, PrismaModule, EndpointsModule, AuthModule, and JwtModule—but not MembershipsModule—so the explicit import in your E2E spec is necessary to wire up that module’s providers. Remove the suggestion to drop it.

Likely an incorrect or invalid review comment.


776-845: Expand coverage: add tests for host, team admin/owner (team-owned event types), and system admin

Short: the new auth gate is only exercised for event-type owner and org admin — please add tests for (a) a host of the event type, (b) a team admin/owner when the event type is team-owned, and (c) a system admin.

What I checked

  • Target test file: apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/managed-user-bookings.e2e-spec.ts (the describe block "event type booking requires authentication", ~lines 776–845).
  • I attempted to find fixture helpers to attach hosts or create team-owned event types (EventTypesRepositoryFixture implementation and helpers like addHost/addHosts or an ownerTeamId/teamId creation field) but could not locate the EventTypesRepositoryFixture implementation in the repository. The test imports test/fixtures/repository/event-types.repository.fixture but the class/host helpers weren't found by search.

Actionable next steps (pick one)

  • If the fixture exposes helpers to assign hosts and create team-owned event types: add the three tests inside the existing describe block (examples below).
  • If the fixture does not yet expose those helpers: add helpers to the fixture (e.g., addHosts(eventTypeId, userIds) and/or createTeamOwned({ ... }, teamId) or accept ownerTeamId in create) or point me to the fixture implementation so I can wire exact calls.

Suggested test snippets to add (inside describe "event type booking requires authentication"):

+ it("can be booked by a host of the event type", async () => {
+   const hostEventType = await eventTypesRepositoryFixture.create(
+     { title: `auth-host-${randomString()}`, slug: `auth-host-${randomString()}`, length: 30, bookingRequiresAuthentication: true },
+     secondManagedUser.user.id
+   );
+   // if fixture supports assignment:
+   // await eventTypesRepositoryFixture.addHosts(hostEventType.id, [firstManagedUser.user.id]);
+
+   const hostBody = { start: new Date(Date.UTC(2030,0,10,10,0,0)).toISOString(), eventTypeId: hostEventType.id, attendee: { email: "external@example.com", name: "External", timeZone: "Europe/Rome" } };
+   const res = await request(app.getHttpServer())
+     .post(`/v2/bookings`)
+     .send(hostBody)
+     .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
+     .set("Authorization", `Bearer ${firstManagedUser.accessToken}`)
+     .expect(201);
+   await bookingsRepositoryFixture.deleteById(res.body.data.id);
+ });
+
+ it("can be booked by a team admin/owner when event type is team-owned", async () => {
+   // Arrange: create team, make orgAdminManagedUser an ADMIN/OWNER via membership fixture, create event type with teamId/ownerTeamId
+   // book with orgAdminManagedUser and expect 201
+ });
+
+ it("can be booked by a system admin", async () => {
+   // Clarify which account/flag represents system admin in tests (platform admin vs membership). If platform admin exists, assert booking succeeds with its credentials.
+ });

I can implement the exact tests and wire fixture calls once you either (A) confirm where EventTypesRepositoryFixture is implemented, or (B) expose helpers to assign hosts/create team-owned event types, or (C) tell me the intended pattern for creating a "system admin" test user in the fixtures.

@supalarry supalarry enabled auto-merge (squash) August 22, 2025 08:46
Copy link
Contributor

@volnei volnei left a comment

Choose a reason for hiding this comment

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

LGTM

@supalarry supalarry merged commit e0dc2ba into main Aug 22, 2025
40 checks passed
@supalarry supalarry deleted the lauris/cal-6281-feat-admin-only-booking branch August 22, 2025 14:22
@coderabbitai coderabbitai bot mentioned this pull request Oct 3, 2025
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only event-types area: event types, event-types ❗️ migrations contains migration files platform Anything related to our platform plan ready-for-e2e

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants