-
-
Notifications
You must be signed in to change notification settings - Fork 102
/modmail slash command #329
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
Changes from 6 commits
2cb5974
52744e5
806bee3
b563a4c
7ec6b33
1bfbf42
e154d7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package org.togetherjava.tjbot.commands.moderation; | ||
|
|
||
| import net.dv8tion.jda.api.JDA; | ||
| import net.dv8tion.jda.api.entities.Guild; | ||
| import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.togetherjava.tjbot.commands.SlashCommandAdapter; | ||
| import org.togetherjava.tjbot.commands.SlashCommandVisibility; | ||
| import org.togetherjava.tjbot.commands.modmail.ModMailUtil; | ||
| import org.togetherjava.tjbot.config.Config; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class ReloadModMailCommand extends SlashCommandAdapter { | ||
|
|
||
| private final JDA jda; | ||
| private static final Config config = Config.getInstance(); | ||
|
|
||
| /** | ||
| * Creates an instance of ReloadMod command. | ||
| * | ||
| * @param jda the JDA instance to find the guild. | ||
| */ | ||
| public ReloadModMailCommand(@NotNull JDA jda) { | ||
| super("reloadmod", "Reloads the list of moderators in the modmail selection menu", | ||
| SlashCommandVisibility.GUILD); | ||
|
|
||
| this.jda = Objects.requireNonNull(jda); | ||
| } | ||
|
|
||
| @Override | ||
| public void onSlashCommand(@NotNull SlashCommandEvent event) { | ||
| Guild guild = Objects.requireNonNull(jda.getGuildById(config.getGuildId()), | ||
| "A Guild is required to use this command. Perhaps the bot isn't on the guild yet"); | ||
|
|
||
| if (ModMailUtil.doesUserHaveModRole(event.getMember(), guild)) { | ||
| event.reply("Only moderators can use this command.").setEphemeral(true).queue(); | ||
| return; | ||
| } | ||
|
|
||
| ModMailUtil.loadMenuOptions(guild); | ||
| event.reply("List of moderators has now been reloaded.").setEphemeral(true).queue(); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| package org.togetherjava.tjbot.commands.modmail; | ||
|
|
||
| import net.dv8tion.jda.api.entities.Guild; | ||
| import net.dv8tion.jda.api.entities.Member; | ||
| import net.dv8tion.jda.api.entities.Role; | ||
| import net.dv8tion.jda.api.interactions.components.selections.SelectOption; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.togetherjava.tjbot.config.Config; | ||
|
|
||
| import java.util.Optional; | ||
| import java.util.function.Predicate; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| /** | ||
| * Utility methods that interact either directly or indirectly with the {@link ModmailCommand}. | ||
| */ | ||
| public class ModMailUtil { | ||
|
|
||
| public static final Predicate<String> isModRole = | ||
| Pattern.compile(Config.getInstance().getHeavyModerationRolePattern()) | ||
| .asMatchPredicate(); | ||
|
|
||
| private ModMailUtil() { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
|
|
||
| /** | ||
| * Clears the list of moderators in the {@link ModmailCommand}. | ||
| */ | ||
| public static void clearMods() { | ||
| ModmailCommand.mods.clear(); | ||
| ModmailCommand.modsMap.clear(); | ||
| } | ||
|
|
||
| /** | ||
| * Finds the moderators on the given guild and stores it for later use. | ||
| * <p> | ||
| * This call is expensive to make thus, it shall only be used preferably once by storing the | ||
| * result somewhere or seldomly when moderators want to reload the list of moderators to choose | ||
| * from from the {@link ModmailCommand}. | ||
| * <p/> | ||
| * The previous result stored by this method will be overwritten if there was any. | ||
| */ | ||
| public static void loadMenuOptions(@NotNull Guild guild) { | ||
| clearMods(); | ||
|
|
||
| Role modRole = getModRole(guild) | ||
| .orElseThrow(() -> new IllegalStateException("No moderator role found")); | ||
|
|
||
| guild.findMembersWithRoles(modRole).get().stream().forEach(mod -> { | ||
|
||
| String modId = mod.getId(); | ||
| ModmailCommand.mods.add(SelectOption.of(mod.getEffectiveName(), modId)); | ||
| ModmailCommand.modsMap.put(modId, mod.getUser()); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Gets the moderator role. | ||
| * | ||
| * @param guild the guild to get the moderator role from | ||
| * @return the moderator role, if found | ||
| */ | ||
| public static @NotNull Optional<Role> getModRole(@NotNull Guild guild) { | ||
| return guild.getRoles().stream().filter(role -> isModRole.test(role.getName())).findAny(); | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether the given member is a moderator on the given guild. | ||
| * | ||
| * @param member the member to check for moderator role. | ||
| * @param guild the guild to get the moderator role from. | ||
| * @return | ||
| */ | ||
| public static boolean doesUserHaveModRole(@NotNull Member member, @NotNull Guild guild) { | ||
| return member.canInteract(getModRole(guild) | ||
| .orElseThrow(() -> new IllegalStateException("No moderator role found"))); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,138 @@ | ||||||
| package org.togetherjava.tjbot.commands.modmail; | ||||||
|
|
||||||
| import net.dv8tion.jda.api.JDA; | ||||||
| import net.dv8tion.jda.api.entities.Guild; | ||||||
| import net.dv8tion.jda.api.entities.User; | ||||||
| import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent; | ||||||
| import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; | ||||||
| import net.dv8tion.jda.api.interactions.commands.OptionType; | ||||||
| import net.dv8tion.jda.api.interactions.components.ActionRow; | ||||||
| import net.dv8tion.jda.api.interactions.components.selections.SelectOption; | ||||||
| import net.dv8tion.jda.api.interactions.components.selections.SelectionMenu; | ||||||
| import org.jetbrains.annotations.NotNull; | ||||||
| import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | ||||||
| import org.togetherjava.tjbot.commands.SlashCommandAdapter; | ||||||
| import org.togetherjava.tjbot.commands.SlashCommandVisibility; | ||||||
| import org.togetherjava.tjbot.config.Config; | ||||||
|
|
||||||
| import java.util.*; | ||||||
|
|
||||||
| public class ModmailCommand extends SlashCommandAdapter { | ||||||
| private static final Logger logger = LoggerFactory.getLogger(ModmailCommand.class); | ||||||
|
|
||||||
| private static final String COMMAND_NAME = "modmail"; | ||||||
| private static final String TARGET_OPTION = "message"; | ||||||
| private static final Config config = Config.getInstance(); | ||||||
|
|
||||||
| static final List<SelectOption> mods = new ArrayList<>(); | ||||||
| static final Map<String, User> modsMap = new HashMap<>(); | ||||||
|
||||||
|
|
||||||
| private final JDA jda; | ||||||
|
|
||||||
| /** | ||||||
| * Creates an instance of the ModMail command. | ||||||
| * | ||||||
| * @param jda the {@link JDA} instance of all slash commands to find the target guild or the | ||||||
| * guild where the moderators are. | ||||||
| */ | ||||||
| public ModmailCommand(@NotNull JDA jda) { | ||||||
| super(COMMAND_NAME, | ||||||
| "sends a message to either a single moderator or on the mod_audit_log channel", | ||||||
| SlashCommandVisibility.GLOBAL); | ||||||
|
|
||||||
| getData().addOption(OptionType.STRING, TARGET_OPTION, "The message to send", true); | ||||||
|
|
||||||
| this.jda = Objects.requireNonNull(jda); | ||||||
|
|
||||||
| mods.add(SelectOption.of("All Moderators", "all")); | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onSlashCommand(@NotNull SlashCommandEvent event) { | ||||||
| String memberId = event.getUser().getId(); | ||||||
|
|
||||||
| // checks if selection menu already contains the moderators | ||||||
| if (mods.size() == 1) { | ||||||
| loadMenuOptions(); | ||||||
| } | ||||||
|
||||||
|
|
||||||
| event.reply(""" | ||||||
| Select the moderator to send message to, or select "All Moderators" to send to | ||||||
| the guild's mod audit channel. | ||||||
| """) | ||||||
| .addActionRow(SelectionMenu | ||||||
| .create(generateComponentId(memberId, event.getOption(TARGET_OPTION).getAsString())) | ||||||
| .addOptions(mods) | ||||||
| .build()) | ||||||
| .setEphemeral(false) | ||||||
| .queue(); | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void onSelectionMenu(@NotNull SelectionMenuEvent event, @NotNull List<String> args) { | ||||||
| String message = args.get(1); | ||||||
| // Ignore if another user clicked the button which is only possible when used within the | ||||||
| // guild. | ||||||
| String userId = args.get(0); | ||||||
| if (event.isFromGuild() | ||||||
| && !userId.equals(Objects.requireNonNull(event.getMember()).getId())) { | ||||||
|
||||||
| && !userId.equals(Objects.requireNonNull(event.getMember()).getId())) { | |
| && !userId.equals(event.getMember().getId())) { |
You're effectively doing
if (member == null) {
member.toString();
}Here, which is, useless
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to change the javadoc for this. I'll just do it tomorrow.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See review above, remove this in favor of the onReady event
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should be able to do
event.getGuild(), no?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could but I didn't due to some pedantic reason. If the command was called on Guild A, but the
guildIdwas Guild B, then it would have inconsistent results.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about that, I think I could perhaps do
event.getGuild()on theModMailCommandas well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think you should SlashCommandEvent#getGuild ^^
If you run the command in Guild B, right now it runs it like it's in Guild A, which is really weird imo
The bot is only in 1 guild, and it'll never join another one