Skip to content

Commit b1eb5a2

Browse files
feat: api v2 POST booking attendees endpoint (calcom#27759)
* feat: add booking attendee endpoint * chore: add attendee added email for add guests handler * cleanup * fix: restore BookingPbacGuard to prevent IDOR vulnerability in booking attendees endpoint Co-Authored-By: unknown <> * chore: implement review feedback, add a core service for booking attendees endpoint * chore: implement PR feedback * fix: dont reuse add guests handler instead add logic to add attendee function * fix: revert previous changes * chore: implement cubic feedback * fix: e2e tests * fix: e2e tests * fix: remove convertTRPCErrorToErrorWithCode not needed --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent bd5d94a commit b1eb5a2

19 files changed

Lines changed: 1053 additions & 104 deletions

File tree

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { Module } from "@nestjs/common";
2+
import { BookingAttendeesController_2024_08_13 } from "@/ee/bookings/2024-08-13/controllers/booking-attendees.controller";
13
import { BookingGuestsController_2024_08_13 } from "@/ee/bookings/2024-08-13/controllers/booking-guests.controller";
24
import { BookingLocationController_2024_08_13 } from "@/ee/bookings/2024-08-13/controllers/booking-location.controller";
35
import { BookingsController_2024_08_13 } from "@/ee/bookings/2024-08-13/controllers/bookings.controller";
46
import { BookingPbacGuard } from "@/ee/bookings/2024-08-13/guards/booking-pbac.guard";
57
import { BookingReferencesRepository_2024_08_13 } from "@/ee/bookings/2024-08-13/repositories/booking-references.repository";
68
import { BookingsRepository_2024_08_13 } from "@/ee/bookings/2024-08-13/repositories/bookings.repository";
9+
import { BookingAttendeesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-attendees.service";
710
import { BookingGuestsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-guests.service";
811
import { BookingLocationService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-location.service";
912
import { BookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-references.service";
@@ -12,17 +15,18 @@ import { CalVideoOutputService } from "@/ee/bookings/2024-08-13/services/cal-vid
1215
import { CalVideoService } from "@/ee/bookings/2024-08-13/services/cal-video.service";
1316
import { ErrorsBookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/errors.service";
1417
import { InputBookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/input.service";
15-
import { OutputBookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/output-booking-references.service";
1618
import { OutputBookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/output.service";
19+
import { OutputBookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/output-booking-references.service";
1720
import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.service";
1821
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
19-
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
2022
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
23+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
2124
import { EventTypesModule_2024_04_15 } from "@/ee/event-types/event-types_2024_04_15/event-types.module";
2225
import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module";
2326
import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository";
2427
import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service";
2528
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
29+
import { BookingEventHandlerModule } from "@/lib/modules/booking-event-handler.module";
2630
import { InstantBookingModule } from "@/lib/modules/instant-booking.module";
2731
import { RecurringBookingModule } from "@/lib/modules/recurring-booking.module";
2832
import { RegularBookingModule } from "@/lib/modules/regular-booking.module";
@@ -50,8 +54,6 @@ import { TeamsModule } from "@/modules/teams/teams/teams.module";
5054
import { TokensModule } from "@/modules/tokens/tokens.module";
5155
import { TokensRepository } from "@/modules/tokens/tokens.repository";
5256
import { UsersModule } from "@/modules/users/users.module";
53-
import { Module } from "@nestjs/common";
54-
import { BookingEventHandlerModule } from "@/lib/modules/booking-event-handler.module";
5557

5658
@Module({
5759
imports: [
@@ -81,6 +83,7 @@ import { BookingEventHandlerModule } from "@/lib/modules/booking-event-handler.m
8183
OAuthClientRepository,
8284
OAuthClientUsersService,
8385
BookingsService_2024_08_13,
86+
BookingAttendeesService_2024_08_13,
8487
BookingGuestsService_2024_08_13,
8588
InputBookingsService_2024_08_13,
8689
OutputBookingsService_2024_08_13,
@@ -110,6 +113,7 @@ import { BookingEventHandlerModule } from "@/lib/modules/booking-event-handler.m
110113
],
111114
controllers: [
112115
BookingsController_2024_08_13,
116+
BookingAttendeesController_2024_08_13,
113117
BookingGuestsController_2024_08_13,
114118
BookingLocationController_2024_08_13,
115119
],
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { BOOKING_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
2+
import { AddAttendeeInput_2024_08_13 } from "@calcom/platform-types";
3+
import { Body, Controller, HttpCode, HttpStatus, Param, Post, UseGuards } from "@nestjs/common";
4+
import { ApiHeader, ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
5+
import { BookingPbacGuard } from "@/ee/bookings/2024-08-13/guards/booking-pbac.guard";
6+
import { BookingUidGuard } from "@/ee/bookings/2024-08-13/guards/booking-uid.guard";
7+
import { AddAttendeeOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/add-attendee.output";
8+
import { BookingAttendeesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-attendees.service";
9+
import { VERSION_2024_08_13, VERSION_2024_08_13_VALUE } from "@/lib/api-versions";
10+
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
11+
import { Throttle } from "@/lib/endpoint-throttler-decorator";
12+
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
13+
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
14+
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
15+
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
16+
import { ApiAuthGuardUser } from "@/modules/auth/strategies/api-auth/api-auth.strategy";
17+
18+
@Controller({
19+
path: "/v2/bookings/:bookingUid/attendees",
20+
version: VERSION_2024_08_13_VALUE,
21+
})
22+
@UseGuards(PermissionsGuard)
23+
@DocsTags("Bookings / Attendees")
24+
@ApiHeader({
25+
name: "cal-api-version",
26+
description: `Must be set to ${VERSION_2024_08_13}. This header is required as this endpoint does not exist in older API versions.`,
27+
example: VERSION_2024_08_13,
28+
required: true,
29+
})
30+
export class BookingAttendeesController_2024_08_13 {
31+
constructor(private readonly bookingAttendeesService: BookingAttendeesService_2024_08_13) {}
32+
33+
@Post("/")
34+
@HttpCode(HttpStatus.CREATED)
35+
@Permissions([BOOKING_WRITE])
36+
@UseGuards(ApiAuthGuard, BookingUidGuard, BookingPbacGuard)
37+
@Throttle({
38+
limit: 5,
39+
ttl: 60000,
40+
blockDuration: 60000,
41+
name: "booking_attendees_add",
42+
})
43+
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
44+
@ApiOperation({
45+
summary: "Add an attendee to a booking",
46+
description: `Add a new attendee to an existing booking by its UID.
47+
48+
**Side effects:**
49+
- The booking's attendee list is updated in the database
50+
- The calendar event is updated on connected calendars (Google Calendar, Outlook, etc.) to include the new attendee
51+
- An email notification is sent to the new attendee with the booking details
52+
53+
**Permissions:**
54+
- The authenticated user must be either the booking organizer, an existing attendee, or have the \`booking.update\` permission for the team
55+
56+
<Note>The cal-api-version header is required for this endpoint. Without it, the request will fail with a 404 error.</Note>
57+
`,
58+
})
59+
async addAttendee(
60+
@Param("bookingUid") bookingUid: string,
61+
@Body() body: AddAttendeeInput_2024_08_13,
62+
@GetUser() user: ApiAuthGuardUser
63+
): Promise<AddAttendeeOutput_2024_08_13> {
64+
const attendee = await this.bookingAttendeesService.addAttendee(bookingUid, body, user);
65+
66+
return {
67+
status: SUCCESS_STATUS,
68+
data: attendee,
69+
};
70+
}
71+
}

0 commit comments

Comments
 (0)