Skip to content

Commit ad4af64

Browse files
fix: return rescheduledByEmail in V2 bookings (calcom#22804)
* Update output.service.ts * Update output.service.ts * Update output.service.ts * Update user-bookings.e2e-spec.ts * fix type err * Update failing test
1 parent 2cc7827 commit ad4af64

2 files changed

Lines changed: 101 additions & 8 deletions

File tree

apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,88 @@ describe("Bookings Endpoints 2024-08-13", () => {
18341834
}
18351835
});
18361836
});
1837+
1838+
it("should return who rescheduled the booking, in the new booking", async () => {
1839+
const rescheduledByEmail = `user-bookings-rescheduler-${randomString()}@rescheduler.com`;
1840+
// Create the original booking that will be rescheduled
1841+
const originalBooking = await bookingsRepositoryFixture.create({
1842+
uid: `original-booking-uid-${eventTypeId}`,
1843+
title: "original booking title",
1844+
startTime: "2050-09-05T10:00:00.000Z",
1845+
endTime: "2050-09-05T11:00:00.000Z",
1846+
eventType: {
1847+
connect: {
1848+
id: eventTypeId,
1849+
},
1850+
},
1851+
status: "CANCELLED",
1852+
rescheduledBy: rescheduledByEmail,
1853+
metadata: {},
1854+
responses: {
1855+
name: "original tester",
1856+
email: "original@example.com",
1857+
guests: [],
1858+
},
1859+
user: {
1860+
connect: {
1861+
id: user.id,
1862+
},
1863+
},
1864+
});
1865+
1866+
// Create the new booking that is the result of the reschedule
1867+
const newBooking = await bookingsRepositoryFixture.create({
1868+
uid: `new-booking-uid-${eventTypeId}`,
1869+
title: "rescheduled booking title",
1870+
startTime: "2050-09-05T14:00:00.000Z",
1871+
endTime: "2050-09-05T15:00:00.000Z",
1872+
eventType: {
1873+
connect: {
1874+
id: eventTypeId,
1875+
},
1876+
},
1877+
status: "ACCEPTED",
1878+
fromReschedule: originalBooking.uid,
1879+
metadata: {},
1880+
responses: {
1881+
name: "new tester",
1882+
email: "newtester@example.com",
1883+
guests: [],
1884+
},
1885+
user: {
1886+
connect: {
1887+
id: user.id,
1888+
},
1889+
},
1890+
});
1891+
1892+
return request(app.getHttpServer())
1893+
.get(`/v2/bookings/${newBooking.uid}`)
1894+
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
1895+
.expect(200)
1896+
.then(async (response) => {
1897+
// Fetch the original booking to get its rescheduledBy value
1898+
const originalBookingFromDb = await bookingsRepositoryFixture.getByUid(originalBooking.uid);
1899+
const expectedRescheduledBy = originalBookingFromDb?.rescheduledBy;
1900+
1901+
await bookingsRepositoryFixture.deleteById(originalBooking.id);
1902+
await bookingsRepositoryFixture.deleteById(newBooking.id);
1903+
const responseBody: GetBookingOutput_2024_08_13 = response.body;
1904+
expect(responseBody.status).toEqual(SUCCESS_STATUS);
1905+
expect(responseBody.data).toBeDefined();
1906+
expect(responseDataIsBooking(responseBody.data)).toBe(true);
1907+
1908+
if (responseDataIsBooking(responseBody.data)) {
1909+
const data: BookingOutput_2024_08_13 = responseBody.data;
1910+
expect(data.uid).toEqual(newBooking.uid);
1911+
expect(rescheduledByEmail).toEqual(expectedRescheduledBy);
1912+
} else {
1913+
throw new Error(
1914+
"Invalid response data - expected booking but received array of possibly recurring bookings"
1915+
);
1916+
}
1917+
});
1918+
});
18371919
});
18381920

18391921
describe("book by username and event type slug", () => {

apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,13 @@ export class OutputBookingsService_2024_08_13 {
101101
);
102102
const metadata = safeParse(bookingMetadataSchema, databaseBooking.metadata, defaultBookingMetadata);
103103
const location = metadata?.videoCallUrl || databaseBooking.location;
104-
const rescheduledToUid = databaseBooking.rescheduled
105-
? await this.getRescheduledToUid(databaseBooking.uid)
104+
const rescheduledToInfo = databaseBooking.rescheduled
105+
? await this.getRescheduledToInfo(databaseBooking.uid)
106106
: undefined;
107+
108+
const rescheduledToUid = rescheduledToInfo?.uid;
109+
const rescheduledByEmail = databaseBooking.rescheduled ? rescheduledToInfo?.rescheduledBy : databaseBooking.rescheduledBy;
110+
107111

108112
const booking = {
109113
id: databaseBooking.id,
@@ -116,7 +120,6 @@ export class OutputBookingsService_2024_08_13 {
116120
databaseBooking.status === "CANCELLED" ? databaseBooking.cancellationReason : undefined,
117121
cancelledByEmail: databaseBooking.status === "CANCELLED" ? databaseBooking.cancelledBy : undefined,
118122
reschedulingReason: bookingResponses?.rescheduledReason,
119-
rescheduledByEmail: databaseBooking.rescheduledBy || undefined,
120123
rescheduledFromUid: databaseBooking.fromReschedule || undefined,
121124
start: databaseBooking.startTime,
122125
end: databaseBooking.endTime,
@@ -142,6 +145,7 @@ export class OutputBookingsService_2024_08_13 {
142145
rating: databaseBooking.rating,
143146
icsUid: databaseBooking.iCalUID,
144147
rescheduledToUid,
148+
rescheduledByEmail,
145149
};
146150

147151
const bookingTransformed = plainToClass(BookingOutput_2024_08_13, booking, { strategy: "excludeAll" });
@@ -151,11 +155,15 @@ export class OutputBookingsService_2024_08_13 {
151155
return bookingTransformed;
152156
}
153157

154-
async getRescheduledToUid(bookingUid: string) {
158+
async getRescheduledToInfo(bookingUid: string): Promise<{ uid?: string; rescheduledBy?: string | null }> {
155159
const rescheduledTo = await this.bookingsRepository.getByFromReschedule(bookingUid);
156-
return rescheduledTo?.uid;
160+
return {
161+
uid: rescheduledTo?.uid,
162+
rescheduledBy: rescheduledTo?.rescheduledBy
163+
};
157164
}
158165

166+
159167
getUserDefinedMetadata(databaseMetadata: DatabaseMetadata) {
160168
if (databaseMetadata === null) return {};
161169

@@ -218,7 +226,6 @@ export class OutputBookingsService_2024_08_13 {
218226
databaseBooking.status === "CANCELLED" ? databaseBooking.cancellationReason : undefined,
219227
cancelledByEmail: databaseBooking.status === "CANCELLED" ? databaseBooking.cancelledBy : undefined,
220228
reschedulingReason: bookingResponses?.rescheduledReason,
221-
rescheduledByEmail: databaseBooking.rescheduledBy || undefined,
222229
rescheduledFromUid: databaseBooking.fromReschedule || undefined,
223230
start: databaseBooking.startTime,
224231
end: databaseBooking.endTime,
@@ -269,9 +276,12 @@ export class OutputBookingsService_2024_08_13 {
269276
const duration = dateEnd.diff(dateStart, "minutes").minutes;
270277
const metadata = safeParse(bookingMetadataSchema, databaseBooking.metadata, defaultBookingMetadata);
271278
const location = metadata?.videoCallUrl || databaseBooking.location;
272-
const rescheduledToUid = databaseBooking.rescheduled
273-
? await this.getRescheduledToUid(databaseBooking.uid)
279+
const rescheduledToInfo = databaseBooking.rescheduled
280+
? await this.getRescheduledToInfo(databaseBooking.uid)
274281
: undefined;
282+
283+
const rescheduledToUid = rescheduledToInfo?.uid;
284+
const rescheduledByEmail = databaseBooking.rescheduled ? rescheduledToInfo?.rescheduledBy : databaseBooking.rescheduledBy;
275285

276286
const booking = {
277287
id: databaseBooking.id,
@@ -299,6 +309,7 @@ export class OutputBookingsService_2024_08_13 {
299309
rating: databaseBooking.rating,
300310
icsUid: databaseBooking.iCalUID,
301311
rescheduledToUid,
312+
rescheduledByEmail,
302313
};
303314

304315
const parsed = plainToClass(GetSeatedBookingOutput_2024_08_13, booking, { strategy: "excludeAll" });

0 commit comments

Comments
 (0)