From 0d53c2069eb347eed82f6751be204c2394c672eb Mon Sep 17 00:00:00 2001 From: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:05:03 +0530 Subject: [PATCH] feat: team owner/admin, be able to confirm/reject "requires confirmation" team events (#15326) * feat: eam owner/admin, be able to confirm/reject requir es confirmation team events * update * addressed requested changes * remove console.log --------- Co-authored-by: Keith Williams Co-authored-by: Somay Chauhan Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com> --- apps/web/components/booking/BookingListItem.tsx | 4 +++- .../trpc/server/routers/viewer/bookings/_router.tsx | 2 +- .../server/routers/viewer/bookings/confirm.handler.ts | 10 +++++++--- .../trpc/server/routers/viewer/bookings/get.handler.ts | 9 ++++++++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/web/components/booking/BookingListItem.tsx b/apps/web/components/booking/BookingListItem.tsx index ae0d19f9f2..2c9efd2c02 100644 --- a/apps/web/components/booking/BookingListItem.tsx +++ b/apps/web/components/booking/BookingListItem.tsx @@ -542,7 +542,9 @@ function BookingListItem(booking: BookingItemProps) { {isUpcoming && !isCancelled ? ( <> - {isPending && userId === booking.user?.id && } + {isPending && (userId === booking.user?.id || booking.isUserTeamAdminOrOwner) && ( + + )} {isConfirmed && } {isRejected &&
{t("rejected")}
} diff --git a/packages/trpc/server/routers/viewer/bookings/_router.tsx b/packages/trpc/server/routers/viewer/bookings/_router.tsx index bece7c9c2b..7cb7b08682 100644 --- a/packages/trpc/server/routers/viewer/bookings/_router.tsx +++ b/packages/trpc/server/routers/viewer/bookings/_router.tsx @@ -75,7 +75,7 @@ export const bookingsRouter = router({ }); }), - confirm: bookingsProcedure.input(ZConfirmInputSchema).mutation(async ({ input, ctx }) => { + confirm: authedProcedure.input(ZConfirmInputSchema).mutation(async ({ input, ctx }) => { if (!UNSTABLE_HANDLER_CACHE.confirm) { UNSTABLE_HANDLER_CACHE.confirm = await import("./confirm.handler").then((mod) => mod.confirmHandler); } diff --git a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts index a079d5dc01..44e43a9278 100644 --- a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @@ -25,12 +25,11 @@ import { TRPCError } from "@trpc/server"; import type { TrpcSessionUser } from "../../../trpc"; import type { TConfirmInputSchema } from "./confirm.schema"; -import type { BookingsProcedureContext } from "./util"; type ConfirmOptions = { ctx: { user: NonNullable; - } & BookingsProcedureContext; + }; input: TConfirmInputSchema; }; @@ -75,6 +74,7 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { team: { select: { parentId: true, + members: true, }, }, workflows: { @@ -122,7 +122,11 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { }, }); - if (eventType && !eventType.users.find((user) => booking.userId === user.id)) { + const membership = booking.eventType?.team?.members.find((membership) => membership.userId === user.id); + const isTeamAdminOrOwner = + membership?.role === MembershipRole.OWNER || membership?.role === MembershipRole.ADMIN; + + if (eventType && !eventType.users.find((user) => booking.userId === user.id) && !isTeamAdminOrOwner) { throw new TRPCError({ code: "UNAUTHORIZED", message: "UNAUTHORIZED" }); } } diff --git a/packages/trpc/server/routers/viewer/bookings/get.handler.ts b/packages/trpc/server/routers/viewer/bookings/get.handler.ts index b479d6b1ca..821b09637d 100644 --- a/packages/trpc/server/routers/viewer/bookings/get.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/get.handler.ts @@ -3,7 +3,7 @@ import getAllUserBookings from "@calcom/lib/bookings/getAllUserBookings"; import type { PrismaClient } from "@calcom/prisma"; import { bookingMinimalSelect } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; -import type { BookingStatus } from "@calcom/prisma/enums"; +import { MembershipRole, type BookingStatus } from "@calcom/prisma/enums"; import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; import type { TrpcSessionUser } from "../../../trpc"; @@ -183,6 +183,7 @@ export async function getBookings({ select: { id: true, name: true, + members: true, }, }, }, @@ -396,6 +397,11 @@ export async function getBookings({ if (booking.seatsReferences.length && !booking.eventType?.seatsShowAttendees) { booking.attendees = booking.attendees.filter((attendee) => attendee.email === user.email); } + + const membership = booking.eventType?.team?.members.find((membership) => membership.userId === user.id); + const isUserTeamAdminOrOwner = + membership?.role === MembershipRole.OWNER || membership?.role === MembershipRole.ADMIN; + return { ...booking, eventType: { @@ -407,6 +413,7 @@ export async function getBookings({ }, startTime: booking.startTime.toISOString(), endTime: booking.endTime.toISOString(), + isUserTeamAdminOrOwner, }; }); return { bookings, recurringInfo };