From d7e4ae53ce7b4f67578c2de47f90647abf0f88e0 Mon Sep 17 00:00:00 2001 From: Sebastian Schumann Date: Fri, 24 Feb 2023 03:39:25 +0100 Subject: [PATCH 1/9] feat: add Signalwire integration --- .../src/apps/signalwire/actions/index.ts | 3 + .../apps/signalwire/actions/send-sms/index.ts | 50 ++++++++++++++ .../src/apps/signalwire/assets/favicon.svg | 1 + .../backend/src/apps/signalwire/auth/index.ts | 65 +++++++++++++++++++ .../apps/signalwire/auth/is-still-verified.ts | 9 +++ .../signalwire/auth/verify-credentials.ts | 11 ++++ .../apps/signalwire/common/add-auth-header.ts | 20 ++++++ .../backend/src/apps/signalwire/index.d.ts | 0 packages/backend/src/apps/signalwire/index.ts | 20 ++++++ .../src/apps/signalwire/triggers/index.ts | 3 + .../triggers/receive-sms/fetch-messages.ts | 27 ++++++++ .../signalwire/triggers/receive-sms/index.ts | 23 +++++++ packages/docs/pages/.vitepress/config.js | 10 +++ .../docs/pages/apps/signalwire/actions.md | 12 ++++ .../docs/pages/apps/signalwire/connection.md | 16 +++++ .../docs/pages/apps/signalwire/triggers.md | 12 ++++ .../docs/pages/build-integrations/examples.md | 2 + packages/docs/pages/guide/available-apps.md | 1 + .../docs/pages/public/favicons/signalwire.svg | 1 + 19 files changed, 286 insertions(+) create mode 100644 packages/backend/src/apps/signalwire/actions/index.ts create mode 100644 packages/backend/src/apps/signalwire/actions/send-sms/index.ts create mode 100644 packages/backend/src/apps/signalwire/assets/favicon.svg create mode 100644 packages/backend/src/apps/signalwire/auth/index.ts create mode 100644 packages/backend/src/apps/signalwire/auth/is-still-verified.ts create mode 100644 packages/backend/src/apps/signalwire/auth/verify-credentials.ts create mode 100644 packages/backend/src/apps/signalwire/common/add-auth-header.ts create mode 100644 packages/backend/src/apps/signalwire/index.d.ts create mode 100644 packages/backend/src/apps/signalwire/index.ts create mode 100644 packages/backend/src/apps/signalwire/triggers/index.ts create mode 100644 packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts create mode 100644 packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts create mode 100644 packages/docs/pages/apps/signalwire/actions.md create mode 100644 packages/docs/pages/apps/signalwire/connection.md create mode 100644 packages/docs/pages/apps/signalwire/triggers.md create mode 100644 packages/docs/pages/public/favicons/signalwire.svg diff --git a/packages/backend/src/apps/signalwire/actions/index.ts b/packages/backend/src/apps/signalwire/actions/index.ts new file mode 100644 index 00000000..d1723dc2 --- /dev/null +++ b/packages/backend/src/apps/signalwire/actions/index.ts @@ -0,0 +1,3 @@ +import sendSms from './send-sms'; + +export default [sendSms]; diff --git a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts new file mode 100644 index 00000000..8f91daa2 --- /dev/null +++ b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts @@ -0,0 +1,50 @@ +import defineAction from '../../../../helpers/define-action'; + +export default defineAction({ + name: 'Send an SMS', + key: 'sendSms', + description: 'Sends an SMS', + arguments: [ + { + label: 'From Number', + key: 'fromNumber', + type: 'string' as const, + required: true, + description: + 'The number to send the SMS from. Include only country code. Example: 491234567890', + variables: true, + }, + { + label: 'To Number', + key: 'toNumber', + type: 'string' as const, + required: true, + description: + 'The number to send the SMS to. Include only country code. Example: 491234567890', + variables: true, + }, + { + label: 'Message', + key: 'message', + type: 'string' as const, + required: true, + description: 'The content of the message.', + variables: true, + }, + ], + + async run($) { + const requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages`; + const messageBody = $.step.parameters.message; + + const fromNumber = '%2B' + ($.step.parameters.fromNumber as string).trim(); + const toNumber = '%2B' + ($.step.parameters.toNumber as string).trim(); + + const response = await $.http.post( + 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + requestPath, + `Body=${messageBody}&From=${fromNumber}&To=${toNumber}` + ); + + $.setActionItem({ raw: response.data }); + }, +}); diff --git a/packages/backend/src/apps/signalwire/assets/favicon.svg b/packages/backend/src/apps/signalwire/assets/favicon.svg new file mode 100644 index 00000000..1dda2037 --- /dev/null +++ b/packages/backend/src/apps/signalwire/assets/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/backend/src/apps/signalwire/auth/index.ts b/packages/backend/src/apps/signalwire/auth/index.ts new file mode 100644 index 00000000..009eca43 --- /dev/null +++ b/packages/backend/src/apps/signalwire/auth/index.ts @@ -0,0 +1,65 @@ +import verifyCredentials from './verify-credentials'; +import isStillVerified from './is-still-verified'; + +export default { + fields: [ + { + key: 'accountSid', + label: 'Project ID', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'Log into your Signalwire account and find the Project ID', + clickToCopy: false, + }, + { + key: 'authToken', + label: 'API Token', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: 'API Token in the respective project', + clickToCopy: false, + }, + { + key: 'spaceRegion', + label: 'Signalwire Region', + type: 'dropdown' as const, + required: true, + readOnly: false, + value: '', + placeholder: null, + description: 'Most people should choose the default, "US"', + clickToCopy: false, + options: [ + { + label: 'US', + value: '', + }, + { + label: 'EU', + value: 'eu-', + }, + ], + }, + { + key: 'spaceName', + label: 'Space Name', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: 'Name of your Signalwire space that contains the project', + clickToCopy: true, + }, + ], + + verifyCredentials, + isStillVerified, +}; diff --git a/packages/backend/src/apps/signalwire/auth/is-still-verified.ts b/packages/backend/src/apps/signalwire/auth/is-still-verified.ts new file mode 100644 index 00000000..66bb963e --- /dev/null +++ b/packages/backend/src/apps/signalwire/auth/is-still-verified.ts @@ -0,0 +1,9 @@ +import { IGlobalVariable } from '@automatisch/types'; +import verifyCredentials from './verify-credentials'; + +const isStillVerified = async ($: IGlobalVariable) => { + await verifyCredentials($); + return true; +}; + +export default isStillVerified; diff --git a/packages/backend/src/apps/signalwire/auth/verify-credentials.ts b/packages/backend/src/apps/signalwire/auth/verify-credentials.ts new file mode 100644 index 00000000..ef75de44 --- /dev/null +++ b/packages/backend/src/apps/signalwire/auth/verify-credentials.ts @@ -0,0 +1,11 @@ +import { IGlobalVariable } from '@automatisch/types'; + +const verifyCredentials = async ($: IGlobalVariable) => { + await $.http.get('https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + '/api/laml/2010-04-01/Accounts'); + + await $.auth.set({ + screenName: $.auth.data.accountSid, + }); +}; + +export default verifyCredentials; diff --git a/packages/backend/src/apps/signalwire/common/add-auth-header.ts b/packages/backend/src/apps/signalwire/common/add-auth-header.ts new file mode 100644 index 00000000..f5f47f85 --- /dev/null +++ b/packages/backend/src/apps/signalwire/common/add-auth-header.ts @@ -0,0 +1,20 @@ +import { TBeforeRequest } from '@automatisch/types'; + +const addAuthHeader: TBeforeRequest = ($, requestConfig) => { + if ( + requestConfig.headers && + $.auth.data?.accountSid && + $.auth.data?.authToken + ) { + requestConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + + requestConfig.auth = { + username: $.auth.data.accountSid as string, + password: $.auth.data.authToken as string, + }; + } + + return requestConfig; +}; + +export default addAuthHeader; diff --git a/packages/backend/src/apps/signalwire/index.d.ts b/packages/backend/src/apps/signalwire/index.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/backend/src/apps/signalwire/index.ts b/packages/backend/src/apps/signalwire/index.ts new file mode 100644 index 00000000..5df3ed0f --- /dev/null +++ b/packages/backend/src/apps/signalwire/index.ts @@ -0,0 +1,20 @@ +import defineApp from '../../helpers/define-app'; +import addAuthHeader from './common/add-auth-header'; +import auth from './auth'; +import triggers from './triggers'; +import actions from './actions'; + +export default defineApp({ + name: 'Signalwire', + key: 'signalwire', + iconUrl: 'https://signalwire.com/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/signalwire/connection', + supportsConnections: true, + baseUrl: 'https://signalwire.com', + apiBaseUrl: '', + primaryColor: '044cf6', + beforeRequest: [addAuthHeader], + auth, + triggers, + actions, +}); diff --git a/packages/backend/src/apps/signalwire/triggers/index.ts b/packages/backend/src/apps/signalwire/triggers/index.ts new file mode 100644 index 00000000..04e1504d --- /dev/null +++ b/packages/backend/src/apps/signalwire/triggers/index.ts @@ -0,0 +1,3 @@ +import receiveSms from './receive-sms'; + +export default [receiveSms]; diff --git a/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts b/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts new file mode 100644 index 00000000..31963130 --- /dev/null +++ b/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts @@ -0,0 +1,27 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +const fetchMessages = async ($: IGlobalVariable) => { + const toNumber = $.step.parameters.toNumber as string; + + let response; + let requestPath = 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages?To=${toNumber}`; + + do { + response = await $.http.get(requestPath); + + response.data.messages.forEach((message: IJSONObject) => { + const dataItem = { + raw: message, + meta: { + internalId: message.date_sent as string, + }, + }; + + $.pushTriggerItem(dataItem); + }); + + requestPath = 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + response.data.next_page_uri; + } while (requestPath); +}; + +export default fetchMessages; diff --git a/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts new file mode 100644 index 00000000..6260d418 --- /dev/null +++ b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts @@ -0,0 +1,23 @@ +import defineTrigger from '../../../../helpers/define-trigger'; +import fetchMessages from './fetch-messages'; + +export default defineTrigger({ + name: 'Receive SMS', + key: 'receiveSms', + pollInterval: 15, + description: 'Triggers when a new SMS is received.', + arguments: [ + { + label: 'To Number', + key: 'toNumber', + type: 'string', + required: true, + description: + 'The number to receive the SMS on. It should be a Signalwire number in your project.', + }, + ], + + async run($) { + await fetchMessages($); + }, +}); diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index 3a16f115..f6a0589f 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -133,6 +133,16 @@ export default defineConfig({ { text: 'Connection', link: '/apps/scheduler/connection' }, ], }, + { + text: 'Signalwire', + collapsible: true, + collapsed: true, + items: [ + { text: 'Triggers', link: '/apps/signalwire/triggers' }, + { text: 'Actions', link: '/apps/signalwire/actions' }, + { text: 'Connection', link: '/apps/signalwire/connection' }, + ], + }, { text: 'Slack', collapsible: true, diff --git a/packages/docs/pages/apps/signalwire/actions.md b/packages/docs/pages/apps/signalwire/actions.md new file mode 100644 index 00000000..bc89edd2 --- /dev/null +++ b/packages/docs/pages/apps/signalwire/actions.md @@ -0,0 +1,12 @@ +--- +favicon: /favicons/signalwire.svg +items: + - name: Send an SMS + desc: Sends an SMS +--- + + + + diff --git a/packages/docs/pages/apps/signalwire/connection.md b/packages/docs/pages/apps/signalwire/connection.md new file mode 100644 index 00000000..8100b06f --- /dev/null +++ b/packages/docs/pages/apps/signalwire/connection.md @@ -0,0 +1,16 @@ +# Signalwire + +:::info +This page explains the steps you need to follow to set up a Signalwire connection in Automatisch. If any of the steps are outdated, please let us know! +::: + +1. Go to the Signalwire API page in your respective project (https://{space}.signalwire.com/credentials) +2. Copy **Project ID** and paste it to the **Project ID** field on the + Automatisch connection creation page. +3. Create/Copy **API Token** and paste it to the **API Token** field on the + Automatisch connection creation page. +4. Select your **Region** (US for most users). +5. Provide your **Space Name** from the URL and paste it to the **Space NAME** field on the + Automatisch connection creation page. +6. Click **Submit** button on Automatisch. +7. Now you can start using the new Signalwire connection! diff --git a/packages/docs/pages/apps/signalwire/triggers.md b/packages/docs/pages/apps/signalwire/triggers.md new file mode 100644 index 00000000..42083cc8 --- /dev/null +++ b/packages/docs/pages/apps/signalwire/triggers.md @@ -0,0 +1,12 @@ +--- +favicon: /favicons/signalwire.svg +items: + - name: Receive SMS + desc: Triggers when a new SMS is received. +--- + + + + diff --git a/packages/docs/pages/build-integrations/examples.md b/packages/docs/pages/build-integrations/examples.md index 308be03f..66895181 100644 --- a/packages/docs/pages/build-integrations/examples.md +++ b/packages/docs/pages/build-integrations/examples.md @@ -33,6 +33,7 @@ The build integrations section is best understood when read from beginning to en - [DeepL](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/deepl/auth/index.ts) - [Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/auth/index.ts) +- [Signalwire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/auth/index.ts) - [SMTP](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/smtp/auth/index.ts) ### Without authentication @@ -60,6 +61,7 @@ If you are developing a webhook-based trigger, you need to ensure that the webho - [Search tweets - Twitter](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twitter/triggers/search-tweets/index.ts) - [New issues - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/triggers/new-issues/index.ts) - [Receive SMS - Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/triggers/receive-sms/index.ts) +- [Receive SMS - Signalwire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts) - [New photos - Flickr](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/flickr/triggers/new-photos/index.ts) ### Pagination with ascending order diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md index 5874ca0c..6f950856 100644 --- a/packages/docs/pages/guide/available-apps.md +++ b/packages/docs/pages/guide/available-apps.md @@ -17,6 +17,7 @@ Following integrations are currently supported by Automatisch. - [RSS](/apps/rss/triggers) - [Salesforce](/apps/salesforce/triggers) - [Scheduler](/apps/scheduler/triggers) +- [Signalwire](/apps/signalwire/triggers) - [Slack](/apps/slack/actions) - [SMTP](/apps/smtp/actions) - [Stripe](/apps/stripe/triggers) diff --git a/packages/docs/pages/public/favicons/signalwire.svg b/packages/docs/pages/public/favicons/signalwire.svg new file mode 100644 index 00000000..1dda2037 --- /dev/null +++ b/packages/docs/pages/public/favicons/signalwire.svg @@ -0,0 +1 @@ + \ No newline at end of file From caef9bb8b55482bbacb114d9ab6f476d8f8629ff Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 19:05:02 +0000 Subject: [PATCH 2/9] chore: reword Signalwire as SignalWire --- packages/backend/src/apps/signalwire/auth/index.ts | 8 ++++---- packages/backend/src/apps/signalwire/index.ts | 2 +- .../src/apps/signalwire/triggers/receive-sms/index.ts | 2 +- packages/docs/pages/.vitepress/config.js | 2 +- packages/docs/pages/apps/signalwire/connection.md | 8 ++++---- packages/docs/pages/build-integrations/examples.md | 4 ++-- packages/docs/pages/guide/available-apps.md | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/backend/src/apps/signalwire/auth/index.ts b/packages/backend/src/apps/signalwire/auth/index.ts index 009eca43..32f9c922 100644 --- a/packages/backend/src/apps/signalwire/auth/index.ts +++ b/packages/backend/src/apps/signalwire/auth/index.ts @@ -12,7 +12,7 @@ export default { value: null, placeholder: null, description: - 'Log into your Signalwire account and find the Project ID', + 'Log into your SignalWire account and find the Project ID', clickToCopy: false, }, { @@ -28,7 +28,7 @@ export default { }, { key: 'spaceRegion', - label: 'Signalwire Region', + label: 'SignalWire Region', type: 'dropdown' as const, required: true, readOnly: false, @@ -55,8 +55,8 @@ export default { readOnly: false, value: null, placeholder: null, - description: 'Name of your Signalwire space that contains the project', - clickToCopy: true, + description: 'Name of your SignalWire space that contains the project', + clickToCopy: false, }, ], diff --git a/packages/backend/src/apps/signalwire/index.ts b/packages/backend/src/apps/signalwire/index.ts index 5df3ed0f..57701d76 100644 --- a/packages/backend/src/apps/signalwire/index.ts +++ b/packages/backend/src/apps/signalwire/index.ts @@ -5,7 +5,7 @@ import triggers from './triggers'; import actions from './actions'; export default defineApp({ - name: 'Signalwire', + name: 'SignalWire', key: 'signalwire', iconUrl: 'https://signalwire.com/favicon.svg', authDocUrl: 'https://automatisch.io/docs/apps/signalwire/connection', diff --git a/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts index 6260d418..3398d9a0 100644 --- a/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts +++ b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts @@ -13,7 +13,7 @@ export default defineTrigger({ type: 'string', required: true, description: - 'The number to receive the SMS on. It should be a Signalwire number in your project.', + 'The number to receive the SMS on. It should be a SignalWire number in your project.', }, ], diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index f6a0589f..59f53567 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -134,7 +134,7 @@ export default defineConfig({ ], }, { - text: 'Signalwire', + text: 'SignalWire', collapsible: true, collapsed: true, items: [ diff --git a/packages/docs/pages/apps/signalwire/connection.md b/packages/docs/pages/apps/signalwire/connection.md index 8100b06f..20a61005 100644 --- a/packages/docs/pages/apps/signalwire/connection.md +++ b/packages/docs/pages/apps/signalwire/connection.md @@ -1,10 +1,10 @@ -# Signalwire +# SignalWire :::info -This page explains the steps you need to follow to set up a Signalwire connection in Automatisch. If any of the steps are outdated, please let us know! +This page explains the steps you need to follow to set up a SignalWire connection in Automatisch. If any of the steps are outdated, please let us know! ::: -1. Go to the Signalwire API page in your respective project (https://{space}.signalwire.com/credentials) +1. Go to the SignalWire API page in your respective project (https://{space}.signalwire.com/credentials) 2. Copy **Project ID** and paste it to the **Project ID** field on the Automatisch connection creation page. 3. Create/Copy **API Token** and paste it to the **API Token** field on the @@ -13,4 +13,4 @@ This page explains the steps you need to follow to set up a Signalwire connectio 5. Provide your **Space Name** from the URL and paste it to the **Space NAME** field on the Automatisch connection creation page. 6. Click **Submit** button on Automatisch. -7. Now you can start using the new Signalwire connection! +7. Now you can start using the new SignalWire connection! diff --git a/packages/docs/pages/build-integrations/examples.md b/packages/docs/pages/build-integrations/examples.md index 66895181..3acb1c80 100644 --- a/packages/docs/pages/build-integrations/examples.md +++ b/packages/docs/pages/build-integrations/examples.md @@ -33,7 +33,7 @@ The build integrations section is best understood when read from beginning to en - [DeepL](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/deepl/auth/index.ts) - [Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/auth/index.ts) -- [Signalwire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/auth/index.ts) +- [SignalWire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/auth/index.ts) - [SMTP](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/smtp/auth/index.ts) ### Without authentication @@ -61,7 +61,7 @@ If you are developing a webhook-based trigger, you need to ensure that the webho - [Search tweets - Twitter](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twitter/triggers/search-tweets/index.ts) - [New issues - Github](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/github/triggers/new-issues/index.ts) - [Receive SMS - Twilio](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/twilio/triggers/receive-sms/index.ts) -- [Receive SMS - Signalwire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts) +- [Receive SMS - SignalWire](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts) - [New photos - Flickr](https://github.com/automatisch/automatisch/tree/main/packages/backend/src/apps/flickr/triggers/new-photos/index.ts) ### Pagination with ascending order diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md index 6f950856..33b9bb2f 100644 --- a/packages/docs/pages/guide/available-apps.md +++ b/packages/docs/pages/guide/available-apps.md @@ -17,7 +17,7 @@ Following integrations are currently supported by Automatisch. - [RSS](/apps/rss/triggers) - [Salesforce](/apps/salesforce/triggers) - [Scheduler](/apps/scheduler/triggers) -- [Signalwire](/apps/signalwire/triggers) +- [SignalWire](/apps/signalwire/triggers) - [Slack](/apps/slack/actions) - [SMTP](/apps/smtp/actions) - [Stripe](/apps/stripe/triggers) From d45fdf605f3159e92457a3e2c16465c0bdb153dc Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 19:05:32 +0000 Subject: [PATCH 3/9] fix(signalwire): localize icon --- packages/backend/src/apps/signalwire/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/apps/signalwire/index.ts b/packages/backend/src/apps/signalwire/index.ts index 57701d76..9d187669 100644 --- a/packages/backend/src/apps/signalwire/index.ts +++ b/packages/backend/src/apps/signalwire/index.ts @@ -7,7 +7,7 @@ import actions from './actions'; export default defineApp({ name: 'SignalWire', key: 'signalwire', - iconUrl: 'https://signalwire.com/favicon.svg', + iconUrl: '{BASE_URL}/apps/signalwire/assets/favicon.svg', authDocUrl: 'https://automatisch.io/docs/apps/signalwire/connection', supportsConnections: true, baseUrl: 'https://signalwire.com', From 42dd67954d3aed1207fad78e428995865ebb96ba Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 19:06:20 +0000 Subject: [PATCH 4/9] refactor(signalwire): utilize axios post params --- .../apps/signalwire/actions/send-sms/index.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts index 8f91daa2..5ce3d379 100644 --- a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts +++ b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts @@ -35,15 +35,18 @@ export default defineAction({ async run($) { const requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages`; - const messageBody = $.step.parameters.message; - const fromNumber = '%2B' + ($.step.parameters.fromNumber as string).trim(); - const toNumber = '%2B' + ($.step.parameters.toNumber as string).trim(); + const Body = $.step.parameters.message; + const From = '+' + ($.step.parameters.fromNumber as string).trim(); + const To = '+' + ($.step.parameters.toNumber as string).trim(); - const response = await $.http.post( - 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + requestPath, - `Body=${messageBody}&From=${fromNumber}&To=${toNumber}` - ); + const response = await $.http.post(requestPath, null, { + params: { + Body, + From, + To, + } + }); $.setActionItem({ raw: response.data }); }, From 10b4066c8215b402527ca0d856b78ed8e7d7dac3 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 19:10:20 +0000 Subject: [PATCH 5/9] refactor(signalwire): add dynamic api base url --- .../apps/signalwire/auth/is-still-verified.ts | 1 + .../signalwire/auth/verify-credentials.ts | 4 ++-- .../apps/signalwire/common/add-auth-header.ts | 23 ++++++++++++------- .../triggers/receive-sms/fetch-messages.ts | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/backend/src/apps/signalwire/auth/is-still-verified.ts b/packages/backend/src/apps/signalwire/auth/is-still-verified.ts index 66bb963e..5a2fe2ae 100644 --- a/packages/backend/src/apps/signalwire/auth/is-still-verified.ts +++ b/packages/backend/src/apps/signalwire/auth/is-still-verified.ts @@ -3,6 +3,7 @@ import verifyCredentials from './verify-credentials'; const isStillVerified = async ($: IGlobalVariable) => { await verifyCredentials($); + return true; }; diff --git a/packages/backend/src/apps/signalwire/auth/verify-credentials.ts b/packages/backend/src/apps/signalwire/auth/verify-credentials.ts index ef75de44..fbbf5ddc 100644 --- a/packages/backend/src/apps/signalwire/auth/verify-credentials.ts +++ b/packages/backend/src/apps/signalwire/auth/verify-credentials.ts @@ -1,10 +1,10 @@ import { IGlobalVariable } from '@automatisch/types'; const verifyCredentials = async ($: IGlobalVariable) => { - await $.http.get('https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + '/api/laml/2010-04-01/Accounts'); + const { data } = await $.http.get(`/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}`); await $.auth.set({ - screenName: $.auth.data.accountSid, + screenName: `${data.friendly_name} (${$.auth.data.accountSid})`, }); }; diff --git a/packages/backend/src/apps/signalwire/common/add-auth-header.ts b/packages/backend/src/apps/signalwire/common/add-auth-header.ts index f5f47f85..f26c2af2 100644 --- a/packages/backend/src/apps/signalwire/common/add-auth-header.ts +++ b/packages/backend/src/apps/signalwire/common/add-auth-header.ts @@ -1,19 +1,26 @@ import { TBeforeRequest } from '@automatisch/types'; const addAuthHeader: TBeforeRequest = ($, requestConfig) => { - if ( - requestConfig.headers && - $.auth.data?.accountSid && - $.auth.data?.authToken - ) { - requestConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + const authData = $.auth.data || {}; + requestConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + + if ( + authData.accountSid && + authData.authToken + ) { requestConfig.auth = { - username: $.auth.data.accountSid as string, - password: $.auth.data.authToken as string, + username: authData.accountSid as string, + password: authData.authToken as string, }; } + if (authData.spaceName) { + const serverUrl = `https://${authData.spaceName}.${authData.spaceRegion}signalwire.com`; + + requestConfig.baseURL = serverUrl as string; + } + return requestConfig; }; diff --git a/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts b/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts index 31963130..425c5b20 100644 --- a/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts +++ b/packages/backend/src/apps/signalwire/triggers/receive-sms/fetch-messages.ts @@ -4,7 +4,7 @@ const fetchMessages = async ($: IGlobalVariable) => { const toNumber = $.step.parameters.toNumber as string; let response; - let requestPath = 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages?To=${toNumber}`; + let requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages?To=${toNumber}`; do { response = await $.http.get(requestPath); @@ -20,7 +20,7 @@ const fetchMessages = async ($: IGlobalVariable) => { $.pushTriggerItem(dataItem); }); - requestPath = 'https://' + $.auth.data.spaceName + '.' + $.auth.data.spaceRegion + 'signalwire.com' + response.data.next_page_uri; + requestPath = response.data.next_page_uri; } while (requestPath); }; From bfb1e817ec5c741b7a3868e964f57b998962cbb5 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 20:13:45 +0000 Subject: [PATCH 6/9] feat(signalwire): introduce dynamic incoming phone numbers --- .../apps/signalwire/actions/send-sms/index.ts | 12 +++- .../src/apps/signalwire/dynamic-data/index.ts | 3 + .../list-incoming-phone-numbers/index.ts | 58 +++++++++++++++++++ packages/backend/src/apps/signalwire/index.ts | 2 + .../signalwire/triggers/receive-sms/index.ts | 12 +++- 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 packages/backend/src/apps/signalwire/dynamic-data/index.ts create mode 100644 packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts diff --git a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts index 5ce3d379..0c6db616 100644 --- a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts +++ b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts @@ -8,11 +8,21 @@ export default defineAction({ { label: 'From Number', key: 'fromNumber', - type: 'string' as const, + type: 'dropdown' as const, required: true, description: 'The number to send the SMS from. Include only country code. Example: 491234567890', variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listIncomingPhoneNumbers', + }, + ], + }, }, { label: 'To Number', diff --git a/packages/backend/src/apps/signalwire/dynamic-data/index.ts b/packages/backend/src/apps/signalwire/dynamic-data/index.ts new file mode 100644 index 00000000..d20d4347 --- /dev/null +++ b/packages/backend/src/apps/signalwire/dynamic-data/index.ts @@ -0,0 +1,3 @@ +import listIncomingPhoneNumbers from './list-incoming-phone-numbers'; + +export default [listIncomingPhoneNumbers]; diff --git a/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts b/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts new file mode 100644 index 00000000..b5f4a97e --- /dev/null +++ b/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts @@ -0,0 +1,58 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +type TAggregatedResponse = { + data: IJSONObject[]; + error?: IJSONObject; +}; + +type TResponse = { + incoming_phone_numbers: TIncomingPhoneNumber[]; + next_page_uri: string; +}; + +type TIncomingPhoneNumber = { + capabilities: { + sms: boolean; + }; + sid: string; + friendly_name: string; + phone_number: string; +}; + +export default { + name: 'List incoming phone numbers', + key: 'listIncomingPhoneNumbers', + + async run($: IGlobalVariable) { + let requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/IncomingPhoneNumbers`; + + const aggregatedResponse: TAggregatedResponse = { + data: [], + }; + + do { + const { data } = await $.http.get(requestPath); + + const smsCapableIncomingPhoneNumbers = data.incoming_phone_numbers + .filter((incomingPhoneNumber) => { + return incomingPhoneNumber.capabilities.sms; + }) + .map((incomingPhoneNumber) => { + const friendlyName = incomingPhoneNumber.friendly_name; + const phoneNumber = incomingPhoneNumber.phone_number; + const sid = incomingPhoneNumber.sid; + const name = [friendlyName, phoneNumber].filter(Boolean).join(' - '); + + return { + value: sid, + name, + }; + }) + aggregatedResponse.data.push(...smsCapableIncomingPhoneNumbers) + + requestPath = data.next_page_uri; + } while (requestPath); + + return aggregatedResponse; + }, +}; diff --git a/packages/backend/src/apps/signalwire/index.ts b/packages/backend/src/apps/signalwire/index.ts index 9d187669..658a9a90 100644 --- a/packages/backend/src/apps/signalwire/index.ts +++ b/packages/backend/src/apps/signalwire/index.ts @@ -3,6 +3,7 @@ import addAuthHeader from './common/add-auth-header'; import auth from './auth'; import triggers from './triggers'; import actions from './actions'; +import dynamicData from './dynamic-data'; export default defineApp({ name: 'SignalWire', @@ -17,4 +18,5 @@ export default defineApp({ auth, triggers, actions, + dynamicData, }); diff --git a/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts index 3398d9a0..896244fa 100644 --- a/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts +++ b/packages/backend/src/apps/signalwire/triggers/receive-sms/index.ts @@ -10,10 +10,20 @@ export default defineTrigger({ { label: 'To Number', key: 'toNumber', - type: 'string', + type: 'dropdown', required: true, description: 'The number to receive the SMS on. It should be a SignalWire number in your project.', + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listIncomingPhoneNumbers', + }, + ], + }, }, ], From cc90f19a46e034af831164aa1c6f6cd2ff52ed45 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 22:11:42 +0000 Subject: [PATCH 7/9] fix: stop checking empty action/trigger input in updateStep --- packages/backend/src/models/app.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend/src/models/app.ts b/packages/backend/src/models/app.ts index d50d3426..2755c6a7 100644 --- a/packages/backend/src/models/app.ts +++ b/packages/backend/src/models/app.ts @@ -40,6 +40,8 @@ class App { static async checkAppAndAction(appKey: string, actionKey: string): Promise { const app = await this.findOneByKey(appKey); + if (!actionKey) return; + const hasAction = app.actions?.find(action => action.key === actionKey); if (!hasAction) { @@ -50,6 +52,8 @@ class App { static async checkAppAndTrigger(appKey: string, triggerKey: string): Promise { const app = await this.findOneByKey(appKey); + if (!triggerKey) return; + const hasTrigger = app.triggers?.find(trigger => trigger.key === triggerKey); if (!hasTrigger) { From aec9595dead359f76b9e5c01b503841746a3a57f Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 22:11:55 +0000 Subject: [PATCH 8/9] fix: stop checking empty app input in createFlow --- packages/backend/src/graphql/mutations/create-flow.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/graphql/mutations/create-flow.ts b/packages/backend/src/graphql/mutations/create-flow.ts index 30c0968f..7243d8c5 100644 --- a/packages/backend/src/graphql/mutations/create-flow.ts +++ b/packages/backend/src/graphql/mutations/create-flow.ts @@ -17,7 +17,9 @@ const createFlow = async ( const connectionId = params?.input?.connectionId; const appKey = params?.input?.triggerAppKey; - await App.findOneByKey(appKey); + if (appKey) { + await App.findOneByKey(appKey); + } const flow = await context.currentUser.$relatedQuery('flows').insert({ name: 'Name your flow', From 7d40ae009fd0bd19fbd7ea7515a67b7d12781cfa Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 Mar 2023 22:32:25 +0000 Subject: [PATCH 9/9] fix(signalwire): use incoming phone number instead of its sid --- packages/backend/src/apps/signalwire/actions/send-sms/index.ts | 2 +- .../dynamic-data/list-incoming-phone-numbers/index.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts index 0c6db616..fee65fbf 100644 --- a/packages/backend/src/apps/signalwire/actions/send-sms/index.ts +++ b/packages/backend/src/apps/signalwire/actions/send-sms/index.ts @@ -47,7 +47,7 @@ export default defineAction({ const requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages`; const Body = $.step.parameters.message; - const From = '+' + ($.step.parameters.fromNumber as string).trim(); + const From = $.step.parameters.fromNumber; const To = '+' + ($.step.parameters.toNumber as string).trim(); const response = await $.http.post(requestPath, null, { diff --git a/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts b/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts index b5f4a97e..969d2e45 100644 --- a/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts +++ b/packages/backend/src/apps/signalwire/dynamic-data/list-incoming-phone-numbers/index.ts @@ -40,11 +40,10 @@ export default { .map((incomingPhoneNumber) => { const friendlyName = incomingPhoneNumber.friendly_name; const phoneNumber = incomingPhoneNumber.phone_number; - const sid = incomingPhoneNumber.sid; const name = [friendlyName, phoneNumber].filter(Boolean).join(' - '); return { - value: sid, + value: phoneNumber, name, }; })