feat: Add private links to API#22943
Conversation
|
Note Reviews pausedUse the following commands to manage reviews:
WalkthroughAdds an Event Types Private Links feature across the API and platform packages. Introduces a NestJS module, controller, repository, input/output/core services, an ownership guard, and e2e tests; wires the module into PlatformEndpointsModule. Adds type and DTO definitions (inputs/outputs) and OpenAPI/Swagger schemas for time-based and usage-based private links. Exposes generateHashedLink and isLinkExpired via a new platform library export and updates HashedLinkService with per-event-type CRUD helpers. Adds tsconfig path alias and updates package exports and versions for platform-libraries. Also appends cal_ai_phone_call to multiple workflow action enums. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎ |
apps/api/v2/src/ee/event-types-private-links/services/private-links-input.service.ts
Show resolved
Hide resolved
apps/api/v2/src/ee/event-types-private-links/services/private-links.service.ts
Show resolved
Hide resolved
bdc2a69 to
f5b1a01
Compare
| expiresAt: input.expiresAt, | ||
| maxUsageCount: input.maxUsageCount, |
There was a problem hiding this comment.
These are both optional so if the user doesn't send either of these in the body, the default action is that it will create a one-time use private link
This comment was marked as resolved.
This comment was marked as resolved.
2 similar comments
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Graphite Automations"Add ready-for-e2e label" took an action on this PR • (08/11/25)1 label was added to this PR based on Keith Williams's automation. |
E2E results are ready! |
* --init * address change requests * adding further changes * address feedback * further changes * further clean-up * clean up * fix module import and others * add guards * remove unnecessary comments * remove unnecessary comments * cleanup * sort coderabbig suggestions * improve check * chore: bump platform libraries --------- Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com> Co-authored-by: supalarry <laurisskraucis@gmail.com>
…ice class with DI (#22974) * refactor: convert findQualifiedHostsWithDelegationCredentials to service class with DI - Create QualifiedHostsService class following UserAvailabilityService pattern - Add IQualifiedHostsService interface with prisma and bookingRepo dependencies - Create DI module and container for qualified hosts service - Update filterHostsBySameRoundRobinHost to accept prisma as parameter - Update all usage sites to use the new service: - loadAndValidateUsers.ts - slots/util.ts - test mocks in _post.test.ts - Maintain backward compatibility with original function export - Fix type issues in team properties (rrResetInterval, rrTimestampBasis) Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: update filterHostsBySameRoundRobinHost test to include prisma parameter - Add missing prisma parameter to all test function calls - Resolves unit test failure caused by function signature change Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: resolve type issues in FilterHostsService - Import PrismaClient type instead of using unknown - Fix type compatibility for BookingRepository constructor - Update test mocks to use proper BookingRepository type - Ensure all DI dependencies are properly typed Co-Authored-By: morgan@cal.com <morgan@cal.com> * refactor: rename DI files to CamelCase and update imports - Rename all files in packages/lib/di from kebab-case to CamelCase - Update 22 external files with import statements to use new file names - Update internal DI module files with corrected imports - Maintain consistency with TypeScript naming conventions Co-Authored-By: morgan@cal.com <morgan@cal.com> * chore: bump platform libs * chore: bump platform libs * fix: remove obsolete vitest mock after service class refactoring - Remove obsolete mock for old function module - Keep correct mock for new DI container - Resolves CI unit test failures Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: correct import path for calAIPhone zod-utils module Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: Booker active booking limit can't be switched off (#23005) * refactor: Get rid of `getServerSideProps` for /getting-started pages (#23003) * refactor * fix type check * fix: Remove Reporting page within Routing Forms (#22990) * fix error in handleNewBooking (#23011) Co-authored-by: CarinaWolli <wollencarina@gmail.com> * Documentation edits made through Mintlify web editor (#23007) Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> * fix: Contact support button position changed from absolute to fixed (#23002) * feat: Add private links to API (#22943) * --init * address change requests * adding further changes * address feedback * further changes * further clean-up * clean up * fix module import and others * add guards * remove unnecessary comments * remove unnecessary comments * cleanup * sort coderabbig suggestions * improve check * chore: bump platform libraries --------- Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com> Co-authored-by: supalarry <laurisskraucis@gmail.com> * chore: release v5.5.15 * chore: bump platform libs * chore: bump platform libs --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: morgan@cal.com <morgan@cal.com> Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Co-authored-by: Benny Joo <sldisek783@gmail.com> Co-authored-by: Sahitya Chandra <sahityajb@gmail.com> Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: Ayush Kumar <kumarayushkumar@protonmail.com> Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com> Co-authored-by: supalarry <laurisskraucis@gmail.com> Co-authored-by: emrysal <me@alexvanandel.com>
What does this PR do?
PR summary
Introduced Event Types Private Links API (v2)
/v2/event-types/{eventTypeId}/private-links/— create a private link/— list private links for an event type/{linkId}— update a private link/{linkId}— delete a private linkNew components
EventTypesPrivateLinksControllerPrivateLinksService,PrivateLinksInputService,PrivateLinksOutputServicePrivateLinksRepositoryEventTypeOwnershipGuardfor ownership checksValidation and behavior
CreatePrivateLinkInput:expiresAt: string, format date-timemaxUsageCount: integer, min 1, default 1UpdatePrivateLinkInput: supportsexpiresAtandmaxUsageCountupdatesEventTypeOwnershipGuardreturns 400 for missing/invalideventTypeId, 404 when not owned/not found, and 403 if no userMandatory Tasks (DO NOT REMOVE)
How should this be tested?
This is a V2 endpoint, so you would need to run the V2 API and then proceed with the following:
Auth
Authorization: Bearer <token>(API key prefixed withcal_or managed user token)EVENT_TYPE_READfor GET,EVENT_TYPE_WRITEfor POST/PATCH/DELETEEventTypeOwnershipGuardenforces the event type belongs to the callerCreate
/v2/event-types/{eventTypeId}/private-links{ "expiresAt": "2025-12-31T23:59:59.000Z" }{ "maxUsageCount": 10 }{ status: "success", data: TimeBasedPrivateLinkOutput | UsageBasedPrivateLinkOutput }List
/v2/event-types/{eventTypeId}/private-links{ status: "success", data: Array<TimeBasedPrivateLinkOutput | UsageBasedPrivateLinkOutput> }Update
/v2/event-types/{eventTypeId}/private-links/{linkId}{ "expiresAt": "…", "maxUsageCount": 5 }{ status: "success", data: TimeBasedPrivateLinkOutput | UsageBasedPrivateLinkOutput }Delete
/v2/event-types/{eventTypeId}/private-links/{linkId}{ status: "success", data: { linkId, message } }Checklist