Files
calendar/packages/lib/bookings/getAllUserBookings.ts
T
da853958f7 feat: get org bookings endpoint api-v2 (#20462)
* feat: get org bookings endpoint api-v2

* fix userId filter transform

* fix: update getBookings to take filter.userIds in account

* refactor: getBooking where clause

* fixup! refactor: getBooking where clause

* feat: enable org owners to see org member bookings as attendees

* update flaky e2e tests

* fixup! feat: enable org owners to see org member bookings as attendees

* fixup! fixup! feat: enable org owners to see org member bookings as attendees

* chore: differentiate between org/team owner/admin

* chore: throw error with invalid userIds filter

* chore: clearly ensure non team orgs when orgId is not specified

* bump libraries and add comments

* bump libraries

* chore: give main profile orgId to getAllUserBookings

---------

Co-authored-by: Eunjae Lee <hey@eunjae.dev>
2025-04-03 17:36:10 -04:00

131 lines
3.7 KiB
TypeScript

import type { TextFilterValue } from "@calcom/features/data-table/lib/types";
import type { PrismaClient } from "@calcom/prisma";
import type { Prisma } from "@calcom/prisma/client";
import { BookingStatus } from "@calcom/prisma/enums";
import { getBookings } from "@calcom/trpc/server/routers/viewer/bookings/get.handler";
type InputByStatus = "upcoming" | "recurring" | "past" | "cancelled" | "unconfirmed";
type SortOptions = {
sortStart?: "asc" | "desc";
sortEnd?: "asc" | "desc";
sortCreated?: "asc" | "desc";
sortUpdated?: "asc" | "desc";
};
type GetOptions = {
ctx: {
user: { id: number; email: string; orgId?: number | null };
prisma: PrismaClient;
};
bookingListingByStatus: InputByStatus[];
take: number;
skip: number;
filters: {
status?: InputByStatus;
teamIds?: number[] | undefined;
userIds?: number[] | undefined;
eventTypeIds?: number[] | undefined;
attendeeEmail?: string | TextFilterValue;
attendeeName?: string | TextFilterValue;
};
sort?: SortOptions;
};
const getAllUserBookings = async ({ ctx, filters, bookingListingByStatus, take, skip, sort }: GetOptions) => {
const { prisma, user } = ctx;
const bookingListingFilters: Record<InputByStatus, Prisma.BookingWhereInput> = {
upcoming: {
endTime: { gte: new Date() },
// These changes are needed to not show confirmed recurring events,
// as rescheduling or cancel for recurring event bookings should be
// handled separately for each occurrence
OR: [
{
recurringEventId: { not: null },
status: { equals: BookingStatus.ACCEPTED },
},
{
recurringEventId: { equals: null },
status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] },
},
],
},
recurring: {
endTime: { gte: new Date() },
AND: [
{ NOT: { recurringEventId: { equals: null } } },
{ status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] } },
],
},
past: {
endTime: { lte: new Date() },
AND: [
{ NOT: { status: { equals: BookingStatus.CANCELLED } } },
{ NOT: { status: { equals: BookingStatus.REJECTED } } },
],
},
cancelled: {
OR: [{ status: { equals: BookingStatus.CANCELLED } }, { status: { equals: BookingStatus.REJECTED } }],
},
unconfirmed: {
endTime: { gte: new Date() },
status: { equals: BookingStatus.PENDING },
},
};
const orderBy = getOrderBy(bookingListingByStatus, sort);
const combinedFilters = bookingListingByStatus.map((status) => bookingListingFilters[status]);
const { bookings, recurringInfo, totalCount } = await getBookings({
user,
prisma,
passedBookingsStatusFilter: {
OR: combinedFilters,
},
filters: filters,
orderBy,
take,
skip,
});
return {
bookings,
recurringInfo,
totalCount,
};
};
function getOrderBy(
bookingListingByStatus: InputByStatus[],
sort?: SortOptions
): Prisma.BookingOrderByWithAggregationInput {
const bookingListingOrderby: Record<InputByStatus, Prisma.BookingOrderByWithAggregationInput> = {
upcoming: { startTime: "asc" },
recurring: { startTime: "asc" },
past: { startTime: "desc" },
cancelled: { startTime: "desc" },
unconfirmed: { startTime: "asc" },
};
if (bookingListingByStatus?.length === 1 && !sort) {
return bookingListingOrderby[bookingListingByStatus[0]];
}
if (sort?.sortStart) {
return { startTime: sort.sortStart };
}
if (sort?.sortEnd) {
return { endTime: sort.sortEnd };
}
if (sort?.sortCreated) {
return { createdAt: sort.sortCreated };
}
if (sort?.sortUpdated) {
return { updatedAt: sort.sortUpdated };
}
return { startTime: "asc" };
}
export default getAllUserBookings;