From 960e267d61c3225eca197b7468bf91a7100f2e90 Mon Sep 17 00:00:00 2001 From: Hassan_Wari <85742599+hassan254-prog@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:11:56 +0300 Subject: [PATCH] feat(integration-templates): add discourse integration template (#2722) ## Describe your changes - Add discourse integration template ## Issue ticket number and link ## Checklist before requesting a review (skip if just adding/editing APIs & templates) - [ ] I added tests, otherwise the reason is: - [ ] I added observability, otherwise the reason is: - [ ] I added analytics, otherwise the reason is: --------- Co-authored-by: Samuel Bodin <1637651+bodinsamuel@users.noreply.github.com> --- .../integration-templates/discourse.mdx | 21 +++++++++ docs-v2/mint.json | 1 + .../discourse/helpers/paginate.ts | 44 +++++++++++++++++++ .../discourse/mappers/toUser.ts | 17 +++++++ integration-templates/discourse/nango.yaml | 17 +++++++ .../discourse/syncs/active-users.ts | 32 ++++++++++++++ integration-templates/discourse/types.ts | 26 +++++++++++ packages/shared/flows.yaml | 16 +++++++ 8 files changed, 174 insertions(+) create mode 100644 docs-v2/integrations/integration-templates/discourse.mdx create mode 100644 integration-templates/discourse/helpers/paginate.ts create mode 100644 integration-templates/discourse/mappers/toUser.ts create mode 100644 integration-templates/discourse/nango.yaml create mode 100644 integration-templates/discourse/syncs/active-users.ts create mode 100644 integration-templates/discourse/types.ts diff --git a/docs-v2/integrations/integration-templates/discourse.mdx b/docs-v2/integrations/integration-templates/discourse.mdx new file mode 100644 index 00000000000..b9d71121e30 --- /dev/null +++ b/docs-v2/integrations/integration-templates/discourse.mdx @@ -0,0 +1,21 @@ +--- +title: 'Discourse API Integration Template' +sidebarTitle: 'Discourse' +--- + +## Get started with the Discourse template + + + Learn how to use integration templates in Nango + + + + Get the latest version of the Discourse integration template from GitHub + + +## Need help with the template? +Please reach out in the [Slack community](https://nango.dev/slack), we are very active there and happy to help! \ No newline at end of file diff --git a/docs-v2/mint.json b/docs-v2/mint.json index 49518175750..5793b99e45a 100644 --- a/docs-v2/mint.json +++ b/docs-v2/mint.json @@ -267,6 +267,7 @@ "integrations/integration-templates/checkr-partner", "integrations/integration-templates/checkr-partner-staging", "integrations/integration-templates/clari-copilot", + "integrations/integration-templates/discourse", "integrations/integration-templates/expensify", "integrations/integration-templates/exact-online", "integrations/integration-templates/evaluagent", diff --git a/integration-templates/discourse/helpers/paginate.ts b/integration-templates/discourse/helpers/paginate.ts new file mode 100644 index 00000000000..dec0f6c4b74 --- /dev/null +++ b/integration-templates/discourse/helpers/paginate.ts @@ -0,0 +1,44 @@ +import type { NangoSync, ProxyConfiguration } from '../../models'; + +export interface PaginationParams { + endpoint: string; + initialPage?: number; + params?: Record; +} + +/** + * Asynchronous generator function for paginating through API results. + * + * This function handles pagination by making repeated requests to the specified API endpoint. + * It yields arrays of results for each page until no more data is available. + * + * @param nango The NangoSync instance used for making API calls. + * @param params Configuration parameters for pagination, including the endpoint, initial page, and additional params. + * @returns An async generator that yields arrays of results from each page. + */ +async function* paginate(nango: NangoSync, { endpoint, initialPage = 1, params }: PaginationParams): AsyncGenerator { + let currentPage = initialPage; + + while (true) { + const payload: ProxyConfiguration = { + endpoint, + params: { + page: currentPage, + ...params + } + }; + + const response = await nango.get(payload); + const responseData = response.data; + + if (!responseData || responseData.length === 0) { + break; + } + + yield responseData; + + currentPage++; + } +} + +export default paginate; diff --git a/integration-templates/discourse/mappers/toUser.ts b/integration-templates/discourse/mappers/toUser.ts new file mode 100644 index 00000000000..b93c034e211 --- /dev/null +++ b/integration-templates/discourse/mappers/toUser.ts @@ -0,0 +1,17 @@ +import type { User } from '../../models'; +import type { DiscourseUser } from '../types'; + +/** + * Converts a DiscourseUser object to a slim User object. + * Only includes essential properties mapped from DiscourseUser. + * @param user The DiscourseUser object to convert. + * @returns User object representing DiscourseUser user information. + */ +export function toUser(user: DiscourseUser): User { + return { + id: user.id, + username: user.username, + name: user.name, + admin: user.admin + }; +} diff --git a/integration-templates/discourse/nango.yaml b/integration-templates/discourse/nango.yaml new file mode 100644 index 00000000000..fdf10bf88ef --- /dev/null +++ b/integration-templates/discourse/nango.yaml @@ -0,0 +1,17 @@ +integrations: + discourse: + syncs: + active-users: + description: | + Fetches a list of active users from Discourse. + endpoint: /discourse/active-users + sync_type: full + runs: every 1 hour + output: User + track_deletes: true +models: + User: + id: number + username: string + name: string + admin: boolean diff --git a/integration-templates/discourse/syncs/active-users.ts b/integration-templates/discourse/syncs/active-users.ts new file mode 100644 index 00000000000..93abd89c5f4 --- /dev/null +++ b/integration-templates/discourse/syncs/active-users.ts @@ -0,0 +1,32 @@ +import type { NangoSync, User } from '../../models'; +import type { DiscourseUser } from '../types'; +import paginate from '../helpers/paginate.js'; +import type { PaginationParams } from '../helpers/paginate'; +import { toUser } from '../mappers/toUser.js'; + +/** + * Fetches user data from an API and saves it in batch. + * + * This function uses the `paginate` helper to fetch active users from the specified API endpoint in a paginated manner. + * It maps the raw user data to a `User` format using the `toUser` mapper function and then saves the mapped data + * using the `nango.batchSave` method. + * For detailed endpoint documentation, refer to: + * https://docs.discourse.org/#tag/Admin/operation/adminListUsers + * + * @param nango The NangoSync instance used for making API calls and saving data. + * @returns A promise that resolves when the data has been successfully fetched and saved. + */ +export default async function fetchData(nango: NangoSync): Promise { + const config: PaginationParams = { + endpoint: '/admin/users/list/active', + params: { + order: 'created', + asc: 'true', + stats: true // Additional parameters for the API request can be added in here + } + }; + + for await (const users of paginate(nango, config)) { + await nango.batchSave(users.map(toUser), 'User'); + } +} diff --git a/integration-templates/discourse/types.ts b/integration-templates/discourse/types.ts new file mode 100644 index 00000000000..8e7d453d4dd --- /dev/null +++ b/integration-templates/discourse/types.ts @@ -0,0 +1,26 @@ +export interface DiscourseUser { + id: number; + username: string; + name: string; + avatar_template: string; + email: string; + secondary_emails: (string | null)[]; + active: boolean; + admin: boolean; + moderator: boolean; + last_seen_at: string; + last_emailed_at: string; + created_at: string; + last_seen_age: number; + last_emailed_age: number; + created_at_age: number; + trust_level: number; + manual_locked_trust_level: string; + title: string; + time_read: number; + staged: boolean; + days_visited: number; + posts_read_count: number; + topics_entered: number; + post_count: number; +} diff --git a/packages/shared/flows.yaml b/packages/shared/flows.yaml index 14145d595d3..1b0d79d4441 100644 --- a/packages/shared/flows.yaml +++ b/packages/shared/flows.yaml @@ -1217,6 +1217,22 @@ integrations: body: storage: object atlas_doc_format: object + discourse: + syncs: + active-users: + description: | + Fetches a list of active users from Discourse. + endpoint: /discourse/active-users + sync_type: full + runs: every 1 hour + output: User + track_deletes: true + models: + User: + id: number + username: string + name: string + admin: boolean evaluagent: syncs: users: