From 3e5ba983b09095ee828c66b9b1237785e2acef96 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 22 Apr 2024 10:32:18 +0300 Subject: [PATCH 1/4] :zap: fix --- .../Discord/v2/actions/channel/deleteChannel.operation.ts | 2 +- .../nodes/Discord/v2/actions/channel/get.operation.ts | 2 +- .../nodes/Discord/v2/actions/message/send.operation.ts | 7 +++++-- packages/nodes-base/nodes/Discord/v2/helpers/utils.ts | 6 +++--- packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/nodes/Discord/v2/actions/channel/deleteChannel.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/channel/deleteChannel.operation.ts index 14a601938ecc7..57c405655f10f 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/channel/deleteChannel.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/channel/deleteChannel.operation.ts @@ -25,7 +25,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/channel/get.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/channel/get.operation.ts index 5d0a09d4bd948..585b5294d405a 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/channel/get.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/channel/get.operation.ts @@ -25,7 +25,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts index eb207c53b1ff3..27d2d6460789b 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts @@ -153,7 +153,7 @@ export async function execute( }; if (embeds) { - body.embeds = prepareEmbeds.call(this, embeds, i); + body.embeds = prepareEmbeds.call(this, embeds); } try { @@ -183,7 +183,10 @@ export async function execute( throw new NodeOperationError(this.getNode(), 'Channel ID is required'); } - if (isOAuth2) await checkAccessToChannel.call(this, channelId, userGuilds, i); + // no need to check if sendTo === 'user' because access to guild was checked before in router + if (isOAuth2 && sendTo === 'channel') { + await checkAccessToChannel.call(this, channelId, userGuilds, i); + } let response: IDataObject[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts index 8951320a3f757..b3852f9527a4b 100644 --- a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts @@ -114,9 +114,9 @@ export function prepareOptions(options: IDataObject, guildId?: string) { return options; } -export function prepareEmbeds(this: IExecuteFunctions, embeds: IDataObject[], i = 0) { +export function prepareEmbeds(this: IExecuteFunctions, embeds: IDataObject[]) { return embeds - .map((embed, index) => { + .map((embed) => { let embedReturnData: IDataObject = {}; if (embed.inputMethod === 'json') { @@ -261,7 +261,7 @@ export async function checkAccessToChannel( if (!guildId) { throw new NodeOperationError( this.getNode(), - `Could not fing server for channel with the id ${channelId}`, + `Could not find server for channel with the id ${channelId}`, { itemIndex, }, diff --git a/packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts b/packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts index 902dfb156360b..abbec430402e0 100644 --- a/packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts +++ b/packages/nodes-base/nodes/Discord/v2/methods/listSearch.ts @@ -124,7 +124,7 @@ export async function categorySearch(this: ILoadOptionsFunctions): Promise { const guildId = await getGuildId.call(this); From 14214d6815463240b1f4f353a994c8e9156eddb2 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 22 Apr 2024 10:43:22 +0300 Subject: [PATCH 2/4] :zap: linter and spelling fixes --- .../nodes/Discord/v2/actions/channel/update.operation.ts | 2 +- .../Discord/v2/actions/message/deleteMessage.operation.ts | 2 +- .../nodes/Discord/v2/actions/message/get.operation.ts | 2 +- .../nodes/Discord/v2/actions/message/getAll.operation.ts | 2 +- .../nodes/Discord/v2/actions/message/react.operation.ts | 2 +- packages/nodes-base/nodes/Discord/v2/transport/discord.api.ts | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/nodes-base/nodes/Discord/v2/actions/channel/update.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/channel/update.operation.ts index 670a875ae13aa..0466bd20c3947 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/channel/update.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/channel/update.operation.ts @@ -104,7 +104,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/deleteMessage.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/deleteMessage.operation.ts index 2d605ad08650e..149d9fc9e90ce 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/deleteMessage.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/deleteMessage.operation.ts @@ -25,7 +25,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/get.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/get.operation.ts index b9366088fa645..e7bb9f6a1871e 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/get.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/get.operation.ts @@ -41,7 +41,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/getAll.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/getAll.operation.ts index 0378bfc82b83c..957dcf210407f 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/getAll.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/getAll.operation.ts @@ -42,7 +42,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/react.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/react.operation.ts index a12acad581002..1041c5626a0e6 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/react.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/react.operation.ts @@ -36,7 +36,7 @@ export const description = updateDisplayOptions(displayOptions, properties); export async function execute( this: IExecuteFunctions, - guildId: string, + _guildId: string, userGuilds: IDataObject[], ): Promise { const returnData: INodeExecutionData[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/transport/discord.api.ts b/packages/nodes-base/nodes/Discord/v2/transport/discord.api.ts index 153e37650bc32..c7a066ef4d2cc 100644 --- a/packages/nodes-base/nodes/Discord/v2/transport/discord.api.ts +++ b/packages/nodes-base/nodes/Discord/v2/transport/discord.api.ts @@ -48,7 +48,7 @@ export async function discordApiRequest( if (remaining === 0) { await sleep(resetAfter); } else { - await sleep(20); //prevent excing global rate limit of 50 requests per second + await sleep(20); //prevent exceeding global rate limit of 50 requests per second } return response.body || { success: true }; @@ -91,7 +91,7 @@ export async function discordApiMultiPartRequest( if (remaining === 0) { await sleep(resetAfter); } else { - await sleep(20); //prevent excing global rate limit of 50 requests per second + await sleep(20); //prevent exceeding global rate limit of 50 requests per second } return jsonParse(response.body); From 58758469e63499a59b646defc274e4e2061e4082 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 22 Apr 2024 11:20:06 +0300 Subject: [PATCH 3/4] :zap: util to check if user is guild member --- .../v2/actions/message/send.operation.ts | 22 ++++++++++--- .../nodes/Discord/v2/helpers/utils.ts | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts index 27d2d6460789b..38968bd1887e2 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts @@ -16,6 +16,7 @@ import { import { checkAccessToChannel, + checkIfUserGuildMember, parseDiscordError, prepareEmbeds, prepareErrorData, @@ -166,11 +167,23 @@ export async function execute( extractValue: true, }) as string; + if (isOAuth2) { + await checkIfUserGuildMember.call(this, guildId, userId, i); + } + channelId = ( (await discordApiRequest.call(this, 'POST', '/users/@me/channels', { recipient_id: userId, })) as IDataObject ).id as string; + + if (!channelId) { + throw new NodeOperationError( + this.getNode(), + 'Could not create a channel to send direct message to', + { itemIndex: i }, + ); + } } if (sendTo === 'channel') { @@ -179,13 +192,12 @@ export async function execute( }) as string; } - if (!channelId) { - throw new NodeOperationError(this.getNode(), 'Channel ID is required'); + if (isOAuth2 && sendTo !== 'user') { + await checkAccessToChannel.call(this, channelId, userGuilds, i); } - // no need to check if sendTo === 'user' because access to guild was checked before in router - if (isOAuth2 && sendTo === 'channel') { - await checkAccessToChannel.call(this, channelId, userGuilds, i); + if (!channelId) { + throw new NodeOperationError(this.getNode(), 'Channel ID is required', { itemIndex: i }); } let response: IDataObject[] = []; diff --git a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts index b3852f9527a4b..4d964f2ebb179 100644 --- a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts @@ -271,6 +271,37 @@ export async function checkAccessToChannel( checkAccessToGuild(this.getNode(), guildId, userGuilds, itemIndex); } +export async function checkIfUserGuildMember( + this: IExecuteFunctions, + guildId: string, + userId: string, + itemIndex = 0, +) { + let lastUserId; + let members; + + while (true) { + members = (await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/members`, undefined, { + limit: 100, + after: lastUserId, + })) as Array<{ user: { id: string } }>; + + if (!members?.length) { + throw new NodeOperationError( + this.getNode(), + `User with the id ${userId} is not a member of the selected guild`, + { + itemIndex, + }, + ); + } else if (members.some((member) => member.user.id === userId)) { + break; + } else { + lastUserId = members[members.length - 1].user.id; + } + } +} + export async function setupChannelGetter(this: IExecuteFunctions, userGuilds: IDataObject[]) { const isOAuth2 = this.getNodeParameter('authentication', 0) === 'oAuth2'; From 82092b5677d9fb4070931bfd905f44defa8fc845 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Wed, 24 Apr 2024 21:29:03 +0300 Subject: [PATCH 4/4] :zap: use get member endpoint instead of iterationg over guild members --- .../v2/actions/message/send.operation.ts | 21 +++++++++++-- .../nodes/Discord/v2/helpers/utils.ts | 31 ------------------- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts index 38968bd1887e2..7e761614a6928 100644 --- a/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts +++ b/packages/nodes-base/nodes/Discord/v2/actions/message/send.operation.ts @@ -4,7 +4,7 @@ import type { INodeExecutionData, INodeProperties, } from 'n8n-workflow'; -import { NodeOperationError } from 'n8n-workflow'; +import { NodeApiError, NodeOperationError } from 'n8n-workflow'; import { updateDisplayOptions } from '../../../../../utils/utilities'; import { discordApiMultiPartRequest, discordApiRequest } from '../../transport'; import { @@ -16,7 +16,6 @@ import { import { checkAccessToChannel, - checkIfUserGuildMember, parseDiscordError, prepareEmbeds, prepareErrorData, @@ -168,7 +167,23 @@ export async function execute( }) as string; if (isOAuth2) { - await checkIfUserGuildMember.call(this, guildId, userId, i); + try { + await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/members/${userId}`); + } catch (error) { + if (error instanceof NodeApiError && error.httpCode === '404') { + throw new NodeOperationError( + this.getNode(), + `User with the id ${userId} is not a member of the selected guild`, + { + itemIndex: i, + }, + ); + } + + throw new NodeOperationError(this.getNode(), error, { + itemIndex: i, + }); + } } channelId = ( diff --git a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts index 4d964f2ebb179..b3852f9527a4b 100644 --- a/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Discord/v2/helpers/utils.ts @@ -271,37 +271,6 @@ export async function checkAccessToChannel( checkAccessToGuild(this.getNode(), guildId, userGuilds, itemIndex); } -export async function checkIfUserGuildMember( - this: IExecuteFunctions, - guildId: string, - userId: string, - itemIndex = 0, -) { - let lastUserId; - let members; - - while (true) { - members = (await discordApiRequest.call(this, 'GET', `/guilds/${guildId}/members`, undefined, { - limit: 100, - after: lastUserId, - })) as Array<{ user: { id: string } }>; - - if (!members?.length) { - throw new NodeOperationError( - this.getNode(), - `User with the id ${userId} is not a member of the selected guild`, - { - itemIndex, - }, - ); - } else if (members.some((member) => member.user.id === userId)) { - break; - } else { - lastUserId = members[members.length - 1].user.id; - } - } -} - export async function setupChannelGetter(this: IExecuteFunctions, userGuilds: IDataObject[]) { const isOAuth2 = this.getNodeParameter('authentication', 0) === 'oAuth2';