From 140034ecbd49f8bc90d35d57e8a8092e862f3b45 Mon Sep 17 00:00:00 2001 From: Vyvy-vi Date: Fri, 27 May 2022 23:12:54 +0530 Subject: [PATCH 1/7] feat: announcement_summary file --- packages/discord-bot/src/utils/dmTargets.ts | 27 +++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/discord-bot/src/utils/dmTargets.ts b/packages/discord-bot/src/utils/dmTargets.ts index ac19b5102..4e741aa47 100644 --- a/packages/discord-bot/src/utils/dmTargets.ts +++ b/packages/discord-bot/src/utils/dmTargets.ts @@ -10,6 +10,7 @@ import { import { CommandInteraction } from 'discord.js'; import { PraiseModel } from 'api/dist/praise/entities'; +import { Buffer } from 'node:buffer'; const sendDMs = async ( interaction: CommandInteraction, @@ -32,11 +33,11 @@ const sendDMs = async ( try { const discordUser = await interaction.guild?.members.fetch(userId); if (!discordUser) { - failed.push(`<@!${userId}`); + failed.push(`<@!${userId}>`); continue; } await discordUser.send(message); - successful.push(`<@!${userId}>`); + successful.push(`${discordUser.user.tag}`); } catch (err) { failed.push(`<@!${userId}>`); } @@ -49,9 +50,31 @@ const sendDMs = async ( : failed.length === 0 ? successMsg : successMsg + '\n' + failedMsg; + + // TODO - Create a utility function to tabularise this data neatly + let summary = `User\t\t\t\tStatus\n`; + successful.forEach((username: string) => { + summary += `${username}${new String(' ').repeat( + 32 - username.length + )}Delivered\n`; + }); + failed.forEach((username: string) => { + summary += `${ + username.length <= 32 + ? username + new String(' ').repeat(24 - username.length) + : username.slice(0, 28) + '... ' + }Not Delivered\n`; + }); + await interaction.editReply({ content: content, components: [], + files: [ + { + attachment: Buffer.from(summary, 'utf8'), + name: 'announcement_summary.txt', + }, + ], }); }; From c621cca3c0eb56508bdd24225433cb9fb5a52413 Mon Sep 17 00:00:00 2001 From: Vyvy-vi Date: Wed, 8 Jun 2022 04:15:57 +0530 Subject: [PATCH 2/7] chore: format dmTargets.ts --- packages/discord-bot/src/utils/dmTargets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord-bot/src/utils/dmTargets.ts b/packages/discord-bot/src/utils/dmTargets.ts index 4e741aa47..511eac225 100644 --- a/packages/discord-bot/src/utils/dmTargets.ts +++ b/packages/discord-bot/src/utils/dmTargets.ts @@ -52,7 +52,7 @@ const sendDMs = async ( : successMsg + '\n' + failedMsg; // TODO - Create a utility function to tabularise this data neatly - let summary = `User\t\t\t\tStatus\n`; + let summary = 'User\t\t\t\tStatus\n'; successful.forEach((username: string) => { summary += `${username}${new String(' ').repeat( 32 - username.length From f36455ace829c068e288d64206be045a0401d502 Mon Sep 17 00:00:00 2001 From: Vyvy-vi Date: Fri, 10 Jun 2022 22:13:39 +0530 Subject: [PATCH 3/7] chore: remove unused imports --- packages/discord-bot/src/commands/forward.ts | 1 - packages/discord-bot/src/commands/praise.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/discord-bot/src/commands/forward.ts b/packages/discord-bot/src/commands/forward.ts index a98f5517c..2362912bd 100644 --- a/packages/discord-bot/src/commands/forward.ts +++ b/packages/discord-bot/src/commands/forward.ts @@ -1,5 +1,4 @@ import { SlashCommandBuilder } from '@discordjs/builders'; -import { APIMessage } from 'discord-api-types/v9'; import logger from 'jet-logger'; import { forwardHandler } from '../handlers/forward'; import { Command } from '../interfaces/Command'; diff --git a/packages/discord-bot/src/commands/praise.ts b/packages/discord-bot/src/commands/praise.ts index d69355ac8..3a6803355 100644 --- a/packages/discord-bot/src/commands/praise.ts +++ b/packages/discord-bot/src/commands/praise.ts @@ -1,5 +1,4 @@ import { SlashCommandBuilder } from '@discordjs/builders'; -import { APIMessage } from 'discord-api-types/v9'; import logger from 'jet-logger'; import { praiseHandler } from '../handlers/praise'; import { Command } from '../interfaces/Command'; From 3e777cc02a8ceb63d7218893e14695628ba91ad4 Mon Sep 17 00:00:00 2001 From: Vyvy-vi Date: Sat, 11 Jun 2022 01:01:58 +0530 Subject: [PATCH 4/7] feat: more detailed announce summary --- .../src/interfaces/FailedToDmUsersList.ts | 6 ++ packages/discord-bot/src/utils/dmTargets.ts | 93 ++++++++++++++++--- 2 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 packages/discord-bot/src/interfaces/FailedToDmUsersList.ts diff --git a/packages/discord-bot/src/interfaces/FailedToDmUsersList.ts b/packages/discord-bot/src/interfaces/FailedToDmUsersList.ts new file mode 100644 index 000000000..14af7809b --- /dev/null +++ b/packages/discord-bot/src/interfaces/FailedToDmUsersList.ts @@ -0,0 +1,6 @@ +export interface FailedToDmUsersList { + invalidUsers: string[]; + notFoundUsers: string[]; + closedDmUsers: string[]; + unknownErrorUsers: string[]; +} diff --git a/packages/discord-bot/src/utils/dmTargets.ts b/packages/discord-bot/src/utils/dmTargets.ts index 511eac225..4811faf66 100644 --- a/packages/discord-bot/src/utils/dmTargets.ts +++ b/packages/discord-bot/src/utils/dmTargets.ts @@ -7,8 +7,9 @@ import { PeriodDocument, PeriodDetailsQuantifierDto, } from 'api/dist/period/types'; +import { FailedToDmUsersList } from 'src/interfaces/FailedToDmUsersList'; -import { CommandInteraction } from 'discord.js'; +import { CommandInteraction, DiscordAPIError } from 'discord.js'; import { PraiseModel } from 'api/dist/praise/entities'; import { Buffer } from 'node:buffer'; @@ -18,7 +19,12 @@ const sendDMs = async ( message: string ): Promise => { const successful = []; - const failed = []; + const failed: FailedToDmUsersList = { + invalidUsers: [], + notFoundUsers: [], + closedDmUsers: [], + unknownErrorUsers: [], + }; if (!users || users.length === 0) { await interaction.editReply( 'Message not sent. No recipients matched filter.' @@ -30,40 +36,99 @@ const sendDMs = async ( user: user._id, }); const userId: string = userAccount?.accountId || 'oops'; + const userName: string = userAccount?.name || userId; try { const discordUser = await interaction.guild?.members.fetch(userId); if (!discordUser) { - failed.push(`<@!${userId}>`); + failed.notFoundUsers.push(userAccount?.name || userId); continue; } await discordUser.send(message); successful.push(`${discordUser.user.tag}`); } catch (err) { - failed.push(`<@!${userId}>`); + const error = err as Error; + if (error instanceof DiscordAPIError) { + /* The numbers used below are status codes from discord's API. + * (ref - https://discord.com/developers/docs/topics/opcodes-and-status-codes#json) + */ + const discordErrorCode = (err as DiscordAPIError).code; + switch (discordErrorCode) { + case 50035: + failed.invalidUsers.push(userName); + break; + case 50007: + failed.closedDmUsers.push(userName); + break; + default: + failed.unknownErrorUsers.push(userAccount?.name || userId); + break; + } + } else { + failed.unknownErrorUsers.push(userAccount?.name || userId); + } } } - const failedMsg = `Announcement could not be delivered to ${failed.length} users.`; + + const failedCount = + failed.invalidUsers.length + + failed.notFoundUsers.length + + failed.closedDmUsers.length + + failed.unknownErrorUsers.length; + const failedMsg = `Announcement could not be delivered to ${failedCount} users.`; const successMsg = `Announcement successfully delivered to ${successful.length} recipients.`; const content = successful.length === 0 ? failedMsg - : failed.length === 0 + : failedCount === 0 ? successMsg : successMsg + '\n' + failedMsg; // TODO - Create a utility function to tabularise this data neatly - let summary = 'User\t\t\t\tStatus\n'; + let summary = 'User\t\t\tStatus\t\tReason\n'; successful.forEach((username: string) => { - summary += `${username}${new String(' ').repeat( - 32 - username.length - )}Delivered\n`; + summary += `${ + username.length <= 24 + ? username + new String(' ').repeat(24 - username.length) + : username.slice(0, 21) + ' ' + }Delivered\t-\n${ + username.length > 24 ? username.slice(21, username.length) + '\n' : '' + }`; + }); + failed.invalidUsers.forEach((username: string) => { + summary += `${ + username.length <= 24 + ? username + new String(' ').repeat(24 - username.length) + : username.slice(0, 21) + ' ' + }Not Delivered\tInvalid User\n${ + username.length > 24 ? username.slice(21, username.length) + '\n' : '' + }`; + }); + failed.notFoundUsers.forEach((username: string) => { + summary += `${ + username.length <= 24 + ? username + new String(' ').repeat(24 - username.length) + : username.slice(0, 21) + ' ' + }Not Delivered\tUser Not Found In Discord\n${ + username.length > 24 ? username.slice(21, username.length) + '\n' : '' + }`; + }); + failed.closedDmUsers.forEach((username: string) => { + summary += `${ + username.length <= 24 + ? username + new String(' ').repeat(24 - username.length) + : username.slice(0, 21) + ' ' + }Not Delivered\tDMs closed\n${ + username.length > 24 ? username.slice(21, username.length) + '\n' : '' + }`; }); - failed.forEach((username: string) => { + failed.unknownErrorUsers.forEach((username: string) => { summary += `${ - username.length <= 32 + username.length <= 24 ? username + new String(' ').repeat(24 - username.length) - : username.slice(0, 28) + '... ' - }Not Delivered\n`; + : username.slice(0, 21) + ' ' + }Not Delivered\tUnknown Error\n${ + username.length > 24 ? username.slice(21, username.length) + '\n' : '' + }`; }); await interaction.editReply({ From cc088fb2086ae4f615ae99ed0c8181b9038bcbe4 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Wed, 15 Jun 2022 09:03:44 +0200 Subject: [PATCH 5/7] Replace "oops" with "Unknown user" --- packages/discord-bot/src/utils/dmTargets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord-bot/src/utils/dmTargets.ts b/packages/discord-bot/src/utils/dmTargets.ts index 4811faf66..3c8d46b4c 100644 --- a/packages/discord-bot/src/utils/dmTargets.ts +++ b/packages/discord-bot/src/utils/dmTargets.ts @@ -35,7 +35,7 @@ const sendDMs = async ( const userAccount = await UserAccountModel.findOne({ user: user._id, }); - const userId: string = userAccount?.accountId || 'oops'; + const userId: string = userAccount?.accountId || 'Unknown user'; const userName: string = userAccount?.name || userId; try { const discordUser = await interaction.guild?.members.fetch(userId); From 9700ad9f79b9463b684e9a1938d7432729ea1ef6 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Wed, 15 Jun 2022 09:26:41 +0200 Subject: [PATCH 6/7] =?UTF-8?q?Add=20message:=20"Sending=E2=80=A6"=20while?= =?UTF-8?q?=20waiting=20for=20operation=20to=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/discord-bot/src/handlers/announce.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/discord-bot/src/handlers/announce.ts b/packages/discord-bot/src/handlers/announce.ts index 9991ba3a9..80db3e155 100644 --- a/packages/discord-bot/src/handlers/announce.ts +++ b/packages/discord-bot/src/handlers/announce.ts @@ -107,6 +107,10 @@ export const announcementHandler: CommandHandler = async (interaction) => { break; } case 'continue': { + await interaction.editReply({ + content: 'Sending…', + components: [], + }); await selectTargets( interaction, selectedUserType, From 78e2b2ee0b8e2d60e897fc66a7089d85ff2d49cf Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Wed, 15 Jun 2022 09:28:22 +0200 Subject: [PATCH 7/7] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b3b405eb..c2306924a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Option to turn on/off the Discord role requirement for Praise givers #419 #434 #440 - Support multiple wallets: WalletConneect, Trust, Rainbow etc #424 +- More verbose output from the `/admin announce` command #317 #441 ### Fixed