Skip to content

Commit

Permalink
Merge pull request #441 from commons-stack/feat/317/verbose-announce-…
Browse files Browse the repository at this point in the history
…summary

Feat/317/verbose /admin announce summary
  • Loading branch information
kristoferlund authored Jun 15, 2022
2 parents 7a0f5fe + 78e2b2e commit e9e2b2a
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion packages/discord-bot/src/commands/forward.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
1 change: 0 additions & 1 deletion packages/discord-bot/src/commands/praise.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
4 changes: 4 additions & 0 deletions packages/discord-bot/src/handlers/announce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export const announcementHandler: CommandHandler = async (interaction) => {
break;
}
case 'continue': {
await interaction.editReply({
content: 'Sending…',
components: [],
});
await selectTargets(
interaction,
selectedUserType,
Expand Down
6 changes: 6 additions & 0 deletions packages/discord-bot/src/interfaces/FailedToDmUsersList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface FailedToDmUsersList {
invalidUsers: string[];
notFoundUsers: string[];
closedDmUsers: string[];
unknownErrorUsers: string[];
}
104 changes: 96 additions & 8 deletions packages/discord-bot/src/utils/dmTargets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@ 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';

const sendDMs = async (
interaction: CommandInteraction,
users: UserDocument[] | PeriodDetailsQuantifierDto[],
message: string
): Promise<void> => {
const successful = [];
const failed = [];
const failed: FailedToDmUsersList = {
invalidUsers: <string[]>[],
notFoundUsers: <string[]>[],
closedDmUsers: <string[]>[],
unknownErrorUsers: <string[]>[],
};
if (!users || users.length === 0) {
await interaction.editReply(
'Message not sent. No recipients matched filter.'
Expand All @@ -28,30 +35,111 @@ 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);
if (!discordUser) {
failed.push(`<@!${userId}`);
failed.notFoundUsers.push(userAccount?.name || userId);
continue;
}
await discordUser.send(message);
successful.push(`<@!${userId}>`);
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\tStatus\t\tReason\n';
successful.forEach((username: string) => {
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.unknownErrorUsers.forEach((username: string) => {
summary += `${
username.length <= 24
? username + new String(' ').repeat(24 - username.length)
: username.slice(0, 21) + ' '
}Not Delivered\tUnknown Error\n${
username.length > 24 ? username.slice(21, username.length) + '\n' : ''
}`;
});

await interaction.editReply({
content: content,
components: [],
files: [
{
attachment: Buffer.from(summary, 'utf8'),
name: 'announcement_summary.txt',
},
],
});
};

Expand Down

0 comments on commit e9e2b2a

Please sign in to comment.