Skip to content

Commit a36b46b

Browse files
zomarsleogPeerRichkodiakhq[bot]
authored
Feat/salesforce app (calcom#5649)
* WIP * warnings and errors, and working app * Refresh token now usable * Correcting env.appStore.example * Reverting changes that will come from Sendgrid App PR * Resetting with main * Renaming all othercalendars * Fixing types * Renaming leftovers * More renaming stuff * Format readme * Adds prettier override for website wordlist * Omit salesforce app in this PR * Revert "Omit salesforce app in this PR" This reverts commit 22c09fe. * Update yarn.lock Co-authored-by: Leo Giovanetti <[email protected]> Co-authored-by: Peer Richelsen <[email protected]> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent a94d51c commit a36b46b

20 files changed

+595
-13
lines changed

.env.appStore.example

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# - ZAPIER
1515
# - LARK
1616
# - WEB3
17+
# - SALESFORCE
1718

1819
# - APP STORE **********************************************************************************************
1920
# ⚠️ ⚠️ ⚠️ THESE WILL BE MIGRATED TO THE DATABASE TO PREVENT AWS's 4KB ENV QUOTA ⚠️ ⚠️ ⚠️
@@ -103,4 +104,9 @@ LARK_OPEN_VERIFICATION_TOKEN=""
103104
# @see https://github.com/calcom/cal.com/blob/main/packages/app-store/rainbow/README.md
104105
ALCHEMY_API_KEY=""
105106
INFURA_API_KEY=""
107+
108+
# - SALESFORCE
109+
# Used for the Salesforce (Sales Cloud) app
110+
SALESFORCE_CONSUMER_KEY=""
111+
SALESFORCE_CONSUMER_SECRET=""
106112
# *********************************************************************************************************

packages/app-store/apps.metadata.generated.ts

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { metadata as qr_code_meta } from "./qr_code/_metadata";
3030
import { metadata as rainbow_meta } from "./rainbow/_metadata";
3131
import { metadata as raycast_meta } from "./raycast/_metadata";
3232
import { metadata as riverside_meta } from "./riverside/_metadata";
33+
import { metadata as salesforce_meta } from "./salesforce/_metadata";
3334
import { metadata as sendgrid_meta } from "./sendgrid/_metadata";
3435
import { metadata as signal_meta } from "./signal/_metadata";
3536
import { metadata as sirius_video_meta } from "./sirius_video/_metadata";
@@ -73,6 +74,7 @@ export const appStoreMetadata = {
7374
rainbow: rainbow_meta,
7475
raycast: raycast_meta,
7576
riverside: riverside_meta,
77+
salesforce: salesforce_meta,
7678
sendgrid: sendgrid_meta,
7779
signal: signal_meta,
7880
sirius_video: sirius_video_meta,

packages/app-store/apps.server.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const apiHandlers = {
2929
rainbow: import("./rainbow/api"),
3030
raycast: import("./raycast/api"),
3131
riverside: import("./riverside/api"),
32+
salesforce: import("./salesforce/api"),
3233
sendgrid: import("./sendgrid/api"),
3334
signal: import("./signal/api"),
3435
sirius_video: import("./sirius_video/api"),

packages/app-store/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import * as jitsivideo from "./jitsivideo";
1515
import * as larkcalendar from "./larkcalendar";
1616
import * as office365calendar from "./office365calendar";
1717
import * as office365video from "./office365video";
18+
import * as salesforce from "./salesforce";
1819
import * as sendgrid from "./sendgrid";
1920
import * as stripepayment from "./stripepayment";
2021
import * as tandemvideo from "./tandemvideo";
@@ -37,6 +38,7 @@ const appStore = {
3738
larkcalendar,
3839
office365calendar,
3940
office365video,
41+
salesforce,
4042
sendgrid,
4143
stripepayment,
4244
tandemvideo,
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
description: Salesforce (Sales Cloud) is a cloud-based application designed to help your salespeople sell smarter and faster by centralizing customer information, logging their interactions with your company, and automating many of the tasks salespeople do every day.
3+
items:
4+
- /api/app-store/salesforce/1.png
5+
---
6+
7+
{description}
8+
<br/>
9+
<p class="mb-0">Features:</p>
10+
<ul class="mt-0">
11+
<li>Creates event attendees as contacts in Salesforce (Sales Cloud)</li>
12+
</ul>
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { AppMeta } from "@calcom/types/App";
2+
3+
import config from "./config.json";
4+
5+
export const metadata = {
6+
category: "other",
7+
...config,
8+
} as AppMeta;
9+
10+
export default metadata;
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import jsforce from "jsforce";
2+
import type { NextApiRequest, NextApiResponse } from "next";
3+
4+
import { WEBAPP_URL } from "@calcom/lib/constants";
5+
6+
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
7+
8+
let consumer_key = "";
9+
10+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
11+
if (req.method !== "GET") return res.status(405).json({ message: "Method not allowed" });
12+
13+
const appKeys = await getAppKeysFromSlug("salesforce");
14+
if (typeof appKeys.consumer_key === "string") consumer_key = appKeys.consumer_key;
15+
if (!consumer_key) return res.status(400).json({ message: "Salesforce client id missing." });
16+
17+
const salesforceClient = new jsforce.Connection({
18+
clientId: consumer_key,
19+
redirectUri: `${WEBAPP_URL}/api/integrations/salesforce/callback`,
20+
});
21+
22+
const url = salesforceClient.oauth2.getAuthorizationUrl({ scope: "refresh_token full" });
23+
res.status(200).json({ url });
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import jsforce from "jsforce";
2+
import type { NextApiRequest, NextApiResponse } from "next";
3+
4+
import { WEBAPP_URL } from "@calcom/lib/constants";
5+
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
6+
import prisma from "@calcom/prisma";
7+
8+
import { decodeOAuthState } from "../../_utils/decodeOAuthState";
9+
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
10+
import getInstalledAppPath from "../../_utils/getInstalledAppPath";
11+
12+
let consumer_key = "";
13+
let consumer_secret = "";
14+
const instance_url = "";
15+
16+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
17+
const { code } = req.query;
18+
19+
if (code === undefined && typeof code !== "string") {
20+
res.status(400).json({ message: "`code` must be a string" });
21+
return;
22+
}
23+
24+
if (!req.session?.user?.id) {
25+
return res.status(401).json({ message: "You must be logged in to do this" });
26+
}
27+
28+
const appKeys = await getAppKeysFromSlug("salesforce");
29+
if (typeof appKeys.consumer_key === "string") consumer_key = appKeys.consumer_key;
30+
if (typeof appKeys.consumer_secret === "string") consumer_secret = appKeys.consumer_secret;
31+
if (!consumer_key) return res.status(400).json({ message: "Salesforce consumer key missing." });
32+
if (!consumer_secret) return res.status(400).json({ message: "Salesforce consumer secret missing." });
33+
34+
const conn = new jsforce.Connection({
35+
clientId: consumer_key,
36+
clientSecret: consumer_secret,
37+
redirectUri: WEBAPP_URL + "/api/integrations/salesforce/callback",
38+
});
39+
40+
const salesforceTokenInfo = await conn.oauth2.requestToken(code as string);
41+
42+
await prisma.credential.create({
43+
data: {
44+
type: "salesforce_other_calendar",
45+
key: salesforceTokenInfo as any,
46+
userId: req.session.user.id,
47+
appId: "salesforce",
48+
},
49+
});
50+
51+
const state = decodeOAuthState(req);
52+
res.redirect(
53+
getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "other", slug: "salesforce" })
54+
);
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as add } from "./add";
2+
export { default as callback } from "./callback";

packages/app-store/salesforce/components/.gitkeep

Whitespace-only changes.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"/*": "Don't modify slug - If required, do it using cli edit command",
3+
"name": "Salesforce",
4+
"slug": "salesforce",
5+
"type": "salesforce_other_calendar",
6+
"imageSrc": "/api/app-store/salesforce/icon.png",
7+
"logo": "/api/app-store/salesforce/icon.png",
8+
"url": "https://cal.com/apps/salesforce",
9+
"variant": "other_calendar",
10+
"categories": ["other"],
11+
"publisher": "Cal.com",
12+
"email": "[email protected]",
13+
"description": "Salesforce (Sales Cloud) is a cloud-based application designed to help your salespeople sell smarter and faster by centralizing customer information, logging their interactions with your company, and automating many of the tasks salespeople do every day.",
14+
"extendsFeature": "User",
15+
"__createdUsingCli": true
16+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * as api from "./api";
2+
export * as lib from "./lib";
3+
export { metadata } from "./_metadata";

0 commit comments

Comments
 (0)