diff --git a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java index ef69e9f..def64eb 100644 --- a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java +++ b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java @@ -150,6 +150,7 @@ public class HidekoBot messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.LoveCalculatorCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.MagicBallCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.SayCommand()); + messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.TimeoutCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.TriviaCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.UrbanDictionaryCommand()); Cache.setMessageCommandListener(messageCommandListener); diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java b/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java index 9c1cd54..10d2358 100644 --- a/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java +++ b/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java @@ -57,7 +57,7 @@ public class UrbanDictionary public static String sanitizeArgs(String term, boolean forUrl) { - term = term.replaceAll("[^\\d\\w\\s]", ""); // only keep letters, numbers and spaces + term = term.replaceAll("[^\\w\\s]", ""); // only keep letters, numbers and spaces term = WordUtils.capitalizeFully(term); // Make Every Word Start With A Capital Letter if(forUrl) term = term.replaceAll("\\s+", "+"); // replace all whitespaces with + for the url if (term.length() > 64) term = term.substring(0, 64); // cut it to length to avoid abuse diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/base/UserPunishment.java b/src/main/java/wtf/beatrice/hidekobot/commands/base/UserPunishment.java index e5e5eb8..f143a3e 100644 --- a/src/main/java/wtf/beatrice/hidekobot/commands/base/UserPunishment.java +++ b/src/main/java/wtf/beatrice/hidekobot/commands/base/UserPunishment.java @@ -9,16 +9,22 @@ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; -import org.apache.commons.text.WordUtils; import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.objects.MessageResponse; +import wtf.beatrice.hidekobot.util.FormatUtil; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.concurrent.TimeUnit; public class UserPunishment { + + private final static Duration maxTimeoutDuration = Duration.of(28, ChronoUnit.DAYS); + private final static Duration minTimeoutDuration = Duration.of(30, ChronoUnit.SECONDS); + public static void handle(MessageReceivedEvent event, String[] args, PunishmentType punishmentType) { Mentions msgMentions = event.getMessage().getMentions(); @@ -70,9 +76,13 @@ public class UserPunishment StringBuilder reasonBuilder = new StringBuilder(); String reason = ""; - if(args.length > 1) + + // some commands require an additional parameter before the reason, so in that case, we should start at 2. + int startingPoint = punishmentType == PunishmentType.TIMEOUT ? 2 : 1; + + if(args.length > startingPoint) { - for(int i = 1; i < args.length; i++) + for(int i = startingPoint; i < args.length; i++) { String arg = args[i]; reasonBuilder.append(arg); @@ -91,6 +101,7 @@ public class UserPunishment } Guild guild = ((TextChannel) channel).getGuild(); + Duration duration = null; AuditableRestAction punishmentAction = null; @@ -98,6 +109,27 @@ public class UserPunishment switch (punishmentType) { case BAN -> punishmentAction = guild.ban(mentioned, 0, TimeUnit.SECONDS); case KICK -> punishmentAction = guild.kick(mentioned); + case TIMEOUT -> { + String durationStr = args[1]; + duration = FormatUtil.parseDuration(durationStr); + + boolean isDurationValid = true; + + if(duration == null) isDurationValid = false; + else + { + if(duration.compareTo(maxTimeoutDuration) > 0) isDurationValid = false; + if(minTimeoutDuration.compareTo(duration) > 0) isDurationValid = false; + } + + if(duration == null || !isDurationValid) + { + // todo nicer looking with emojis + return new MessageResponse("Sorry, but the specified duration is invalid!", null); + } + + punishmentAction = guild.timeoutFor(mentioned, duration); + } } } catch (RuntimeException ignored) { // todo nicer looking with emojis @@ -122,8 +154,10 @@ public class UserPunishment embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setTitle("User " + punishmentType.getPastTense()); - embedBuilder.addField("\uD83D\uDC64 User", mentioned.getAsMention(), true); - embedBuilder.addField("✂️ By", author.getAsMention(), true); + embedBuilder.addField("\uD83D\uDC64 User", mentioned.getAsMention(), false); + embedBuilder.addField("✂️ By", author.getAsMention(), false); + if(duration != null) + embedBuilder.addField("⏱️ Duration", FormatUtil.getNiceDuration(duration), false); if(reason.isEmpty()) reason = "*No reason specified*"; @@ -138,6 +172,7 @@ public class UserPunishment public enum PunishmentType { KICK("kicked"), BAN("banned"), + TIMEOUT("timed out"), ; diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/TimeoutCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/TimeoutCommand.java new file mode 100644 index 0000000..50aa23a --- /dev/null +++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/TimeoutCommand.java @@ -0,0 +1,58 @@ +package wtf.beatrice.hidekobot.commands.message; + +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import wtf.beatrice.hidekobot.commands.base.UserPunishment; +import wtf.beatrice.hidekobot.objects.commands.CommandCategory; +import wtf.beatrice.hidekobot.objects.commands.MessageCommand; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class TimeoutCommand implements MessageCommand +{ + + @Override + public LinkedList getCommandLabels() { + return new LinkedList<>(Collections.singletonList("timeout")); + } + + @Nullable + @Override + public List getPermissions() { + return new ArrayList(Collections.singletonList(Permission.MODERATE_MEMBERS)); + } + + @Override + public boolean passRawArgs() { + return false; + } + + @NotNull + @Override + public CommandCategory getCategory() { + return CommandCategory.MODERATION; + } + + @NotNull + @Override + public String getDescription() { + return "Timeout the mentioned user."; + } + + @Nullable + @Override + public String getUsage() { + return " [reason]"; + } + + @Override + public void runCommand(MessageReceivedEvent event, String label, String[] args) + { + UserPunishment.handle(event, args, UserPunishment.PunishmentType.TIMEOUT); + } +}