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 <keithwillcode@gmail.com>
Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2024-07-25 09:35:03 +02:00
1 parent 3b559525a8
commit 0d53c2069e
4 files changed
+19 -6

No files matched your search

@@ -542,7 +542,9 @@ function BookingListItem(booking: BookingItemProps) {
<td className="flex w-full justify-end py-4 pl-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:pl-0">
{isUpcoming && !isCancelled ? (
<>
{isPending && userId === booking.user?.id && <TableActions actions={pendingActions} />}
{isPending && (userId === booking.user?.id || booking.isUserTeamAdminOrOwner) && (
<TableActions actions={pendingActions} />
)}
{isConfirmed && <TableActions actions={bookedActions} />}
{isRejected && <div className="text-subtle text-sm">{t("rejected")}</div>}
</>
@@ -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);
}
@@ -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<TrpcSessionUser>;
} & 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" });
}
}
@@ -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 };