Skip to content

Commit 4a35689

Browse files
authored
Intercom Connector: Models & Skeleton to manage connector object (#2564)
* Intercom Connector: Models & Skeleton to manage connector object * Apply feedback
1 parent e07abbb commit 4a35689

File tree

8 files changed

+359
-0
lines changed

8 files changed

+359
-0
lines changed

connectors/package-lock.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

connectors/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"fs-extra": "^11.1.1",
3636
"googleapis": "^118.0.0",
3737
"hot-shots": "^10.0.0",
38+
"intercom-client": "^4.0.0",
3839
"io-ts": "^2.2.20",
3940
"io-ts-reporters": "^2.0.1",
4041
"lodash.get": "^4.4.2",

connectors/src/admin/db.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import {
2222
SlackConfiguration,
2323
SlackMessages,
2424
} from "@connectors/lib/models";
25+
import {
26+
IntercomArticle,
27+
IntercomCollection,
28+
} from "@connectors/lib/models/intercom";
2529
import logger from "@connectors/logger/logger";
2630

2731
async function main(): Promise<void> {
@@ -44,6 +48,8 @@ async function main(): Promise<void> {
4448
await NotionConnectorPageCacheEntry.sync({ alter: true });
4549
await NotionConnectorResourcesToCheckCacheEntry.sync({ alter: true });
4650
await GoogleDriveConfig.sync({ alter: true });
51+
await IntercomCollection.sync({ alter: true });
52+
await IntercomArticle.sync({ alter: true });
4753

4854
// enable the `unaccent` extension
4955
await sequelize_conn.query("CREATE EXTENSION IF NOT EXISTS unaccent;");

connectors/src/connectors/index.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ import {
2020
updateGoogleDriveConnector,
2121
} from "@connectors/connectors/google_drive";
2222
import { launchGoogleDriveFullSyncWorkflow } from "@connectors/connectors/google_drive/temporal/client";
23+
import {
24+
cleanupIntercomConnector,
25+
createIntercomConnector,
26+
fullResyncIntercomConnector,
27+
resumeIntercomConnector,
28+
retrieveIntercomConnectorPermissions,
29+
retrieveIntercomResourcesTitles,
30+
stopIntercomConnector,
31+
updateIntercomConnector,
32+
} from "@connectors/connectors/intercom";
2333
import {
2434
BotEnabledGetter,
2535
BotToggler,
@@ -73,6 +83,7 @@ export const CREATE_CONNECTOR_BY_TYPE: Record<
7383
notion: createNotionConnector,
7484
github: createGithubConnector,
7585
google_drive: createGoogleDriveConnector,
86+
intercom: createIntercomConnector,
7687
};
7788

7889
export const UPDATE_CONNECTOR_BY_TYPE: Record<
@@ -83,6 +94,7 @@ export const UPDATE_CONNECTOR_BY_TYPE: Record<
8394
notion: updateNotionConnector,
8495
github: updateGithubConnector,
8596
google_drive: updateGoogleDriveConnector,
97+
intercom: updateIntercomConnector,
8698
};
8799

88100
export const STOP_CONNECTOR_BY_TYPE: Record<
@@ -99,6 +111,7 @@ export const STOP_CONNECTOR_BY_TYPE: Record<
99111
logger.info({ connectorId }, `Stopping Google Drive connector is a no-op.`);
100112
return new Ok(connectorId);
101113
},
114+
intercom: stopIntercomConnector,
102115
};
103116

104117
export const DELETE_CONNECTOR_BY_TYPE: Record<
@@ -109,6 +122,7 @@ export const DELETE_CONNECTOR_BY_TYPE: Record<
109122
notion: cleanupNotionConnector,
110123
github: cleanupGithubConnector,
111124
google_drive: cleanupGoogleDriveConnector,
125+
intercom: cleanupIntercomConnector,
112126
};
113127

114128
export const RESUME_CONNECTOR_BY_TYPE: Record<
@@ -124,6 +138,7 @@ export const RESUME_CONNECTOR_BY_TYPE: Record<
124138
google_drive: async (connectorId: string) => {
125139
throw new Error(`Not implemented ${connectorId}`);
126140
},
141+
intercom: resumeIntercomConnector,
127142
};
128143

129144
const toggleBotNotImplemented = async (
@@ -139,6 +154,7 @@ export const TOGGLE_BOT_BY_TYPE: Record<ConnectorProvider, BotToggler> = {
139154
notion: toggleBotNotImplemented,
140155
github: toggleBotNotImplemented,
141156
google_drive: toggleBotNotImplemented,
157+
intercom: toggleBotNotImplemented,
142158
};
143159

144160
const getBotEnabledNotImplemented = async (
@@ -159,6 +175,7 @@ export const GET_BOT_ENABLED_BY_TYPE: Record<
159175
notion: getBotEnabledNotImplemented,
160176
github: getBotEnabledNotImplemented,
161177
google_drive: getBotEnabledNotImplemented,
178+
intercom: getBotEnabledNotImplemented,
162179
};
163180

164181
export const SYNC_CONNECTOR_BY_TYPE: Record<ConnectorProvider, SyncConnector> =
@@ -167,6 +184,7 @@ export const SYNC_CONNECTOR_BY_TYPE: Record<ConnectorProvider, SyncConnector> =
167184
notion: fullResyncNotionConnector,
168185
github: fullResyncGithubConnector,
169186
google_drive: launchGoogleDriveFullSyncWorkflow,
187+
intercom: fullResyncIntercomConnector,
170188
};
171189

172190
export const RETRIEVE_CONNECTOR_PERMISSIONS_BY_TYPE: Record<
@@ -177,6 +195,7 @@ export const RETRIEVE_CONNECTOR_PERMISSIONS_BY_TYPE: Record<
177195
github: retrieveGithubConnectorPermissions,
178196
notion: retrieveNotionConnectorPermissions,
179197
google_drive: retrieveGoogleDriveConnectorPermissions,
198+
intercom: retrieveIntercomConnectorPermissions,
180199
};
181200

182201
export const SET_CONNECTOR_PERMISSIONS_BY_TYPE: Record<
@@ -195,6 +214,13 @@ export const SET_CONNECTOR_PERMISSIONS_BY_TYPE: Record<
195214
);
196215
},
197216
google_drive: setGoogleDriveConnectorPermissions,
217+
intercom: async () => {
218+
return new Err(
219+
new Error(
220+
`Setting Intercom connector permissions is not implemented yet.`
221+
)
222+
);
223+
},
198224
};
199225

200226
export const BATCH_RETRIEVE_RESOURCE_TITLE_BY_TYPE: Record<
@@ -205,6 +231,7 @@ export const BATCH_RETRIEVE_RESOURCE_TITLE_BY_TYPE: Record<
205231
notion: retrieveNotionResourcesTitles,
206232
github: retrieveGithubReposTitles,
207233
google_drive: retrieveGoogleDriveObjectsTitles,
234+
intercom: retrieveIntercomResourcesTitles,
208235
};
209236

210237
export const RETRIEVE_RESOURCE_PARENTS_BY_TYPE: Record<
@@ -215,6 +242,7 @@ export const RETRIEVE_RESOURCE_PARENTS_BY_TYPE: Record<
215242
google_drive: retrieveGoogleDriveObjectsParents,
216243
slack: async () => new Ok([]), // Slack is flat
217244
github: async () => new Ok([]), // Github is flat,
245+
intercom: async () => new Ok([]), // Intercom is not truly flat as we can put articles & collections inside collections but will handle this later
218246
};
219247

220248
export const SET_CONNECTOR_CONFIG_BY_TYPE: Record<
@@ -231,6 +259,9 @@ export const SET_CONNECTOR_CONFIG_BY_TYPE: Record<
231259
throw new Error("Not implemented");
232260
},
233261
google_drive: setGoogleDriveConfig,
262+
intercom: async () => {
263+
throw new Error("Not implemented");
264+
},
234265
};
235266

236267
export const GET_CONNECTOR_CONFIG_BY_TYPE: Record<
@@ -247,4 +278,7 @@ export const GET_CONNECTOR_CONFIG_BY_TYPE: Record<
247278
throw new Error("Not implemented");
248279
},
249280
google_drive: getGoogleDriveConfig,
281+
intercom: async () => {
282+
throw new Error("Not implemented");
283+
},
250284
};
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { validateAccessToken } from "@connectors/connectors/intercom/lib/intercom_api";
2+
import { ConnectorPermissionRetriever } from "@connectors/connectors/interface";
3+
import { Connector, ModelId } from "@connectors/lib/models";
4+
import { getAccessTokenFromNango } from "@connectors/lib/nango_helpers";
5+
import { Err, Ok, Result } from "@connectors/lib/result";
6+
import logger from "@connectors/logger/logger";
7+
import { DataSourceConfig } from "@connectors/types/data_source_config";
8+
import { ConnectorsAPIErrorResponse } from "@connectors/types/errors";
9+
import { NangoConnectionId } from "@connectors/types/nango_connection_id";
10+
import {
11+
ConnectorPermission,
12+
ConnectorResource,
13+
} from "@connectors/types/resources";
14+
15+
const { NANGO_INTERCOM_CONNECTOR_ID } = process.env;
16+
17+
export async function createIntercomConnector(
18+
dataSourceConfig: DataSourceConfig,
19+
connectionId: NangoConnectionId
20+
): Promise<Result<string, Error>> {
21+
const nangoConnectionId = connectionId;
22+
23+
if (!NANGO_INTERCOM_CONNECTOR_ID) {
24+
throw new Error("NANGO_INTERCOM_CONNECTOR_ID not set");
25+
}
26+
27+
const accessToken = await getAccessTokenFromNango({
28+
connectionId: nangoConnectionId,
29+
integrationId: NANGO_INTERCOM_CONNECTOR_ID,
30+
useCache: false,
31+
});
32+
33+
if (!validateAccessToken(accessToken)) {
34+
return new Err(new Error("Intercom access token is invalid"));
35+
}
36+
37+
try {
38+
const connector = await Connector.create({
39+
type: "intercom",
40+
connectionId: nangoConnectionId,
41+
workspaceAPIKey: dataSourceConfig.workspaceAPIKey,
42+
workspaceId: dataSourceConfig.workspaceId,
43+
dataSourceName: dataSourceConfig.dataSourceName,
44+
defaultNewResourcePermission: "read_write",
45+
});
46+
// @todo Daph lauch workflow await launchIntercomSyncWorkflow(connector.id);
47+
return new Ok(connector.id.toString());
48+
} catch (e) {
49+
logger.error({ error: e }, "Error creating Intercom connector.");
50+
return new Err(e as Error);
51+
}
52+
}
53+
54+
export async function updateIntercomConnector(
55+
connectorId: ModelId,
56+
{
57+
connectionId,
58+
newDefaultNewResourcePermission,
59+
}: {
60+
connectionId?: NangoConnectionId | null;
61+
newDefaultNewResourcePermission?: ConnectorPermission | null;
62+
}
63+
): Promise<Result<string, ConnectorsAPIErrorResponse>> {
64+
console.log({ connectorId, connectionId, newDefaultNewResourcePermission });
65+
throw new Error("Not implemented");
66+
}
67+
68+
export async function cleanupIntercomConnector(
69+
connectorId: string
70+
): Promise<Result<void, Error>> {
71+
console.log({ connectorId });
72+
throw new Error("Not implemented");
73+
}
74+
75+
export async function stopIntercomConnector(
76+
connectorId: string
77+
): Promise<Result<string, Error>> {
78+
console.log({ connectorId });
79+
throw new Error("Not implemented");
80+
}
81+
82+
export async function resumeIntercomConnector(
83+
connectorId: string
84+
): Promise<Result<string, Error>> {
85+
console.log({ connectorId });
86+
throw new Error("Not implemented");
87+
}
88+
89+
export async function fullResyncIntercomConnector(
90+
connectorId: string,
91+
fromTs: number | null
92+
): Promise<Result<string, Error>> {
93+
console.log({ connectorId, fromTs });
94+
throw new Error("Not implemented");
95+
}
96+
97+
export async function retrieveIntercomConnectorPermissions({
98+
connectorId,
99+
parentInternalId,
100+
}: Parameters<ConnectorPermissionRetriever>[0]): Promise<
101+
Result<ConnectorResource[], Error>
102+
> {
103+
console.log({ connectorId, parentInternalId });
104+
throw new Error("Not implemented");
105+
}
106+
107+
export async function retrieveIntercomResourcesTitles(
108+
connectorId: ModelId,
109+
internalIds: string[]
110+
): Promise<Result<Record<string, string | null>, Error>> {
111+
console.log({ connectorId, internalIds });
112+
throw new Error("Not implemented");
113+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Client } from "intercom-client";
2+
3+
export async function validateAccessToken(intercomAccessToken: string) {
4+
const intercomClient = new Client({
5+
tokenAuth: { token: intercomAccessToken },
6+
});
7+
try {
8+
await intercomClient.admins.list(); // trying a simple request
9+
} catch (e) {
10+
return false;
11+
}
12+
return true;
13+
}

0 commit comments

Comments
 (0)