feat(api-v2): add GET /v2/bookings/by-seat/{seatUid} endpoint (#26786)
* feat(api-v2): add GET /v2/bookings/by-seat/{seatUid} endpoint
- Add new endpoint to retrieve a booking by its seat reference UID
- Add getByReferenceUidIncludeBookingWithAttendeesAndUserAndEvent method to BookingSeatRepository
- Add getBookingBySeatUid method to BookingsService
- Add e2e tests for the new endpoint
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use Object.prototype.hasOwnProperty.call for ES compatibility in e2e tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use select instead of include in BookingSeatRepository for security and performance
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: add teamId and userId to eventType select for access check
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: return seatUid attendee when not admin and seatsShowAttendees is false
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use select for eventType in repository and fetch full eventType for access check
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
morgan@cal.com
Devin AI
parent
49a2fcaf65
commit
4367028492
@@ -1,3 +1,50 @@
|
||||
import { BOOKING_READ, BOOKING_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import {
|
||||
CancelBookingInput,
|
||||
CancelBookingInput_2024_08_13,
|
||||
CancelBookingInputPipe,
|
||||
CancelSeatedBookingInput_2024_08_13,
|
||||
CreateBookingInput,
|
||||
CreateBookingInput_2024_08_13,
|
||||
CreateBookingInputPipe,
|
||||
CreateInstantBookingInput_2024_08_13,
|
||||
CreateRecurringBookingInput_2024_08_13,
|
||||
DeclineBookingInput_2024_08_13,
|
||||
GetBookingOutput_2024_08_13,
|
||||
GetBookingRecordingsOutput,
|
||||
GetBookingsInput_2024_08_13,
|
||||
GetBookingsOutput_2024_08_13,
|
||||
GetBookingTranscriptsOutput,
|
||||
GetBookingVideoSessionsOutput,
|
||||
MarkAbsentBookingInput_2024_08_13,
|
||||
ReassignToUserBookingInput_2024_08_13,
|
||||
RescheduleBookingInput,
|
||||
RescheduleBookingInput_2024_08_13,
|
||||
RescheduleBookingInputPipe,
|
||||
RescheduleSeatedBookingInput_2024_08_13,
|
||||
} from "@calcom/platform-types";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Logger,
|
||||
Param,
|
||||
Post,
|
||||
Query,
|
||||
Req,
|
||||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import {
|
||||
ApiBody,
|
||||
ApiExtraModels,
|
||||
ApiHeader,
|
||||
ApiOperation,
|
||||
ApiTags as DocsTags,
|
||||
getSchemaPath,
|
||||
} from "@nestjs/swagger";
|
||||
import { Request } from "express";
|
||||
import { BookingPbacGuard } from "@/ee/bookings/2024-08-13/guards/booking-pbac.guard";
|
||||
import { BookingUidGuard } from "@/ee/bookings/2024-08-13/guards/booking-uid.guard";
|
||||
import { BookingReferencesFilterInput_2024_08_13 } from "@/ee/bookings/2024-08-13/inputs/booking-references-filter.input";
|
||||
@@ -11,7 +58,7 @@ import { RescheduleBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/out
|
||||
import { BookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/booking-references.service";
|
||||
import { BookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/bookings.service";
|
||||
import { CalVideoService } from "@/ee/bookings/2024-08-13/services/cal-video.service";
|
||||
import { VERSION_2024_08_13_VALUE, VERSION_2024_08_13 } from "@/lib/api-versions";
|
||||
import { VERSION_2024_08_13, VERSION_2024_08_13_VALUE } from "@/lib/api-versions";
|
||||
import {
|
||||
API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||
OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||
@@ -31,56 +78,6 @@ import { OptionalApiAuthGuard } from "@/modules/auth/guards/optional-api-auth/op
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { ApiAuthGuardUser } from "@/modules/auth/strategies/api-auth/api-auth.strategy";
|
||||
import { UsersService } from "@/modules/users/services/users.service";
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Logger,
|
||||
Body,
|
||||
UseGuards,
|
||||
Req,
|
||||
Get,
|
||||
Param,
|
||||
Query,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from "@nestjs/common";
|
||||
import {
|
||||
ApiOperation,
|
||||
ApiTags as DocsTags,
|
||||
ApiHeader,
|
||||
getSchemaPath,
|
||||
ApiBody,
|
||||
ApiExtraModels,
|
||||
} from "@nestjs/swagger";
|
||||
import { Request } from "express";
|
||||
|
||||
import { BOOKING_READ, BOOKING_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import {
|
||||
CancelBookingInput,
|
||||
CancelBookingInput_2024_08_13,
|
||||
CancelBookingInputPipe,
|
||||
CancelSeatedBookingInput_2024_08_13,
|
||||
GetBookingOutput_2024_08_13,
|
||||
GetBookingsOutput_2024_08_13,
|
||||
RescheduleBookingInput,
|
||||
RescheduleBookingInput_2024_08_13,
|
||||
RescheduleBookingInputPipe,
|
||||
RescheduleSeatedBookingInput_2024_08_13,
|
||||
GetBookingRecordingsOutput,
|
||||
GetBookingTranscriptsOutput,
|
||||
GetBookingVideoSessionsOutput,
|
||||
} from "@calcom/platform-types";
|
||||
import {
|
||||
CreateBookingInputPipe,
|
||||
CreateBookingInput,
|
||||
GetBookingsInput_2024_08_13,
|
||||
ReassignToUserBookingInput_2024_08_13,
|
||||
MarkAbsentBookingInput_2024_08_13,
|
||||
CreateBookingInput_2024_08_13,
|
||||
CreateInstantBookingInput_2024_08_13,
|
||||
CreateRecurringBookingInput_2024_08_13,
|
||||
DeclineBookingInput_2024_08_13,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/bookings",
|
||||
@@ -178,6 +175,33 @@ export class BookingsController_2024_08_13 {
|
||||
};
|
||||
}
|
||||
|
||||
@Get("/by-seat/:seatUid")
|
||||
@UseGuards(OptionalApiAuthGuard)
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
@ApiOperation({
|
||||
summary: "Get a booking by seat UID",
|
||||
description: `Get a seated booking by its seat reference UID. This is useful when you have a seatUid from a seated booking and want to retrieve the full booking details.
|
||||
|
||||
If you are fetching a seated booking for an event type with 'show attendees' disabled, then to retrieve attendees in the response either set 'show attendees' to true on event type level or
|
||||
you have to provide an authentication method of event type owner, host, team admin or owner or org admin or owner.
|
||||
|
||||
<Note>Please make sure to pass in the cal-api-version header value as mentioned in the Headers section. Not passing the correct value will default to an older version of this endpoint.</Note>
|
||||
`,
|
||||
})
|
||||
async getBookingBySeatUid(
|
||||
@Param("seatUid") seatUid: string,
|
||||
@GetOptionalUser() user: AuthOptionalUser
|
||||
): Promise<GetBookingOutput_2024_08_13> {
|
||||
const booking = await this.bookingsService.getBookingBySeatUid(seatUid, user);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: booking,
|
||||
};
|
||||
}
|
||||
|
||||
@Get("/:bookingUid")
|
||||
@UseGuards(BookingUidGuard, OptionalApiAuthGuard)
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
|
||||
+183
-2
@@ -364,6 +364,185 @@ describe("Bookings Endpoints 2024-08-13", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should get a booking by seatUid", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/bookings/by-seat/${createdSeatedBooking.seatUid}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: GetBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsGetSeatedBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsGetSeatedBooking(responseBody.data)) {
|
||||
const data: GetSeatedBookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.id).toEqual(createdSeatedBooking.id);
|
||||
expect(data.uid).toEqual(createdSeatedBooking.uid);
|
||||
expect(data.hosts[0].id).toEqual(user.id);
|
||||
expect(data.status).toEqual("accepted");
|
||||
expect(data.eventTypeId).toEqual(seatedEventTypeId);
|
||||
expect(data.eventType).toEqual({
|
||||
id: seatedEventTypeId,
|
||||
slug: seatedEventSlug,
|
||||
});
|
||||
expect(data.attendees.length).toEqual(2);
|
||||
} else {
|
||||
throw new Error(
|
||||
"Invalid response data - expected seated booking but received non seated booking response"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should return 404 when getting booking by non-existent seatUid", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get("/v2/bookings/by-seat/non-existent-seat-uid")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(404)
|
||||
.then(async (response) => {
|
||||
expect(response.body.error.message).toEqual(
|
||||
"Booking with seatUid=non-existent-seat-uid was not found in the database"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("get booking by seatUid with seatsShowAttendees disabled", () => {
|
||||
let bookingWithAttendeesDisabled: CreateSeatedBookingOutput_2024_08_13;
|
||||
let secondAttendeeSeatUid: string;
|
||||
const emailAttendeeThree = `seated-bookings-attendee3-${randomString()}@api.com`;
|
||||
const nameAttendeeThree = `Attendee Three ${randomString()}`;
|
||||
|
||||
it("should book first seat on event type with seatsShowAttendees disabled", async () => {
|
||||
const body: CreateBookingInput_2024_08_13 = {
|
||||
start: new Date(Date.UTC(2030, 0, 11, 13, 0, 0)).toISOString(),
|
||||
eventTypeId: seatedEventTypeIdAttendeesDisabledId,
|
||||
attendee: {
|
||||
name: nameAttendeeOne,
|
||||
email: emailAttendeeOne,
|
||||
timeZone: "Europe/Rome",
|
||||
language: "it",
|
||||
},
|
||||
bookingFieldsResponses: {
|
||||
codingLanguage: "TypeScript",
|
||||
},
|
||||
metadata: {
|
||||
userId: "100",
|
||||
},
|
||||
};
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.post("/v2/bookings")
|
||||
.send(body)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: CreateBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsCreateSeatedBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsCreateSeatedBooking(responseBody.data)) {
|
||||
const data: CreateSeatedBookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.seatUid).toBeDefined();
|
||||
bookingWithAttendeesDisabled = data;
|
||||
} else {
|
||||
throw new Error("Invalid response data - expected seated booking");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should book second seat on same event type with seatsShowAttendees disabled", async () => {
|
||||
const body: CreateBookingInput_2024_08_13 = {
|
||||
start: new Date(Date.UTC(2030, 0, 11, 13, 0, 0)).toISOString(),
|
||||
eventTypeId: seatedEventTypeIdAttendeesDisabledId,
|
||||
attendee: {
|
||||
name: nameAttendeeThree,
|
||||
email: emailAttendeeThree,
|
||||
timeZone: "Europe/Rome",
|
||||
language: "it",
|
||||
},
|
||||
bookingFieldsResponses: {
|
||||
codingLanguage: "Rust",
|
||||
},
|
||||
metadata: {
|
||||
userId: "300",
|
||||
},
|
||||
};
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.post("/v2/bookings")
|
||||
.send(body)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: CreateBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsCreateSeatedBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsCreateSeatedBooking(responseBody.data)) {
|
||||
const data: CreateSeatedBookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.seatUid).toBeDefined();
|
||||
secondAttendeeSeatUid = data.seatUid;
|
||||
} else {
|
||||
throw new Error("Invalid response data - expected seated booking");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should return only the attendee for the specific seatUid when seatsShowAttendees is false and no auth", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/bookings/by-seat/${secondAttendeeSeatUid}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: GetBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsGetSeatedBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsGetSeatedBooking(responseBody.data)) {
|
||||
const data: GetSeatedBookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.id).toEqual(bookingWithAttendeesDisabled.id);
|
||||
expect(data.uid).toEqual(bookingWithAttendeesDisabled.uid);
|
||||
expect(data.eventTypeId).toEqual(seatedEventTypeIdAttendeesDisabledId);
|
||||
expect(data.attendees.length).toEqual(1);
|
||||
expect(data.attendees[0].email).toEqual(emailAttendeeThree);
|
||||
expect(data.attendees[0].name).toEqual(nameAttendeeThree);
|
||||
expect(data.attendees[0].seatUid).toEqual(secondAttendeeSeatUid);
|
||||
} else {
|
||||
throw new Error("Invalid response data - expected seated booking");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should return all attendees when admin auth is provided", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/bookings/by-seat/${secondAttendeeSeatUid}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: GetBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsGetSeatedBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsGetSeatedBooking(responseBody.data)) {
|
||||
const data: GetSeatedBookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.id).toEqual(bookingWithAttendeesDisabled.id);
|
||||
expect(data.uid).toEqual(bookingWithAttendeesDisabled.uid);
|
||||
expect(data.eventTypeId).toEqual(seatedEventTypeIdAttendeesDisabledId);
|
||||
expect(data.attendees.length).toEqual(2);
|
||||
await bookingsRepositoryFixture.deleteById(data.id);
|
||||
} else {
|
||||
throw new Error("Invalid response data - expected seated booking");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should not be able to reschedule seated booking if seatUid is not provided", async () => {
|
||||
const body = {
|
||||
start: new Date(Date.UTC(2030, 0, 8, 15, 0, 0)).toISOString(),
|
||||
@@ -924,11 +1103,13 @@ describe("Bookings Endpoints 2024-08-13", () => {
|
||||
});
|
||||
|
||||
function responseDataIsCreateSeatedBooking(data: any): data is CreateSeatedBookingOutput_2024_08_13 {
|
||||
return Object.hasOwn(data, "seatUid");
|
||||
return Object.prototype.hasOwnProperty.call(data, "seatUid");
|
||||
}
|
||||
|
||||
function responseDataIsGetSeatedBooking(data: any): data is GetSeatedBookingOutput_2024_08_13 {
|
||||
return data?.attendees?.every((attendee: any) => attendee?.hasOwnProperty("seatUid"));
|
||||
return data?.attendees?.every((attendee: any) =>
|
||||
Object.prototype.hasOwnProperty.call(attendee, "seatUid")
|
||||
);
|
||||
}
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@@ -615,6 +615,50 @@ export class BookingsService_2024_08_13 {
|
||||
return this.outputService.getOutputRecurringBookings(ids);
|
||||
}
|
||||
|
||||
async getBookingBySeatUid(seatUid: string, authUser: AuthOptionalUser) {
|
||||
const bookingSeat =
|
||||
await this.bookingSeatRepository.getByReferenceUidIncludeBookingWithAttendeesAndUserAndEvent(seatUid);
|
||||
|
||||
if (!bookingSeat || !bookingSeat.booking) {
|
||||
throw new NotFoundException(`Booking with seatUid=${seatUid} was not found in the database`);
|
||||
}
|
||||
|
||||
const booking = bookingSeat.booking;
|
||||
const userIsEventTypeAdminOrOwner =
|
||||
authUser && booking.eventType
|
||||
? await this.eventTypeAccessService.userIsEventTypeAdminOrOwner(
|
||||
authUser,
|
||||
booking.eventType as EventType
|
||||
)
|
||||
: false;
|
||||
|
||||
const isRecurring = !!booking.recurringEventId;
|
||||
const seatsShowAttendees = !!booking.eventType?.seatsShowAttendees;
|
||||
const showAllAttendees = userIsEventTypeAdminOrOwner || seatsShowAttendees;
|
||||
|
||||
// When user is not admin and seatsShowAttendees is false, show only the attendee for this seatUid
|
||||
if (!showAllAttendees) {
|
||||
const seatAttendee = booking.attendees.find(
|
||||
(attendee) => attendee.bookingSeat?.referenceUid === seatUid
|
||||
);
|
||||
const bookingWithFilteredAttendees = {
|
||||
...booking,
|
||||
attendees: seatAttendee ? [seatAttendee] : [],
|
||||
};
|
||||
|
||||
if (isRecurring) {
|
||||
return this.outputService.getOutputRecurringSeatedBooking(bookingWithFilteredAttendees, true);
|
||||
}
|
||||
return this.outputService.getOutputSeatedBooking(bookingWithFilteredAttendees, true);
|
||||
}
|
||||
|
||||
if (isRecurring) {
|
||||
return this.outputService.getOutputRecurringSeatedBooking(booking, true);
|
||||
}
|
||||
|
||||
return this.outputService.getOutputSeatedBooking(booking, true);
|
||||
}
|
||||
|
||||
async getBookings(
|
||||
queryParams: GetBookingsInput_2024_08_13,
|
||||
user: { email: string; id: number; orgId?: number },
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class BookingSeatRepository {
|
||||
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
|
||||
constructor(
|
||||
private readonly dbRead: PrismaReadService,
|
||||
private readonly dbWrite: PrismaWriteService
|
||||
) {}
|
||||
|
||||
async getByReferenceUid(referenceUid: string) {
|
||||
return this.dbRead.prisma.bookingSeat.findUnique({
|
||||
@@ -16,4 +19,101 @@ export class BookingSeatRepository {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getByReferenceUidIncludeBookingWithAttendeesAndUserAndEvent(referenceUid: string) {
|
||||
return this.dbRead.prisma.bookingSeat.findUnique({
|
||||
where: {
|
||||
referenceUid,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
referenceUid: true,
|
||||
data: true,
|
||||
metadata: true,
|
||||
bookingId: true,
|
||||
attendeeId: true,
|
||||
booking: {
|
||||
select: {
|
||||
id: true,
|
||||
uid: true,
|
||||
userId: true,
|
||||
idempotencyKey: true,
|
||||
userPrimaryEmail: true,
|
||||
title: true,
|
||||
description: true,
|
||||
customInputs: true,
|
||||
responses: true,
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
status: true,
|
||||
location: true,
|
||||
metadata: true,
|
||||
paid: true,
|
||||
destinationCalendarId: true,
|
||||
cancellationReason: true,
|
||||
rejectionReason: true,
|
||||
reassignReason: true,
|
||||
reassignById: true,
|
||||
dynamicEventSlugRef: true,
|
||||
dynamicGroupSlugRef: true,
|
||||
fromReschedule: true,
|
||||
rescheduled: true,
|
||||
recurringEventId: true,
|
||||
smsReminderNumber: true,
|
||||
scheduledJobs: true,
|
||||
isRecorded: true,
|
||||
iCalUID: true,
|
||||
iCalSequence: true,
|
||||
rating: true,
|
||||
ratingFeedback: true,
|
||||
noShowHost: true,
|
||||
oneTimePassword: true,
|
||||
cancelledBy: true,
|
||||
rescheduledBy: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
eventTypeId: true,
|
||||
creationSource: true,
|
||||
attendees: {
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
timeZone: true,
|
||||
locale: true,
|
||||
phoneNumber: true,
|
||||
noShow: true,
|
||||
bookingSeat: {
|
||||
select: {
|
||||
id: true,
|
||||
referenceUid: true,
|
||||
data: true,
|
||||
metadata: true,
|
||||
bookingId: true,
|
||||
attendeeId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
eventType: {
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
seatsShowAttendees: true,
|
||||
teamId: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user