Merge pull request #666 from automatisch/discord/send-message-to-channel
feat(discord): add send message to channel action
This commit is contained in:
@@ -1 +1,5 @@
|
|||||||
export default [];
|
import sendMessageToChannel from "./send-message-to-channel";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
sendMessageToChannel
|
||||||
|
];
|
||||||
|
@@ -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 });
|
||||||
|
},
|
||||||
|
});
|
@@ -13,6 +13,7 @@ export default async function createAuthData($: IGlobalVariable) {
|
|||||||
client_id: $.auth.data.consumerKey as string,
|
client_id: $.auth.data.consumerKey as string,
|
||||||
redirect_uri: callbackUrl,
|
redirect_uri: callbackUrl,
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
|
permissions: '2146958591',
|
||||||
scope: scopes.join(' '),
|
scope: scopes.join(' '),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -39,6 +39,18 @@ export default {
|
|||||||
description: null,
|
description: null,
|
||||||
docUrl: 'https://automatisch.io/docs/discord#consumer-secret',
|
docUrl: 'https://automatisch.io/docs/discord#consumer-secret',
|
||||||
clickToCopy: false
|
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: [
|
authenticationSteps: [
|
||||||
@@ -62,6 +74,10 @@ export default {
|
|||||||
{
|
{
|
||||||
name: 'consumerSecret',
|
name: 'consumerSecret',
|
||||||
value: '{fields.consumerSecret}'
|
value: '{fields.consumerSecret}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'botToken',
|
||||||
|
value: '{fields.botToken}'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -154,6 +170,10 @@ export default {
|
|||||||
{
|
{
|
||||||
name: 'consumerSecret',
|
name: 'consumerSecret',
|
||||||
value: '{fields.consumerSecret}'
|
value: '{fields.consumerSecret}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'botToken',
|
||||||
|
value: '{fields.botToken}'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,10 @@ const verifyCredentials = async ($: IGlobalVariable) => {
|
|||||||
expires_in: expiresIn,
|
expires_in: expiresIn,
|
||||||
scope: scope,
|
scope: scope,
|
||||||
token_type: tokenType,
|
token_type: tokenType,
|
||||||
|
guild: {
|
||||||
|
id: guildId,
|
||||||
|
name: guildName,
|
||||||
|
}
|
||||||
} = verifiedCredentials;
|
} = verifiedCredentials;
|
||||||
|
|
||||||
await $.auth.set({
|
await $.auth.set({
|
||||||
@@ -44,6 +48,8 @@ const verifyCredentials = async ($: IGlobalVariable) => {
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
screenName: user.username,
|
screenName: user.username,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
guildId,
|
||||||
|
guildName,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
import { TBeforeRequest } from '@automatisch/types';
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||||
const { tokenType, accessToken } = $.auth.data;
|
const { tokenType, botToken } = $.auth.data;
|
||||||
if (tokenType && accessToken) {
|
if (tokenType && botToken) {
|
||||||
requestConfig.headers.Authorization = `${tokenType} ${accessToken}`;
|
requestConfig.headers.Authorization = `Bot ${botToken}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return requestConfig;
|
return requestConfig;
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
const scopes = ['identify', 'email'];
|
const scopes = ['bot', 'identify'];
|
||||||
|
|
||||||
export default scopes;
|
export default scopes;
|
||||||
|
5
packages/backend/src/apps/discord/data/index.ts
Normal file
5
packages/backend/src/apps/discord/data/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import listChannels from "./list-channels";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
listChannels,
|
||||||
|
];
|
@@ -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;
|
||||||
|
},
|
||||||
|
};
|
@@ -1,6 +1,7 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
import defineApp from '../../helpers/define-app';
|
||||||
import addAuthHeader from './common/add-auth-header';
|
import addAuthHeader from './common/add-auth-header';
|
||||||
import auth from './auth';
|
import auth from './auth';
|
||||||
|
import data from './data';
|
||||||
import actions from './actions';
|
import actions from './actions';
|
||||||
import triggers from './triggers';
|
import triggers from './triggers';
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ export default defineApp({
|
|||||||
primaryColor: '5865f2',
|
primaryColor: '5865f2',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
data,
|
||||||
triggers,
|
triggers,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -25,7 +25,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Connections',
|
text: 'Connections',
|
||||||
link: '/connections/twitter',
|
link: '/connections/discord',
|
||||||
activeMatch: '/connections/',
|
activeMatch: '/connections/',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -35,6 +35,7 @@ export default defineConfig({
|
|||||||
text: 'Connections',
|
text: 'Connections',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
items: [
|
items: [
|
||||||
|
{ text: 'Discord', link: '/connections/discord' },
|
||||||
{ text: 'Flickr', link: '/connections/flickr' },
|
{ text: 'Flickr', link: '/connections/flickr' },
|
||||||
{ text: 'Github', link: '/connections/github' },
|
{ text: 'Github', link: '/connections/github' },
|
||||||
{ text: 'Scheduler', link: '/connections/scheduler' },
|
{ text: 'Scheduler', link: '/connections/scheduler' },
|
||||||
|
26
packages/docs/pages/connections/discord.md
Normal file
26
packages/docs/pages/connections/discord.md
Normal file
@@ -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.
|
@@ -71,6 +71,8 @@ export default function AddAppConnection(props: AddAppConnectionProps): React.Re
|
|||||||
const error = err as Error;
|
const error = err as Error;
|
||||||
console.log(error);
|
console.log(error);
|
||||||
setErrorMessage(error.message);
|
setErrorMessage(error.message);
|
||||||
|
setInProgress(false);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,13 +38,20 @@ function getObjectOfEntries(iterator: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const processOpenWithPopup = (step: IAuthenticationStep, variables: IJSONObject) => {
|
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 windowFeatures = 'toolbar=no, titlebar=no, menubar=no, width=500, height=700, top=100, left=100';
|
||||||
const url = variables.url;
|
const url = variables.url;
|
||||||
|
|
||||||
const popup = window.open(url as string, '_blank', windowFeatures) as WindowProxy;
|
const popup = window.open(url as string, '_blank', windowFeatures) as WindowProxy;
|
||||||
popup?.focus();
|
popup?.focus();
|
||||||
|
|
||||||
|
const closeCheckIntervalId = setInterval(() => {
|
||||||
|
if (popup.closed) {
|
||||||
|
clearInterval(closeCheckIntervalId);
|
||||||
|
reject({ message: 'Error occured while verifying credentials!' });
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
const messageHandler = async (event: MessageEvent) => {
|
const messageHandler = async (event: MessageEvent) => {
|
||||||
if (event.data.source !== 'automatisch') {
|
if (event.data.source !== 'automatisch') {
|
||||||
return;
|
return;
|
||||||
@@ -53,6 +60,7 @@ const processOpenWithPopup = (step: IAuthenticationStep, variables: IJSONObject)
|
|||||||
const data = parseUrlSearchParams(event);
|
const data = parseUrlSearchParams(event);
|
||||||
window.removeEventListener('message', messageHandler);
|
window.removeEventListener('message', messageHandler);
|
||||||
|
|
||||||
|
clearInterval(closeCheckIntervalId);
|
||||||
resolve(data);
|
resolve(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user