Skip to content

Conversation

@hussam789
Copy link

@hussam789 hussam789 commented Oct 30, 2025

Add guest management functionality to existing bookings

* 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]>
@qodo-code-review
Copy link

qodo-code-review bot commented Oct 30, 2025

PR Overview by Qodo

⏱️ 10 to 30 minute review ✅ ️100% Passing Rules (24) ✨ New Feature

This PR adds guest management functionality to booking list items, including UI, backend handlers, and email notifications

Walkthroughs
Description

✨ New Feature (5) 📝 Documentation (1)

• Add guest management UI dialog to booking list items
• Implement backend handler for adding guests to bookings
• Create email notifications for organizers and attendees
• Add multi-email input component for guest selection
• Update calendar events with newly added guests
Diagram
flowchart LR
 A["BookingListItem"] -->|"opens"| B["AddGuestsDialog"]
 B -->|"submits emails"| C["addGuestsHandler"]
 C -->|"updates"| D["Booking Attendees"]
 C -->|"updates"| E["Calendar Event"]
 C -->|"sends"| F["Email Notifications"]
 F -->|"to organizer"| G["OrganizerAddGuestsEmail"]
 F -->|"to attendees"| H["AttendeeAddGuestsEmail"]
Loading

Files
➀ apps/web/components/booking/BookingListItem.tsx +15 lines ✨ New Feature
• Add guest management dialog to booking actions
• Integrated AddGuestsDialog component
• Added UI controls for guest management

apps/web/components/booking/BookingListItem.tsx [45-89]


➁ apps/web/components/dialog/AddGuestsDialog.tsx +107 lines ✨ New Feature
• New dialog component for adding guests
• Implements multi-email input for guest selection
• Handles guest addition submission to backend

apps/web/components/dialog/AddGuestsDialog.tsx [1-107]


➂ packages/lib/server/email-manager.ts +28 lines ✨ New Feature
• Add email sending function for guest additions
• Sends notifications to organizers and attendees
• Handles email delivery for guest management events

packages/lib/server/email-manager.ts [234-262]


➃ packages/emails/templates/AttendeeAddGuestsEmail.tsx +10 lines ✨ New Feature
• New email template for attendee notifications
• Notifies attendees when guests are added to their booking
• Provides booking details and guest information

packages/emails/templates/AttendeeAddGuestsEmail.tsx [1-10]


➄ packages/emails/templates/OrganizerAddGuestsEmail.tsx +11 lines ✨ New Feature
• New email template for organizer notifications
• Notifies organizers when guests are added to bookings
• Includes guest list and booking details

packages/emails/templates/OrganizerAddGuestsEmail.tsx [1-11]


➅ packages/emails/templates/index.ts +2 lines ✨ New Feature
• Export new guest addition email templates
• Added exports for AttendeeAddGuestsEmail and OrganizerAddGuestsEmail
• Makes templates available throughout the application

packages/emails/templates/index.ts [45-78]


➆ packages/lib/emails/attendee-add-guests-email.ts +34 lines ✨ New Feature
• Email payload generation for attendees
• Constructs email data for attendee notifications
• Includes booking and guest information

packages/lib/emails/attendee-add-guests-email.ts [1-34]


➇ packages/lib/emails/organizer-add-guests-email.ts +38 lines ✨ New Feature
• Email payload generation for organizers
• Constructs email data for organizer notifications
• Formats guest list and booking details

packages/lib/emails/organizer-add-guests-email.ts [1-38]


➈ packages/trpc/server/routers/viewer/bookings/_router.tsx +19 lines ✨ New Feature
• Register addGuests mutation in bookings router
• Creates API endpoint for guest addition
• Connects frontend to backend handler

packages/trpc/server/routers/viewer/bookings/_router.tsx [78-123]


⑩ apps/web/public/static/locales/en/common.json +6 lines 📝 Documentation
• Add translation keys for guest management
• Provides localized text for guest addition feature
• Includes labels for dialogs, buttons, and messages

apps/web/public/static/locales/en/common.json [456-789]


 ⓘ Don't like the new UI? Learn how to revert the configuration  

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Oct 30, 2025

Code Review by Qodo (Alpha)

Automated review surfaced additional insights for this pull request.

💡 Suggestions (2) 🐞 Bugs (2) ⚠️ Rule Violations (0) 📋 Requirements Gap (0)


Grey Divider

Issue Findings


Action Required

➀ Overly permissive authorization allows any attendee to add guests 🐞 bug
Description
The current authorization logic permits any booking attendee to add more guests to an event. This
is overly permissive and creates potential security and privacy risks. Any attendee who receives
a booking invitation can add additional guests without the organizer's knowledge or consent. This
could lead to:
- Privacy violations when sensitive meetings have unexpected attendees added
- Event capacity issues when attendees add more guests than planned
- Abuse scenarios where malicious attendees add spam or unwanted guests
- Loss of control for the event organizer over who attends their events

The permission to add guests should be restricted to only the event organizer and team
administrators who have appropriate authority over the event.

⛨ Security

Code Reference
const isAttendee = !!booking.attendees.find((attendee) => attendee.email === user.email);

if (!isTeamAdminOrOwner && !isOrganizer && !isAttendee) {
 throw new TRPCError({ code: "FORBIDDEN", message: "you_do_not_have_permission" });
}

packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[52-56]

Agent Prompt
## Issue Description
The authorization check allows any booking attendee to add guests, which is overly permissive and creates security and privacy risks.

## Issue Context
The current logic checks if the user is a team admin, organizer, OR attendee. This means any attendee can add additional guests without organizer approval, which could lead to privacy violations and abuse.

## Fix Focus Areas
- packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[52-56]

Restrict authorization to only admins and organizers:
```typescript
const isTeamAdminOrOwner = ...;
const isOrganizer = booking.userId === user.id;

// Remove isAttendee from authorization check
if (!isTeamAdminOrOwner && !isOrganizer) {
 throw new TRPCError({ code: "FORBIDDEN", message: "you_do_not_have_permission" });
}
```

Alternative: Add a configurable option on the event type if attendee guest addition should be allowed:
```typescript
const canAttendeesAddGuests = booking.eventType.metadata?.allowAttendeesToAddGuests;
if (!isTeamAdminOrOwner && !isOrganizer && !(isAttendee && canAttendeesAddGuests)) {
 throw new TRPCError({ code: "FORBIDDEN" });
}
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation Recommended

➁ Incorrect logical operator in authorization check 🐞 bug

✓ Correctness ◐ Remediation Recommended

Description
The authorization check for `isTeamAdminOrOwner` uses a logical AND (`&&`) operator instead of
OR (`||`), which is incorrect given the variable name and intended behavior. This bug means that a
user must be BOTH a team admin AND a team owner to pass this check, which is virtually impossible
since these are typically mutually exclusive roles. The correct logic should check if the user is
EITHER a team admin OR a team owner. This bug could improperly deny access to legitimate team
administrators and team owners who should have permission to add guests.
Code Reference
const isTeamAdminOrOwner =
 (await isTeamAdmin(user.id, booking.eventType?.teamId ?? 0)) &&
 (await isTeamOwner(user.id, booking.eventType?.teamId ?? 0));

packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[46-48]

Agent Prompt
## Issue Description
The authorization logic uses AND (`&&`) instead of OR (`||`) when checking if a user is a team admin or owner, which incorrectly requires both conditions to be true.

## Issue Context
The variable name `isTeamAdminOrOwner` indicates it should be true if the user is either a team admin OR a team owner. Using AND means only users who are both admin AND owner would pass, which is not the intended behavior.

## Fix Focus Areas
- packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[46-48]

Change the logical operator from AND to OR:
```typescript
const isTeamAdminOrOwner =
 (await isTeamAdmin(user.id, booking.eventType?.teamId ?? 0)) ||
 (await isTeamOwner(user.id, booking.eventType?.teamId ?? 0));
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


➂ Filter empty emails before validation 💡 Suggestion

✧ Quality ◐ Remediation Recommended

Description
The `handleAdd` function validates `multiEmailValue` without first filtering out empty email
strings. This could lead to poor user experience when users accidentally have empty fields in the
multi-email input (for example, trailing commas or empty lines). The validation would fail and show
an error even though the user's intent was clear. By filtering out empty email strings before
validation, the function becomes more user-friendly and forgiving of minor input mistakes. This
also ensures that only meaningful email addresses are validated and sent to the server.
Code Reference
const handleAdd = () => {
 if (multiEmailValue.length === 0) {
   return;
 }
 const validationResult = ZAddGuestsInputSchema.safeParse(multiEmailValue);
 if (validationResult.success) {
   addGuestsMutation.mutate({ bookingId, guests: multiEmailValue });
 } else {
   setIsInvalidEmail(true);
 }
};

apps/web/components/dialog/AddGuestsDialog.tsx[48-58]

Agent Prompt
## Issue Description
The email validation doesn't filter out empty strings before validation, which could cause unnecessary validation errors for minor user input mistakes.

## Issue Context
Users might accidentally include empty fields in multi-email input (trailing commas, empty lines). Without filtering, these cause validation failures even when the user's intent is clear.

## Fix Focus Areas
- apps/web/components/dialog/AddGuestsDialog.tsx[48-58]

Filter empty emails before validation:
```typescript
const handleAdd = () => {
 const guests = multiEmailValue.filter((email) => email.trim() !== "");
 if (guests.length === 0) {
   return;
 }
 const validationResult = ZAddGuestsInputSchema.safeParse(guests);
 if (validationResult.success) {
   setIsInvalidEmail(false);
   addGuestsMutation.mutate({ bookingId, guests });
 } else {
   setIsInvalidEmail(true);
 }
};
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory Comments

➃ Use case-insensitive email comparison 💡 Suggestion

✧ Quality ⚙ Advisory Comment

Description
The `uniqueGuests` filter uses case-sensitive string comparison when checking for duplicate
emails. Since email addresses are case-insensitive according to RFC 5321, comparing emails without
normalizing case could allow duplicate guests to be added if the same email is entered with
different casing (e.g., "[email protected]" vs "[email protected]"). While most email systems handle
this correctly, it's better to normalize email comparisons in the application to ensure data
integrity and prevent any confusion. This is particularly important for filtering against
blacklisted emails, where case variations could bypass the filter.
Code Reference
const uniqueGuests = guests.filter(
 (guest) =>
   !booking.attendees.some((attendee) => guest === attendee.email) &&
   !blacklistedGuestEmails.includes(guest)
);

packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[74-78]

Agent Prompt
## Issue Description
Email comparisons are case-sensitive, which could allow duplicate guests with different casing and bypass blacklist filters.

## Issue Context
Email addresses are case-insensitive per RFC 5321. Without case normalization, the same email with different casing ([email protected] vs [email protected]) could be treated as different, leading to duplicates.

## Fix Focus Areas
- packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts[74-78]

Use case-insensitive comparison:
```typescript
const uniqueGuests = guests.filter(
 (guest) =>
   !booking.attendees.some((attendee) => guest.toLowerCase() === attendee.email.toLowerCase()) &&
   !blacklistedGuestEmails.includes(guest.toLowerCase())
);
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Grey Divider

✦ Collected Context

Commits (2)

baa9045 a1b2c3d

Files
packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts [1-150] apps/web/components/dialog/AddGuestsDialog.tsx [1-200]
Diffs
packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts [40-85] apps/web/components/dialog/AddGuestsDialog.tsx [45-65]
Branches (2)
⎇ main ⎇ feature/add-guests-enhancement
PRs & Comments (1)
PR #9
Tickets
Linear | CAL-425
MCP & Custom Context
Notion | Authorization Guidelines

Grey Divider

⁈ Additional Information

Review Configuration
User
@SecurityReviewer
License
Enterprise
Mode
Comprehensive
Finding Categories

⛨ Security (1) ✓ Correctness (1) ✧ Quality (2) ⚠️ Action Required (1) ◐ Remediation Recommended (2) ⚙ Advisory Comment (1)

Grey Divider

Qodo Logo

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants