Skip to content

Commit 5151cf7

Browse files
Add the /mute, /unmute, and /mute-role commands
1 parent 921172c commit 5151cf7

6 files changed

Lines changed: 241 additions & 25 deletions

File tree

src/main/java/technobot/commands/CommandRegistry.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ public CommandRegistry(TechnoBot bot) {
9898
new UnlockCommand(bot),
9999
new RoleCommand(bot),
100100
new SetNickCommand(bot),
101+
new MuteCommand(bot),
102+
new UnMuteCommand(bot),
103+
new MuteRoleCommand(bot),
101104

102105
//Music commands
103106
new PlayCommand(bot),

src/main/java/technobot/commands/staff/MuteCommand.java

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
import technobot.TechnoBot;
1313
import technobot.commands.Category;
1414
import technobot.commands.Command;
15+
import technobot.data.GuildData;
1516
import technobot.util.CommandUtils;
1617
import technobot.util.embeds.EmbedColor;
1718
import technobot.util.embeds.EmbedUtils;
1819

19-
import java.util.Date;
20-
2120
/**
2221
* Command that adds a muted role to a user in the guild.
2322
*
@@ -28,10 +27,10 @@ public class MuteCommand extends Command {
2827
public MuteCommand(TechnoBot bot) {
2928
super(bot);
3029
this.name = "mute";
31-
this.description = "Kicks a user from your server.";
30+
this.description = "Mutes a user in your server.";
3231
this.category = Category.STAFF;
33-
this.args.add(new OptionData(OptionType.USER, "user", "The user to kick", true));
34-
this.args.add(new OptionData(OptionType.STRING, "reason", "Reason for the kick"));
32+
this.args.add(new OptionData(OptionType.USER, "user", "The user to mute", true));
33+
this.args.add(new OptionData(OptionType.STRING, "reason", "Reason for the mute"));
3534
this.permission = Permission.MANAGE_ROLES;
3635
}
3736

@@ -45,46 +44,47 @@ public void execute(SlashCommandInteractionEvent event) {
4544
event.getHook().sendMessageEmbeds(EmbedUtils.createError("That user is not in this server!")).queue();
4645
return;
4746
} else if (target.getIdLong() == event.getJDA().getSelfUser().getIdLong()) {
48-
event.getHook().sendMessageEmbeds(EmbedUtils.createError("Do you seriously expect me to kick myself?")).queue();
47+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("Do you seriously expect me to mute myself?")).queue();
4948
return;
5049
}
5150
OptionMapping reasonOption = event.getOption("reason");
5251
String reason = reasonOption != null ? reasonOption.getAsString() : "Unspecified";
5352

53+
// Check that muted role is valid and not already added to user
54+
Role muteRole = GuildData.get(event.getGuild()).moderationHandler.getMuteRole();
55+
if (muteRole == null) {
56+
String text = "This server does not have a mute role, use `/mute-role <role>` to set one or `/mute-role create [name]` to create one.";
57+
event.getHook().sendMessageEmbeds(EmbedUtils.createError(text)).queue();
58+
return;
59+
}
60+
if (target.getRoles().contains(muteRole)) {
61+
String text = "That user is already muted!";
62+
event.getHook().sendMessageEmbeds(EmbedUtils.createError(text)).queue();
63+
return;
64+
}
65+
5466
// Check that bot has necessary permissions
5567
Role botRole = event.getGuild().getBotRole();
56-
if (!CommandUtils.hasPermission(botRole, this.permission) || target.isOwner()) {
57-
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't kick that user. Please check my permissions and role position.")).queue();
68+
int botPos = botRole.getPosition();
69+
if (!CommandUtils.hasPermission(botRole, this.permission) || target.isOwner() || muteRole.getPosition() >= botPos) {
70+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't mute that user. Please check my permissions and role position.")).queue();
5871
return;
5972
}
6073

6174
// Check if bot has a higher role than user
62-
int botPos = botRole.getPosition();
6375
for (Role role : target.getRoles()) {
6476
if (role.getPosition() >= botPos) {
65-
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't kick that user. Please check my permissions and role position.")).queue();
77+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't mute that user. Please check my permissions and role position.")).queue();
6678
return;
6779
}
6880
}
6981

70-
// Kick user from guild
71-
user.openPrivateChannel().queue(privateChannel -> {
72-
// Private message user with reason for kick
73-
EmbedBuilder embed = new EmbedBuilder()
74-
.setColor(EmbedColor.ERROR.color)
75-
.setTitle(EmbedUtils.RED_X + " You were kicked!")
76-
.addField("Server", event.getGuild().getName(), false)
77-
.addField("Reason", reason, false)
78-
.setTimestamp(new Date().toInstant());
79-
privateChannel.sendMessageEmbeds(embed.build()).queue(
80-
message -> target.kick(reason).queue(),
81-
failure -> target.kick(reason).queue()
82-
);
83-
}, fail -> target.kick(reason).queue());
82+
// Add muted role to user
83+
event.getGuild().addRoleToMember(target, muteRole).queue();
8484

8585
// Send confirmation message
8686
event.getHook().sendMessageEmbeds(new EmbedBuilder()
87-
.setAuthor(user.getAsTag() + " has been kicked", null, user.getEffectiveAvatarUrl())
87+
.setAuthor(user.getAsTag() + " has been muted", null, user.getEffectiveAvatarUrl())
8888
.setDescription("**Reason:** " + reason)
8989
.setColor(EmbedColor.DEFAULT.color)
9090
.build()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package technobot.commands.staff;
2+
3+
import net.dv8tion.jda.api.Permission;;
4+
import net.dv8tion.jda.api.entities.Guild;
5+
import net.dv8tion.jda.api.entities.GuildChannel;
6+
import net.dv8tion.jda.api.entities.Role;
7+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
8+
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
9+
import net.dv8tion.jda.api.interactions.commands.OptionType;
10+
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
11+
import net.dv8tion.jda.api.requests.restaction.RoleAction;
12+
import technobot.TechnoBot;
13+
import technobot.commands.Category;
14+
import technobot.commands.Command;
15+
import technobot.data.GuildData;
16+
import technobot.util.embeds.EmbedColor;
17+
import technobot.util.embeds.EmbedUtils;
18+
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.List;
22+
23+
/**
24+
* Command that sets/creates the mute role to give on /mute.
25+
*
26+
* @author TechnoVision
27+
*/
28+
public class MuteRoleCommand extends Command {
29+
30+
public MuteRoleCommand(TechnoBot bot) {
31+
super(bot);
32+
this.name = "mute-role";
33+
this.description = "Create or set a mute role for the server.";
34+
this.category = Category.STAFF;
35+
this.permission = Permission.MANAGE_SERVER;
36+
this.subCommands.add(new SubcommandData("set", "Set an existing role as the mute role.")
37+
.addOption(OptionType.ROLE, "role", "The role to set as the mute role", true));
38+
this.subCommands.add(new SubcommandData("create", "Create a mute role for this server.")
39+
.addOption(OptionType.STRING, "name", "Name for the mute role"));
40+
}
41+
42+
@Override
43+
public void execute(SlashCommandInteractionEvent event) {
44+
event.deferReply().queue();
45+
Guild guild = event.getGuild();
46+
GuildData data = GuildData.get(guild);
47+
48+
// Check for admin permissions
49+
Role botRole = event.getGuild().getBotRole();
50+
if (!botRole.hasPermission(Permission.ADMINISTRATOR)) {
51+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I am unable to create roles. Please check my permissions and role position.")).queue();
52+
return;
53+
}
54+
55+
switch(event.getSubcommandName()) {
56+
case "set" -> {
57+
// Set existing role as the mute role
58+
Role role = event.getOption("role").getAsRole();
59+
data.moderationHandler.setMuteRole(role.getIdLong());
60+
String text = EmbedUtils.BLUE_TICK + " The "+role.getAsMention()+" role will be used for the `mute` command.";
61+
event.getHook().sendMessageEmbeds(EmbedUtils.createDefault(text)).queue();
62+
}
63+
case "create" -> {
64+
// Create new role
65+
RoleAction action = guild.createRole().setColor(EmbedColor.ERROR.color).setPermissions(new ArrayList<>());
66+
OptionMapping nameOption = event.getOption("name");
67+
if (nameOption != null) action = action.setName(nameOption.getAsString());
68+
else action = action.setName("Muted");
69+
70+
action.queue(role -> {
71+
// Create list of denied perms
72+
List<Permission> denyPerms = Arrays.asList(
73+
Permission.MESSAGE_SEND,
74+
Permission.MESSAGE_ADD_REACTION,
75+
Permission.MESSAGE_SEND_IN_THREADS,
76+
Permission.CREATE_PUBLIC_THREADS,
77+
Permission.CREATE_PRIVATE_THREADS
78+
);
79+
// Apply overwrites to channels
80+
long roleID = role.getIdLong();
81+
for (GuildChannel channel : guild.getChannels()) {
82+
channel.getPermissionContainer().getManager().putRolePermissionOverride(roleID, null, denyPerms).queue();
83+
}
84+
data.moderationHandler.setMuteRole(roleID);
85+
String text = EmbedUtils.BLUE_TICK + " The "+role.getAsMention()+" role will be used for the `mute` command.";
86+
event.getHook().sendMessageEmbeds(EmbedUtils.createDefault(text)).queue();
87+
});
88+
}
89+
}
90+
}
91+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package technobot.commands.staff;
2+
3+
import net.dv8tion.jda.api.EmbedBuilder;
4+
import net.dv8tion.jda.api.Permission;
5+
import net.dv8tion.jda.api.entities.Member;
6+
import net.dv8tion.jda.api.entities.Role;
7+
import net.dv8tion.jda.api.entities.User;
8+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
9+
import net.dv8tion.jda.api.interactions.commands.OptionType;
10+
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
11+
import technobot.TechnoBot;
12+
import technobot.commands.Category;
13+
import technobot.commands.Command;
14+
import technobot.data.GuildData;
15+
import technobot.util.CommandUtils;
16+
import technobot.util.embeds.EmbedColor;
17+
import technobot.util.embeds.EmbedUtils;
18+
19+
/**
20+
* Command that removes a muted role from a user in the guild.
21+
*
22+
* @author TechnoVision
23+
*/
24+
public class UnMuteCommand extends Command {
25+
26+
public UnMuteCommand(TechnoBot bot) {
27+
super(bot);
28+
this.name = "unmute";
29+
this.description = "Unmutes a user in your server.";
30+
this.category = Category.STAFF;
31+
this.args.add(new OptionData(OptionType.USER, "user", "The user to unmute", true));
32+
this.permission = Permission.MANAGE_ROLES;
33+
}
34+
35+
@Override
36+
public void execute(SlashCommandInteractionEvent event) {
37+
event.deferReply().queue();
38+
// Get command and member data
39+
User user = event.getOption("user").getAsUser();
40+
Member target = event.getOption("user").getAsMember();
41+
if (target == null) {
42+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("That user is not in this server!")).queue();
43+
return;
44+
} else if (target.getIdLong() == event.getJDA().getSelfUser().getIdLong()) {
45+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("Do you seriously expect me to unmute myself?")).queue();
46+
return;
47+
}
48+
49+
// Check that muted role is valid and user has it
50+
Role muteRole = GuildData.get(event.getGuild()).moderationHandler.getMuteRole();
51+
if (muteRole == null) {
52+
String text = "This server does not have a mute role, use `/mute-role <role>` to set one or `/mute-role create [name]` to create one.";
53+
event.getHook().sendMessageEmbeds(EmbedUtils.createError(text)).queue();
54+
return;
55+
}
56+
if (!target.getRoles().contains(muteRole)) {
57+
String text = "That user is not muted!";
58+
event.getHook().sendMessageEmbeds(EmbedUtils.createError(text)).queue();
59+
return;
60+
}
61+
62+
// Check that bot has necessary permissions
63+
Role botRole = event.getGuild().getBotRole();
64+
int botPos = botRole.getPosition();
65+
if (!CommandUtils.hasPermission(botRole, this.permission) || target.isOwner() || muteRole.getPosition() >= botPos) {
66+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't unmute that user. Please check my permissions and role position.")).queue();
67+
return;
68+
}
69+
70+
// Check if bot has a higher role than user
71+
for (Role role : target.getRoles()) {
72+
if (role.getPosition() >= botPos) {
73+
event.getHook().sendMessageEmbeds(EmbedUtils.createError("I couldn't unmute that user. Please check my permissions and role position.")).queue();
74+
return;
75+
}
76+
}
77+
78+
// Remove muted role to user
79+
event.getGuild().removeRoleFromMember(target, muteRole).queue();
80+
81+
// Send confirmation message
82+
event.getHook().sendMessageEmbeds(new EmbedBuilder()
83+
.setAuthor(user.getAsTag() + " is now unmuted", null, user.getEffectiveAvatarUrl())
84+
.setColor(EmbedColor.DEFAULT.color)
85+
.build()
86+
).queue();
87+
}
88+
}

src/main/java/technobot/data/cache/moderation/Moderation.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package technobot.data.cache.moderation;
22

33
import kotlin.Pair;
4+
import org.bson.codecs.pojo.annotations.BsonProperty;
45

56
import java.util.ArrayList;
67
import java.util.HashMap;
@@ -17,6 +18,8 @@ public class Moderation {
1718
private long guild;
1819
private int total;
1920
private int count;
21+
@BsonProperty("mute_role")
22+
private Long muteRole;
2023
private HashMap<String, Ban> bans;
2124
private HashMap<String, List<Warning>> warnings;
2225

@@ -131,6 +134,14 @@ public void setCount(int count) {
131134
this.count = count;
132135
}
133136

137+
public Long getMuteRole() {
138+
return muteRole;
139+
}
140+
141+
public void setMuteRole(Long muteRole) {
142+
this.muteRole = muteRole;
143+
}
144+
134145
public HashMap<String, Ban> getBans() {
135146
return bans;
136147
}

src/main/java/technobot/handlers/ModerationHandler.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import com.mongodb.client.model.Filters;
44
import com.mongodb.client.model.Updates;
5+
import com.mongodb.lang.Nullable;
56
import kotlin.Pair;
67
import net.dv8tion.jda.api.entities.Guild;
8+
import net.dv8tion.jda.api.entities.Role;
79
import net.dv8tion.jda.api.entities.User;
810
import org.bson.conversions.Bson;
911
import technobot.TechnoBot;
@@ -174,4 +176,25 @@ public int removeWarning(int id) {
174176
}
175177
return 0;
176178
}
179+
180+
/**
181+
* Sets the mute role for this guild.
182+
*
183+
* @param roleID the ID of the mute role to set.
184+
*/
185+
public void setMuteRole(long roleID) {
186+
moderation.setMuteRole(roleID);
187+
bot.database.moderation.updateOne(filter, Updates.set("mute_role", roleID));
188+
}
189+
190+
/**
191+
* Get the mute role for this guild if set.
192+
*
193+
* @return the set mute role, or null if not set or invalid.
194+
*/
195+
public @Nullable Role getMuteRole() {
196+
Long roleID = moderation.getMuteRole();
197+
if (roleID == null) return null;
198+
return guild.getRoleById(roleID);
199+
}
177200
}

0 commit comments

Comments
 (0)