feat(Discord Node): Overhaul (#5351)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Marcus <marcus@n8n.io>
This commit is contained in:
2
packages/nodes-base/nodes/Discord/v2/methods/index.ts
Normal file
2
packages/nodes-base/nodes/Discord/v2/methods/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * as listSearch from './listSearch';
|
||||
export * as loadOptions from './loadOptions';
|
||||
164
packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts
Normal file
164
packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import {
|
||||
type IDataObject,
|
||||
type ILoadOptionsFunctions,
|
||||
type INodeListSearchResult,
|
||||
} from 'n8n-workflow';
|
||||
import { discordApiRequest } from '../transport';
|
||||
import { checkAccessToGuild } from '../helpers/utils';
|
||||
|
||||
async function getGuildId(this: ILoadOptionsFunctions) {
|
||||
const guildId = this.getNodeParameter('guildId', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const isOAuth2 = this.getNodeParameter('authentication', '') === 'oAuth2';
|
||||
|
||||
if (isOAuth2) {
|
||||
const userGuilds = (await discordApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/users/@me/guilds',
|
||||
)) as IDataObject[];
|
||||
|
||||
checkAccessToGuild(this.getNode(), guildId, userGuilds);
|
||||
}
|
||||
|
||||
return guildId;
|
||||
}
|
||||
|
||||
async function checkBotAccessToGuild(this: ILoadOptionsFunctions, guildId: string, botId: string) {
|
||||
try {
|
||||
const members: Array<{ user: { id: string } }> = await discordApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/guilds/${guildId}/members`,
|
||||
undefined,
|
||||
{ limit: 1000 },
|
||||
);
|
||||
|
||||
return members.some((member) => member.user.id === botId);
|
||||
} catch (error) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function guildSearch(this: ILoadOptionsFunctions): Promise<INodeListSearchResult> {
|
||||
const response = (await discordApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/users/@me/guilds',
|
||||
)) as IDataObject[];
|
||||
|
||||
let guilds: IDataObject[] = [];
|
||||
|
||||
const isOAuth2 = this.getNodeParameter('authentication', 0) === 'oAuth2';
|
||||
|
||||
if (isOAuth2) {
|
||||
const botId = (await discordApiRequest.call(this, 'GET', '/users/@me')).id as string;
|
||||
|
||||
for (const guild of response) {
|
||||
if (!(await checkBotAccessToGuild.call(this, guild.id as string, botId))) continue;
|
||||
guilds.push(guild);
|
||||
}
|
||||
} else {
|
||||
guilds = response;
|
||||
}
|
||||
|
||||
return {
|
||||
results: guilds.map((guild) => ({
|
||||
name: guild.name as string,
|
||||
value: guild.id as string,
|
||||
url: `https://discord.com/channels/${guild.id}`,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function channelSearch(this: ILoadOptionsFunctions): Promise<INodeListSearchResult> {
|
||||
const guildId = await getGuildId.call(this);
|
||||
const response = await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/channels`);
|
||||
|
||||
return {
|
||||
results: (response as IDataObject[])
|
||||
.filter((cannel) => cannel.type !== 4) // Filter out categories
|
||||
.map((channel) => ({
|
||||
name: channel.name as string,
|
||||
value: channel.id as string,
|
||||
url: `https://discord.com/channels/${guildId}/${channel.id}`,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function textChannelSearch(
|
||||
this: ILoadOptionsFunctions,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const guildId = await getGuildId.call(this);
|
||||
|
||||
const response = await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/channels`);
|
||||
|
||||
return {
|
||||
results: (response as IDataObject[])
|
||||
.filter((cannel) => ![2, 4].includes(cannel.type as number)) // Only text channels
|
||||
.map((channel) => ({
|
||||
name: channel.name as string,
|
||||
value: channel.id as string,
|
||||
url: `https://discord.com/channels/${guildId}/${channel.id}`,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function categorySearch(this: ILoadOptionsFunctions): Promise<INodeListSearchResult> {
|
||||
const guildId = await getGuildId.call(this);
|
||||
|
||||
const response = await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/channels`);
|
||||
|
||||
return {
|
||||
results: (response as IDataObject[])
|
||||
.filter((cannel) => cannel.type === 4) // Return only categories
|
||||
.map((channel) => ({
|
||||
name: channel.name as string,
|
||||
value: channel.id as string,
|
||||
url: `https://discord.com/channels/${guildId}/${channel.id}`,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function userSearch(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const guildId = await getGuildId.call(this);
|
||||
|
||||
const limit = 100;
|
||||
const qs = { limit, after: paginationToken };
|
||||
|
||||
const response = await discordApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/guilds/${guildId}/members`,
|
||||
undefined,
|
||||
qs,
|
||||
);
|
||||
|
||||
if (response.length === 0) {
|
||||
return {
|
||||
results: [],
|
||||
paginationToken: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
let lastUserId;
|
||||
|
||||
//less then limit means that there are no more users to return, so leave lastUserId undefined
|
||||
if (!(response.length < limit)) {
|
||||
lastUserId = response[response.length - 1].user.id as string;
|
||||
}
|
||||
|
||||
return {
|
||||
results: (response as Array<{ user: IDataObject }>).map(({ user }) => ({
|
||||
name: user.username as string,
|
||||
value: user.id as string,
|
||||
})),
|
||||
paginationToken: lastUserId,
|
||||
};
|
||||
}
|
||||
46
packages/nodes-base/nodes/Discord/v2/methods/loadOptions.ts
Normal file
46
packages/nodes-base/nodes/Discord/v2/methods/loadOptions.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { IDataObject, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
||||
import { discordApiRequest } from '../transport';
|
||||
import { checkAccessToGuild } from '../helpers/utils';
|
||||
|
||||
export async function getRoles(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const guildId = this.getNodeParameter('guildId', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const isOAuth2 = this.getNodeParameter('authentication', '') === 'oAuth2';
|
||||
|
||||
if (isOAuth2) {
|
||||
const userGuilds = (await discordApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/users/@me/guilds',
|
||||
)) as IDataObject[];
|
||||
|
||||
checkAccessToGuild(this.getNode(), guildId, userGuilds);
|
||||
}
|
||||
|
||||
let response = await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/roles`);
|
||||
|
||||
const operations = this.getNodeParameter('operation') as string;
|
||||
|
||||
if (operations === 'roleRemove') {
|
||||
const userId = this.getNodeParameter('userId', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const userRoles = ((
|
||||
await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/members/${userId}`)
|
||||
).roles || []) as string[];
|
||||
|
||||
response = response.filter((role: IDataObject) => {
|
||||
return userRoles.includes(role.id as string);
|
||||
});
|
||||
}
|
||||
|
||||
return response
|
||||
.filter((role: IDataObject) => role.name !== '@everyone' && !role.managed)
|
||||
.map((role: IDataObject) => ({
|
||||
name: role.name as string,
|
||||
value: role.id as string,
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user