Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context menu button, Ban Spammer #548

Open
wants to merge 71 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
f41f9c5
Create context button
Mclilzee Jun 5, 2024
979c3d9
Fix calling wrong service
Mclilzee Jun 5, 2024
7f676a5
Refactor naming
Mclilzee Jun 5, 2024
437c2c2
Update logic to spammer-banning service
Mclilzee Jun 5, 2024
9fd096f
Reformat message to contain new line
Mclilzee Jun 6, 2024
abba810
Fix contact email
Mclilzee Jun 6, 2024
b9abfe5
Reverse to send message directly
Mclilzee Jun 6, 2024
2f14d87
Fix message sending issue
Mclilzee Jun 6, 2024
adc4216
Update structure of calls
Mclilzee Jun 6, 2024
6ba618b
Add announcing user banning and failure
Mclilzee Jun 6, 2024
d87a0ef
Refactor
Mclilzee Jun 6, 2024
af62905
Update sending error to stderr channel
Mclilzee Jun 6, 2024
d1aab86
Refactor modules
Mclilzee Jun 6, 2024
1df4b9c
Add tests
Mclilzee Jun 6, 2024
95642d4
Update tests and use snapshot
Mclilzee Jun 6, 2024
6fb440a
Finalize first full test
Mclilzee Jun 6, 2024
d67ab6f
Add second test for users that isn't able to recieve messages
Mclilzee Jun 6, 2024
0615b95
Add test for user that is not on the server anymore
Mclilzee Jun 6, 2024
5ff7903
Add function to announce the ban
Mclilzee Jun 7, 2024
4ec49fa
Refactor naming
Mclilzee Jun 9, 2024
f14c8df
Update tests
Mclilzee Jun 9, 2024
d9f4187
Refactor seperate tests
Mclilzee Jun 9, 2024
72fa7eb
Refactor testing to seperate ideas
Mclilzee Jun 9, 2024
ef50d97
Add reaction testing
Mclilzee Jun 9, 2024
97a3d07
Update snapshot
Mclilzee Jun 9, 2024
2e167a3
Add testing channel sending
Mclilzee Jun 9, 2024
ee45097
Refactor fix issue with snapshots
Mclilzee Jun 9, 2024
f6344b4
Add tests to users who has left the server
Mclilzee Jun 10, 2024
9650107
Update logic
Mclilzee Jun 10, 2024
aa0dc04
Update testing to test number of calls
Mclilzee Jun 10, 2024
e08b268
Refactor to use creation mocks
Mclilzee Jun 11, 2024
c5015f6
Fix tests mocks
Mclilzee Jun 11, 2024
06527f4
Fix second test suite
Mclilzee Jun 11, 2024
0caaee9
Finish up third test suite
Mclilzee Jun 11, 2024
1d3adc8
Refactor to test specifically for channel id arguments
Mclilzee Jun 11, 2024
7b55f46
Add tests against banning a bot
Mclilzee Jun 11, 2024
25e4db3
Add tests for banning a bot
Mclilzee Jun 11, 2024
5d1d4fe
Refactor test repitition
Mclilzee Jun 11, 2024
8627404
Add logic to prevent banning an admin
Mclilzee Jun 11, 2024
805b4b1
Refactor and add other team members tests
Mclilzee Jun 11, 2024
86ec115
Fix bug of retrieving user role name without using the name field
Mclilzee Jun 11, 2024
504519d
Update logging message
Mclilzee Jun 12, 2024
82db911
Refactor interaction reply to be emphernal
Mclilzee Jun 13, 2024
9c0d2c6
Fix mock time to not fail tests that require timestamp snapshot
Mclilzee Jun 13, 2024
a5d0798
Fix comment typo
Mclilzee Jun 13, 2024
bd23a75
Add mod log channel id to log
Mclilzee Jun 13, 2024
1a2b15b
Update permission to mods with ability to ban only
Mclilzee Jun 13, 2024
b4567dd
Fix tests for core members
Mclilzee Jun 13, 2024
c1a34fa
Update to use user ID
Mclilzee Aug 5, 2024
00a5263
Update tests
Mclilzee Aug 5, 2024
f75bf98
Update channel id name
Mclilzee Aug 5, 2024
3bea73d
Refactor channel name id in tests
Mclilzee Aug 5, 2024
f6f11dd
Update user message
Mclilzee Aug 5, 2024
a4a2d0e
Update channel id name
Mclilzee Aug 5, 2024
bb6d4e2
Update tests
Mclilzee Aug 5, 2024
3f88707
Update date object to work with github cli test tools
Mclilzee Aug 5, 2024
b8a415e
Update to use fetch method on getting the channel
Mclilzee Aug 5, 2024
bf38ad3
Update to handle fetch promise
Mclilzee Aug 5, 2024
2c8fa34
Add handling error when channel is not found
Mclilzee Aug 5, 2024
b35b524
Remove mailto link in contact user message
Mclilzee Aug 5, 2024
6f8a323
Send user message to enable embed links
Mclilzee Aug 6, 2024
c6fcd00
Update message to include new mod email
Mclilzee Aug 8, 2024
d3ecdb8
Update test snippets
Mclilzee Aug 8, 2024
7cb62f8
Remove duplicated key
Mclilzee Aug 8, 2024
fbf17a2
Run prettier
Mclilzee Aug 8, 2024
1c1f795
Use new isAdmin util function
Mclilzee Aug 8, 2024
dfad9d9
Apply suggestions from code review
Mclilzee Aug 8, 2024
6f87b8f
Update ban message with appeal template
Mclilzee Aug 10, 2024
4877b72
Refactor sentence structure
Mclilzee Aug 10, 2024
ccc7030
Update test snippets to reflect newest changes
Mclilzee Aug 10, 2024
f319ac5
Update filename
Mclilzee Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const config = {
WSLChannelId: '1179839248803844117',
ContactModeratorsChannelId: '1059513837197459547',
rulesChannelId: '693244715839127653',
moderationLogChannelId: '922520585018433536'
},
roles: {
NOBOTRoleId: '783764176178774036',
Expand Down
12 changes: 12 additions & 0 deletions new-era-commands/context-menu/ban-spammer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, PermissionFlagsBits, } = require("discord.js");
const SpamBanningService = require("../../services/spam-ban/spam-banning.service");

module.exports = {
data: new ContextMenuCommandBuilder()
.setName("Ban Spammer")
.setType(ApplicationCommandType.Message)
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers),
execute: async (interaction) => {
await SpamBanningService.handleInteraction(interaction);
},
};
202 changes: 202 additions & 0 deletions services/spam-ban/__snapshots__/spam-banning.service.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Attempting to ban a bot or team member Does not ban admins 1`] = `
{
"content": "You do not have the permission to ban this user",
"ephemeral": true,
}
`;

exports[`Attempting to ban a bot or team member Does not ban bots 1`] = `
{
"content": "You do not have the permission to ban this user",
"ephemeral": true,
}
`;

exports[`Attempting to ban a bot or team member Does not ban core 1`] = `
{
"content": "You do not have the permission to ban this user",
"ephemeral": true,
}
`;

exports[`Attempting to ban a bot or team member Does not ban maintainers 1`] = `
{
"content": "You do not have the permission to ban this user",
"ephemeral": true,
}
`;

exports[`Attempting to ban a bot or team member Does not ban moderators 1`] = `
{
"content": "You do not have the permission to ban this user",
"ephemeral": true,
}
`;

exports[`Attempting to log banned user in moderation log channel Sends log to the correct channel 1`] = `
{
"embeds": [
{
"author": {
"icon_url": "image.jpg",
"name": "Ban | bad.spammer",
},
"color": 15747399,
"fields": [
{
"inline": true,
"name": "User",
"value": "<@123>",
},
{
"inline": true,
"name": "Moderator",
"value": "<@007>",
},
{
"inline": true,
"name": "Reason",
"value": "Account is compromised and spamming phishing links.",
},
],
"footer": {
"text": "ID: 123",
},
"timestamp": "2024-02-01T00:00:00.000Z",
},
],
}
`;

exports[`Banning spammer that has left the server Reacts with the correct emoji to automod message 1`] = `"❌"`;

exports[`Banning spammer that has left the server Sends back correct interaction reply to calling moderator 1`] = `
{
"content": "Couldn't ban <@123>. User is not on the server.",
"ephemeral": true,
}
`;

exports[`Banning spammer who has DM set to private Discord ban api is called with the correct reason 1`] = `
{
"reason": "Account is compromised",
}
`;

exports[`Banning spammer who has DM set to private Reacts with the correct emoji 1`] = `"✅"`;

exports[`Banning spammer who has DM set to private Sends back correct interaction reply to calling moderator 1`] = `
{
"content": "Banned <@123> for spam but wasn't able to contact the user.",
"ephemeral": true,
}
`;

exports[`Banning spammer who has DM set to private Sends log to the correct channel 1`] = `
{
"embeds": [
{
"author": {
"icon_url": "image.jpg",
"name": "Ban | bad.spammer",
},
"color": 15747399,
"fields": [
{
"inline": true,
"name": "User",
"value": "<@123>",
},
{
"inline": true,
"name": "Moderator",
"value": "<@007>",
},
{
"inline": true,
"name": "Reason",
"value": "Account is compromised and spamming phishing links.",
},
],
"footer": {
"text": "ID: 123",
},
"timestamp": "2024-02-01T00:00:00.000Z",
},
],
}
`;

exports[`Banning spammer with DM enabled Discord ban api is called with the correct reason 1`] = `
{
"reason": "Account is compromised",
}
`;

exports[`Banning spammer with DM enabled Discord message api is called with the correct message 1`] = `
{
"content": "Your account has been banned. Please enable embeds in Discord settings if you cannot see the message below.",
"embeds": [
{
"description": "Your account has been banned from The Odin Project Discord server for sending spam. If this account is compromised, please follow the steps linked in this [Discord support article about securing your account](https://support.discord.com/hc/en-us/articles/24160905919511-My-Discord-Account-was-Hacked-or-Compromised).

Once your account is secure, you may appeal your ban by emailing \`[email protected]\` with the following template:

- Banned username:
- Reason for ban:
- Date of ban:
- Steps taken to secure my account:
- Additional comments (optional):

Please note that it may take at least several days for our volunteer staff to process your request.",
"title": "Banned: Compromised account / Spam",
},
],
}
`;

exports[`Banning spammer with DM enabled Reacts with the correct emoji 1`] = `"✅"`;

exports[`Banning spammer with DM enabled Sends back correct interaction reply to calling moderator 1`] = `
{
"content": "Successfully banned <@123> for spam.",
"ephemeral": true,
}
`;

exports[`Banning spammer with DM enabled Sends log to the correct channel 1`] = `
{
"embeds": [
{
"author": {
"icon_url": "image.jpg",
"name": "Ban | bad.spammer",
},
"color": 15747399,
"fields": [
{
"inline": true,
"name": "User",
"value": "<@123>",
},
{
"inline": true,
"name": "Moderator",
"value": "<@007>",
},
{
"inline": true,
"name": "Reason",
"value": "Account is compromised and spamming phishing links.",
},
],
"footer": {
"text": "ID: 123",
},
"timestamp": "2024-02-01T00:00:00.000Z",
},
],
}
`;
3 changes: 3 additions & 0 deletions services/spam-ban/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const SpamBanningService = require('./spam-banning.service');

module.exports = SpamBanningService;
111 changes: 111 additions & 0 deletions services/spam-ban/spam-banning.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const { EmbedBuilder } = require('discord.js');
const { isAdmin } = require('../../utils/is-admin');
const config = require('../../config');

class SpamBanningService {
static async handleInteraction(interaction) {
const message = interaction.options.getMessage('message');
if (message.author.bot || isAdmin(message.member)) {
interaction.reply({
content: 'You do not have the permission to ban this user',
ephemeral: true,
});
return;
}

try {
let reply;

if (!message.member) {
message.react('❌');
reply = `Couldn't ban <@${message.author.id}>. User is not on the server.`;
} else {
reply = await SpamBanningService.#banUser(message);
await SpamBanningService.#announceBan(interaction, message);
}

interaction.reply({ content: reply, ephemeral: true });
} catch (error) {
console.error(error);
}
}

static async #banUser(message) {
let reply = `Successfully banned <@${message.author.id}> for spam.`;
try {
// Make sure to send the message before banning otherwise user will not be found
await SpamBanningService.#sendMessageToUser(message.author);
} catch (error) {
reply = `Banned <@${message.author.id}> for spam but wasn't able to contact the user.`;
}

message.member.ban({ reason: 'Account is compromised' });
message.react('✅');
return reply;
}

static async #sendMessageToUser(author) {
const embedMessage = new EmbedBuilder()
.setTitle('Banned: Compromised account / Spam')
.setDescription(
`Your account has been banned from The Odin Project Discord server for sending spam. If this account is compromised, please follow the steps linked in this [Discord support article about securing your account](https://support.discord.com/hc/en-us/articles/24160905919511-My-Discord-Account-was-Hacked-or-Compromised).

Once your account is secure, you may appeal your ban by emailing \`[email protected]\` with the following template:

- Banned username:
- Reason for ban:
- Date of ban:
- Steps taken to secure my account:
- Additional comments (optional):

Please note that it may take at least several days for our volunteer staff to process your request.`,
);

await author.send({
content:
'Your account has been banned. Please enable embeds in Discord settings if you cannot see the message below.',
embeds: [embedMessage],
});
}

static async #announceBan(interaction, message) {
const channelID = config.channels.moderationLogChannelId;
const channel = await interaction.guild.channels.fetch(channelID);
if (channel == null) {
throw new Error(`No channel with the ID ${channelID} was found.`);
}

const embed = {
timestamp: `${new Date().toISOString()}`,
color: 15747399,
footer: {
text: `ID: ${message.author.id}`,
},
author: {
name: `Ban | ${message.author.username}`,
icon_url: `${message.author.displayAvatarURL()}`,
},
fields: [
{
value: `<@${message.author.id}>`,
name: 'User',
inline: true,
},
{
value: `<@${interaction.user.id}>`,
name: 'Moderator',
inline: true,
},
{
value: 'Account is compromised and spamming phishing links.',
name: 'Reason',
inline: true,
},
],
};

channel.send({ embeds: [embed] });
}
}

module.exports = SpamBanningService;
Loading