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: