7441 Commits
Author SHA1 Message Date
Benny JooandDevin AI e3eaa69339 fix: return 400 instead of 500 for invalid eventTypeId in booking flow (#26732)
* fix: return 400 instead of 500 for invalid eventTypeId in booking flow

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: use ErrorWithCode instead of HttpError in BotDetectionService

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: use vi.stubEnv for safer environment variable handling in tests

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 07:07:35 -03:00
Benny JooandDevin AI fc0a2b5a37 refactor: Remove trpc/server dependency from @calcom/atoms (#26717)
* mv useTeamMembersWithSegment

* remove

* fix ts error

* remove

* remove

* remove

* biome rule

* wip

* refactor: remove remaining @calcom/trpc/server imports from atoms

- Create local types for schedule handlers (CreateScheduleHandlerReturn, DuplicateScheduleHandlerReturn, GetAvailabilityListHandlerReturn, CreateScheduleInput)
- Create local GetAvailableSlotsResponse type for slots hook
- Update imports in useAtomCreateSchedule, useAtomDuplicateSchedule, useAtomGetAllSchedules, and useAvailableSlots

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix: add userId to Schedule type and create ScheduleForList type

- Schedule type now includes userId for create/duplicate handlers
- Created ScheduleForList type for list handler (uses select without userId)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix

* fix

* fix

* fix: correct fromUser/toUser types in GetAvailableSlotsResponse

- fromUser: { id, displayName } (matches IFromUser)
- toUser: { id, username, displayName } (matches IToUser)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 07:06:22 -03:00
Rajiv Sahal f7dee536d7 fix: dont import directly from @calcom/trpc or @calom/features (#26734) 2026-01-12 10:05:39 +00:00
0994050b0f fix(api): return original email without OAuth suffix in bookings (#25593)
* fix(api): remove OAuth client ID suffix from email in booking API responses

Fixes #25494 | Linear: CAL-6843

When managed users create or receive bookings, their emails were being returned with an internal OAuth client ID suffix (e.g., bob+cuid123@example.com). This suffix is used internally for user identification but should not be exposed in API responses.

Changes:
- Add cleanOAuthEmailSuffix() helper using CUID regex pattern
- Clean email suffix in hosts[], attendees[], bookingFieldsResponses.email, bookingFieldsResponses.guests[], and reassignedTo.email
- Pattern consistent with google-calendar.service.ts implementation

Affected output methods:
- getOutputBooking
- getOutputRecurringBooking
- getOutputSeatedBooking
- getOutputRecurringSeatedBooking
- getOutputReassignedBooking
- getHost

* refactor(api): preserve original email, add displayEmail field

Per team discussion, keep original email unchanged to avoid breaking changes for platform customers.
Add displayEmail field with CUID suffix removed for display purposes

* feat(api): add displayEmail to booking output DTOs

Add displayEmail property to BookingAttendee, BookingHost and ReassignedToDto for API documentation and type safety

* test(api): add e2e tests for displayEmail fields in managed user bookings

Add tests to verify that displayEmail fields correctly strip CUID suffix from OAuth managed user emails in booking API responses:

- Test host displayEmail returns email without CUID suffix
- Test attendee displayEmail returns email without CUID suffix
- Test bookingFieldsResponses.displayEmail returns clean email
- Test displayGuests array returns emails without CUID suffix

* false positive breaking change

* false positive breaking change

* test(api): update existing e2e tests to expect displayEmail field

* fix(api): add missing displayEmail to seated booking test assertions

The seated booking tests were missing displayEmail in the attendee
assertions for the second booking test and cancel-as-host test,
causing CI test failures

---------

Co-authored-by: cal.com <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-12 07:48:37 +00:00
Syed Ali ShahbazandVolnei Munhoz 3e7e376100 chore: Some minor fixes and follow up to #26446 (#26587)
* init

* DI and other improvements

* type fix

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-12 04:32:55 +00:00
Anik Dhabal Babu 93cac5a1c9 fix: don't include ics for unconfirmed booking (#26718) 2026-01-12 03:48:27 +00:00
Alex van Andel 312733ce68 refactor: Extract schedule determination to seperate fn (#26600)
* refactor: Extract schedule determination to seperate fn

* refactor: Extract schedule detection to seperate file and add tests

* RouterOutputs should be used in hooks, not direct type imports
2026-01-11 19:44:09 -03:00
58798f27d2 feat: add source: 'onboarding' metadata to subscriptions from onboarding v3 (#26619)
When a user signs up to a team/org from onboarding v3, the subscription
now includes source: 'onboarding' in its metadata. This helps track
which subscriptions originated from the onboarding flow.

Changes:
- Add source: 'onboarding' to subscription_data.metadata in team checkout
  when isOnboarding is true
- Add source: 'onboarding' to subscription metadata for organization
  onboarding flow

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2026-01-11 21:49:10 +00:00
Anik Dhabal Babu 98ef45be18 fix: prevent calendar event creation for unconfirmed round robin reschedules (#26719)
* fix rr booking

* fix test

* use actual prisma

* fix

* Refactor
2026-01-11 16:38:46 +00:00
Keith WilliamsandDevin AI 7a6f4b2594 fix: add global CRM services mock to prevent test flakes (#26716)
* fix: mock CRM services to prevent test flakes in handlePaymentSuccess.test.ts

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: add global CRM services mock to prevent test flakes

The test flakes were caused by the Salesforce CRM service importing @urql/core,
which triggers fetch calls during module loading. These fetch calls remain
pending when the Vitest worker shuts down, causing the error:
'[vitest-worker]: Closing rpc while fetch was pending'

This fix adds a global mock for CrmServiceMap in setupVitest.ts, similar to
how payment services are already mocked. This prevents the Salesforce module
from being loaded during test execution.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-11 18:18:05 +05:30
Benny Joo c826e9cea8 refactor: Remove trpc/react dependency from @calcom/atoms (#26694)
* mv useTeamMembersWithSegment

* remove

* fix ts error

* remove

* remove

* remove

* biome rule
2026-01-11 08:02:30 -03:00
08edd4f361 chore: Add logging to msteams (#23684)
* Add logging

* fix: Add response status checking to MS Teams adapter error handling

- Add response.ok checks before parsing JSON in createMeeting and updateMeeting
- Remove console.log statements that could leak credential information
- Ensure error handling matches original handleErrorsRaw behavior for tests

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Fix logs

* Revert "fix: Add response status checking to MS Teams adapter error handling"

This reverts commit 35820d21e1a54d9e04d83fd5f53584d64a5459b6.

* fix: Add response status checking to MS Teams adapter error handling

- Check response.ok before parsing JSON in createMeeting and updateMeeting
- Re-throw HttpError instances instead of wrapping them in catch blocks
- This ensures HTTP errors (like 500) are properly propagated

Co-Authored-By: unknown <>

* fix: Correct log message in updateMeeting to say 'updating' instead of 'creating'

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2026-01-11 10:34:02 +05:30
Keith WilliamsandDevin AI 539214b164 fix: improve BookingReferenceRepository integration test isolation (#26707)
The integration tests were flaky because they relied on a shared booking
created in beforeAll, which could cause race conditions when tests run
in parallel or when cleanup from previous runs interfered.

Changes:
- Use seed user (member0-acme@example.com) when available, fallback to
  creating a test user for local development
- Create a fresh booking in beforeEach instead of sharing one across tests
- Track created bookings and clean them up properly in afterEach
- Fix import organization to satisfy linter

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-11 10:01:25 +05:30
Anik Dhabal BabuandDevin AI eecf9e1ab9 fix: make BookingReferenceRepository integration tests use unique identifiers (#26701)
The integration tests were flaky because they used fixed identifiers
(email, username, uid) that could conflict across parallel test runs
or with leftover data from previous runs.

Changes:
- Add unique testRunId using timestamp and random suffix
- Use testRunId in email, username, and booking uid
- Change afterAll cleanup to use deleteMany instead of delete to
  prevent failures when records are already deleted

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-10 16:20:11 -03:00
Keith WilliamsandDevin AI d9b49b2c41 fix: mock salesforce graphql queries to prevent flaky test failures (#26688)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-10 23:22:44 +05:30
d3e7554835 refactor: move WebWrapper files from packages/platform to apps/web/modules (#26629)
* refactor: move WebWrapper files from packages/platform to apps/web/modules

Move the following WebWrapper files to their appropriate locations in apps/web/modules:
- EventTypeWebWrapper and related tab wrappers to apps/web/modules/event-types/components/wrappers/
- BookerWebWrapper to apps/web/modules/bookings/components/
- ConferencingAppsViewWebWrapper to apps/web/modules/apps/components/
- SelectedCalendarsSettingsWebWrapper to apps/web/modules/calendars/components/
- AddMembersWithSwitchWebWrapper to apps/web/modules/event-types/components/

This reduces the number of files in packages/platform that import from @calcom/web,
improving the separation between platform and web-specific code.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: move web-specific hooks to apps/web and update imports

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* add back comments

* fix

* fix

* fix

* fix

* fix: correct relative import paths in moved WebWrapper files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* final

* fix: use package alias for event-type hooks instead of deeply nested relative paths

- Move sortHosts function to @calcom/lib/bookings/hostGroupUtils.ts for shared access
- Add exports for useEventTypeForm, useHandleRouteChange, useTabsNavigations to @calcom/atoms package.json
- Update EventTypeWebWrapper.tsx to use @calcom/atoms package alias instead of ../../../../../packages/... paths
- Update useEventTypeForm.ts to import sortHosts from @calcom/lib instead of @calcom/web
- Re-export sortHosts from HostEditDialogs.tsx for backward compatibility

This addresses the Cubic AI review feedback about fragile deeply nested relative paths that bypass proper package resolution.

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-10 12:55:39 +00:00
f6d3b11582 refactor: Membership.findByUserIdAndTeamId to instance method (#26628)
* Make  and instance method

* Refactor files

* fix: update MembershipRepository mocks to use vi.hoisted() for proper hoisting

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-09 22:37:42 -03:00
a12ab5bb65 chore: add database-backed feature flag for sidebar tips section (#26516)
* chore: remove tips section from sidebar

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* chore: add feature flag for sidebar tips section

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* chore: use database-backed feature flag for sidebar tips section

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-09 22:31:45 +05:30
AnshumancanrockandKeith Williams 5b1ee1a7ac fix: Text cursor barely visible in calendar event name field (#26563)
* fix: cursor visibility in input fields

* fix: cursor visibility in input fields with suffix addons

* fix: text cursor visibility in input fields

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-09 12:09:24 +00:00
Udit Takkar 0330d14210 feat: system admin blocklist table (#25039)
* feat: system admin blocklist table

* chore: text

* fix: type error

* fix: type error

* fix: type error

* fix: frontend bug

* chore: improvments

* refactor: use shared components

* refactor: improvements

* fix: delete

* refactor: support multiple watchlist

* chore: update translation

* fix: type err

* fix: bulk bug

* tests: add unit test

* refactor: file

* refactor: file

* fix: type error

* fix: type error

* chore: translation

* refactor: use shared comments

* fix: imports

* fix: type error
2026-01-09 08:19:54 -03:00
Pedro Castro 51639e38d7 fix(auth): block OAuth linking for unverified accounts (#26598)
* fix(auth): sanitize unverified accounts during OAuth linking

- Add AccountSanitizationService for secure account cleanup
- Clear webhooks, API keys, credentials, and sessions for unverified accounts
- Reset password and 2FA settings during OAuth conversion
- Nullify redirect URLs on event types

Only affects accounts that never completed email verification

* fix(auth): block OAuth linking for unverified accounts

  Replace sanitization with simpler blocking approach:
  - Unverified CAL accounts cannot link to OAuth (Google/SAML)
  - Add user-friendly error message with recovery path
  - Remove AccountSanitizationService (no data loss risk)
2026-01-09 11:04:39 +00:00
c380ea810c feat: rename --font-cal to --font-heading + use Cal Sans UI (#26064)
* feat: rename --font-cal to --font-heading + use Cal Sans UI

* chore: remove font-weight from font-heading elements and CSS variables

Co-Authored-By: pasquale@cal.com <pasquale@cal.com>

* chore: remove unneeded css vars

* fix: cubic issues

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: pasquale@cal.com <pasquale@cal.com>
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
2026-01-09 10:42:23 +00:00
Hariom Balhara f3a37886e3 chore: Integrate reschedule request booking audit (#26527)
## What does this PR do?

Adds audit logging for the reschedule request flow. When an organizer requests an attendee to reschedule a booking, this action is now logged to the booking audit system.

This is part of the booking audit integration effort, following the pattern established in PR #26046 (booking creation/rescheduling audit) and PR #26458 (cancellation audit).

## Changes

- Added audit logging call to `requestReschedule.handler.ts` using `BookingEventHandlerService.onRescheduleRequested()`
- Captures audit data:
  - `rescheduleReason`: The reason provided for requesting the reschedule (nullable string)
  - `rescheduledRequestedBy`: Email of the user who requested the reschedule
- Uses `makeUserActor(user.uuid)` to identify the actor performing the action
- Added required `source` parameter for action source tracking (passed as `"WEBAPP"` from tRPC router)
- Updated `RescheduleRequestedAuditActionService` schema to use simpler field structure
- Updated test helper `getTrpcHandlerData` to pass `source: "WEBAPP"` parameter

## Updates since last revision

- Changed `source` parameter from optional with default to required - tests now explicitly pass `source: "WEBAPP"` instead of relying on a default value

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. N/A - follows established audit pattern with existing infrastructure tests.

## How should this be tested?

1. Log in as a user with a booking
2. Navigate to the booking and click "Request Reschedule"
3. Provide a reschedule reason and submit
4. Verify the audit log is created with the correct data (requires access to audit log storage/database)

The audit logging follows the same pattern as other booking audit integrations, so if those are working, this should work as well.

## Checklist

- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings

---

**Link to Devin run**: https://app.devin.ai/sessions/ae84d093c4594a5d89b88c45639a6a06
**Requested by**: @hariombalhara

## Human Review Checklist

- [ ] Verify the audit data schema matches `RescheduleRequestedAuditActionService` expectations (fields: `rescheduleReason`, `rescheduledRequestedBy`)
- [ ] Confirm the schema change from change-based fields (`{ old, new }`) to simple nullable strings is intentional
- [ ] Confirm `user.uuid` is available in the tRPC session context
- [ ] Note: API v2 does not have a reschedule request endpoint, so no API v2 changes are needed
2026-01-09 14:03:01 +05:30
Pedro Castro d9aef5b6a6 fix: add URL validation for logo fields (#26522)
* fix(auth): add URL validation for organization logo fields

- Add URL validation utility for server-side fetched URLs
- Validate logo URLs in tRPC organization schema
- Validate logo URLs in API v2 team DTOs
- Add graceful fallback in logo route for invalid URLs
- Only allow HTTPS and image data URLs
- Add unit tests for URL validation

* fix: add missing IP range and type validation

- Add RFC 6598 CGNAT range (100.64.0.0/10) to blocked IPs
- Add @IsString() decorator before custom URL validators
- Add boundary tests for new IP range

* fix: address review feedback

   - Export validateUrlForSSRFSync via @calcom/platform-libraries
   - Fix nullable/optional order in Zod schema

* fix: block localhost hostname and explicit null check

- Add localhost to BLOCKED_HOSTNAMES for sync validation
- Use explicit null check (url == null) instead of falsy check

* fix: allow empty string in URL validation

* refactor: extract shared validation logic

- Extract validateUrlCore() to eliminate duplication between sync/async versions
- Add JSDoc to all exported functions for better discoverability
- Remove redundant comments that repeated function names
- Simplify existing comments to be more concise

* fix: reject empty strings in URL validator

Previously if (!url) allowed empty strings to bypass validation.
Now explicitly checks for null/undefined only
2026-01-08 22:03:54 +00:00
Volnei Munhoz a5387bbffe update yarn lock (#26596) 2026-01-08 18:59:03 +00:00
ccff0045fc fix: Add email verification requirement for API v1 and v2 email updates (#24988)
* fix: Add email verification requirement for API v1 and v2 email updates

- API v2 (/v2/me): Implement email verification check when updating primary email
  - Store new email in metadata as emailChangeWaitingForVerification when verification is required
  - Send verification email using sendChangeOfEmailVerification
  - Allow immediate email change if new email is already a verified secondary email
  - Add hasEmailBeenChanged and sendEmailVerification flags to response
  - Add tests to verify email verification behavior
  - Add findVerifiedSecondaryEmail method to UsersRepository
  - Add PrismaFeaturesRepository to MeModule providers

- API v1 (/v1/users/{userId}): Implement same email verification logic
  - Check if email-verification feature flag is enabled
  - Store new email in metadata when verification is required
  - Send verification email for unverified email changes
  - Allow immediate change for verified secondary emails
  - Preserve existing API v1 response format

- Test fixtures: Add createSecondaryEmail method to UserRepositoryFixture

This fixes the vulnerability where users could update their primary email
without verification via API endpoints.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* update

* update

* refactor: Extract business logic to MeService and add platform-managed bypass

- Create MeService with all business logic extracted from MeController
- Update MeController to delegate to MeService (thin controller pattern)
- Add PrismaWorkerModule to MeModule imports to provide PrismaWriteService
- Add isPlatformManaged bypass: platform-managed users can update email without verification
- Fix test cleanup to use delete by ID instead of email to avoid failures when email changes
- Remove hasEmailBeenChanged and sendEmailVerification response flags per reviewer feedback
- Add comprehensive documentation to @ApiOperation describing email verification behavior
- Update tests to remove flag assertions

Addresses PR comments:
- supalarry: Extract logic to service layer
- supalarry: Allow platform-managed users to update email without verification
- supalarry: Remove response flags and document behavior in @ApiOperation instead
- cubic-dev-ai: Fix module dependency for PrismaFeaturesRepository
- cubic-dev-ai: Fix test cleanup issue

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* docs: Simplify API operation description

Remove internal implementation details about metadata staging and shorten the description to focus on API consumer behavior.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix

* update

* update

* update

* remove comment

* addressed commit

* review addressed

* use repository

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 15:51:11 +00:00
Alex van Andel 23ecd1c906 refactor: First high level changes to getUsersAvailability (#26566)
* refactor: First high level changes to getUsersAvailability

* Fix usage of getUserAvailability where getUsersAvailability is unused

* Fix user.schema.ts in APIv2

* User handler did not provide initial data

* Small ts fixes

* Set user non-nullable in getTimezoneFromDelegatedCredential

* Small ts fixes, ensure consumers are aware its nonnullable

* Mode is defaulted to none

* Mode is defaulted to none, fix ts when directly using fn (temp)
2026-01-08 14:45:26 +00:00
Pedro CastroandKeith Williams f8dcc6b13d fix: filter Google Workspace credentials by current user (#26216)
* fix: filter Google Workspace credentials by current user

Add userId filter to getUsersFromGWorkspace credential query and add
unit tests for all googleWorkspace handler functions. Also fix OAuth2Client
import to use google-auth-library for proper type compatibility

* refactor(tests): improve googleWorkspace handler test structure

Move dynamic imports to beforeEach block to reduce repetition
and improve test readability

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-08 14:44:50 +00:00
f629b61be7 fix: capitalize German 'Uhr' in 24-hour time format (#25403)
* fix: capitalize German 'Uhr' in 24-hour time format

- Conditionally apply toLowerCase() only for 12-hour format (AM/PM)
- Preserve proper capitalization for 24-hour format in German and other locales
- German 'Uhr' now displays correctly as 'Uhr' instead of 'uhr'

Fixes #24455

* refactor: remove code comments for clarity

* use ternary in return instead of mutable variable

* refactor: remove toLowerCase from time formatting

* addressed cubic suggestion

---------

Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
2026-01-08 14:25:50 +00:00
Mehmet SungurandPallav 9c4754dfcc fix(ui): prevent nested <p> hydration errors in confirmation dialogs (#25643)
Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
2026-01-08 10:27:11 -03:00
ac3699dcb4 fix: set attendeeSeatId in evt for seated booking reschedule emails (#26498)
* fix: set attendeeSeatId in evt for seated booking reschedule emails

When an attendee reschedules a seated booking, the reschedule/cancel links
in emails were using bookingUid instead of seatUid after the first reschedule.
This was because evt.attendeeSeatId was not being set before sending the email.

This fix ensures that evt.attendeeSeatId is set to bookingSeat.referenceUid
so that the email links consistently use seatUid for seated bookings.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* test: add E2E test for seatUid preservation across multiple reschedules

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: use valid time slots within availability window for E2E test

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: make E2E test self-contained to avoid shared state issues

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update E2E test to validate seatUid usability across reschedules

Co-Authored-By: morgan@cal.com <morgan@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 14:15:40 +02:00
a62eb2bdac refactor: replace shouldServeCache with mode parameter for calendar cache control (#26539)
* refactor: replace shouldServeCache with mode parameter for calendar cache control

Replace the boolean shouldServeCache parameter with a new CalendarFetchMode type
that can have values 'slots', 'overlay', and 'booking'. This provides better
control over when to serve cache vs relay on calendar providers.

- 'slots' mode: Check feature flags and use cache when available (for getting
  actual calendar availability)
- 'overlay' mode: Don't use cache (for overlay calendar availability)
- 'booking' mode: Don't use cache (for booking confirmation)
- undefined: Same as 'slots' for backwards compatibility

The cache decision logic is now centralized in getCalendar.ts based on the mode
parameter.

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: update CalendarService.test.ts to use mode parameter

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: use shared GetAvailabilityParams type across all calendar services

- Import GetAvailabilityParams and GetAvailabilityWithTimeZonesParams from @calcom/types/Calendar
- Replace inline type definitions with shared types in all calendar service implementations
- Update BaseCalendarService, CalendarCacheWrapper, and CalendarTelemetryWrapper
- Ensures consistent typing and follows DRY principles

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add missing IntegrationCalendar import and update mock getAvailability signature

- Add IntegrationCalendar back to sendgrid CalendarService imports
- Update bookingScenario mock getAvailability to use typed params object
- Add listCalendars method to mock Calendar object

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: update test files to use typed params object for getAvailability methods

- Update CalendarCacheWrapper.test.ts to call getAvailability/getAvailabilityWithTimeZones with params object
- Update getCalendarsEvents.test.ts toHaveBeenCalledWith assertions to expect params object
- All 32 tests now pass

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: consolidate to single GetAvailabilityParams type for both getAvailability methods

- Remove GetAvailabilityWithTimeZonesParams, use GetAvailabilityParams for both methods
- Add mode parameter to getAvailabilityWithTimeZones calls
- Update wrapper classes to pass mode through to underlying calendar
- Update test files to include mode in getAvailabilityWithTimeZones calls and assertions

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: use EventBusyDate with optional timeZone for getAvailabilityWithTimeZones

- Add optional timeZone field to EventBusyDate type
- Update getAvailabilityWithTimeZones return type to use EventBusyDate[]
- Update Google Calendar service and wrapper classes to use the new type

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: type errors and remove unused calendar watching methods

- Fix type errors in CalendarCacheWrapper.ts (convert null to undefined for timeZone)
- Fix type errors in getCalendarsEvents.ts (ensure timeZone is always present)
- Remove unused watchCalendar/unwatchCalendar from Calendar interface
- Remove unused startWatchingCalendarsInGoogle/stopWatchingCalendarsInGoogle from GoogleCalendarService
- Remove unused imports (uuid, uniqueBy, GOOGLE_WEBHOOK_URL, ONE_MONTH_IN_MS)

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: remove watchCalendar/unwatchCalendar from CalendarTelemetryWrapper

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: remove verbose JSDoc param comments from wrapper classes

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: make mode parameter required in getCalendar

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add required mode parameter to all getCalendar callers

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: provide default mode value in getBusyCalendarTimes

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to remaining getCalendar callers

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to vital and wipemycalother reschedule

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to credential-sync API endpoint

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: add 'none' mode to CalendarFetchMode and use as default

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* test: add mode parameter to getCalendarsEvents test calls

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* Update packages/app-store/delegationCredential.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-08 09:07:41 -03:00
Syed Ali Shahbazandcubic-dev-ai[bot] 59fca85d92 fix: use graceful filtering for previously hard failing blocked users in team events (#26446)
* init

* typefix

* --

* fix test

* update index

* cleanup

* rm unnecessary comments

* improvements

* add tests

* test fixes

* fixes

* fixes

* fixes

* add try catch to make booking fail-open

* Update packages/features/watchlist/operations/check-user-blocking.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix type

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-08 08:30:54 -03:00
Benny JooandDevin AI f5d345b133 refactor: remove @calcom/web imports from @calcom/features and add @calcom/testing package (#26480)
* fix: remove @calcom/web imports from packages/features to eliminate circular dependency

- Migrate UserTableUser and MemberPermissions types to packages/features/users/types/user-table.ts
- Migrate useGeo hook to packages/features/geo/GeoContext.tsx
- Migrate buildLegacyRequest to packages/lib/buildLegacyCtx.ts
- Migrate Calendar component to packages/features/calendars/weeklyview/components/
- Move test utilities (bookingScenario, fixtures) to packages/features/test/
- Update all imports in packages/features to use new locations
- Add re-exports in apps/web for backward compatibility

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: delete original implementation files and fix type issues

- Delete original calendar component files in apps/web (keep only re-export stubs)
- Migrate OutOfOfficeInSlots to packages/features/bookings/components
- Convert apps/web OutOfOfficeInSlots to re-export stub
- Fix className vs class issue in Calendar.tsx
- Fix @calcom/trpc import violation in user-table.ts by using structural type

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing isGroup and contains fields to UserTableUser attributes type

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update customRole type to match actual Prisma Role model

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix build

* fix

* fix

* cleanup weeklyview

* fix

* refactor to mv MemberPermissions to types package

* add types dependency to features

* fix

* fix

* fix

* fix

* fix

* fix

* rename

* rename

* migrate

* migrate

* migrate

* fix

* fix

* fix

* refactor: move test utilities from packages/features/test to tests/libs

- Move bookingScenario utilities to tests/libs/bookingScenario
- Move fixtures to tests/libs/fixtures
- Update all imports in packages/features test files to use new location
- Update all imports in apps/web test files to use new location
- Eliminates duplication of test utilities between packages/features and apps/web

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: correct relative import paths for tests/libs in test files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: replace test utility implementations with re-exports to tests/libs

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: fix test import paths and move signup handler tests to apps/web

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: move buildLegacyCtx to packages/lib and restore handlers to packages/features

- Move buildLegacyCtx from apps/web/lib to packages/lib to break circular dependency
- Update apps/web/lib/buildLegacyCtx.ts to re-export from @calcom/lib
- Restore signup handlers and tests to packages/features/auth/signup/handlers
- Update handler imports to use @calcom/lib/buildLegacyCtx instead of @calcom/web/lib/buildLegacyCtx

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update recurring-event.test.ts imports to use tests/libs path

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: delete test re-export files and update imports to use tests/libs directly

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update remaining test imports to use tests/libs directly

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update handleRecurringEventBooking calls to match function signature (1 arg)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* remove

* migrate tests

* migrate tests

* refactor: update test mock imports by removing  and using async  for mock creators.

* fix type errors

* fix: add type assertion for MockUser in p2002.test-suite.ts

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: restore locale import in compareReminderBodyToTemplate.test.ts using relative path

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* feat: create @calcom/testing package and migrate tests from /tests directory

- Created new @calcom/testing package in /packages/testing
- Moved all files from /tests to /packages/testing
- Updated all imports across the codebase to use @calcom/testing alias
- Removed /tests directory at root level

This allows other packages like @calcom/features and @calcom/web to import
testing utilities using the @calcom/testing alias instead of relative paths.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix

* fix: add missing useBookings export to @calcom/atoms package

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing useCalendarsBusyTimes and useConnectedCalendars exports to @calcom/atoms

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* chore: add @calcom/testing as explicit devDependency to packages that use it

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: move setupVitest.ts into @calcom/testing package

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* chore: add biome rules to restrict @calcom/testing imports

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* rename libs to lib

* rename libs to lib

* add rule

* add rule

* refactor: remove @calcom/features imports from @calcom/testing

- Move mockPaymentSuccessWebhookFromStripe to fresh-booking.test.ts
- Replace ProfileRepository.generateProfileUid() with uuidv4()
- Clone Tracking type into @calcom/testing/src/lib/types.ts
- Update imports in expects.ts and getMockRequestDataForBooking.ts
- Move source files into src/ folder
- Move CalendarManager mock to @calcom/features

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add explicit exports for nested paths in @calcom/testing

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* improve

* improve

* fix

* fix

* fix type checks

* fix type checks

* fix type checks

* fix tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 16:59:11 +09:00
Joe Au-YeungandDevin AI 0cf5de5ef8 fix: log Zoom token refresh errors at ERROR level (#26547)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 21:49:11 +00:00
Anik Dhabal Babu f54a3d1d0c test: all flaky unit tests (#26558) 2026-01-07 17:53:19 +00:00
Pallav cdd946cf39 refactor: single line app feature desc (#26553) 2026-01-07 17:27:52 +00:00
4585d7402d fix: BOOKING_PAID webhook & workflow isn't triggering after payment successful (#26044)
* fix booking paid webhook

* Update handlePaymentSuccess to include updatedBooking status

* Fix videoCallUrl undefined error in BOOKING_PAID workflow trigger

- Import getVideoCallUrlFromCalEvent to properly compute meeting URL
- Use conditional metadata to avoid passing undefined videoCallUrl
- Matches original handleConfirmation.ts behavior

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Add missing schedulingType to calendarEventForWorkflow

- Added schedulingType field to match original handleConfirmation.ts behavior
- This field was present in the original implementation but missing in the refactor

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Fix paymentMetadata nullability to match original behavior

- Changed from ?? null to optional chaining (undefined) to match original handleConfirmation.ts
- This ensures webhook consumers using z.string().optional() schemas continue to work
- undefined values are omitted from JSON, while null values would be explicitly included

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Fix type errors: add schedulingType to getBooking and use null for metadata

- Added schedulingType to getBooking.ts eventType select to make it available
- Changed paymentMetadata to use ?? null instead of undefined for type compatibility
- The metadata type expects { [key: string]: string | number | boolean | null }

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* await

* add tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 15:00:54 +00:00
2cadc0b1e9 fix: remove shouldServeCache in getCalendarEvent getAvailability call (#26541)
* fix: remove shouldServeCache in getCalendarEvent getAvailability call

* test: remove shouldServeCache parameter from getAvailability test expectations

Co-Authored-By: morgan@cal.com <morgan@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 19:55:47 +05:30
Dhairyashil Shinde dcf10935de feat: add missing event type fields for advanced settings in api v2 (#25739)
* feat: api v2 add missing event type fields for advanced settings

Add 9 event type fields to API v2 that were available in tRPC but missing from the platform API:

- disableCancelling: disable cancelling for guests/organizer
- disableRescheduling: disable rescheduling for guests/organizer
- canSendCalVideoTranscriptionEmails: send Cal Video transcription emails
- autoTranslateInstantMeetingTitleEnabled: auto-translate instant meeting titles
- interfaceLanguage: preferred booking interface language
- allowReschedulingPastBookings: allow rescheduling past events
- allowReschedulingCancelledBookings: allow booking via reschedule link
- customReplyToEmail: custom reply-to email for confirmations
- showOptimizedSlots: optimize time slot arrangement

Updated output/input schemas, transformation services, and E2E tests.

* fix(api-v2): add proper OpenAPI types for nullable event type fields

Add explicit type and nullable properties to @ApiPropertyOptional decorators
for fields with `boolean | null` or `string | null` types. Without these,
Swagger was generating incorrect "type": "object" instead of the correct types.

Fixed fields:
- disableCancelling: type: Boolean, nullable: true
- disableRescheduling: type: Boolean, nullable: true
- interfaceLanguage: type: String, nullable: true
- allowReschedulingCancelledBookings: type: Boolean, nullable: true
- customReplyToEmail: type: String, nullable: true
- showOptimizedSlots: type: Boolean, nullable: true

* refactor: customReplyToEmail was intentionally excluded from this PR. The web UI
restricts this field to only allow the user's own verified emails via a
dropdown, but implementing the same validation in the API requires additional
business logic. This will be addressed in a separate PR with proper email
ownership validation.

* feat(api-v2): add validation for interfaceLanguage field

Add @IsIn validation to interfaceLanguage field to only accept supported
locales. This ensures API v2 matches the web UI behavior where users can
only select from a predefined dropdown of supported languages.

Changes:
- Add SUPPORTED_LOCALES constant to @calcom/platform-constants
- Add @IsIn([...SUPPORTED_LOCALES]) validation to create/update DTOs
- Add E2E tests for invalid locale rejection (400 error)
- Add cross-reference comments in i18n.json and api.ts to keep in sync

* docs(api): add default values to event type input field documentation

Added default value documentation to @DocsPropertyOptional decorators
for the new event type fields in API v2 (2024_06_14):

- disableCancelling: false
- disableRescheduling: false
- canSendCalVideoTranscriptionEmails: true
- autoTranslateInstantMeetingTitleEnabled: false
- allowReschedulingPastBookings: false
- allowReschedulingCancelledBookings: false
- showOptimizedSlots: false

This improves API documentation by clearly communicating default
values to API consumers in the OpenAPI spec.

* feat(api-v2): refactor event type settings to object types for future extensibility

- Convert disableRescheduling from boolean to object with disabled and minutesBefore properties
- Convert disableCancelling from boolean to object with disabled property
- Move canSendCalVideoTranscriptionEmails into CalVideoSettings as sendTranscriptionEmails
- Remove autoTranslateInstantMeetingTitleEnabled (Enterprise-only feature)
- Add DisableRescheduling_2024_06_14 and DisableCancelling_2024_06_14 input/output types
- Add transformation methods for new object types in input and output services
- Update E2E tests for new API contract

BREAKING CHANGE: disableRescheduling and disableCancelling now accept objects instead of booleans

* fix(api-v2): prevent clearing calVideoSettings when only sendTranscriptionEmails is provided

Only include calVideoSettings in transformed output if it has properties,
avoiding unintentional reset of existing settings during updates.
2026-01-07 16:03:01 +02:00
4571215794 feat(calendar-subscription): add telemetry metrics for cache performance and webhook calls (#26501)
* feat(calendar-subscription): add telemetry metrics for cache performance and webhook calls

- Add Sentry span telemetry to CalendarCacheWrapper.getAvailability() and getAvailabilityWithTimeZones() to measure:
  - Cache fetch duration (cacheFetchDurationMs)
  - Original calendar fetch duration (originalFetchDurationMs)
  - Number of calendars from cache vs original source
  - Number of events from each source
  - Whether cache was used (cacheUsed)

- Add Sentry span telemetry to CalendarSubscriptionService.processWebhook() to track:
  - Provider (google_calendar, office365_calendar)
  - Success/failure status
  - Processing duration (durationMs)
  - Error messages on failure
  - Channel ID and selected calendar ID

- Create telemetry module with types, sentry-span, and no-op-span implementations

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor(calendar-subscription): move telemetry to @calcom/lib for reusability

- Add withSpan helper to @calcom/lib/sentryWrapper for reusable telemetry
- Update CalendarCacheWrapper to use withSpan from @calcom/lib
- Update CalendarTelemetryWrapper to use withSpan from @calcom/lib
- Update CalendarSubscriptionService to use withSpan from @calcom/lib
- Remove old telemetry module from calendar-subscription feature
- Add telemetry tracking when cache is disabled for performance comparison

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix(calendar-subscription): only apply telemetry wrapper when Sentry is configured

- Fix unit test failures by checking if Sentry is configured before wrapping
- Remove ESLint inline rules from getCalendar.ts

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor(calendar-subscription): move CalendarTelemetryWrapper to telemetry directory

- Move CalendarTelemetryWrapper from cache/ to telemetry/ directory
- Update import path in getCalendar.ts

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* feat(telemetry): add console fallback when Sentry is not configured

- Add console logging fallback in development mode when Sentry is not configured
- Create isTelemetryEnabled() helper to check if telemetry should be enabled
- Update getCalendar.ts to use isTelemetryEnabled() helper
- Logs span name, operation, duration, and attributes to console via @calcom/lib/logger

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor(calendar-subscription): wrap all calendars with CalendarTelemetryWrapper

- CalendarTelemetryWrapper now wraps ALL cache-supported calendars with cacheEnabled parameter
- CalendarCacheWrapper keeps cache-specific metrics with distinct op (calendar.cache.internal.*)
- CalendarTelemetryWrapper uses canonical op (calendar.getAvailability) for consistent querying
- Nested spans: outer telemetry wrapper measures end-to-end, inner cache wrapper measures cache internals

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 11:27:40 +00:00
61a932f8f5 feat: OAuth2 controller api v2 + refactor oAuth Trpc handlers (#25989)
* feat(api-v2): add OAuth2 controller skeleton for auth module

- Add new OAuth2 module under /auth with controller, service, repository, and DTOs
- Implement skeleton endpoints:
  - GET /v2/auth/oauth2/clients/:clientId - Get OAuth client info
  - POST /v2/auth/oauth2/clients/:clientId/authorize - Generate authorization code
  - POST /v2/auth/oauth2/clients/:clientId/exchange - Exchange code for tokens
  - POST /v2/auth/oauth2/clients/:clientId/refresh - Refresh access token
- Create input DTOs for authorize, exchange, and refresh operations
- Create output DTOs for client info, authorization code, and tokens
- Register OAuth2Module in endpoints.module.ts

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: add missing functions to platform libraries

* feat(api-v2): integrate OAuthService from platform-libraries into OAuth2 controller

- Add OAuthService export to platform-libraries
- Refactor OAuth2Service to use OAuthService.validateClient() and OAuthService.verifyPKCE()
- Remove duplicate local implementations of validateClient and verifyPKCE methods

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): use local validateClient and verifyPKCE implementations

- Remove OAuthService export from platform-libraries (will be deprecated)
- Reimplement validateClient and verifyPKCE methods locally in OAuth2Service
- Use verifyCodeChallenge and generateSecret from platform-libraries directly

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor(api-v2): separate repositories for OAuth2, access codes, and teams

- Create AccessCodeRepository for access code Prisma operations
- Add findTeamBySlugWithAdminRole method to TeamsRepository
- Move generateAuthorizationCode, createTokens, verifyRefreshToken to OAuth2Service
- Update OAuth2Repository to only contain OAuth client operations
- Update OAuth2Module to import TeamsModule and provide AccessCodeRepository

Addresses PR review comments to properly separate concerns

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): implement JWT token creation and verification for OAuth2

- Implement createTokens method using jsonwebtoken to sign access and refresh tokens
- Implement verifyRefreshToken method to verify JWT refresh tokens
- Add ConfigService injection for CALENDSO_ENCRYPTION_KEY access
- Import ConfigModule in OAuth2Module for dependency injection

Based on logic from apps/web/app/api/auth/oauth/token/route.ts and
apps/web/app/api/auth/oauth/refreshToken/route.ts

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: refactor and dayjs import fix

* feat(api-v2): add ApiAuthGuard to getClient endpoint and e2e tests for OAuth2

- Add @UseGuards(ApiAuthGuard) to getClient endpoint for authentication
- Add comprehensive e2e tests for all OAuth2 endpoints:
  - GET /v2/auth/oauth2/clients/:clientId
  - POST /v2/auth/oauth2/clients/:clientId/authorize
  - POST /v2/auth/oauth2/clients/:clientId/exchange
  - POST /v2/auth/oauth2/clients/:clientId/refresh
- Tests cover happy paths and error cases (invalid client, invalid code, etc.)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore(api-v2): hide OAuth2 endpoints from Swagger documentation

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* hide endpoints from doc

* fix(api-v2): address PR feedback for OAuth2 controller

- Fix P0 critical bug: token_type field name mismatch in DecodedRefreshToken interface
- Add @Equals('authorization_code') validation to exchange.input.ts grantType
- Add @Equals('refresh_token') validation to refresh.input.ts grantType
- Add @IsNotEmpty() validation to get-client.input.ts clientId
- Add @Expose() decorators to all output DTOs for proper serialization
- Add security test assertion to verify clientSecret is not returned in response

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): implement redirect behavior for OAuth2 authorize endpoint

- Update authorize endpoint to return HTTP 303 redirect with authorization code
- Add exact match validation for redirect URI (security requirement)
- Implement error handling with redirect to redirect URI and error query params
- Add state parameter support for CSRF protection
- Update e2e tests to verify redirect behavior (303 status, Location header, error redirects)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor(api-v2): address PR feedback for OAuth2 authorize endpoint

- Make redirectUri a required input parameter (remove optional fallback)
- Move buildRedirectUrl and mapErrorToOAuthError to oauth2Service
- Add return statements to res.redirect() calls
- Simplify controller by delegating redirect URL building to service

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* wip move code outside of api v2

* feat(oauth): wire up dependency injection for OAuthService and repositories

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor: oAuthService used in routes

* fix imports

* fix(api-v2): return 404 for invalid client ID instead of redirect in authorize endpoint

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api-v2): fix E2E test URL paths and remove bootstrap() in authenticated section

- Remove bootstrap() call in authenticated section to match working test pattern
- Change URL paths from /api/v2/... to /v2/... in authenticated section
- Keep bootstrap() and /api/v2/... paths in unauthenticated section

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api-v2): mock getToken from next-auth/jwt for E2E tests

- Add jest.mock for next-auth/jwt getToken function
- Mock returns null for unauthenticated tests
- Mock returns { email: userEmail } for authenticated tests
- Remove withNextAuth helper since ApiAuthGuard uses ApiAuthStrategy
  which calls getToken directly, not NextAuthStrategy

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix tests and code review

* cleanup generate secrets

* cleanup controller

* chore: remove console.log from OAuthService.validateClient

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* Update apps/web/app/api/auth/oauth/refreshToken/route.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix(api-v2): add bootstrap() to authenticated E2E tests and update URL paths to /api/v2/

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* Merge remote-tracking branch 'origin/devin/oauth2-controller-skeleton-1765988792' and remove console.log from token route

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: remove dead code

* refactor

* refactor: generateAuthCode trpc handler and getClient trpc handler

* remove pkce check for refreshToken endpoint

* Update packages/trpc/server/routers/viewer/oAuth/getClient.handler.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* refactor: error handling

* refactor: error handling

* refactor: error handling

* remove console log

* provide redirectUri in generateAuthCodeHandler

* provide redirectUri in authorize view

* refactor: replace HttpError with ErrorWithCode in OAuth files

- Update OAuthService to use ErrorWithCode instead of HttpError
- Update mapErrorToOAuthError to check ErrorCode instead of status codes
- Update token/route.ts and refreshToken/route.ts to use ErrorWithCode
- Add ErrorWithCode export to platform-libraries
- Use getHttpStatusCode to map ErrorCode to HTTP status codes

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update generateAuthCode handler to use ErrorWithCode instead of HttpError

The handler was still checking for HttpError in its catch block, but OAuthService
now throws ErrorWithCode. This caused the error messages to be lost and replaced
with 'server_error' instead of the specific error messages.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update OAuth2 controller to use ErrorWithCode instead of HttpError

The controller was still checking for HttpError in its catch blocks, but OAuthService
now throws ErrorWithCode. This caused all errors to return 500 Internal Server Error
instead of the correct HTTP status codes (400, 401, 404).

Also added getHttpStatusCode export to platform-libraries.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: add explicit unknown type annotation to catch blocks in OAuth2 controller

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: change NotFoundException to HttpException in authorize endpoint

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: handle err with ErrorWithCode in authorize endpoint catch block

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: move errorWithCode

* fix: error code rfc

* fix: no need to handle errors there is a middleware

* refactor errors

* refactor errors

* refactor redirecturi and state from api

* refactor: address PR comments for OAuth2 controller

- Remove unused GetOAuth2ClientInput class
- Change API tag from 'Auth / OAuth2' to 'OAuth2'
- Move OAuthClientFixture to separate fixture file (oauth2-client.repository.fixture.ts)
- Add 'type' property to OAuth2ClientDto for confidential/public client type
- Rename 'clientId' to 'id' in OAuth2ClientDto (using @Expose mapping)
- Clean up duplicate provider declarations in oauth2.module.ts
- Update e2e tests to use new fixture and verify type property

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Volnei Munhoz <volnei.munhoz@gmail.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-07 08:05:21 -03:00
Hariom Balhara ca32f04cc1 chore: Integrate booking cancellation audit (#26458)
## What does this PR do?
> **⚠️ Note: This PR does not enable booking audit in production.** The `BookingAuditTaskerProducerService` has an [`IS_PRODUCTION` guard](https://github.com/calcom/cal.com/blob/integrate-booking-creation-reschedule-audit/packages/features/booking-audit/lib/service/BookingAuditTaskerProducerService.ts#L106-L108) that skips audit task queueing in production environments. This allows the integration to be tested in development before enabling it in production.

Integrates audit logging for booking cancellations, following the pattern established in PR #26046 for booking creation/rescheduling audit.

- Related to #25125 (Booking Audit Infrastructure)

### Changes:
- Add audit logging for single booking cancellation via `onBookingCancelled`
- Add audit logging for bulk recurring booking cancellation via `onBulkBookingsCancelled`
- Pass `userUuid` and `actionSource` from webapp cancel route (WEBAPP)
- Pass `userUuid` and `actionSource` from API-v2 bookings service (API_V2)
- Create `getAuditActor` helper to derive actor from userUuid or create synthetic guest actor
- Add `getUniqueIdentifier` helper for generating unique actor identifiers
- Add warning log when `actionSource` is "UNKNOWN" for observability
- Add integration tests for booking cancellation audit

### Audit Data Captured:
- `cancellationReason` (simple string value)
- `cancelledBy` (simple string value)  
- `status` (old → new, e.g., "ACCEPTED" → "CANCELLED")

### Updates since last revision:
- Simplified `CancelledAuditActionService` schema: `cancellationReason` and `cancelledBy` are now stored as simple nullable strings instead of change objects (old/new), since cancellation is a one-time event where tracking previous values doesn't apply
- Added integration tests for cancelled booking audit in `booking-audit-cancelled.integration-test.ts`
- Added `getUniqueIdentifier` helper function in actor.ts for generating unique identifiers with prefixes

## Mandatory Tasks (DO NOT REMOVE)

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

## How should this be tested?

1. Cancel a single booking via the webapp - verify audit record is created with actor and actionSource="WEBAPP"
2. Cancel a single booking via API v2 - verify audit record is created with actionSource="API_V2"
3. Cancel all remaining bookings in a recurring series - verify bulk audit records are created with shared operationId
4. Cancel via unauthenticated cancel link - verify guest actor is created with synthetic email (prefixed with "param-" or "fallback-")
5. Run integration tests: `yarn test packages/features/booking-audit/lib/service/__tests__/booking-audit-cancelled.integration-test.ts`

## Human Review Checklist

- [ ] Verify `onBookingCancelled` and `onBulkBookingsCancelled` methods exist in `BookingEventHandlerService`
- [ ] Review the `getAuditActor` fallback logic - creates synthetic email with "fallback-" or "param-" prefix when no userUuid available
- [ ] Confirm the simplified schema for `cancellationReason`/`cancelledBy` (no longer tracking old→new) is intentional
- [ ] Note: Audit logging calls are awaited directly - if audit service fails, the cancellation will fail. Confirm this is the desired behavior.
- [ ] Verify `CancelledAuditDisplayData` type no longer includes `previousReason` and `previousCancelledBy` fields

---

Link to Devin run: https://app.devin.ai/sessions/42404e76a66946fe9e46fa07fb12e779
Requested by: @hariombalhara (hariom@cal.com)
2026-01-07 16:15:57 +05:30
110491ecb9 fix: generate compliant passwords using meeting_password_requirement (#26148)
* fix(zoomvideo): generate compliant passwords using meeting_password_requirement

- Add meetingPasswordRequirementSchema to parse Zoom's password policy settings
- Implement validatePasswordAgainstRequirements() to check if a password meets the policy
- Implement generateCompliantPassword() to create passwords that comply with the policy
- Update translateEvent() to use getCompliantPassword() which validates the default password
  or generates a new compliant one based on meeting_password_requirement
- Add meeting_password_requirement to the settings API filter
- Improve error handling for non-JSON responses in OAuthManager (XML validation errors)

This fixes the frequent 'Error in JSON parsing Zoom API response' errors caused by
Zoom returning XML validation errors when the password doesn't comply with the
account's password policy (e.g., numeric-only requirement).

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* refactor: use cleaner single-pass consecutive character check

- Replace nested-loop O(n*k) implementation with single-pass O(n) helper
- Add proper guard for consecutiveLength < 4 (Zoom allows 0, 4-8)
- Move consecutive check before only_allow_numeric to apply it for all cases
- Fix edge-case bug where consecutiveLength 1-3 could incorrectly reject passwords

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Optimize OAuth response handling

Refactor OAuth response validation to read body only once.

* Improve error handling in Zoom API response parsing

Refactor error handling for Zoom API response parsing to improve logging and clarity.

* Improve compliant password generation logic

Enhance password generation to avoid consecutive characters when numeric only is required.

* Remove password requirement handling from VideoApiAdapter

Removed meeting password requirement schema and related functions for password validation and generation.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 09:51:30 +00:00
Hariom Balhara 010ac9e8f2 Make booking-audit integration test utils reusable (#26526) 2026-01-07 14:22:09 +05:30
Pedro Castro 01be9f1ef2 fix: validate owner email on platform org creation (#26286)
Remove isPlatform bypass from owner verification to ensure users can only create organizations where they are the designated owner. Add test coverage for create and intentToCreateOrg handlers:

- Regression tests for isPlatform bypass fix
- Happy path for admin creating org for another user
2026-01-06 22:46:44 -03:00
Pedro Castro 30ef38804c refactor: use structured logger in video adapters (#26285)
- Remove debug console.log/console.error statements
- Add logger.debug for observability (meeting lifecycle events)
- Add logger.error with safe error pattern (message + name only)
- Fix error messages to avoid exposing response details
- Remove redundant try/catch blocks (errors propagate naturally)
2026-01-06 22:29:17 -03:00
b8b9251f76 fix: Support 10-digit phone numbers for Ivory Coast (+225) (#26465)
* fix: update ivory coast mask to 10 digits

* update formating for Benin numbers

---------

Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2026-01-06 22:31:21 +00:00
Pedro Castro 170203051f fix: handle existing users on invite token flow (#26217)
* fix(auth): validate user before signup with invite token

Validate if user already exists before creating account when
signing up with team or organization invite tokens. Existing users
are redirected to login to accept the invitation.

- Add user existence check in signup handlers
- Return 409 for existing users with redirect to login
- Extract signup fetch logic to dedicated module
- Add e2e test coverage

* fix(auth): address code review feedback

- Fix fetchSignup tests to use vi.spyOn for proper mock restoration
- Add content-type validation before parsing JSON response
- Guard against undefined error in Stripe callback
- Use t() for localized error message
- Fix race condition in handlers by catching P2002 on create

* fix(auth): address additional code review feedback

- Add INVALID_SERVER_RESPONSE constant to follow established pattern
- Check error.meta.target includes email before returning USER_ALREADY_EXISTS
to avoid false positives from other unique constraint violations
- Add select: { id: true } to user.create calls since downstream functions only
need the user id

* test: add unit tests for P2002 handling in signup handlers

- Add shared test suite covering all P2002 edge cases
- Ensure 409 only for email constraint violations
- Fix non-token paths to use atomic create + catch pattern

* fix: update error message copy per review feedback

* fix(auth): address code review feedback and prevent orphan Stripe customers

- Add user existence check before Stripe customer creation (token flow)
- Add select clause to user.create for consistency
- Fix showToast argument order (pre-existing bug)
- Use toHaveURL instead of waitForURL in E2E tests

* fix(auth): resolve 500 errors by fixing Prisma error detection across module boundaries

The instanceof check for PrismaClientKnownRequestError fails when different
Prisma client instances are loaded. Added fallback check by constructor name

* fix(auth): validate invitedTo before upsert on team invite signup

* test(auth): update P2002 tests for new invite flow

P2002 tests now use non-token flow since token flow uses upsert
Added tests for invitedTo validation on invite signup

* fix(auth): add guards and P2002 handling per review feedback

- Guard existingUser check with if (foundToken?.teamId)
- Guard username check with if (username) for premium flow
- Add `select` clause to findFirst/findUnique queries
- Add try-catch on upsert for race condition P2002 errors

* fix(auth): narrow P2002 handling to email/username targets
2026-01-06 22:10:36 +00:00
8b5d9202db refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency (#26515)
* refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: use Prisma types from generated client instead of custom types

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 18:09:07 +00:00