From b7e38f9d1cdbab94f15c6f522d7dedbda058e94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20Akca?= Date: Mon, 19 Feb 2024 17:23:26 +0300 Subject: [PATCH] feat(bigin-by-zoho-crm): add bigin by zoho crm integration --- .../apps/bigin-by-zoho-crm/assets/favicon.svg | 32 +++++++++ .../auth/generate-auth-url.js | 25 +++++++ .../src/apps/bigin-by-zoho-crm/auth/index.js | 66 +++++++++++++++++++ .../auth/is-still-verified.js | 8 +++ .../bigin-by-zoho-crm/auth/refresh-token.js | 34 ++++++++++ .../auth/verify-credentials.js | 46 +++++++++++++ .../common/add-auth-header.js | 9 +++ .../bigin-by-zoho-crm/common/auth-scope.js | 10 +++ .../common/get-current-organization.js | 6 ++ .../common/region-url-map.js | 8 +++ .../bigin-by-zoho-crm/common/set-base-url.js | 14 ++++ .../src/apps/bigin-by-zoho-crm/index.js | 17 +++++ packages/docs/pages/.vitepress/config.js | 10 ++- .../apps/bigin-by-zoho-crm/connection.md | 18 +++++ .../public/favicons/bigin-by-zoho-crm.svg | 32 +++++++++ 15 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/assets/favicon.svg create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/auth/generate-auth-url.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/auth/index.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/auth/is-still-verified.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/auth/refresh-token.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/auth/verify-credentials.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/common/add-auth-header.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/common/auth-scope.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/common/get-current-organization.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/common/region-url-map.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/common/set-base-url.js create mode 100644 packages/backend/src/apps/bigin-by-zoho-crm/index.js create mode 100644 packages/docs/pages/apps/bigin-by-zoho-crm/connection.md create mode 100644 packages/docs/pages/public/favicons/bigin-by-zoho-crm.svg diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/assets/favicon.svg b/packages/backend/src/apps/bigin-by-zoho-crm/assets/favicon.svg new file mode 100644 index 00000000..e5a3ac9c --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/assets/favicon.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/auth/generate-auth-url.js b/packages/backend/src/apps/bigin-by-zoho-crm/auth/generate-auth-url.js new file mode 100644 index 00000000..661b80d7 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/auth/generate-auth-url.js @@ -0,0 +1,25 @@ +import { URLSearchParams } from 'url'; +import authScope from '../common/auth-scope.js'; + +export default async function generateAuthUrl($) { + const oauthRedirectUrlField = $.app.auth.fields.find( + (field) => field.key == 'oAuthRedirectUrl' + ); + const redirectUri = oauthRedirectUrlField.value; + const searchParams = new URLSearchParams({ + scope: authScope.join(','), + client_id: $.auth.data.clientId, + response_type: 'code', + access_type: 'offline', + redirect_uri: redirectUri, + }); + + const domain = + $.auth.data.region !== 'cn' ? 'account.zoho.com' : 'accounts.zoho.com.cn'; + + const url = `https://${domain}/oauth/v2/auth?${searchParams.toString()}`; + + await $.auth.set({ + url, + }); +} diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/auth/index.js b/packages/backend/src/apps/bigin-by-zoho-crm/auth/index.js new file mode 100644 index 00000000..e735f7fb --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/auth/index.js @@ -0,0 +1,66 @@ +import generateAuthUrl from './generate-auth-url.js'; +import verifyCredentials from './verify-credentials.js'; +import refreshToken from './refresh-token.js'; +import isStillVerified from './is-still-verified.js'; + +export default { + fields: [ + { + key: 'oAuthRedirectUrl', + label: 'OAuth Redirect URL', + type: 'string', + required: true, + readOnly: true, + value: '{WEB_APP_URL}/app/bigin-by-zoho-crm/connections/add', + placeholder: null, + description: + 'When asked to input a redirect URL in Bigin By Zoho CRM, enter the URL above.', + clickToCopy: true, + }, + { + key: 'region', + label: 'Region', + type: 'dropdown', + required: true, + readOnly: false, + value: null, + placeholder: null, + description: '', + options: [ + { label: 'United States', value: 'us' }, + { label: 'European Union', value: 'eu' }, + { label: 'Australia', value: 'au' }, + { label: 'India', value: 'in' }, + { label: 'China', value: 'cn' }, + ], + clickToCopy: false, + }, + { + key: 'clientId', + label: 'Client ID', + type: 'string', + required: true, + readOnly: false, + value: null, + placeholder: null, + description: null, + clickToCopy: false, + }, + { + key: 'clientSecret', + label: 'Client Secret', + type: 'string', + required: true, + readOnly: false, + value: null, + placeholder: null, + description: null, + clickToCopy: false, + }, + ], + + generateAuthUrl, + verifyCredentials, + isStillVerified, + refreshToken, +}; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/auth/is-still-verified.js b/packages/backend/src/apps/bigin-by-zoho-crm/auth/is-still-verified.js new file mode 100644 index 00000000..8c7c47b1 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/auth/is-still-verified.js @@ -0,0 +1,8 @@ +import getCurrentOrganization from '../common/get-current-organization.js'; + +const isStillVerified = async ($) => { + const org = await getCurrentOrganization($); + return !!org.id; +}; + +export default isStillVerified; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/auth/refresh-token.js b/packages/backend/src/apps/bigin-by-zoho-crm/auth/refresh-token.js new file mode 100644 index 00000000..3da61e39 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/auth/refresh-token.js @@ -0,0 +1,34 @@ +import { URLSearchParams } from 'node:url'; + +import authScope from '../common/auth-scope.js'; +import { regionUrlMap } from '../common/region-url-map.js'; + +const refreshToken = async ($) => { + const location = $.auth.data.location; + const params = new URLSearchParams({ + client_id: $.auth.data.clientId, + client_secret: $.auth.data.clientSecret, + refresh_token: $.auth.data.refreshToken, + grant_type: 'refresh_token', + }); + + const { data } = await $.http.post( + `${regionUrlMap[location]}/oauth/v2/token`, + params.toString(), + { + additionalProperties: { + skipAddingBaseUrl: true, + }, + } + ); + + await $.auth.set({ + accessToken: data.access_token, + apiDomain: data.api_domain, + scope: authScope.join(','), + tokenType: data.token_type, + expiresIn: data.expires_in, + }); +}; + +export default refreshToken; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/auth/verify-credentials.js b/packages/backend/src/apps/bigin-by-zoho-crm/auth/verify-credentials.js new file mode 100644 index 00000000..27d7f262 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/auth/verify-credentials.js @@ -0,0 +1,46 @@ +import { URLSearchParams } from 'node:url'; +import { regionUrlMap } from '../common/region-url-map.js'; +import getCurrentOrganization from '../common/get-current-organization.js'; + +const verifyCredentials = async ($) => { + const oauthRedirectUrlField = $.app.auth.fields.find( + (field) => field.key == 'oAuthRedirectUrl' + ); + const redirectUri = oauthRedirectUrlField.value; + const location = $.auth.data.location; + const params = new URLSearchParams({ + client_id: $.auth.data.clientId, + client_secret: $.auth.data.clientSecret, + code: $.auth.data.code, + redirect_uri: redirectUri, + grant_type: 'authorization_code', + }); + + const { data } = await $.http.post( + `${regionUrlMap[location]}/oauth/v2/token`, + params.toString() + ); + + await $.auth.set({ + accessToken: data.access_token, + tokenType: data.token_type, + apiDomain: data.api_domain, + }); + + const organization = await getCurrentOrganization($); + + const screenName = [organization.company_name, organization.primary_email] + .filter(Boolean) + .join(' @ '); + + await $.auth.set({ + clientId: $.auth.data.clientId, + clientSecret: $.auth.data.clientSecret, + scope: $.auth.data.scope, + expiresIn: data.expires_in, + refreshToken: data.refresh_token, + screenName, + }); +}; + +export default verifyCredentials; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/common/add-auth-header.js b/packages/backend/src/apps/bigin-by-zoho-crm/common/add-auth-header.js new file mode 100644 index 00000000..82437e17 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/common/add-auth-header.js @@ -0,0 +1,9 @@ +const addAuthHeader = ($, requestConfig) => { + if ($.auth.data?.accessToken) { + requestConfig.headers.Authorization = `Zoho-oauthtoken ${$.auth.data.accessToken}`; + } + + return requestConfig; +}; + +export default addAuthHeader; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/common/auth-scope.js b/packages/backend/src/apps/bigin-by-zoho-crm/common/auth-scope.js new file mode 100644 index 00000000..2dde7331 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/common/auth-scope.js @@ -0,0 +1,10 @@ +const authScope = [ + 'ZohoBigin.notifications.ALL', + 'ZohoBigin.users.ALL', + 'ZohoBigin.modules.ALL', + 'ZohoBigin.org.READ', + 'ZohoBigin.settings.ALL', + 'ZohoBigin.modules.ALL', +]; + +export default authScope; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/common/get-current-organization.js b/packages/backend/src/apps/bigin-by-zoho-crm/common/get-current-organization.js new file mode 100644 index 00000000..30f7b5ca --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/common/get-current-organization.js @@ -0,0 +1,6 @@ +const getCurrentOrganization = async ($) => { + const response = await $.http.get('/bigin/v2/org'); + return response.data.org[0]; +}; + +export default getCurrentOrganization; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/common/region-url-map.js b/packages/backend/src/apps/bigin-by-zoho-crm/common/region-url-map.js new file mode 100644 index 00000000..8adb5eaa --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/common/region-url-map.js @@ -0,0 +1,8 @@ +export const regionUrlMap = { + us: 'https://accounts.zoho.com', + au: 'https://accounts.zoho.com.au', + eu: 'https://accounts.zoho.eu', + in: 'https://accounts.zoho.in', + cn: 'https://accounts.zoho.com.cn', + jp: 'https://accounts.zoho.jp', +}; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/common/set-base-url.js b/packages/backend/src/apps/bigin-by-zoho-crm/common/set-base-url.js new file mode 100644 index 00000000..33b8c289 --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/common/set-base-url.js @@ -0,0 +1,14 @@ +const setBaseUrl = ($, requestConfig) => { + if (requestConfig.additionalProperties?.skipAddingBaseUrl) + return requestConfig; + + const apiDomain = $.auth.data.apiDomain; + + if (apiDomain) { + requestConfig.baseURL = apiDomain; + } + + return requestConfig; +}; + +export default setBaseUrl; diff --git a/packages/backend/src/apps/bigin-by-zoho-crm/index.js b/packages/backend/src/apps/bigin-by-zoho-crm/index.js new file mode 100644 index 00000000..5fcbb39e --- /dev/null +++ b/packages/backend/src/apps/bigin-by-zoho-crm/index.js @@ -0,0 +1,17 @@ +import defineApp from '../../helpers/define-app.js'; +import addAuthHeader from './common/add-auth-header.js'; +import auth from './auth/index.js'; +import setBaseUrl from './common/set-base-url.js'; + +export default defineApp({ + name: 'Bigin By Zoho CRM', + key: 'bigin-by-zoho-crm', + baseUrl: 'https://www.bigin.com', + apiBaseUrl: '', + iconUrl: '{BASE_URL}/apps/bigin-by-zoho-crm/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/bigin-by-zoho-crm/connection', + primaryColor: '039649', + supportsConnections: true, + beforeRequest: [setBaseUrl, addAuthHeader], + auth, +}); diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index 04d3fdcf..555cb294 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -32,6 +32,14 @@ export default defineConfig({ ], sidebar: { '/apps/': [ + { + text: 'Bigin By Zoho CRM', + collapsible: true, + collapsed: true, + items: [ + { text: 'Connection', link: '/apps/bigin-by-zoho-crm/connection' }, + ], + }, { text: 'Carbone', collapsible: true, @@ -305,7 +313,7 @@ export default defineConfig({ collapsed: true, items: [ { text: 'Actions', link: '/apps/removebg/actions' }, - { text: 'Connection', link: '/apps/removebg/connection' } + { text: 'Connection', link: '/apps/removebg/connection' }, ], }, { diff --git a/packages/docs/pages/apps/bigin-by-zoho-crm/connection.md b/packages/docs/pages/apps/bigin-by-zoho-crm/connection.md new file mode 100644 index 00000000..d723d177 --- /dev/null +++ b/packages/docs/pages/apps/bigin-by-zoho-crm/connection.md @@ -0,0 +1,18 @@ +# Bigin By Zoho CRM + +:::info +This page explains the steps you need to follow to set up the Bigin By Zoho CRM +connection in Automatisch. If any of the steps are outdated, please let us know! +::: + +1. Go to the [Zoho API Console](https://api-console.zoho.com) to register an application. +2. Login to your account. +3. Click on the **GET STARTED** button. +4. Choose the **Server-based Applications** client type. +5. Fill the **Create New Client** form. +6. Copy **OAuth Redirect URL** from Automatisch to **Authorized redirect URIs** field, and click on the **Create** button. +7. Copy the **Client ID** value to the `Client ID` field on Automatisch. +8. Copy the **Client Secret** value to the `Client Secret` field on Automatisch. +9. Select the region appropriate for your account. +10. Click **Submit** button on Automatisch. +11. Congrats! Start using your new Bigin By Zoho CRM connection within the flows. diff --git a/packages/docs/pages/public/favicons/bigin-by-zoho-crm.svg b/packages/docs/pages/public/favicons/bigin-by-zoho-crm.svg new file mode 100644 index 00000000..e5a3ac9c --- /dev/null +++ b/packages/docs/pages/public/favicons/bigin-by-zoho-crm.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file