Skip to content

Conversation

@dakshgup
Copy link

@dakshgup dakshgup commented Jul 14, 2025

This is a copy of #22492

Originally by: anikdhabal

Remove Revert.dev dependency from Pipedrive integration

Summary

This PR removes the dependency on Revert.dev from the Pipedrive CRM integration and implements direct OAuth2 authentication with Pipedrive's native API. The changes follow the same patterns used by other CRM integrations in the codebase (particularly HubSpot).

Key Changes:

  • OAuth Flow: Replaced Revert redirect with direct Pipedrive OAuth2 authorization
  • API Integration: Converted all API calls from Revert's unified format to Pipedrive's native REST API
  • Token Management: Implemented OAuth token storage and basic refresh logic
  • Environment Variables: Removed REVERT_* variables, now requires PIPEDRIVE_CLIENT_ID and PIPEDRIVE_CLIENT_SECRET
  • Data Mapping: Mapped contact and activity data between Revert's unified format and Pipedrive's native structure

Breaking Change: Existing Pipedrive integrations will need to be reconfigured with new OAuth credentials.

Review & Testing Checklist for Human

  • Test OAuth flow end-to-end - Create a Pipedrive OAuth app and verify the complete authorization flow works
  • Test contact creation and search - Verify contacts can be created and searched properly with real data
  • Test activity/meeting management - Verify activities can be created, updated, and deleted correctly
  • Verify token refresh logic - The current implementation is incomplete and may need proper refresh token handling
  • Test error handling - Verify proper error responses for failed API calls and invalid tokens

Recommended Test Plan:

  1. Set up a Pipedrive developer account and create an OAuth app
  2. Configure PIPEDRIVE_CLIENT_ID and PIPEDRIVE_CLIENT_SECRET in environment
  3. Test the integration setup flow in Cal.com
  4. Create a test booking and verify it creates contacts and activities in Pipedrive
  5. Test updating and canceling bookings

Diagram

%%{ init : { "theme" : "default" }}%%
graph TB
    subgraph "OAuth Flow"
        A["api/add.ts<br/>OAuth Authorization"]:::major-edit
        B["api/callback.ts<br/>Token Exchange"]:::major-edit
    end
    
    subgraph "CRM Integration"
        C["lib/CrmService.ts<br/>Pipedrive API Client"]:::major-edit
        D["config.json<br/>App Configuration"]:::minor-edit
    end
    
    subgraph "Configuration"
        E["turbo.json<br/>Environment Variables"]:::minor-edit
        F[".env.appStore.example<br/>Environment Template"]:::minor-edit
    end
    
    subgraph "External APIs"
        G["Pipedrive OAuth API<br/>oauth.pipedrive.com"]:::context
        H["Pipedrive REST API<br/>api.pipedrive.com"]:::context
    end
    
    A --> B
    B --> C
    C --> H
    A --> G
    B --> G
    C --> D
    
    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit
        L3[Context/No Edit]:::context
    end
    
    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#ADD8E6
    classDef context fill:#FFFFFF
Loading

Notes

  • Token Refresh: The current getValidAccessToken() implementation is incomplete - it doesn't actually refresh expired tokens, just returns the existing one. This should be addressed before production use.
  • OAuth Scopes: Using comprehensive scopes: deals:read,deals:write,persons:read,persons:write,activities:read,activities:write
  • API Mapping: Activities are used for meetings/events instead of a separate events API, following Pipedrive's data model
  • Error Handling: Basic error handling is implemented but may need enhancement for production edge cases

Session Info:

Summary by CodeRabbit

  • New Features

    • Improved Pipedrive integration to use secure OAuth authentication, including automatic token refresh and enhanced error handling.
    • Updated contact and activity management to align with Pipedrive’s latest API formats.
  • Refactor

    • Replaced previous API key-based authentication with OAuth tokens for all Pipedrive-related actions.
    • Renamed and updated methods to reflect Pipedrive’s terminology and API endpoints.
  • Chores

    • Removed obsolete Revert integration environment variables from configuration files.
    • Updated publisher and support information for the Pipedrive integration.

…drive integration

Originally by: anikdhabal

# Remove Revert.dev dependency from Pipedrive integration

## Summary

This PR removes the dependency on Revert.dev from the Pipedrive CRM integration and implements direct OAuth2 authentication with Pipedrive's native API. The changes follow the same patterns used by other CRM integrations in the codebase (particularly HubSpot).

**Key Changes:**
- **OAuth Flow**: Replaced Revert redirect with direct Pipedrive OAuth2 authorization
- **API Integration**: Converted all API calls from Revert's unified format to Pipedrive's native REST API
- **Token Management**: Implemented OAuth token storage and basic refresh logic
- **Environment Variables**: Removed `REVERT_*` variables, now requires `PIPEDRIVE_CLIENT_ID` and `PIPEDRIVE_CLIENT_SECRET`
- **Data Mapping**: Mapped contact and activity data between Revert's unified format and Pipedrive's native structure

**Breaking Change**: Existing Pipedrive integrations will need to be reconfigured with new OAuth credentials.

## Review & Testing Checklist for Human

- [ ] **Test OAuth flow end-to-end** - Create a Pipedrive OAuth app and verify the complete authorization flow works
- [ ] **Test contact creation and search** - Verify contacts can be created and searched properly with real data
- [ ] **Test activity/meeting management** - Verify activities can be created, updated, and deleted correctly
- [ ] **Verify token refresh logic** - The current implementation is incomplete and may need proper refresh token handling
- [ ] **Test error handling** - Verify proper error responses for failed API calls and invalid tokens

**Recommended Test Plan:**
1. Set up a Pipedrive developer account and create an OAuth app
2. Configure `PIPEDRIVE_CLIENT_ID` and `PIPEDRIVE_CLIENT_SECRET` in environment
3. Test the integration setup flow in Cal.com
4. Create a test booking and verify it creates contacts and activities in Pipedrive
5. Test updating and canceling bookings

---

### Diagram

```mermaid
%%{ init : { "theme" : "default" }}%%
graph TB
    subgraph "OAuth Flow"
        A["api/add.ts<br/>OAuth Authorization"]:::major-edit
        B["api/callback.ts<br/>Token Exchange"]:::major-edit
    end

    subgraph "CRM Integration"
        C["lib/CrmService.ts<br/>Pipedrive API Client"]:::major-edit
        D["config.json<br/>App Configuration"]:::minor-edit
    end

    subgraph "Configuration"
        E["turbo.json<br/>Environment Variables"]:::minor-edit
        F[".env.appStore.example<br/>Environment Template"]:::minor-edit
    end

    subgraph "External APIs"
        G["Pipedrive OAuth API<br/>oauth.pipedrive.com"]:::context
        H["Pipedrive REST API<br/>api.pipedrive.com"]:::context
    end

    A --> B
    B --> C
    C --> H
    A --> G
    B --> G
    C --> D

    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit
        L3[Context/No Edit]:::context
    end

    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#ADD8E6
    classDef context fill:#FFFFFF
```

### Notes

- **Token Refresh**: The current `getValidAccessToken()` implementation is incomplete - it doesn't actually refresh expired tokens, just returns the existing one. This should be addressed before production use.
- **OAuth Scopes**: Using comprehensive scopes: `deals:read,deals:write,persons:read,persons:write,activities:read,activities:write`
- **API Mapping**: Activities are used for meetings/events instead of a separate events API, following Pipedrive's data model
- **Error Handling**: Basic error handling is implemented but may need enhancement for production edge cases

**Session Info**:
- Link to Devin run: https://app.devin.ai/sessions/ca8c7c0a8b9b4b87ae92d5db2d23039a
- Requested by: @anikdhabal
@vercel
Copy link

vercel bot commented Jul 14, 2025

@dakshgup is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

Walkthrough

This update removes all references to the "REVERT" integration and its environment variables, transitioning the Pipedrive CRM integration to use direct OAuth authentication and API calls. The Pipedrive service logic, configuration, and API handlers are refactored for OAuth, and publisher metadata is updated. Unused variables and legacy comments are eliminated.

Changes

Files/Groups Change Summary
.env.appStore.example, turbo.json Removed all REVERT-related environment variables and associated comments.
packages/app-store/pipedrive-crm/api/add.ts Refactored OAuth URL construction, improved state handling, and cleaned up unused variables.
packages/app-store/pipedrive-crm/api/callback.ts Implemented explicit OAuth token exchange, credential retrieval, and improved validation.
packages/app-store/pipedrive-crm/config.json Updated publisher, email, and URL metadata from Revert.dev to Cal.com and Pipedrive.
packages/app-store/pipedrive-crm/lib/CrmService.ts Refactored to use OAuth tokens, added token refresh logic, updated API calls, and improved errors.

Poem

🐰
Goodbye to REVERT, the keys are all gone,
OAuth now dances with tokens at dawn.
Pipedrive shines with direct API calls,
Cal.com’s the publisher, standing tall.
No more old configs, no more confusion—
Just streamlined code in bunny profusion!
Hooray for the hop to a cleaner solution!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/app-store/pipedrive-crm/api/callback.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

packages/app-store/pipedrive-crm/api/add.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

packages/app-store/pipedrive-crm/lib/CrmService.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Jul 14, 2025
@graphite-app graphite-app bot requested a review from a team July 14, 2025 22:42
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 14, 2025

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 "Copy of PR #22492: feat: remove Revert.dev dependency from Pipedrive integration". 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 github-actions bot added the ❗️ .env changes contains changes to env variables label Jul 14, 2025
@dosubot dosubot bot added api area: API, enterprise API, access token, OAuth crm-apps area: crm apps, salesforce, hubspot, close.com, sendgrid labels Jul 14, 2025
@graphite-app
Copy link

graphite-app bot commented Jul 14, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (07/14/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add community label" took an action on this PR • (07/14/25)

1 label was added to this PR based on Keith Williams's automation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/app-store/pipedrive-crm/lib/CrmService.ts (2)

121-121: Remove redundant double negation.

The double negation is unnecessary as the value will be coerced to boolean in the ternary operator.

-const [firstName, lastName] = !!attendee.name ? attendee.name.split(" ") : [attendee.email, ""];
+const [firstName, lastName] = attendee.name ? attendee.name.split(" ") : [attendee.email, ""];

337-343: Consider implementing placeholder methods.

The unimplemented methods getAppOptions and handleAttendeeNoShow use console.log statements. Consider throwing a NotImplementedError or returning appropriate default values to better indicate these are intentionally not implemented.

 getAppOptions() {
-  console.log("No options implemented");
+  // Intentionally not implemented for Pipedrive integration
+  return {};
 }

 async handleAttendeeNoShow() {
-  console.log("Not implemented");
+  // Intentionally not implemented for Pipedrive integration
+  return Promise.resolve();
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe4946a and 9d7561f.

📒 Files selected for processing (6)
  • .env.appStore.example (0 hunks)
  • packages/app-store/pipedrive-crm/api/add.ts (2 hunks)
  • packages/app-store/pipedrive-crm/api/callback.ts (1 hunks)
  • packages/app-store/pipedrive-crm/config.json (1 hunks)
  • packages/app-store/pipedrive-crm/lib/CrmService.ts (2 hunks)
  • turbo.json (0 hunks)
💤 Files with no reviewable changes (2)
  • turbo.json
  • .env.appStore.example
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/app-store/pipedrive-crm/api/callback.ts (2)
packages/app-store/pipedrive-crm/api/add.ts (1)
  • handler (12-44)
packages/lib/constants.ts (1)
  • WEBAPP_URL_FOR_OAUTH (22-22)
🪛 Biome (1.9.4)
packages/app-store/pipedrive-crm/lib/CrmService.ts

[error] 121-121: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Security Check
🔇 Additional comments (4)
packages/app-store/pipedrive-crm/config.json (1)

7-12: LGTM! Metadata updates align with the migration.

The configuration changes correctly update the publisher information and URLs to reflect the direct Pipedrive integration.

packages/app-store/pipedrive-crm/api/add.ts (1)

35-41: OAuth implementation looks secure and well-structured.

The OAuth authorization URL is properly constructed with:

  • Dynamic redirect URI using WEBAPP_URL_FOR_OAUTH
  • Encoded state parameter for CSRF protection
  • Comprehensive scopes for CRM operations
  • Proper URL encoding of all parameters
packages/app-store/pipedrive-crm/lib/CrmService.ts (2)

54-115: Token refresh implementation is well-structured.

The getValidAccessToken method correctly:

  • Checks token expiry before refreshing
  • Uses Basic Auth for refresh requests
  • Updates the token in the database
  • Has proper error handling and logging

209-222: Activity creation properly formats Pipedrive data.

The implementation correctly:

  • Calculates duration in minutes
  • Formats date and time according to Pipedrive's API requirements
  • Uses plain text for notes instead of HTML
  • Associates the activity with the first contact

Comment on lines +46 to +60
const tokenResponse = await fetch("https://oauth.pipedrive.com/oauth/token", {
method: "POST",
headers: {
Authorization: authHeader,
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
code: code || "",
redirect_uri: redirectUri,
}),
});

const pipedriveToken: PipedriveToken = await tokenResponse.json();

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for token exchange response.

The token exchange request should check the response status before parsing JSON to handle failures gracefully.

Apply this fix:

 const tokenResponse = await fetch("https://oauth.pipedrive.com/oauth/token", {
   method: "POST",
   headers: {
     Authorization: authHeader,
     "Content-Type": "application/x-www-form-urlencoded",
   },
   body: new URLSearchParams({
     grant_type: "authorization_code",
     code: code || "",
     redirect_uri: redirectUri,
   }),
 });

+if (!tokenResponse.ok) {
+  const errorText = await tokenResponse.text();
+  return res.status(400).json({ 
+    message: `Failed to exchange authorization code: ${tokenResponse.status} ${errorText}` 
+  });
+}

 const pipedriveToken: PipedriveToken = await tokenResponse.json();
🤖 Prompt for AI Agents
In packages/app-store/pipedrive-crm/api/callback.ts between lines 46 and 60, the
code fetches the token without checking if the response was successful. Add a
check for tokenResponse.ok after the fetch call; if false, handle the error by
throwing or returning an appropriate error message before parsing the JSON. This
ensures graceful handling of failed token exchange requests.

@hbjORbj hbjORbj closed this Jul 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api area: API, enterprise API, access token, OAuth community Created by Linear-GitHub Sync crm-apps area: crm apps, salesforce, hubspot, close.com, sendgrid ❗️ .env changes contains changes to env variables

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants