Skip to content

Conversation

@Pallava-Joshi
Copy link
Member

What does this PR do?

When a booking is made, automatically sets the HubSpot contact's hubspot_owner_id to match the Cal.com organizer (the sales rep assigned to the meeting). Also overwrites the owner, if the toggle is on, otherwise set to the first sales rep.

Video Demo (if applicable):

Screen.Recording.2026-01-07.at.12.53.43.PM.mov

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Jan 7, 2026
@vercel
Copy link

vercel bot commented Jan 7, 2026

@Pallava-Joshi is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 4 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/hubspot/lib/CrmService.ts">

<violation number="1" location="packages/app-store/hubspot/lib/CrmService.ts:407">
P1: Rule violated: **Avoid Logging Sensitive Information**

Logging the entire `meetingEvent` object exposes potentially sensitive user data. The meeting body contains user form responses, additional notes, location, and description. Consider reverting to logging only the meeting ID:
```typescript
this.log.debug("meeting:creation:ok", { meetingId: meetingEvent.id });
```</violation>

<violation number="2" location="packages/app-store/hubspot/lib/CrmService.ts:549">
P2: The `getPage()` call without parameters fetches all HubSpot owners instead of filtering by email server-side. The previous implementation used the email parameter to filter server-side. This causes unnecessary data transfer and may miss the owner if there are more owners than the default page size (pagination not handled).

Consider passing the email parameter to enable server-side filtering:
```typescript
const ownersResponse = await this.hubspotClient.crm.owners.ownersApi.getPage(email);
```</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@Pallava-Joshi
Copy link
Member Author

@cubic-dev-ai leave a review

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Jan 9, 2026

@cubic-dev-ai leave a review

@Pallava-Joshi I have started the AI code review. It will take a few minutes to complete.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/hubspot/lib/CrmService.ts">

<violation number="1" location="packages/app-store/hubspot/lib/CrmService.ts:66">
P2: Organizer information was removed from the HubSpot meeting body. This may be unintentional - the PR description mentions adding a contact owner toggle, but doesn't mention removing organizer info from meeting descriptions. HubSpot meeting records will no longer show who organized the meeting in the body text. If this is intentional, please confirm; otherwise, consider preserving the organizer info.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@Amit91848 Amit91848 left a comment

Choose a reason for hiding this comment

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

Added some comments

Comment on lines +4189 to +4190
"hubspot_set_organizer_as_owner": "Set organizer as contact owner",
"hubspot_overwrite_contact_owner": "Overwrite existing contact owner",
Copy link
Contributor

Choose a reason for hiding this comment

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

since the text is not app specific, can we rename the keys here to not include app name. We can re use it for other apps then

Comment on lines -440 to -445
const organizerEmail = event.organizer.email;
this.log.debug("hubspot:meeting:fetching_owner");

const hubspotOwnerId = await this.getHubspotOwnerIdByEmail(organizerEmail);

const meetingEvent = await this.hubspotCreateMeeting(event, hubspotOwnerId);
Copy link
Contributor

@Amit91848 Amit91848 Jan 9, 2026

Choose a reason for hiding this comment

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

Contact owners and meeting owners are two separate things.

Meeeting owners basically mean the organizer / host of the current meeting. This will always be the event.organizer.email. This logic will remain the same
booking organizer -> will always be the meeting owner

Can you revert this please

Comment on lines +591 to +597
private async maybeSetContactOwner(
contactId: string,
ownerId: string,
overwriteContactOwner: boolean
): Promise<void> {
if (overwriteContactOwner) {
await this.setContactOwner(contactId, ownerId);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a big fan of such naming maybeSetContactOwner, can we have something more conclusive so it's easy to know what the function does just name?

setOwnerIf....

Comment on lines +415 to +429
const appOptions = this.getAppOptions();
if (appOptions?.setOrganizerAsOwner) {
const organizerEmail = event.organizer.email;
const ownerId = await this.getHubspotOwnerIdFromEmail(organizerEmail);
if (ownerId) {
const firstContact = contacts[0];
if (firstContact?.id) {
await this.maybeSetContactOwner(
firstContact.id,
ownerId,
appOptions?.overwriteContactOwner ?? false
);
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make this easy on the eyes

Suggested change
const appOptions = this.getAppOptions();
if (appOptions?.setOrganizerAsOwner) {
const organizerEmail = event.organizer.email;
const ownerId = await this.getHubspotOwnerIdFromEmail(organizerEmail);
if (ownerId) {
const firstContact = contacts[0];
if (firstContact?.id) {
await this.maybeSetContactOwner(
firstContact.id,
ownerId,
appOptions?.overwriteContactOwner ?? false
);
}
}
}
const firstContact = contacts[0];
const appOptions = this.getAppOptions();
// Since you are reverting the change where you removed meeting owner from being set earlier
if (hubspotOwnerId && firstContact?.id && appOptions?.setOrganizerAsOwner) {
await this.maybeSetContactOwner(
firstContact.id,
ownerId,
appOptions?.overwriteContactOwner ?? false
)
}

@github-actions github-actions bot marked this pull request as draft January 9, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Created by Linear-GitHub Sync ready-for-e2e size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants