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>
This commit is contained in:
Pedro Castro
2026-01-12 07:48:37 +00:00
committed by GitHub
co-authored by cal.com Morgan
parent 3e7e376100
commit 0994050b0f
14 changed files with 226 additions and 5 deletions
+6
View File
@@ -2,3 +2,9 @@ GET /v2/event-types/{eventTypeId} added to the 'data' response property 'oneOf'
GET /v2/event-types/{eventTypeId} added '#/components/schemas/EventTypeOutput_2024_06_14, #/components/schemas/TeamEventTypeOutput_2024_06_14' to the 'data' response property 'oneOf' list for the response status '200'
GET /v2/bookings/{bookingUid}/recordings added the new required 'header' request parameter 'Authorization'
GET /v2/bookings/{bookingUid}/transcripts added the new required 'header' request parameter 'Authorization'
POST /v2/bookings added 'subschema #2, subschema #4' to the 'data' response property 'oneOf' list for the response status '201'
GET /v2/bookings/{bookingUid} added 'subschema #3, subschema #6' to the 'data' response property 'oneOf' list for the response status '200'
POST /v2/bookings/{bookingUid}/cancel added 'subschema #3, subschema #6' to the 'data' response property 'oneOf' list for the response status '200'
POST /v2/bookings/{bookingUid}/confirm added 'subschema #3, subschema #6' to the 'data' response property 'oneOf' list for the response status '200'
POST /v2/bookings/{bookingUid}/decline added 'subschema #3, subschema #6' to the 'data' response property 'oneOf' list for the response status '200'
POST /v2/bookings/{bookingUid}/guests added 'subschema #3, subschema #6' to the 'data' response property 'oneOf' list for the response status '200'
@@ -177,6 +177,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -624,6 +624,91 @@ describe("Managed user bookings 2024-08-13", () => {
});
});
describe("displayEmail fields", () => {
it("should return displayEmail without CUID suffix for host", async () => {
const body: CreateBookingInput_2024_08_13 = {
start: new Date(Date.UTC(2030, 0, 7, 10, 0, 0)).toISOString(),
eventTypeId: firstManagedUserEventTypeId,
attendee: {
name: "External Attendee",
email: "external-display-email-test@example.com",
timeZone: "Europe/Rome",
language: "en",
},
location: "https://meet.google.com/abc-def-ghi",
};
const response = await request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(201);
const bookingData = response.body.data;
// Host email should have CUID, displayEmail should not
expect(bookingData.hosts[0].email).toEqual(firstManagedUser.user.email);
expect(bookingData.hosts[0].displayEmail).toEqual(firstManagedUserEmail);
});
it("should return displayEmail without CUID suffix for attendee", async () => {
const body: CreateBookingInput_2024_08_13 = {
start: new Date(Date.UTC(2030, 0, 7, 10, 30, 0)).toISOString(),
eventTypeId: firstManagedUserEventTypeId,
attendee: {
name: secondManagedUser.user.name!,
email: secondManagedUser.user.email,
timeZone: secondManagedUser.user.timeZone,
language: secondManagedUser.user.locale,
},
location: "https://meet.google.com/abc-def-ghi",
};
const response = await request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(201);
const bookingData = response.body.data;
// Attendee email should have CUID, displayEmail should not
expect(bookingData.attendees[0].email).toEqual(secondManagedUser.user.email);
expect(bookingData.attendees[0].displayEmail).toEqual(secondManagedUserEmail);
// bookingFieldsResponses should also have displayEmail
expect(bookingData.bookingFieldsResponses.email).toEqual(secondManagedUser.user.email);
expect(bookingData.bookingFieldsResponses.displayEmail).toEqual(secondManagedUserEmail);
});
it("should return displayGuests without CUID suffix", async () => {
const body: CreateBookingInput_2024_08_13 = {
start: new Date(Date.UTC(2030, 0, 7, 11, 0, 0)).toISOString(),
eventTypeId: firstManagedUserEventTypeId,
attendee: {
name: "External Attendee",
email: "external-display-guests-test@example.com",
timeZone: "Europe/Rome",
language: "en",
},
guests: [secondManagedUser.user.email],
location: "https://meet.google.com/abc-def-ghi",
};
const response = await request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(201);
const bookingData = response.body.data;
// guests should have CUID, displayGuests should not
expect(bookingData.bookingFieldsResponses.guests).toContain(secondManagedUser.user.email);
expect(bookingData.bookingFieldsResponses.displayGuests).toContain(secondManagedUserEmail);
});
});
describe("booking confirmation by org admin", () => {
it("should allow org admin managed user to confirm booking using access token", async () => {
const bookingRequiringConfirmation = await bookingsRepositoryFixture.create({
@@ -492,6 +492,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
id: teamUser2.id,
name: teamUser2.name,
email: teamUser2.email,
displayEmail: teamUser2.email,
});
const reassigned = await bookingsRepositoryFixture.getByUid(roundRobinBooking.uid);
@@ -532,6 +533,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
id: teamUser1.id,
name: teamUser1.name,
email: teamUser1.email,
displayEmail: teamUser1.email,
});
const reassigned = await bookingsRepositoryFixture.getByUid(roundRobinBooking.uid);
@@ -185,6 +185,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(firstBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -206,6 +207,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(secondBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -262,6 +264,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(firstBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -284,6 +287,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(secondBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -304,6 +308,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(thirdBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -201,6 +201,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -276,6 +277,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(firstAttendee).toEqual({
name: createdSeatedBooking.attendees[0].name,
email: createdSeatedBooking.attendees[0].email,
displayEmail: createdSeatedBooking.attendees[0].displayEmail,
timeZone: createdSeatedBooking.attendees[0].timeZone,
language: createdSeatedBooking.attendees[0].language,
absent: false,
@@ -291,6 +293,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(secondAttendee).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -418,6 +421,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: attendee?.name,
email: attendee?.email,
displayEmail: attendee?.displayEmail,
timeZone: attendee?.timeZone,
language: attendee?.language,
absent: false,
@@ -841,6 +845,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -519,6 +519,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -573,6 +574,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: "919876543210@sms.cal.com",
displayEmail: "919876543210@sms.cal.com",
phoneNumber: body.attendee.phoneNumber,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
@@ -629,6 +631,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -636,6 +639,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[1]).toEqual({
name: teamUser2.name,
email: teamUser2.email,
displayEmail: teamUser2.email,
timeZone: teamUser2.timeZone,
language: teamUser2.locale,
absent: false,
@@ -690,6 +694,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -744,6 +749,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -927,6 +933,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: phoneBasedBooking.attendees[0].name,
email: phoneBasedBooking.attendees[0].email,
displayEmail: phoneBasedBooking.attendees[0].displayEmail,
phoneNumber: phoneBasedBooking.attendees[0].phoneNumber,
timeZone: phoneBasedBooking.attendees[0].timeZone,
language: phoneBasedBooking.attendees[0].language,
@@ -1010,6 +1017,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -483,6 +483,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -493,8 +494,10 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.bookingFieldsResponses).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
...body.bookingFieldsResponses,
guests: body.guests,
displayGuests: body.guests,
location: {
optionValue: googleMeetUrl,
value: "link",
@@ -566,6 +569,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(firstBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -588,6 +592,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(secondBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -609,6 +614,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(thirdBooking.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -2077,6 +2083,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -2087,8 +2094,10 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.bookingFieldsResponses).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
...body.bookingFieldsResponses,
guests: body.guests,
displayGuests: body.guests,
location: {
optionValue: googleMeetUrl,
value: "link",
@@ -2527,6 +2536,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
phoneNumber: body.attendee.phoneNumber,
@@ -2535,6 +2545,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
expect(data.bookingFieldsResponses).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
attendeePhoneNumber: body.attendee.phoneNumber,
smsReminderNumber: body.attendee.phoneNumber,
});
@@ -93,6 +93,10 @@ type DatabaseMetadata = z.infer<typeof bookingMetadataSchema>;
export class OutputBookingsService_2024_08_13 {
constructor(private readonly bookingsRepository: BookingsRepository_2024_08_13) {}
private getDisplayEmail(email: string): string {
return email.replace(/\+[a-zA-Z0-9]{25}/, "");
}
async getOutputBooking(databaseBooking: DatabaseBooking) {
const dateStart = DateTime.fromISO(databaseBooking.startTime.toISOString());
const dateEnd = DateTime.fromISO(databaseBooking.endTime.toISOString());
@@ -127,6 +131,7 @@ export class OutputBookingsService_2024_08_13 {
attendees: databaseBooking.attendees.map((attendee) => ({
name: attendee.name,
email: attendee.email,
displayEmail: this.getDisplayEmail(attendee.email),
timeZone: attendee.timeZone,
language: attendee.locale,
absent: !!attendee.noShow,
@@ -149,6 +154,25 @@ export class OutputBookingsService_2024_08_13 {
// note(Lauris): I don't know why plainToClass erases bookings responses and metadata so attaching manually
bookingTransformed.bookingFieldsResponses = bookingResponses;
bookingTransformed.metadata = this.getUserDefinedMetadata(metadata);
if (
bookingTransformed.bookingFieldsResponses?.email &&
typeof bookingTransformed.bookingFieldsResponses.email === "string"
) {
bookingTransformed.bookingFieldsResponses.displayEmail = this.getDisplayEmail(
bookingTransformed.bookingFieldsResponses.email
);
}
if (
bookingTransformed.bookingFieldsResponses?.guests &&
Array.isArray(bookingTransformed.bookingFieldsResponses.guests)
) {
bookingTransformed.bookingFieldsResponses.displayGuests = bookingTransformed.bookingFieldsResponses.guests.map(
(guest: string) => this.getDisplayEmail(guest)
);
}
return bookingTransformed;
}
@@ -192,12 +216,14 @@ export class OutputBookingsService_2024_08_13 {
id: "unknown",
name: "unknown",
email: "unknown",
displayEmail: "unknown",
username: "unknown",
};
}
return {
...user,
displayEmail: this.getDisplayEmail(user.email),
username: user.username || "unknown",
};
}
@@ -249,6 +275,7 @@ export class OutputBookingsService_2024_08_13 {
attendees: databaseBooking.attendees.map((attendee) => ({
name: attendee.name,
email: attendee.email,
displayEmail: this.getDisplayEmail(attendee.email),
timeZone: attendee.timeZone,
language: attendee.locale,
absent: !!attendee.noShow,
@@ -272,6 +299,25 @@ export class OutputBookingsService_2024_08_13 {
// note(Lauris): I don't know why plainToClass erases bookings responses and metadata so attaching manually
bookingTransformed.bookingFieldsResponses = bookingResponses;
bookingTransformed.metadata = this.getUserDefinedMetadata(metadata);
if (
bookingTransformed.bookingFieldsResponses?.email &&
typeof bookingTransformed.bookingFieldsResponses.email === "string"
) {
bookingTransformed.bookingFieldsResponses.displayEmail = this.getDisplayEmail(
bookingTransformed.bookingFieldsResponses.email
);
}
if (
bookingTransformed.bookingFieldsResponses?.guests &&
Array.isArray(bookingTransformed.bookingFieldsResponses.guests)
) {
bookingTransformed.bookingFieldsResponses.displayGuests = bookingTransformed.bookingFieldsResponses.guests.map(
(guest: string) => this.getDisplayEmail(guest)
);
}
return bookingTransformed;
}
@@ -337,6 +383,7 @@ export class OutputBookingsService_2024_08_13 {
const attendeeData = {
name: attendee.name,
email: attendee.email,
displayEmail: this.getDisplayEmail(attendee.email),
timeZone: attendee.timeZone,
language: attendee.locale,
absent: !!attendee.noShow,
@@ -465,6 +512,7 @@ export class OutputBookingsService_2024_08_13 {
const attendeeData = {
name: attendee.name,
email: attendee.email,
displayEmail: this.getDisplayEmail(attendee.email),
timeZone: attendee.timeZone,
language: attendee.locale,
absent: !!attendee.noShow,
@@ -497,6 +545,9 @@ export class OutputBookingsService_2024_08_13 {
id: databaseBooking?.user?.id || 0,
name: databaseBooking?.user?.name || "unknown",
email: databaseBooking?.user?.email || "unknown",
displayEmail: databaseBooking?.user?.email
? this.getDisplayEmail(databaseBooking.user.email)
: "unknown",
},
};
}
@@ -335,6 +335,7 @@ describe("Organizations Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -388,6 +389,7 @@ describe("Organizations Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -441,6 +443,7 @@ describe("Organizations Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: orgUserEmail,
displayEmail: orgUserEmail,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -494,6 +497,7 @@ describe("Organizations Bookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: orgUserEmail2,
displayEmail: orgUserEmail2,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -250,6 +250,7 @@ describe("Organizations TeamsBookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -233,6 +233,7 @@ describe("Organizations UsersBookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -291,6 +292,7 @@ describe("Organizations UsersBookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
@@ -347,6 +349,7 @@ describe("Organizations UsersBookings Endpoints 2024-08-13", () => {
expect(data.attendees[0]).toEqual({
name: body.attendee.name,
email: body.attendee.email,
displayEmail: body.attendee.email,
timeZone: body.attendee.timeZone,
language: body.attendee.language,
absent: false,
+29 -5
View File
@@ -31712,6 +31712,11 @@
"type": "string",
"example": "jane100@example.com"
},
"displayEmail": {
"type": "string",
"example": "jane100@example.com",
"description": "Clean email for display purposes"
},
"username": {
"type": "string",
"example": "jane100"
@@ -31721,10 +31726,11 @@
"example": "America/Los_Angeles"
}
},
"required": [
"required": [
"id",
"name",
"email",
"displayEmail",
"username",
"timeZone"
]
@@ -31757,6 +31763,11 @@
"type": "string",
"example": "john@example.com"
},
"displayEmail": {
"type": "string",
"example": "john@example.com",
"description": "Clean email for display purposes"
},
"timeZone": {
"type": "string",
"example": "America/New_York"
@@ -31819,9 +31830,10 @@
"example": "+1234567890"
}
},
"required": [
"required": [
"name",
"email",
"displayEmail",
"timeZone",
"absent"
]
@@ -32168,6 +32180,11 @@
"type": "string",
"example": "john@example.com"
},
"displayEmail": {
"type": "string",
"example": "john@example.com",
"description": "Clean email for display purposes"
},
"timeZone": {
"type": "string",
"example": "America/New_York"
@@ -32247,9 +32264,10 @@
}
}
},
"required": [
"required": [
"name",
"email",
"displayEmail",
"timeZone",
"absent",
"seatUid",
@@ -33342,12 +33360,18 @@
"email": {
"type": "string",
"example": "john.doe@example.com"
},
"displayEmail": {
"type": "string",
"example": "john.doe@example.com",
"description": "Clean email for display purposes"
}
},
"required": [
"required": [
"id",
"name",
"email"
"email",
"displayEmail"
]
},
"ReassignBookingOutput_2024_08_13": {
@@ -29,6 +29,11 @@ class BookingAttendee {
@Expose()
email!: string;
@ApiProperty({ type: String, example: "john@example.com", description: "Clean email for display purposes" })
@IsString()
@Expose()
displayEmail!: string;
@ApiProperty({ type: String, example: "America/New_York" })
@IsTimeZone()
@Expose()
@@ -95,6 +100,11 @@ class BookingHost {
@Expose()
email!: string;
@ApiProperty({ type: String, example: "jane100@example.com", description: "Clean email for display purposes" })
@IsString()
@Expose()
displayEmail!: string;
@ApiProperty({ type: String, example: "jane100" })
@IsString()
@Expose()
@@ -395,6 +405,11 @@ class ReassignedToDto {
@IsEmail()
@Expose()
email!: string;
@ApiProperty({ type: String, example: "john.doe@example.com", description: "Clean email for display purposes" })
@IsString()
@Expose()
displayEmail!: string;
}
export class ReassignBookingOutput_2024_08_13 {