fix: remove wrong conditions to fetch users on /bookings (#19580)

This commit is contained in:
Eunjae Lee
2025-02-27 11:58:13 -05:00
committed by GitHub
parent 4d769d636c
commit 5be2b5bbba
2 changed files with 98 additions and 74 deletions
+75 -1
View File
@@ -2,7 +2,7 @@ import { expect } from "@playwright/test";
import prisma from "@calcom/prisma";
import { BookingStatus } from "@calcom/prisma/client";
import { MembershipRole } from "@calcom/prisma/enums";
import { MembershipRole, SchedulingType } from "@calcom/prisma/enums";
import { createTeamEventType } from "./fixtures/users";
import type { Fixtures } from "./lib/fixtures";
@@ -378,6 +378,80 @@ test.describe("Bookings", () => {
thirdUpcomingBooking.locator(`text=${thirdUserAttendeeTeamEvent!.title}`)
).toBeVisible();
});
test("Does not show booking from another user from collective event type when a member is filtered", async ({
page,
users,
bookings,
}) => {
const teamMatesObj = [
{ name: "teammate-1" },
{ name: "teammate-2" },
{ name: "teammate-3" },
{ name: "teammate-4" },
];
const owner = await users.create(
{ username: "pro-user", name: "pro-user" },
{
hasTeam: true,
teammates: teamMatesObj,
schedulingType: SchedulingType.COLLECTIVE,
}
);
const { team } = await owner.getFirstTeamMembership();
const eventType = await owner.getFirstTeamEvent(team.id);
const { id: eventTypeId, title: teamEventTitle, slug: teamEventSlug } = eventType;
// remove myself from host of this event type
await prisma.host.delete({
where: {
userId_eventTypeId: {
userId: owner.id,
eventTypeId,
},
},
});
// teammate-1
const host = await prisma.membership.findFirstOrThrow({
where: {
teamId: team.id,
userId: {
not: owner.id,
},
},
include: {
user: true,
},
});
await createBooking({
bookingsFixture: bookings,
organizer: host.user,
organizerEventType: eventType,
attendees: [{ name: "test user", email: "test@example.com", timeZone: "Europe/Paris" }],
relativeDate: 0,
title: "Booking from test user",
});
// teammate-2
const anotherUser = teamMatesObj.find((m) => m.name !== host.user.name)?.name;
await owner.apiLogin();
await page.goto("/bookings/upcoming");
await page.waitForResponse((response) => /\/api\/trpc\/bookings\/get.*/.test(response.url()));
await page.locator('[data-testid="add-filter-button"]').click();
await page.locator('[data-testid="add-filter-item-userId"]').click();
await page.locator('[data-testid="filter-popover-trigger-userId"]').click();
await page
.locator(`[data-testid="multi-select-options-userId"] [role="option"]:has-text("${anotherUser}")`)
.click();
await page.waitForResponse((response) => /\/api\/trpc\/bookings\/get.*/.test(response.url()));
await expect(page.locator('[data-testid="booking-item"]')).toHaveCount(0);
});
});
async function createBooking({
@@ -170,13 +170,13 @@ export async function getBookings({
const [
eventTypeIdsFromTeamIdsFilter,
{ attendeeEmailsFromUserIdsFilter, eventTypeIdsFromUserIdsFilter },
attendeeEmailsFromUserIdsFilter,
eventTypeIdsFromEventTypeIdsFilter,
eventTypeIdsWhereUserIsAdminOrOwener,
userIdsWhereUserIsOrgAdminOrOwener,
] = await Promise.all([
getEventTypeIdsFromTeamIdsFilter(prisma, filters?.teamIds),
getIdsFromUserIdsFilter(prisma, user.email, filters?.userIds),
getAttendeeEmailsFromUserIdsFilter(prisma, user.email, filters?.userIds),
getEventTypeIdsFromEventTypeIdsFilter(prisma, filters?.eventTypeIds),
getEventTypeIdsWhereUserIsAdminOrOwner(prisma, membershipConditionWhereUserIsAdminOwner),
getUserIdsWhereUserIsOrgAdminOrOwner(prisma, membershipConditionWhereUserIsAdminOwner),
@@ -226,7 +226,7 @@ export async function getBookings({
},
]
: []),
...(filters?.userIds && filters.userIds.length > 0 && eventTypeIdsFromUserIdsFilter
...(filters?.userIds && filters.userIds.length > 0
? [
{
OR: [
@@ -235,15 +235,6 @@ export async function getBookings({
in: filters.userIds,
},
},
...(eventTypeIdsFromUserIdsFilter?.length
? [
{
eventTypeId: {
in: eventTypeIdsFromUserIdsFilter,
},
},
]
: []),
...(attendeeEmailsFromUserIdsFilter?.length
? [
{
@@ -491,71 +482,30 @@ async function getEventTypeIdsFromTeamIdsFilter(prisma: PrismaClient, teamIds?:
return Array.from(new Set([...directTeamEventTypeIds, ...parentTeamEventTypeIds]));
}
async function getIdsFromUserIdsFilter(prisma: PrismaClient, userEmail: string, userIds?: number[]) {
async function getAttendeeEmailsFromUserIdsFilter(
prisma: PrismaClient,
userEmail: string,
userIds?: number[]
) {
if (!userIds || userIds.length === 0) {
return {
eventTypeIdsFromUserIdsFilter: undefined,
attendeeEmailsFromUserIdsFilter: undefined,
};
return;
}
const [attendeeEmailsFromUserIdsFilter, eventTypeIdsFromHostsFilter, eventTypeIdsFromUsersFilter] =
await Promise.all([
prisma.user
.findMany({
where: {
id: {
in: userIds,
},
},
select: {
email: true,
},
})
// Include booking if current user is an attendee, regardless of user ID filter
.then((users) => users.map((user) => user.email).concat([userEmail])),
const attendeeEmailsFromUserIdsFilter = await prisma.user
.findMany({
where: {
id: {
in: userIds,
},
},
select: {
email: true,
},
})
// Include booking if current user is an attendee, regardless of user ID filter
.then((users) => users.map((user) => user.email).concat([userEmail]));
prisma.eventType
.findMany({
where: {
hosts: {
some: {
userId: {
in: userIds,
},
isFixed: true,
},
},
},
select: {
id: true,
},
})
.then((eventTypes) => eventTypes.map((eventType) => eventType.id)),
prisma.eventType
.findMany({
where: {
users: {
some: {
id: {
in: userIds,
},
},
},
},
select: {
id: true,
},
})
.then((eventTypes) => eventTypes.map((eventType) => eventType.id)),
]);
const eventTypeIdsFromUserIdsFilter = Array.from(
new Set([...eventTypeIdsFromHostsFilter, ...eventTypeIdsFromUsersFilter])
);
return { attendeeEmailsFromUserIdsFilter, eventTypeIdsFromUserIdsFilter };
return attendeeEmailsFromUserIdsFilter;
}
async function getEventTypeIdsFromEventTypeIdsFilter(prisma: PrismaClient, eventTypeIds?: number[]) {