Skip to content

Conversation

@everettbu
Copy link

Test 10

* feat: ability to add guests via app.cal.com/bookings

* fix: some update

* fix: minor issue

* fix: final update

* update

* update

* add requested changes

* fix type error

* small update

* final update

* fix type error

* fix location

* update calender event

---------

Co-authored-by: Somay Chauhan <[email protected]>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR implements guest management functionality for existing bookings, allowing users to add additional attendees after a booking has been created. The implementation introduces a complete end-to-end feature spanning frontend UI, backend API, and email notifications.

Frontend Changes:

  • Adds an "Add Guests" action to the booking list item menu that opens a modal dialog
  • Creates a new AddGuestsDialog component with proper form validation using Zod schemas
  • Introduces a reusable MultiEmail component (with lazy loading) for managing multiple email addresses
  • Integrates with the existing TRPC mutation system and provides appropriate loading states and error handling

Backend API:

  • Adds a new addGuests TRPC endpoint in the bookings router with comprehensive authorization checks
  • Implements permission validation ensuring only organizers, attendees, or team admins/owners can add guests
  • Includes duplicate prevention and blacklist filtering for guest emails
  • Integrates with calendar systems to update external calendar events when guests are added

Email System:

  • Creates specialized email templates for both organizers (OrganizerAddGuestsEmail) and attendees (AttendeeAddGuestsEmail)
  • Implements a new sendAddGuestsEmails function that differentiates between newly added guests (who receive scheduled emails) and existing attendees (who receive guest addition notifications)
  • Email templates reuse existing scheduled email components with customized titles and subjects for the guest addition context

The implementation follows Cal.com's established architectural patterns including lazy-loaded TRPC handlers, component composition for email templates, and the existing UI component library structure. The feature integrates seamlessly with existing systems like database operations, calendar synchronization, and internationalization.

Confidence score: 2/5

  • This PR has significant security and logic issues that make it unsafe to merge without major revisions
  • Critical permission validation logic uses AND instead of OR operators, potentially breaking authorization checks completely
  • Multiple areas lack proper error handling, input validation, and could cause runtime failures
  • Files that need more attention: packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts, packages/emails/templates/organizer-add-guests-email.ts, packages/ui/form/MultiEmail.tsx

14 files reviewed, 7 comments

Edit Code Review Bot Settings | Greptile

input,
});
}),
addGuests: authedProcedure.input(ZAddGuestsInputSchema).mutation(async ({ input, ctx }) => {
Copy link

Choose a reason for hiding this comment

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

logic: Using authedProcedure instead of bookingsProcedure means this endpoint bypasses the existing booking authorization middleware in util.ts. This creates inconsistent security patterns compared to other booking operations like editLocation.

import { z } from "zod";

export const ZAddGuestsInputSchema = z.object({
bookingId: z.number(),
Copy link

Choose a reason for hiding this comment

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

style: Consider using .int().positive() for more explicit booking ID validation

replyTo: [this.calEvent.organizer.email, ...this.calEvent.attendees.map(({ email }) => email)],
subject: `${this.t("guests_added_event_type_subject", {
eventType: this.calEvent.type,
name: this.calEvent.attendees[0].name,
Copy link

Choose a reason for hiding this comment

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

logic: Unsafe array access - calEvent.attendees[0] will throw if attendees array is empty. Add validation or use optional chaining.

});
const { isOpenDialog, setIsOpenDialog, bookingId } = props;
const utils = trpc.useUtils();
const [multiEmailValue, setMultiEmailValue] = useState<string[]>([""]);
Copy link

Choose a reason for hiding this comment

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

style: Consider using an empty array [] instead of [""] as the initial state to be more semantically correct and avoid the validation issue mentioned above

Comment on lines +26 to +29
const ZAddGuestsInputSchema = z.array(z.string().email()).refine((emails) => {
const uniqueEmails = new Set(emails);
return uniqueEmails.size === emails.length;
});
Copy link

Choose a reason for hiding this comment

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

style: The Zod schema is duplicated from the backend schema file. Consider importing the schema from packages/trpc/server/routers/viewer/bookings/addGuests.schema.ts to maintain single source of truth


function MultiEmail({ value, readOnly, label, setValue, placeholder }: MultiEmailProps) {
const { t } = useLocale();
value = value || [];
Copy link

Choose a reason for hiding this comment

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

logic: Mutating props directly can cause unexpected behavior. Use a derived state or default value instead.

Suggested change
value = value || [];
const emails = value || [];

Comment on lines +25 to +26
{value.map((field, index) => (
<li key={index}>
Copy link

Choose a reason for hiding this comment

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

logic: Using array index as React key can cause rendering issues when items are reordered. Consider using a unique ID for each email entry.

Comment on lines +80 to +82
color="minimal"
variant="button"
StartIcon="user-plus"
Copy link

Choose a reason for hiding this comment

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

syntax: The variant="button" prop may not be valid for Button component based on the component's interface.

Comment on lines +70 to +72
const blacklistedGuestEmails = process.env.BLACKLISTED_GUEST_EMAILS
? process.env.BLACKLISTED_GUEST_EMAILS.split(",").map((email) => email.toLowerCase())
: [];
Copy link

Choose a reason for hiding this comment

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

logic: Case sensitivity issue: blacklisted emails are converted to lowercase but guest emails aren't, potentially allowing blacklisted emails through

Suggested change
const blacklistedGuestEmails = process.env.BLACKLISTED_GUEST_EMAILS
? process.env.BLACKLISTED_GUEST_EMAILS.split(",").map((email) => email.toLowerCase())
: [];
const uniqueGuests = guests.filter(
(guest) =>
!booking.attendees.some((attendee) => guest === attendee.email) &&
!blacklistedGuestEmails.includes(guest.toLowerCase())
);

@github-actions
Copy link
Contributor

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Add guest management functionality to existing bookings". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@github-actions
Copy link
Contributor

This PR is being marked as stale due to inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants