fix: v2 bookings attendeeEmail filter (#20506)
* fix: GET bookings if attendeeEmail belong to managed user * fix: GET bookings if attendeeEmail belong to managed user but does not include oAuthId
This commit is contained in:
+70
-4
@@ -301,8 +301,8 @@ describe("Managed user bookings 2024-08-13", () => {
|
||||
attendee: {
|
||||
name: thirdManagedUser.user.name!,
|
||||
email: thirdManagedUserEmail,
|
||||
timeZone: secondManagedUser.user.timeZone,
|
||||
language: secondManagedUser.user.locale,
|
||||
timeZone: thirdManagedUser.user.timeZone,
|
||||
language: thirdManagedUser.user.locale,
|
||||
},
|
||||
guests: [secondManagedUserEmail],
|
||||
location: "https://meet.google.com/abc-def-ghi",
|
||||
@@ -418,8 +418,8 @@ describe("Managed user bookings 2024-08-13", () => {
|
||||
attendee: {
|
||||
name: thirdManagedUser.user.name!,
|
||||
email: thirdManagedUser.user.email,
|
||||
timeZone: secondManagedUser.user.timeZone,
|
||||
language: secondManagedUser.user.locale,
|
||||
timeZone: thirdManagedUser.user.timeZone,
|
||||
language: thirdManagedUser.user.locale,
|
||||
},
|
||||
guests: [secondManagedUser.user.email],
|
||||
location: "https://meet.google.com/abc-def-ghi",
|
||||
@@ -477,6 +477,72 @@ describe("Managed user bookings 2024-08-13", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("fetch bookings by attendeeEmail", () => {
|
||||
it("should return bookings for the original email when original email is attendee only", async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/v2/bookings?attendeeEmail=${thirdManagedUserEmail}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.set("Authorization", `Bearer ${firstManagedUser.accessToken}`)
|
||||
.expect(200);
|
||||
|
||||
const thirdManagedUserAttendeeBookingsResponseBody: GetBookingsOutput_2024_08_13 = response.body;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const thirdManagedUserAttendeeBookings: BookingOutput_2024_08_13[] =
|
||||
thirdManagedUserAttendeeBookingsResponseBody.data;
|
||||
expect(thirdManagedUserBookingsCount).toEqual(2);
|
||||
expect(thirdManagedUserAttendeeBookings.length).toEqual(thirdManagedUserBookingsCount);
|
||||
});
|
||||
|
||||
it("should return bookings for the oAuth email when original oAuth email is attendee only", async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/v2/bookings?attendeeEmail=${thirdManagedUser.user.email}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.set("Authorization", `Bearer ${firstManagedUser.accessToken}`)
|
||||
.expect(200);
|
||||
|
||||
const thirdManagedUserAttendeeBookingsResponseBody: GetBookingsOutput_2024_08_13 = response.body;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const thirdManagedUserAttendeeBookings: BookingOutput_2024_08_13[] =
|
||||
thirdManagedUserAttendeeBookingsResponseBody.data;
|
||||
expect(thirdManagedUserBookingsCount).toEqual(2);
|
||||
expect(thirdManagedUserAttendeeBookings.length).toEqual(thirdManagedUserBookingsCount);
|
||||
});
|
||||
|
||||
it("should return bookings for the original email when original email is attendee or guest", async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/v2/bookings?attendeeEmail=${secondManagedUserEmail}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.set("Authorization", `Bearer ${firstManagedUser.accessToken}`)
|
||||
.expect(200);
|
||||
|
||||
const secondManagedUserAttendeeBookingsResponseBody: GetBookingsOutput_2024_08_13 = response.body;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const secondManagedUserAttendeeBookings: BookingOutput_2024_08_13[] =
|
||||
secondManagedUserAttendeeBookingsResponseBody.data;
|
||||
expect(secondManagedUserBookingsCount).toEqual(4);
|
||||
expect(secondManagedUserAttendeeBookings.length).toEqual(secondManagedUserBookingsCount);
|
||||
});
|
||||
|
||||
it("should return bookings for the oAuth email when original oAuth email is attendee or guest", async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/v2/bookings?attendeeEmail=${secondManagedUser.user.email}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.set("Authorization", `Bearer ${firstManagedUser.accessToken}`)
|
||||
.expect(200);
|
||||
|
||||
const secondManagedUserAttendeeBookingsResponseBody: GetBookingsOutput_2024_08_13 = response.body;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const secondManagedUserAttendeeBookings: BookingOutput_2024_08_13[] =
|
||||
secondManagedUserAttendeeBookingsResponseBody.data;
|
||||
expect(secondManagedUserBookingsCount).toEqual(4);
|
||||
expect(secondManagedUserAttendeeBookings.length).toEqual(secondManagedUserBookingsCount);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.delete(firstManagedUser.user.id);
|
||||
await userRepositoryFixture.delete(secondManagedUser.user.id);
|
||||
|
||||
@@ -6,6 +6,8 @@ import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.
|
||||
import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository";
|
||||
import { BillingService } from "@/modules/billing/services/billing.service";
|
||||
import { BookingSeatRepository } from "@/modules/booking-seat/booking-seat.repository";
|
||||
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
|
||||
import { OAuthClientUsersService } from "@/modules/oauth-clients/services/oauth-clients-users.service";
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { UsersService } from "@/modules/users/services/users.service";
|
||||
import { UsersRepository, UserWithProfile } from "@/modules/users/users.repository";
|
||||
@@ -72,7 +74,8 @@ export class BookingsService_2024_08_13 {
|
||||
private readonly billingService: BillingService,
|
||||
private readonly usersService: UsersService,
|
||||
private readonly usersRepository: UsersRepository,
|
||||
private readonly platformBookingsService: PlatformBookingsService
|
||||
private readonly platformBookingsService: PlatformBookingsService,
|
||||
private readonly oAuthClientRepository: OAuthClientRepository
|
||||
) {}
|
||||
|
||||
async createBooking(request: Request, body: CreateBookingInput) {
|
||||
@@ -226,6 +229,10 @@ export class BookingsService_2024_08_13 {
|
||||
}
|
||||
|
||||
async getBookings(queryParams: GetBookingsInput_2024_08_13, user: { email: string; id: number }) {
|
||||
if (queryParams.attendeeEmail) {
|
||||
queryParams.attendeeEmail = await this.getAttendeeEmail(queryParams.attendeeEmail, user);
|
||||
}
|
||||
|
||||
const fetchedBookings: { bookings: { id: number }[] } = await getAllUserBookings({
|
||||
bookingListingByStatus: queryParams.status || [],
|
||||
skip: queryParams.skip ?? 0,
|
||||
@@ -281,6 +288,35 @@ export class BookingsService_2024_08_13 {
|
||||
return formattedBookings;
|
||||
}
|
||||
|
||||
async getAttendeeEmail(queryParamsAttendeeEmail: string, user: { id: number }) {
|
||||
// note(Lauris): this is to handle attendees that are managed users - in attendee table their email is one of managed users e.g
|
||||
// urdasdqinm+clxyyy21o0003sbk7yw5z6tzg@example.com but if attendeeEmail is passed as urdasdqinm@example.com then we check if user whose
|
||||
// access token is used is a managed user and if attendee with passed email has managed user email composed of passed email without oAuth client id +
|
||||
// authenticated user oAuth client id.
|
||||
const oAuthClient = await this.oAuthClientRepository.getByUserId(user.id);
|
||||
if (!oAuthClient) {
|
||||
return queryParamsAttendeeEmail;
|
||||
}
|
||||
// note(Lauris): query param already contains oAuth client id in the attendeeEmail
|
||||
if (queryParamsAttendeeEmail.includes(oAuthClient.id)) {
|
||||
return queryParamsAttendeeEmail;
|
||||
}
|
||||
|
||||
const managedAttendeeEmail = OAuthClientUsersService.getOAuthUserEmail(
|
||||
oAuthClient.id,
|
||||
queryParamsAttendeeEmail
|
||||
);
|
||||
const [attendee, managedAttendee] = await Promise.all([
|
||||
this.usersRepository.findByEmail(queryParamsAttendeeEmail),
|
||||
this.usersRepository.findByEmail(managedAttendeeEmail),
|
||||
]);
|
||||
if (!attendee && managedAttendee) {
|
||||
return managedAttendeeEmail;
|
||||
}
|
||||
|
||||
return queryParamsAttendeeEmail;
|
||||
}
|
||||
|
||||
async rescheduleBooking(request: Request, bookingUid: string, body: RescheduleBookingInput) {
|
||||
try {
|
||||
const bookingRequest = await this.inputService.createRescheduleBookingRequest(
|
||||
|
||||
@@ -61,6 +61,14 @@ export class GetBookingsInput_2024_08_13 {
|
||||
description: "Filter bookings by the attendee's email address.",
|
||||
example: "example@domain.com",
|
||||
})
|
||||
@Transform(({ value }) => {
|
||||
if (typeof value === "string") {
|
||||
// note(Lauris): we replace inner white spaces with "+" because managed user emails have "+" in them but if they are not URL encoded
|
||||
// when making request "+" becomes empty space " ".
|
||||
return value.trim().replace(/\s+/g, "+");
|
||||
}
|
||||
return value;
|
||||
})
|
||||
attendeeEmail?: string;
|
||||
|
||||
@IsString()
|
||||
|
||||
Reference in New Issue
Block a user