From c2b020fc94fc6494902f9926d71472105664b0d5 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 22:25:11 +0100 Subject: [PATCH 1/6] feat(discord): use bot auth instead of user --- .../src/apps/discord/auth/create-auth-data.ts | 1 + .../backend/src/apps/discord/auth/index.ts | 20 +++++++++++++++++++ .../apps/discord/auth/verify-credentials.ts | 6 ++++++ .../apps/discord/common/add-auth-header.ts | 6 +++--- .../backend/src/apps/discord/common/scopes.ts | 2 +- 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/apps/discord/auth/create-auth-data.ts b/packages/backend/src/apps/discord/auth/create-auth-data.ts index 79ae7fbd..992d1e98 100644 --- a/packages/backend/src/apps/discord/auth/create-auth-data.ts +++ b/packages/backend/src/apps/discord/auth/create-auth-data.ts @@ -13,6 +13,7 @@ export default async function createAuthData($: IGlobalVariable) { client_id: $.auth.data.consumerKey as string, redirect_uri: callbackUrl, response_type: 'code', + permissions: '2146958591', scope: scopes.join(' '), }); diff --git a/packages/backend/src/apps/discord/auth/index.ts b/packages/backend/src/apps/discord/auth/index.ts index f247e86f..fc3d2fde 100644 --- a/packages/backend/src/apps/discord/auth/index.ts +++ b/packages/backend/src/apps/discord/auth/index.ts @@ -39,6 +39,18 @@ export default { description: null, docUrl: 'https://automatisch.io/docs/discord#consumer-secret', clickToCopy: false + }, + { + key: 'botToken', + label: 'Bot token', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: null, + docUrl: 'https://automatisch.io/docs/discord#bot-token', + clickToCopy: false } ], authenticationSteps: [ @@ -62,6 +74,10 @@ export default { { name: 'consumerSecret', value: '{fields.consumerSecret}' + }, + { + name: 'botToken', + value: '{fields.botToken}' } ] } @@ -154,6 +170,10 @@ export default { { name: 'consumerSecret', value: '{fields.consumerSecret}' + }, + { + name: 'botToken', + value: '{fields.botToken}' } ] } diff --git a/packages/backend/src/apps/discord/auth/verify-credentials.ts b/packages/backend/src/apps/discord/auth/verify-credentials.ts index b7c5c3ad..75056702 100644 --- a/packages/backend/src/apps/discord/auth/verify-credentials.ts +++ b/packages/backend/src/apps/discord/auth/verify-credentials.ts @@ -28,6 +28,10 @@ const verifyCredentials = async ($: IGlobalVariable) => { expires_in: expiresIn, scope: scope, token_type: tokenType, + guild: { + id: guildId, + name: guildName, + } } = verifiedCredentials; await $.auth.set({ @@ -44,6 +48,8 @@ const verifyCredentials = async ($: IGlobalVariable) => { userId: user.id, screenName: user.username, email: user.email, + guildId, + guildName, }); }; diff --git a/packages/backend/src/apps/discord/common/add-auth-header.ts b/packages/backend/src/apps/discord/common/add-auth-header.ts index 6f879476..f4fc8f0f 100644 --- a/packages/backend/src/apps/discord/common/add-auth-header.ts +++ b/packages/backend/src/apps/discord/common/add-auth-header.ts @@ -1,9 +1,9 @@ import { TBeforeRequest } from '@automatisch/types'; const addAuthHeader: TBeforeRequest = ($, requestConfig) => { - const { tokenType, accessToken } = $.auth.data; - if (tokenType && accessToken) { - requestConfig.headers.Authorization = `${tokenType} ${accessToken}`; + const { tokenType, botToken } = $.auth.data; + if (tokenType && botToken) { + requestConfig.headers.Authorization = `Bot ${botToken}`; } return requestConfig; diff --git a/packages/backend/src/apps/discord/common/scopes.ts b/packages/backend/src/apps/discord/common/scopes.ts index f0e5bba5..c924ca83 100644 --- a/packages/backend/src/apps/discord/common/scopes.ts +++ b/packages/backend/src/apps/discord/common/scopes.ts @@ -1,3 +1,3 @@ -const scopes = ['identify', 'email']; +const scopes = ['bot', 'identify']; export default scopes; From 9c40bc58635ffdf2f661a76554ad70f0a32a2d05 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 22:27:27 +0100 Subject: [PATCH 2/6] fix(web): discard failed auth process --- .../web/src/components/AddAppConnection/index.tsx | 2 ++ packages/web/src/helpers/authenticationSteps.ts | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/web/src/components/AddAppConnection/index.tsx b/packages/web/src/components/AddAppConnection/index.tsx index fb0428be..4627fd71 100644 --- a/packages/web/src/components/AddAppConnection/index.tsx +++ b/packages/web/src/components/AddAppConnection/index.tsx @@ -71,6 +71,8 @@ export default function AddAppConnection(props: AddAppConnectionProps): React.Re const error = err as Error; console.log(error); setErrorMessage(error.message); + setInProgress(false); + break; } diff --git a/packages/web/src/helpers/authenticationSteps.ts b/packages/web/src/helpers/authenticationSteps.ts index 80bfe05d..02b9998b 100644 --- a/packages/web/src/helpers/authenticationSteps.ts +++ b/packages/web/src/helpers/authenticationSteps.ts @@ -15,7 +15,7 @@ const processMutation = async (step: IAuthenticationStep, variables: IJSONObject context: { autoSnackbar: false, }, - }); + }); const responseData = mutationResponse.data[step.name]; return responseData; @@ -38,13 +38,20 @@ function getObjectOfEntries(iterator: any) { } const processOpenWithPopup = (step: IAuthenticationStep, variables: IJSONObject) => { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { const windowFeatures = 'toolbar=no, titlebar=no, menubar=no, width=500, height=700, top=100, left=100'; const url = variables.url; const popup = window.open(url as string, '_blank', windowFeatures) as WindowProxy; popup?.focus(); + const closeCheckIntervalId = setInterval(() => { + if (popup.closed) { + clearInterval(closeCheckIntervalId); + reject({ message: 'Error occured while verifying credentials!' }); + } + }, 1000) + const messageHandler = async (event: MessageEvent) => { if (event.data.source !== 'automatisch') { return; @@ -53,6 +60,7 @@ const processOpenWithPopup = (step: IAuthenticationStep, variables: IJSONObject) const data = parseUrlSearchParams(event); window.removeEventListener('message', messageHandler); + clearInterval(closeCheckIntervalId); resolve(data); }; From 79e609e68228f26d3b0bd76e1ca7a8a91ed5ed0a Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 22:28:16 +0100 Subject: [PATCH 3/6] feat(discord): add list channels data --- .../backend/src/apps/discord/data/index.ts | 5 +++ .../apps/discord/data/list-channels/index.ts | 32 +++++++++++++++++++ packages/backend/src/apps/discord/index.ts | 2 ++ 3 files changed, 39 insertions(+) create mode 100644 packages/backend/src/apps/discord/data/index.ts create mode 100644 packages/backend/src/apps/discord/data/list-channels/index.ts diff --git a/packages/backend/src/apps/discord/data/index.ts b/packages/backend/src/apps/discord/data/index.ts new file mode 100644 index 00000000..596f701b --- /dev/null +++ b/packages/backend/src/apps/discord/data/index.ts @@ -0,0 +1,5 @@ +import listChannels from "./list-channels"; + +export default [ + listChannels, +]; diff --git a/packages/backend/src/apps/discord/data/list-channels/index.ts b/packages/backend/src/apps/discord/data/list-channels/index.ts new file mode 100644 index 00000000..eaff6527 --- /dev/null +++ b/packages/backend/src/apps/discord/data/list-channels/index.ts @@ -0,0 +1,32 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +export default { + name: 'List channels', + key: 'listChannels', + + async run($: IGlobalVariable) { + const channels: { + data: IJSONObject[]; + error: IJSONObject | null; + } = { + data: [], + error: null, + }; + + const response = await $.http.get(`/guilds/${$.auth.data.guildId}/channels`); + + channels.data = response.data + .filter((channel: IJSONObject) => { + // filter in text channels only + return channel.type === 0; + }) + .map((channel: IJSONObject) => { + return { + value: channel.id, + name: channel.name, + }; + }); + + return channels; + }, +}; diff --git a/packages/backend/src/apps/discord/index.ts b/packages/backend/src/apps/discord/index.ts index 9734fd34..25972f7d 100644 --- a/packages/backend/src/apps/discord/index.ts +++ b/packages/backend/src/apps/discord/index.ts @@ -1,6 +1,7 @@ import defineApp from '../../helpers/define-app'; import addAuthHeader from './common/add-auth-header'; import auth from './auth'; +import data from './data'; import actions from './actions'; import triggers from './triggers'; @@ -15,6 +16,7 @@ export default defineApp({ primaryColor: '5865f2', beforeRequest: [addAuthHeader], auth, + data, triggers, actions, }); From dfa076ba89dc18e6d1c37a0ffd9a92403726d648 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 22:28:50 +0100 Subject: [PATCH 4/6] feat(discord): add send message to channel action --- .../backend/src/apps/discord/actions/index.ts | 6 +- .../actions/send-message-to-channel/index.ts | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 packages/backend/src/apps/discord/actions/send-message-to-channel/index.ts diff --git a/packages/backend/src/apps/discord/actions/index.ts b/packages/backend/src/apps/discord/actions/index.ts index d6d1738d..c698a42c 100644 --- a/packages/backend/src/apps/discord/actions/index.ts +++ b/packages/backend/src/apps/discord/actions/index.ts @@ -1 +1,5 @@ -export default []; +import sendMessageToChannel from "./send-message-to-channel"; + +export default [ + sendMessageToChannel +]; diff --git a/packages/backend/src/apps/discord/actions/send-message-to-channel/index.ts b/packages/backend/src/apps/discord/actions/send-message-to-channel/index.ts new file mode 100644 index 00000000..34af6ce6 --- /dev/null +++ b/packages/backend/src/apps/discord/actions/send-message-to-channel/index.ts @@ -0,0 +1,58 @@ +import defineAction from '../../../../helpers/define-action'; + +export default defineAction({ + name: 'Send a message to channel', + key: 'sendMessageToChannel', + description: 'Send a message to a specific channel you specify.', + substeps: [ + { + key: 'chooseConnection', + name: 'Choose connection', + }, + { + key: 'chooseAction', + name: 'Set up action', + arguments: [ + { + label: 'Channel', + key: 'channel', + type: 'dropdown' as const, + required: true, + description: 'Pick a channel to send the message to.', + variables: false, + source: { + type: 'query', + name: 'getData', + arguments: [ + { + name: 'key', + value: 'listChannels', + }, + ], + }, + }, + { + label: 'Message text', + key: 'message', + type: 'string' as const, + required: true, + description: 'The content of your new message.', + variables: true, + } + ], + }, + { + key: 'testStep', + name: 'Test action', + }, + ], + + async run($) { + const data = { + content: $.step.parameters.message as string, + }; + const response = await $.http?.post(`/channels/${$.step.parameters.channel}/messages`, data); + + $.setActionItem({ raw: response.data }); + }, +}); From d8a91ac62ddc317c6c5a954a1bf62f9fe08955e9 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 22:52:56 +0100 Subject: [PATCH 5/6] docs(discord): describe discord setup --- packages/docs/pages/connections/discord.md | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/docs/pages/connections/discord.md diff --git a/packages/docs/pages/connections/discord.md b/packages/docs/pages/connections/discord.md new file mode 100644 index 00000000..10e9ee8d --- /dev/null +++ b/packages/docs/pages/connections/discord.md @@ -0,0 +1,26 @@ +# Discord + +:::info +This page explains the steps you need to follow to set up the Discord +connection in Automatisch. If any of the steps are outdated, please let us know! +::: + +1. Go to the [link](https://discord.com/developers/applications) to register a **new application** on Discord. +1. Fill **Name**. +1. Check the checkboxes. +1. Click on the **create** button. +1. Go to **OAuth2** > **General** page. +1. Copy the **Client ID** and save it to use later. +1. Reset the **Client secret** to get the initial client secret and copy it to use later. +1. Click the **Add Redirect** button to define a redirect URI. +1. Copy **OAuth Redirect URL** from Automatisch to **Redirect** field. +1. Save the changes. +1. Go to **Bot** page. +1. Click **Add Bot** button. +1. Acknowledge the warning and click **Yes, do it!**. +1. Click **Reset Token** to get the initial bot token and copy it to use later. +1. Fill the **Consumer key** field with the **Client ID** value we copied. +1. Fill the **Consumer secret** field with the **Client Secret** value we copied. +1. Fill the **Bot token** field with the **Bot Token** value we copied. +1. Click **Submit** button on Automatisch. +1. Congrats! Start using your new Discord connection within the flows. From f272e5c4a80efd3717d22f5dcc243973d8e27b93 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 30 Oct 2022 23:12:04 +0100 Subject: [PATCH 6/6] docs: add discord in connections --- packages/docs/pages/.vitepress/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js index f4dabd95..60b63bd9 100644 --- a/packages/docs/pages/.vitepress/config.js +++ b/packages/docs/pages/.vitepress/config.js @@ -25,7 +25,7 @@ export default defineConfig({ }, { text: 'Connections', - link: '/connections/twitter', + link: '/connections/discord', activeMatch: '/connections/', }, ], @@ -35,6 +35,7 @@ export default defineConfig({ text: 'Connections', collapsible: true, items: [ + { text: 'Discord', link: '/connections/discord' }, { text: 'Flickr', link: '/connections/flickr' }, { text: 'Github', link: '/connections/github' }, { text: 'Scheduler', link: '/connections/scheduler' },