fix: view team bookings (#13591)

* fix: view team bookings

* fix: edge case- common user across 2 different teams

* @SomayChauhan fix: edge case- common user across 2 different teams v2.0

* feat: added booking list test for collective event-types

* feat: added booking list test for round-robin event-types

* feat: added test for managed event types bookings

* feat: added test for individual events bookings

* refactor code

* added comments

* added isFixed to collective event hosts

* better function naming

* code refactor

* fix: assertBookingVisibleFor ignoring today's meetings

* fix: handling case for organizations

* fix: non org bookings-list test

* feat: added tests for organisations booking list

* added comments for better clarity

* booking-list in org tests

* uncommented doOnOrgDomain

* removed extra selectors

* fix: failing tests

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
Somay ChauhanandUdit Takkar authored and GitHub committed 2024-03-12 11:54:07 -03:00
1 parent ae2446f42f
commit 4585199b5e
5 files changed
+790 -4

No files matched your search

+209
View File
@@ -1,9 +1,15 @@
import { expect } from "@playwright/test";
import { randomString } from "@calcom/lib/random";
import slugify from "@calcom/lib/slugify";
import prisma from "@calcom/prisma";
import { BookingStatus } from "@calcom/prisma/client";
import { SchedulingType } from "@calcom/prisma/enums";
import { createTeamEventType } from "./fixtures/users";
import type { Fixtures } from "./lib/fixtures";
import { test } from "./lib/fixtures";
import { assertBookingVisibleFor, bookTeamEvent, bookUserEvent } from "./lib/testUtils";
test.afterEach(({ users }) => users.deleteAll());
@@ -61,6 +67,137 @@ test.describe("Bookings", () => {
secondUpcomingBooking.locator(`text=${bookingWhereFirstUserIsOrganizer!.title}`)
).toBeVisible();
});
test("collective eventType booking should be visible to team admin", async ({ page, users }) => {
const { owner1, owner2, commonUser, team1_teammate1 } = await createTeams(users);
const { team: team1 } = await owner1.getFirstTeamMembership();
const scenario = {
schedulingType: SchedulingType.COLLECTIVE,
teamEventTitle: `collective-team-event`,
teamEventSlug: slugify(`collective-team-event-${randomString(5)}`),
};
const eventType = await createTeamEventType(owner1, team1, scenario);
const { id: eventId, slug: evnetSlug } = eventType;
await prisma.host.createMany({
data: [
{
userId: commonUser.id,
eventTypeId: eventId,
isFixed: true,
},
{
userId: team1_teammate1.id,
eventTypeId: eventId,
isFixed: true,
},
],
});
// to test if booking is visible to team admin/owner even if he is not part of the booking
await prisma.host.deleteMany({
where: {
userId: owner1.id,
eventTypeId: eventId,
},
});
await bookTeamEvent(page, team1, eventType);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(owner1, page, eventType, true);
// booking should not be visible for other team host
await assertBookingVisibleFor(owner2, page, eventType, false);
// booking should be visible for commonUser as he is part of the booking
await assertBookingVisibleFor(commonUser, page, eventType, true);
// booking should be visible for team1_teammate1 as he is part of the booking
await assertBookingVisibleFor(team1_teammate1, page, eventType, true);
});
test("round-robin eventType booking should be visible to team admin", async ({ page, users }) => {
const { owner1, owner2, commonUser, team1_teammate1 } = await createTeams(users);
const { team: team1 } = await owner1.getFirstTeamMembership();
const scenario = {
schedulingType: SchedulingType.ROUND_ROBIN,
teamEventTitle: `round-robin-team-event`,
teamEventSlug: slugify(`round-robin-team-event-${randomString(5)}`),
};
const eventType = await createTeamEventType(owner1, team1, scenario);
const { id: eventId } = eventType;
await prisma.host.createMany({
data: [
{
userId: commonUser.id,
eventTypeId: eventId,
},
{
userId: team1_teammate1.id,
eventTypeId: eventId,
},
],
});
await prisma.host.deleteMany({
where: {
userId: owner1.id,
eventTypeId: eventId,
},
});
await bookTeamEvent(page, team1, eventType);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(owner1, page, eventType, true);
// bookings should not be visible for other team host
await assertBookingVisibleFor(owner2, page, eventType, false);
});
test("managed eventType booking should be visible to team admin", async ({ page, users }) => {
const { owner1, owner2, commonUser, team1_teammate1 } = await createTeams(users);
const { team: team1 } = await owner1.getFirstTeamMembership();
await owner1.apiLogin();
await page.goto(`/event-types?dialog=new&eventPage=team%2F${team1.slug}&teamId=${team1.id}`);
await page.getByTestId("managed-event-type").click();
await page.getByTestId("event-type-quick-chat").click();
await page.getByTestId("event-type-quick-chat").fill("managed-event");
await page.getByRole("button", { name: "Continue" }).click();
await page.getByTestId("vertical-tab-assignment").click();
await page.getByRole("combobox", { name: "assignment-dropdown" }).fill("commonUser");
await page.getByRole("combobox", { name: "assignment-dropdown" }).press("Enter");
await page.getByRole("combobox", { name: "assignment-dropdown" }).fill("team1_teammate1");
await page.getByRole("combobox", { name: "assignment-dropdown" }).press("Enter");
await page.getByTestId("update-eventtype").click();
const eventType = await owner1.getFirstTeamEvent(team1.id);
await bookUserEvent(page, commonUser, eventType);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(owner1, page, eventType, true);
// booking should not be visible for other team host
await assertBookingVisibleFor(owner2, page, eventType, false);
// booking should be visible for commonUser as he is part of the booking
await assertBookingVisibleFor(commonUser, page, eventType, true);
// booking should not be visible for team1_teammate1 as we booked for commonUser
await assertBookingVisibleFor(team1_teammate1, page, eventType, false);
});
test("individual team members booking should not be visible to team admin", async ({ page, users }) => {
const { owner1, owner2, commonUser, team1_teammate1 } = await createTeams(users);
const eventType = await commonUser.getFirstEventAsOwner();
await bookUserEvent(page, commonUser, eventType);
// non-team bookings should not be visible for the team host
await assertBookingVisibleFor(owner1, page, eventType, false);
// non-team bookings should not be visible for other team host
await assertBookingVisibleFor(owner2, page, eventType, false);
// booking should be visible for commonUser as he is part of the booking
await assertBookingVisibleFor(commonUser, page, eventType, true);
});
});
});
@@ -111,3 +248,75 @@ async function createBooking({
},
});
}
const createTeams = async (userFixture: Fixtures["users"]) => {
const owner1 = await userFixture.create({ name: "team-owner-1" });
const owner2 = await userFixture.create({ name: "team-owner-2" });
const commonUser = await userFixture.create({ name: "commonUser" });
const team1_teammate1 = await userFixture.create({ name: "team1_teammate1" });
const team2_teammate1 = await userFixture.create({ name: "team2_teammate1" });
const teamOne = await prisma.team.create({
data: {
name: "bookings-test-team-1",
slug: slugify(`bookings-test-team-2-${randomString(5)}`),
},
});
const teamTwo = await prisma.team.create({
data: {
name: "bookings-test-team-2",
slug: slugify(`bookings-test-team-2-${randomString(5)}`),
},
});
// create memberships
await prisma.membership.createMany({
data: [
{
userId: owner1.id,
teamId: teamOne.id,
accepted: true,
role: "OWNER",
},
{
userId: commonUser.id,
teamId: teamOne.id,
accepted: true,
role: "MEMBER",
},
{
userId: team1_teammate1.id,
teamId: teamOne.id,
accepted: true,
role: "MEMBER",
},
{
userId: owner2.id,
teamId: teamTwo.id,
accepted: true,
role: "OWNER",
},
{
userId: commonUser.id,
teamId: teamTwo.id,
accepted: true,
role: "MEMBER",
},
{
userId: team2_teammate1.id,
teamId: teamTwo.id,
accepted: true,
role: "MEMBER",
},
],
});
return {
owner1,
owner2,
commonUser,
team1_teammate1,
team2_teammate1,
teamOne,
teamTwo,
};
};
+1 -1
View File
@@ -58,7 +58,7 @@ const createTeamWorkflow = async (user: { id: number }, team: { id: number }) =>
});
};
const createTeamEventType = async (
export const createTeamEventType = async (
user: { id: number },
team: { id: number },
scenario?: {
+51
View File
@@ -1,4 +1,5 @@
import type { Frame, Page } from "@playwright/test";
import type { APIResponse } from "@playwright/test";
import { expect } from "@playwright/test";
import { createHash } from "crypto";
import EventEmitter from "events";
@@ -369,3 +370,53 @@ export async function doOnOrgDomain(
// When App directory is there, this is the 404 page text. We should work on fixing the 404 page as it changed due to app directory.
export const NotFoundPageTextAppDir = "This page does not exist.";
// export const NotFoundPageText = "ERROR 404";
export type Team = {
id: number;
slug: string | null;
name: string;
};
export type EventType = {
id: number;
title: string;
slug: string;
};
export type User = {
id: number;
name: string | null;
username: string | null;
};
export async function bookTeamEvent(page: Page, team: Team, eventType: EventType) {
await page.goto(`/team/${team.slug}/${eventType.slug}/`);
await bookEventOnThisPage(page);
const bookingTitle = `${eventType.title} between ${team.name} and ${testName}`;
await assertBookingIsCorrect(page, bookingTitle);
}
export async function bookUserEvent(page: Page, user: User, eventType: EventType) {
await page.goto(`/${user.username}/${eventType.slug}/`);
await bookEventOnThisPage(page);
const bookingTitle = `${eventType.title} between ${user.name} and ${testName}`;
await assertBookingIsCorrect(page, bookingTitle);
}
export async function assertBookingIsCorrect(page: Page, bookingTitle: string) {
await expect(page.locator("[data-testid=booking-title]")).toHaveText(bookingTitle);
// The booker should be in the attendee list
await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
}
export const assertBookingVisibleFor = async (
user: { apiLogin: () => Promise<APIResponse> },
pageFixture: Fixtures["page"],
eventType: EventType,
shouldBeVisible: boolean
) => {
await user.apiLogin();
await pageFixture.goto(`/bookings/upcoming`);
const upcomingBookingList = pageFixture.locator('[data-testid="booking-item"]');
shouldBeVisible
? await expect(upcomingBookingList.locator(`text=${eventType.title}`)).toBeVisible()
: await expect(upcomingBookingList.locator(`text=${eventType.title}`)).toBeHidden();
};
@@ -0,0 +1,391 @@
import type { Page } from "@playwright/test";
import { expect } from "@playwright/test";
import { randomString } from "@calcom/lib/random";
import slugify from "@calcom/lib/slugify";
import prisma from "@calcom/prisma";
import { MembershipRole, SchedulingType } from "@calcom/prisma/enums";
import { createTeamEventType } from "../fixtures/users";
import { test } from "../lib/fixtures";
import type { Fixtures } from "../lib/fixtures";
import {
assertBookingVisibleFor,
bookTimeSlot,
doOnOrgDomain,
NotFoundPageTextAppDir,
selectFirstAvailableTimeSlotNextMonth,
testName,
} from "../lib/testUtils";
test.describe("Bookings list for organizations", () => {
test.afterEach(({ orgs, users }) => {
orgs.deleteAll();
users.deleteAll();
});
test.describe("Team Event", () => {
test("Collective EventType booking list", async ({ page, users, orgs }) => {
const { org, orgOwner, orgAdmin, team1owner, team2owner, commonUser, team1_teammate1 } =
await createOrg(orgs, users);
const { team: team1 } = await team1owner.getFirstTeamMembership();
const scenario = {
schedulingType: SchedulingType.COLLECTIVE,
teamEventTitle: `collective-team-event`,
teamEventSlug: slugify(`collective-team-event-${randomString(5)}`),
};
const eventType = await createTeamEventType(team1owner, team1, scenario);
const { id: eventId, slug: evnetSlug } = eventType;
await prisma.host.createMany({
data: [
{
userId: commonUser.id,
eventTypeId: eventId,
isFixed: true,
},
{
userId: team1_teammate1.id,
eventTypeId: eventId,
isFixed: true,
},
],
});
// to test if booking is visible to team admin/owner even if he is not part of the booking
await prisma.host.deleteMany({
where: {
userId: team1owner.id,
eventTypeId: eventId,
},
});
await expectPageToBeNotFound({ page, url: `/team/${team1.slug}/${eventType.slug}` });
await doOnOrgDomain(
{
orgSlug: org.slug,
page,
},
async () => {
await bookTeamEvent({ page, team: team1, event: eventType });
}
);
// booking should be visible for the Org OWNER even though he is not part of the booking
await assertBookingVisibleFor(orgOwner, page, eventType, true);
// booking should be visible for the Org ADMIN even though he is not part of the booking
await assertBookingVisibleFor(orgAdmin, page, eventType, true);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(team1owner, page, eventType, true);
// booking should not be visible for other team host, because its a team1 team-event
await assertBookingVisibleFor(team2owner, page, eventType, false);
// booking should be visible for commonUser as he is part of the booking
await assertBookingVisibleFor(commonUser, page, eventType, true);
// booking should be visible for team1_teammate1 as he is part of the booking
await assertBookingVisibleFor(team1_teammate1, page, eventType, true);
});
test("Round Robin EventType booking list", async ({ page, users, orgs }) => {
const { org, orgOwner, orgAdmin, team1owner, team2owner, commonUser, team1_teammate1 } =
await createOrg(orgs, users);
const { team: team1 } = await team1owner.getFirstTeamMembership();
const scenario = {
schedulingType: SchedulingType.ROUND_ROBIN,
teamEventTitle: `round-robin-team-event`,
teamEventSlug: slugify(`round-robin-team-event-${randomString(5)}`),
};
const eventType = await createTeamEventType(team1owner, team1, scenario);
const { id: eventId } = eventType;
await prisma.host.createMany({
data: [
{
userId: commonUser.id,
eventTypeId: eventId,
},
{
userId: team1_teammate1.id,
eventTypeId: eventId,
},
],
});
await prisma.host.deleteMany({
where: {
userId: team1owner.id,
eventTypeId: eventId,
},
});
await expectPageToBeNotFound({ page, url: `/team/${team1.slug}/${eventType.slug}` });
await doOnOrgDomain(
{
orgSlug: org.slug,
page,
},
async () => {
await bookTeamEvent({ page, team: team1, event: eventType });
}
);
// booking should be visible for the Org OWNER even though he is not part of the booking
await assertBookingVisibleFor(orgOwner, page, eventType, true);
// booking should be visible for the Org ADMIN even though he is not part of the booking
await assertBookingVisibleFor(orgAdmin, page, eventType, true);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(team1owner, page, eventType, true);
// booking should not be visible for other team host
await assertBookingVisibleFor(team2owner, page, eventType, false);
});
test("Managed EventType booking list", async ({ page, users, orgs }) => {
const { org, orgOwner, orgAdmin, team1owner, team2owner, commonUser, team1_teammate1 } =
await createOrg(orgs, users);
const { team: team1 } = await team1owner.getFirstTeamMembership();
await team1owner.apiLogin();
await page.goto(`/event-types?dialog=new&eventPage=team%2F${team1.slug}&teamId=${team1.id}`);
await page.getByTestId("managed-event-type").click();
await page.getByTestId("event-type-quick-chat").click();
await page.getByTestId("event-type-quick-chat").fill("managed-event");
await page.getByRole("button", { name: "Continue" }).click();
await page.getByTestId("vertical-tab-assignment").click();
await page.getByRole("combobox", { name: "assignment-dropdown" }).fill("commonUser");
await page.getByRole("combobox", { name: "assignment-dropdown" }).press("Enter");
await page.getByRole("combobox", { name: "assignment-dropdown" }).fill("team1_teammate1");
await page.getByRole("combobox", { name: "assignment-dropdown" }).press("Enter");
await page.getByTestId("update-eventtype").click();
const eventType = await team1owner.getFirstTeamEvent(team1.id);
await expectPageToBeNotFound({ page, url: `/${commonUser.username}/${eventType.slug}` });
await doOnOrgDomain(
{
orgSlug: org.slug,
page,
},
async () => {
await bookUserEvent({ page, user: commonUser, event: eventType });
}
);
// booking should be visible for the Org OWNER even though he is not part of the booking
await assertBookingVisibleFor(orgOwner, page, eventType, true);
// booking should be visible for the Org ADMIN even though he is not part of the booking
await assertBookingVisibleFor(orgAdmin, page, eventType, true);
// booking should be visible for the team host even though he is not part of the booking
await assertBookingVisibleFor(team1owner, page, eventType, true);
// booking should not be visible for other team host
await assertBookingVisibleFor(team2owner, page, eventType, false);
});
});
test.describe("User Event", () => {
test("User personal booking list", async ({ page, users, orgs }) => {
const { org, orgOwner, orgAdmin, team1owner, team2owner, commonUser, team1_teammate1 } =
await createOrg(orgs, users);
const event = await commonUser.getFirstEventAsOwner();
await page.goto(`/${commonUser.username}/${event.slug}`);
// Shouldn't be servable on the non-org domain
await expect(page.locator(`text=${NotFoundPageTextAppDir}`)).toBeVisible();
await doOnOrgDomain(
{
orgSlug: org.slug,
page,
},
async () => {
await bookUserEvent({ page, user: commonUser, event });
}
);
// booking should be visible for the Org OWNER
await assertBookingVisibleFor(orgOwner, page, event, true);
// booking should be visible for the Org ADMIN
await assertBookingVisibleFor(orgAdmin, page, event, true);
// booking should be visible for the team host
await assertBookingVisibleFor(team1owner, page, event, true);
// booking should be visible for other team host because commonUser is part of both teams
await assertBookingVisibleFor(team2owner, page, event, true);
// booking should be visible for commonUser as he is part of the booking
await assertBookingVisibleFor(commonUser, page, event, true);
// booking should not be visible for team1_teammate1
await assertBookingVisibleFor(team1_teammate1, page, event, false);
});
});
});
async function bookUserEvent({
page,
user,
event,
}: {
page: Page;
user: {
username: string | null;
name: string | null;
};
event: { slug: string; title: string };
}) {
await page.goto(`/${user.username}/${event.slug}`);
await selectFirstAvailableTimeSlotNextMonth(page);
await bookTimeSlot(page);
await expect(page.getByTestId("success-page")).toBeVisible();
// The title of the booking
const BookingTitle = `${event.title} between ${user.name} and ${testName}`;
await expect(page.getByTestId("booking-title")).toHaveText(BookingTitle);
// The booker should be in the attendee list
await expect(page.getByTestId(`attendee-name-${testName}`)).toHaveText(testName);
}
async function bookTeamEvent({
page,
team,
event,
}: {
page: Page;
team: {
slug: string | null;
name: string | null;
};
event: { slug: string; title: string };
}) {
// Note that even though the default way to access a team booking in an organization is to not use /team in the URL, but it isn't testable with playwright as the rewrite is taken care of by Next.js config which can't handle on the fly org slug's handling
// So, we are using /team in the URL to access the team booking
// There are separate tests to verify that the next.config.js rewrites are working
// Also there are additional checkly tests that verify absolute e2e flow. They are in __checks__/organization.spec.ts
await page.goto(`/team/${team.slug}/${event.slug}`);
await selectFirstAvailableTimeSlotNextMonth(page);
await bookTimeSlot(page);
await expect(page.getByTestId("success-page")).toBeVisible();
// The title of the booking
const BookingTitle = `${event.title} between ${team.name} and ${testName}`;
await expect(page.getByTestId("booking-title")).toHaveText(BookingTitle);
// The booker should be in the attendee list
await expect(page.getByTestId(`attendee-name-${testName}`)).toHaveText(testName);
}
async function expectPageToBeNotFound({ page, url }: { page: Page; url: string }) {
await page.goto(`${url}`);
await expect(page.locator(`text=${NotFoundPageTextAppDir}`)).toBeVisible();
}
const createOrg = async (orgs: Fixtures["orgs"], userFixture: Fixtures["users"]) => {
const org = await orgs.create({
name: "TestOrg",
});
const orgOwner = await userFixture.create({
name: "org-owner",
organizationId: org.id,
roleInOrganization: MembershipRole.OWNER,
});
const orgAdmin = await userFixture.create({
name: "org-admin",
organizationId: org.id,
roleInOrganization: MembershipRole.ADMIN,
});
const team1owner = await userFixture.create({
name: "team-owner-1",
organizationId: org.id,
roleInOrganization: MembershipRole.MEMBER,
});
const team2owner = await userFixture.create({
name: "team-owner-2",
organizationId: org.id,
roleInOrganization: MembershipRole.MEMBER,
});
const commonUser = await userFixture.create({
name: "commonUser",
organizationId: org.id,
roleInOrganization: MembershipRole.MEMBER,
});
const team1_teammate1 = await userFixture.create({
name: "team1_teammate1",
organizationId: org.id,
roleInOrganization: MembershipRole.MEMBER,
});
const team2_teammate1 = await userFixture.create({
name: "team2_teammate1",
organizationId: org.id,
roleInOrganization: MembershipRole.MEMBER,
});
const teamOne = await prisma.team.create({
data: {
name: "bookings-test-team-1",
slug: slugify(`bookings-test-team-2-${randomString(5)}`),
parentId: org.id,
},
});
const teamTwo = await prisma.team.create({
data: {
name: "bookings-test-team-2",
slug: slugify(`bookings-test-team-2-${randomString(5)}`),
parentId: org.id,
},
});
// create memberships
await prisma.membership.createMany({
data: [
{
userId: team1owner.id,
teamId: teamOne.id,
accepted: true,
role: "OWNER",
},
{
userId: commonUser.id,
teamId: teamOne.id,
accepted: true,
role: "MEMBER",
},
{
userId: team1_teammate1.id,
teamId: teamOne.id,
accepted: true,
role: "MEMBER",
},
{
userId: team2owner.id,
teamId: teamTwo.id,
accepted: true,
role: "OWNER",
},
{
userId: commonUser.id,
teamId: teamTwo.id,
accepted: true,
role: "MEMBER",
},
{
userId: team2_teammate1.id,
teamId: teamTwo.id,
accepted: true,
role: "MEMBER",
},
],
});
return {
org,
orgOwner,
orgAdmin,
team1owner,
team2owner,
commonUser,
team1_teammate1,
team2_teammate1,
teamOne,
teamTwo,
};
};
@@ -189,7 +189,6 @@ async function getBookings({
],
},
};
const filtersCombined: Prisma.BookingWhereInput[] = !filters
? []
: Object.keys(filters)
@@ -262,7 +261,8 @@ async function getBookings({
// Note that because we are applying `take` to individual queries, we will usually get more bookings then we need. It is okay to have more bookings faster than having what we need slower
bookingsQueryUserId,
bookingsQueryAttendees,
bookingsQueryTeamMember,
bookingsQueryTeamEvents,
bookingsQueryTeamUsersPersonalEvents,
bookingsQuerySeatReference,
//////////////////////////
@@ -300,9 +300,28 @@ async function getBookings({
take: take + 1,
skip,
}),
// get team bookings (managed + collective + round-robin)
prisma.booking.findMany({
where: {
OR: [
// all (collective + round-robin) team bookings should be visible to org-owner and org-admins
{
eventType: {
team: {
parent: {
members: {
some: {
userId: user.id,
role: {
in: ["ADMIN", "OWNER"],
},
},
},
},
},
},
},
// all (collective + round-robin) team bookings should be visible to team-owner and team-admins
{
eventType: {
team: {
@@ -317,6 +336,43 @@ async function getBookings({
},
},
},
// all managed team bookings should be visible to team-owner and team-admins
{
eventType: {
parent: {
team: {
members: {
some: {
userId: user.id,
role: {
in: ["ADMIN", "OWNER"],
},
},
},
},
},
},
},
// all managed team bookings should be visible to org-owner and org-admins
{
eventType: {
parent: {
team: {
parent: {
members: {
some: {
userId: user.id,
role: {
in: ["ADMIN", "OWNER"],
},
},
},
},
},
},
},
},
],
AND: [passedBookingsStatusFilter, ...filtersCombined],
},
@@ -324,6 +380,84 @@ async function getBookings({
take: take + 1,
skip,
}),
// only get personal bookings
prisma.booking.findMany({
where: {
AND: [
// only show personal booking to org-owner and org-admins
{
user: {
teams: {
some: {
team: {
parentId: { gt: 0 },
},
},
},
},
},
{
OR: [
{
user: {
teams: {
some: {
team: {
parent: {
members: {
some: {
userId: user.id,
role: {
in: ["ADMIN", "OWNER"],
},
},
},
},
},
},
},
},
},
{
user: {
teams: {
some: {
team: {
members: {
some: {
userId: user.id,
role: {
in: ["ADMIN", "OWNER"],
},
},
},
},
},
},
},
},
],
},
// filter out all (collective + round-robin) event bookings
{
eventType: {
teamId: null,
},
},
// filter out all (managed) event bookings
{
eventType: {
parentId: null,
},
},
passedBookingsStatusFilter,
...filtersCombined,
],
},
orderBy,
take: take + 1,
skip,
}),
prisma.booking.findMany({
where: {
OR: [
@@ -407,7 +541,8 @@ async function getBookings({
// It's going to mess up the orderBy as we are concatenating independent queries results
bookingsQueryUserId
.concat(bookingsQueryAttendees)
.concat(bookingsQueryTeamMember)
.concat(bookingsQueryTeamEvents)
.concat(bookingsQueryTeamUsersPersonalEvents)
.concat(bookingsQuerySeatReference)
);