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 70 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
8ec607b
Create context button
Mclilzee Jun 5, 2024
bc93656
Fix calling wrong service
Mclilzee Jun 5, 2024
df980ad
Refactor naming
Mclilzee Jun 5, 2024
e8664f0
Update logic to spammer-banning service
Mclilzee Jun 5, 2024
765abce
Reformat message to contain new line
Mclilzee Jun 6, 2024
3615580
Fix contact email
Mclilzee Jun 6, 2024
e693636
Reverse to send message directly
Mclilzee Jun 6, 2024
9b351cf
Fix message sending issue
Mclilzee Jun 6, 2024
2928b70
Update structure of calls
Mclilzee Jun 6, 2024
818c395
Add announcing user banning and failure
Mclilzee Jun 6, 2024
0384dcf
Refactor
Mclilzee Jun 6, 2024
9c9a895
Update sending error to stderr channel
Mclilzee Jun 6, 2024
21dafe4
Refactor modules
Mclilzee Jun 6, 2024
c1508f3
Add tests
Mclilzee Jun 6, 2024
75cb035
Update tests and use snapshot
Mclilzee Jun 6, 2024
310f677
Finalize first full test
Mclilzee Jun 6, 2024
680184f
Add second test for users that isn't able to recieve messages
Mclilzee Jun 6, 2024
1f748a9
Add test for user that is not on the server anymore
Mclilzee Jun 6, 2024
133c0e8
Add function to announce the ban
Mclilzee Jun 7, 2024
282e02f
Refactor naming
Mclilzee Jun 9, 2024
94ddcb9
Update tests
Mclilzee Jun 9, 2024
349be4a
Refactor seperate tests
Mclilzee Jun 9, 2024
cad7b18
Refactor testing to seperate ideas
Mclilzee Jun 9, 2024
9afb67f
Add reaction testing
Mclilzee Jun 9, 2024
2c82062
Update snapshot
Mclilzee Jun 9, 2024
a0dcf98
Add testing channel sending
Mclilzee Jun 9, 2024
233b998
Refactor fix issue with snapshots
Mclilzee Jun 9, 2024
beda9d5
Add tests to users who has left the server
Mclilzee Jun 10, 2024
caf9b75
Update logic
Mclilzee Jun 10, 2024
4b7a513
Update testing to test number of calls
Mclilzee Jun 10, 2024
e1df63b
Refactor to use creation mocks
Mclilzee Jun 11, 2024
d9474c0
Fix tests mocks
Mclilzee Jun 11, 2024
91c444a
Fix second test suite
Mclilzee Jun 11, 2024
1652dcf
Finish up third test suite
Mclilzee Jun 11, 2024
26b5e4e
Refactor to test specifically for channel id arguments
Mclilzee Jun 11, 2024
57d9902
Add tests against banning a bot
Mclilzee Jun 11, 2024
8771039
Add tests for banning a bot
Mclilzee Jun 11, 2024
f6f1b49
Refactor test repitition
Mclilzee Jun 11, 2024
cfca7b4
Add logic to prevent banning an admin
Mclilzee Jun 11, 2024
0f24ae0
Refactor and add other team members tests
Mclilzee Jun 11, 2024
c080030
Fix bug of retrieving user role name without using the name field
Mclilzee Jun 11, 2024
e0e2ee1
Update logging message
Mclilzee Jun 12, 2024
90c52c8
Refactor interaction reply to be emphernal
Mclilzee Jun 13, 2024
55d3b40
Fix mock time to not fail tests that require timestamp snapshot
Mclilzee Jun 13, 2024
11a660b
Fix comment typo
Mclilzee Jun 13, 2024
84e08dd
Update permission to mods with ability to ban only
Mclilzee Jun 13, 2024
7b06e7e
Fix tests for core members
Mclilzee Jun 13, 2024
a783143
Update to use user ID
Mclilzee Aug 5, 2024
6b37c9b
Update tests
Mclilzee Aug 5, 2024
4c3d730
Update channel id name
Mclilzee Aug 5, 2024
def4298
Refactor channel name id in tests
Mclilzee Aug 5, 2024
844d413
Update user message
Mclilzee Aug 5, 2024
7f47a61
Update channel id name
Mclilzee Aug 5, 2024
0621b11
Update tests
Mclilzee Aug 5, 2024
47e7f75
Update date object to work with github cli test tools
Mclilzee Aug 5, 2024
d13b274
Update to use fetch method on getting the channel
Mclilzee Aug 5, 2024
5db3444
Update to handle fetch promise
Mclilzee Aug 5, 2024
dfc53bc
Add handling error when channel is not found
Mclilzee Aug 5, 2024
584817e
Remove mailto link in contact user message
Mclilzee Aug 5, 2024
5549d23
Send user message to enable embed links
Mclilzee Aug 6, 2024
aaa4316
Update message to include new mod email
Mclilzee Aug 8, 2024
38349b1
Update test snippets
Mclilzee Aug 8, 2024
f12cc80
Run prettier
Mclilzee Aug 8, 2024
62b5a60
Use new isAdmin util function
Mclilzee Aug 8, 2024
bda809c
Apply suggestions from code review
Mclilzee Aug 8, 2024
df4c760
Update ban message with appeal template
Mclilzee Aug 10, 2024
2bd8cff
Refactor sentence structure
Mclilzee Aug 10, 2024
c61ac3d
Update test snippets to reflect newest changes
Mclilzee Aug 10, 2024
c7f63ec
Update filename
Mclilzee Aug 12, 2024
c6e0692
Format for linting
Mclilzee Dec 1, 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
16 changes: 16 additions & 0 deletions new-era-commands/context-menu/ban-spammer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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');
Comment on lines +6 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming we'll be calling this command only inside the automod channel. We'll add this condition in our discord server's setting. Though a sanity check here won't hurt. Can we add a guard here to check if this command is only called in that channel?

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this channel id in the config file?

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
Loading