Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 84 additions & 4 deletions apps/api/v1/pages/api/attendees/_post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
import prisma from "@calcom/prisma";

import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/validations/attendee";

/**
Expand Down Expand Up @@ -52,16 +53,95 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isSystemWideAdmin } = req;
const { userId, isSystemWideAdmin, isOrganizationOwnerOrAdmin } = req;
const body = schemaAttendeeCreateBodyParams.parse(req.body);

if (!isSystemWideAdmin) {
const userBooking = await prisma.booking.findFirst({
if (isOrganizationOwnerOrAdmin) {
const booking = await prisma.booking.findUnique({
where: { id: body.bookingId },
select: { userId: true },
});
if (booking) {
const bookingUserId = booking.userId;
if (bookingUserId) {
const accessibleUsersIds = await getAccessibleUsers({
adminUserId: userId,
memberUserIds: [bookingUserId],
});
if (accessibleUsersIds.length > 0) {
const data = await prisma.attendee.create({
data: {
email: body.email,
name: body.name,
timeZone: body.timeZone,
booking: { connect: { id: body.bookingId } },
},
});

return {
attendee: schemaAttendeeReadPublic.parse(data),
message: "Attendee created successfully",
};
Comment on lines +72 to +85
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don’t duplicate the creation logic. If the user lacks access, return an error and exit. Run all checks first; only after they pass, perform the create action once, at the end.
makes code easier to follow and understand

}
}
}
}

const user = await prisma.user.findUnique({
where: { id: userId },
select: { email: true },
});

if (!user) throw new HttpError({ statusCode: 404, message: "User not found" });

const bookingAsOwner = prisma.booking.findFirst({
where: { userId, id: body.bookingId },
select: { id: true },
});
// Here we make sure to only return attendee's of the user's own bookings.
if (!userBooking) throw new HttpError({ statusCode: 403, message: "Forbidden" });

const bookingAsAttendee = prisma.booking.findMany({
where: {
id: body.bookingId,
attendees: { some: { email: user.email } },
},
});

const bookingAsEventTypeOwner = prisma.booking.findMany({
where: {
id: body.bookingId,
eventType: {
owner: { id: userId },
},
},
});

const bookingAsTeamOwnerOrAdmin = prisma.booking.findMany({
where: {
id: body.bookingId,
eventType: {
team: {
members: {
some: { userId, role: { in: ["ADMIN", "OWNER"] }, accepted: true },
},
},
},
},
});

const [ownerResult, attendeeResult, eventTypeOwnerResult, teamOwnerResult] = await Promise.all([
bookingAsOwner,
bookingAsAttendee,
bookingAsEventTypeOwner,
bookingAsTeamOwnerOrAdmin,
]);
Comment on lines +103 to +137
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach triggers four parallel database calls, which creates unnecessary load on the system. Since the booking table is our largest table, I wouldn’t recommend doing this. We should look for a more efficient solution, as this approach is quite resource-intensive


const hasAccess =
!!ownerResult || !!attendeeResult.length || !!eventTypeOwnerResult.length || !!teamOwnerResult.length;

if (!hasAccess) {
throw new HttpError({ statusCode: 403, message: "Forbidden" });
}
}

const data = await prisma.attendee.create({
Expand Down
Loading