* feat: remove Revert.dev dependency from Pipedrive integration - Replace Revert API calls with direct Pipedrive OAuth2 and REST API - Update OAuth flow to use Pipedrive's authorization endpoint - Implement token exchange in callback handler - Map Revert's unified API format to Pipedrive's native API structure - Remove REVERT_* environment variables from configuration - Update app config to reflect direct Pipedrive integration - Follow patterns from other CRM integrations like HubSpot Breaking change: Requires PIPEDRIVE_CLIENT_ID and PIPEDRIVE_CLIENT_SECRET environment variables instead of REVERT_* variables Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * feat: implement proper token refresh logic for Pipedrive OAuth - Add token refresh implementation following Pipedrive OAuth2 specification - Use proper Basic Auth for token refresh requests - Handle token refresh errors with appropriate logging - Update access token and expiry date after successful refresh - Add note about database credential update requirement Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * feat: add database credential updates for Pipedrive token refresh - Import updateTokenObjectInDb utility for proper credential management - Store credentialId in constructor for database updates - Update token refresh logic to persist refreshed tokens to database - Follow Cal.com patterns for OAuth credential management - Ensure tokens are properly updated after successful refresh Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * refactor: use OAuthManager for Pipedrive token management - Refactor CrmService.ts to use OAuthManager instead of manual token refresh - Create getPipedriveAppKeys helper function for client credentials - Update callback.ts to use the new helper function - Add requestPipedrive helper method for all API calls - Implement proper token refresh callbacks (isTokenObjectUnusable, isAccessTokenUnusable) This addresses the review comments from hariom and cubic on PR #22492. Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * fix: validate token endpoint response before storing Pipedrive credentials Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
|
|
import { createDefaultInstallation } from "@calcom/app-store/_utils/installation";
|
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
|
import { WEBAPP_URL_FOR_OAUTH } from "@calcom/lib/constants";
|
|
import { HttpError } from "@calcom/lib/http-error";
|
|
|
|
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
|
|
import { encodeOAuthState } from "../../_utils/oauth/encodeOAuthState";
|
|
import appConfig from "../config.json";
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
if (req.method !== "GET") return res.status(405).json({ message: "Method not allowed" });
|
|
|
|
const appKeys = await getAppKeysFromSlug(appConfig.slug);
|
|
let client_id = "";
|
|
if (typeof appKeys.client_id === "string") client_id = appKeys.client_id;
|
|
if (!client_id) return res.status(400).json({ message: "Pipedrive client id missing." });
|
|
|
|
req.session = await getServerSession({ req });
|
|
const { teamId } = req.query;
|
|
const user = req.session?.user;
|
|
if (!user) {
|
|
throw new HttpError({ statusCode: 401, message: "You must be logged in to do this" });
|
|
}
|
|
|
|
await createDefaultInstallation({
|
|
appType: `${appConfig.slug}_other_calendar`,
|
|
user,
|
|
slug: appConfig.slug,
|
|
key: {},
|
|
teamId: Number(teamId),
|
|
});
|
|
|
|
const redirectUri = `${WEBAPP_URL_FOR_OAUTH}/api/integrations/pipedrive-crm/callback`;
|
|
const state = encodeOAuthState(req);
|
|
const scopes = "deals:read,deals:write,persons:read,persons:write,activities:read,activities:write";
|
|
|
|
const url = `https://oauth.pipedrive.com/oauth/authorize?client_id=${client_id}&redirect_uri=${encodeURIComponent(
|
|
redirectUri
|
|
)}&state=${encodeURIComponent(state || "")}&response_type=code&scope=${encodeURIComponent(scopes)}`;
|
|
|
|
res.status(200).json({ url, newTab: true });
|
|
}
|