Skip to content

Commit

Permalink
Merge pull request #20 from NangoHQ/wari/ext-173-intercom-article-sync
Browse files Browse the repository at this point in the history
feat(integrations): add intercom articles sync
  • Loading branch information
khaliqgant authored Oct 1, 2024
2 parents 2e50ef3 + f5492be commit 47fdbc4
Show file tree
Hide file tree
Showing 76 changed files with 4,973 additions and 505 deletions.
122 changes: 100 additions & 22 deletions flows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2384,56 +2384,134 @@ integrations:
description: |
Fetches a list of conversations from Intercom
output:
- IntercomConversation
- IntercomConversationMessage
- Conversation
- ConversationMessage
sync_type: incremental
version: 1.0.0
endpoint:
- GET /intercom/conversations
- GET /intercom/conversations-message
- GET /conversations
- GET /conversation-messages
contacts:
runs: every 6 hours
description: |
Fetches a list of contacts from Intercom
output: IntercomContact
output: Contact
sync_type: full
track_deletes: true
version: 1.0.0
endpoint: GET /contacts
articles:
runs: every 6 hours
description: |
Fetches a list of articles from Intercom
output: Article
sync_type: full
endpoint: GET /intercom/contacts
track_deletes: true
version: 1.0.0
endpoint: GET /articles
models:
IntercomContact:
Contact:
id: string
workspace_id: string
external_id: string
external_id: string | null
type: string
email: string | null
email: string
phone: string | null
name: string | null
created_at: date
updated_at: date
last_seen_at: date | null
last_replied_at: date | null
IntercomConversation:
created_at: string
updated_at: string
last_seen_at: string | null
last_replied_at: string | null
Conversation:
id: string
created_at: date
updated_at: date
waiting_since: date | null
snoozed_until: date | null
title: string
created_at: string
updated_at: string
waiting_since: string | null
snoozed_until: string | null
title: string | null
contacts:
- contact_id: string
state: string
open: boolean
read: boolean
priority: string
IntercomConversationMessage:
ConversationMessage:
id: string
conversation_id: string
body: string
type: string
created_at: date
updated_at: date | null
created_at: string
updated_at: string
author:
type: string
name: string
id: string
Article:
type: string
id: string
workspace_id: string
title: string
description: string | null
body: string | null
author_id: number
state: string
created_at: string
updated_at: string
url: string | null
parent_id: number | null
parent_ids: number[]
parent_type: string | null
default_locale?: string | undefined
translated_content?: TranslatedContent | null | undefined
ArticleContent:
type: string | null
title: string
description: string
body: string
author_id: number
state: string
created_at: number
updated_at: number
url: string
TranslatedContent:
type: string | null
ar: ArticleContent | null
bg: ArticleContent | null
bs: ArticleContent | null
ca: ArticleContent | null
cs: ArticleContent | null
da: ArticleContent | null
de: ArticleContent | null
el: ArticleContent | null
en: ArticleContent | null
es: ArticleContent | null
et: ArticleContent | null
fi: ArticleContent | null
fr: ArticleContent | null
he: ArticleContent | null
hr: ArticleContent | null
hu: ArticleContent | null
id: ArticleContent | null
it: ArticleContent | null
ja: ArticleContent | null
ko: ArticleContent | null
lt: ArticleContent | null
lv: ArticleContent | null
mn: ArticleContent | null
nb: ArticleContent | null
nl: ArticleContent | null
pl: ArticleContent | null
pt: ArticleContent | null
ro: ArticleContent | null
ru: ArticleContent | null
sl: ArticleContent | null
sr: ArticleContent | null
sv: ArticleContent | null
tr: ArticleContent | null
vi: ArticleContent | null
pt-BR: ArticleContent | null
zh-CN: ArticleContent | null
zh-TW: ArticleContent | null
jira:
syncs:
issues:
Expand Down
41 changes: 23 additions & 18 deletions integrations/calendly/tests/calendly-event-invitees.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { vi, expect, it, describe } from "vitest";
import type { NangoSync } from "../models.js";

import fetchData from "../syncs/event-invitees.js";

Expand All @@ -10,39 +9,45 @@ describe("calendly event-invitees tests", () => {
Model: "EventInvitee"
});

const models = "EventInvitee".split(',');
const batchSaveSpy = vi.spyOn(nangoMock, 'batchSave');

it("should get, map correctly the data and batchSave the result", async () => {
await fetchData(nangoMock);

const batchSaveData = await nangoMock.getBatchSaveData();
for (const model of models) {
const batchSaveData = await nangoMock.getBatchSaveData(model);

const totalCalls = batchSaveSpy.mock.calls.length;
const totalCalls = batchSaveSpy.mock.calls.length;

if (totalCalls > 1) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);
if (totalCalls > models.length) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);

const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}
const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}

splitBatchSaveData.forEach((data, index) => {
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});
splitBatchSaveData.forEach((data, index) => {
// @ts-ignore
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});

} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, "EventInvitee");
} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, model);
}
}
});

it('should get, map correctly the data and batchDelete the result', async () => {
await fetchData(nangoMock);

const batchDeleteData = await nangoMock.getBatchDeleteData();
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, "EventInvitee");
for (const model of models) {
const batchDeleteData = await nangoMock.getBatchDeleteData(model);
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, model);
}
}
});
});
41 changes: 23 additions & 18 deletions integrations/calendly/tests/calendly-event-types.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { vi, expect, it, describe } from "vitest";
import type { NangoSync } from "../models.js";

import fetchData from "../syncs/event-types.js";

Expand All @@ -10,39 +9,45 @@ describe("calendly event-types tests", () => {
Model: "EventType"
});

const models = "EventType".split(',');
const batchSaveSpy = vi.spyOn(nangoMock, 'batchSave');

it("should get, map correctly the data and batchSave the result", async () => {
await fetchData(nangoMock);

const batchSaveData = await nangoMock.getBatchSaveData();
for (const model of models) {
const batchSaveData = await nangoMock.getBatchSaveData(model);

const totalCalls = batchSaveSpy.mock.calls.length;
const totalCalls = batchSaveSpy.mock.calls.length;

if (totalCalls > 1) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);
if (totalCalls > models.length) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);

const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}
const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}

splitBatchSaveData.forEach((data, index) => {
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});
splitBatchSaveData.forEach((data, index) => {
// @ts-ignore
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});

} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, "EventType");
} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, model);
}
}
});

it('should get, map correctly the data and batchDelete the result', async () => {
await fetchData(nangoMock);

const batchDeleteData = await nangoMock.getBatchDeleteData();
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, "EventType");
for (const model of models) {
const batchDeleteData = await nangoMock.getBatchDeleteData(model);
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, model);
}
}
});
});
41 changes: 23 additions & 18 deletions integrations/calendly/tests/calendly-events.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { vi, expect, it, describe } from "vitest";
import type { NangoSync } from "../models.js";

import fetchData from "../syncs/events.js";

Expand All @@ -10,39 +9,45 @@ describe("calendly events tests", () => {
Model: "Event"
});

const models = "Event".split(',');
const batchSaveSpy = vi.spyOn(nangoMock, 'batchSave');

it("should get, map correctly the data and batchSave the result", async () => {
await fetchData(nangoMock);

const batchSaveData = await nangoMock.getBatchSaveData();
for (const model of models) {
const batchSaveData = await nangoMock.getBatchSaveData(model);

const totalCalls = batchSaveSpy.mock.calls.length;
const totalCalls = batchSaveSpy.mock.calls.length;

if (totalCalls > 1) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);
if (totalCalls > models.length) {
const splitSize = Math.ceil(batchSaveData.length / totalCalls);

const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}
const splitBatchSaveData = [];
for (let i = 0; i < totalCalls; i++) {
const chunk = batchSaveData.slice(i * splitSize, (i + 1) * splitSize);
splitBatchSaveData.push(chunk);
}

splitBatchSaveData.forEach((data, index) => {
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});
splitBatchSaveData.forEach((data, index) => {
// @ts-ignore
expect(batchSaveSpy?.mock.calls[index][0]).toEqual(data);
});

} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, "Event");
} else {
expect(nangoMock.batchSave).toHaveBeenCalledWith(batchSaveData, model);
}
}
});

it('should get, map correctly the data and batchDelete the result', async () => {
await fetchData(nangoMock);

const batchDeleteData = await nangoMock.getBatchDeleteData();
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, "Event");
for (const model of models) {
const batchDeleteData = await nangoMock.getBatchDeleteData(model);
if (batchDeleteData && batchDeleteData.length > 0) {
expect(nangoMock.batchDelete).toHaveBeenCalledWith(batchDeleteData, model);
}
}
});
});
28 changes: 28 additions & 0 deletions integrations/intercom/mappers/to-article.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { IntercomArticle } from '../types';
import type { Article } from '../../models';
/**
* Maps an IntercomArticle object to an Article object
*
* @param article The IntercomArticle object to convert.
* @returns Article object representing IntercomArticle article information.
*/
export function toArticle(article: IntercomArticle): Article {
return {
type: article.type,
id: article.id,
workspace_id: article.workspace_id,
title: article.title,
description: article.description,
body: article.body,
author_id: article.author_id,
state: article.state,
created_at: new Date(article.created_at * 1000).toISOString(),
updated_at: new Date(article.updated_at * 1000).toISOString(),
url: article.url,
parent_id: article.parent_id,
parent_ids: article.parent_ids,
parent_type: article.parent_type,
default_locale: article.default_locale,
translated_content: article.translated_content
};
}
Loading

0 comments on commit 47fdbc4

Please sign in to comment.