From a3f4e2b918a8dd99a108c048a1fe612e4935c4f7 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Jul 2024 19:46:48 +0100 Subject: [PATCH] finish moderation --- pom.xml | 5 + .../cc/fascinated/bat/command/BatCommand.java | 59 ++- ...onBuilder.java => DescriptionBuilder.java} | 10 +- .../cc/fascinated/bat/common/RoleUtils.java | 11 + .../autorole/command/SyncSubCommand.java | 4 +- .../base/commands/fun/EightBallCommand.java | 10 +- .../base/commands/fun/PPSizeCommand.java | 4 +- .../commands/general/BotStatsCommand.java | 2 +- .../base/commands/general/VoteCommand.java | 4 +- .../commands/utility/PastebinCommand.java | 4 +- .../utility/lookup/UserSubCommand.java | 4 +- .../leveling/command/CurrentSubCommand.java | 4 +- .../bat/features/logging/LogCategory.java | 3 +- .../bat/features/logging/LogFeature.java | 3 + .../bat/features/logging/LogType.java | 9 +- .../logging/command/ListSubCommand.java | 6 +- .../logging/command/RemoveSubCommand.java | 8 +- .../logging/command/SetSubCommand.java | 8 +- .../logging/listeners/ChannelListener.java | 26 +- .../logging/listeners/EmojiListener.java | 8 +- .../logging/listeners/GuildListener.java | 44 +- .../logging/listeners/MemberListener.java | 28 +- .../logging/listeners/MessageListener.java | 6 +- .../logging/listeners/RoleListener.java | 16 +- .../logging/listeners/StickerListener.java | 8 +- .../command/DeletedSubCommand.java | 4 +- .../features/minecraft/MinecraftProfile.java | 2 +- .../minecraft/LookupPlayerSubCommand.java | 4 +- .../minecraft/LookupServerSubCommand.java | 4 +- .../command/serverwatcher/ListSubCommand.java | 4 +- .../moderation/ModerationFeature.java | 94 ++++- .../moderation/command/BanCommand.java | 75 ++++ .../moderation/command/KickCommand.java | 65 +++ .../moderation/command/MuteCommand.java | 75 ++++ .../command/PunishHistoryCommand.java | 102 +++++ .../moderation/command/PurgeCommand.java | 33 +- .../moderation/command/UnbanCommand.java | 72 ++++ .../moderation/command/UnmuteCommand.java | 72 ++++ .../moderation/command/WarnCommand.java | 63 +++ .../moderation/punish/Punishment.java | 45 ++ .../moderation/punish/PunishmentProfile.java | 395 ++++++++++++++++++ .../moderation/punish/PunishmentType.java | 11 + .../reminder/command/ListSubCommand.java | 4 +- .../command/scoresaber/ScoreSaberCommand.java | 2 +- .../statschannel/command/AddSubCommand.java | 4 +- .../command/CurrentSubCommand.java | 4 +- .../welcomer/command/EmbedSubCommand.java | 4 +- .../welcomer/command/MessageSubCommand.java | 4 +- .../cc/fascinated/bat/model/BatGuild.java | 10 + .../bat/service/DiscordService.java | 3 + 50 files changed, 1312 insertions(+), 137 deletions(-) rename src/main/java/cc/fascinated/bat/common/{EmbedDescriptionBuilder.java => DescriptionBuilder.java} (71%) create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/BanCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/KickCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/MuteCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/PunishHistoryCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/UnbanCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/UnmuteCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/WarnCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/punish/Punishment.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentProfile.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentType.java diff --git a/pom.xml b/pom.xml index 8817203..d53a15c 100644 --- a/pom.xml +++ b/pom.xml @@ -191,5 +191,10 @@ mcutils-java-library 1.2.4 + + com.github.ygimenez + Pagination-Utils + 4.0.6 + diff --git a/src/main/java/cc/fascinated/bat/command/BatCommand.java b/src/main/java/cc/fascinated/bat/command/BatCommand.java index 2dd8623..58f9834 100644 --- a/src/main/java/cc/fascinated/bat/command/BatCommand.java +++ b/src/main/java/cc/fascinated/bat/command/BatCommand.java @@ -3,18 +3,17 @@ package cc.fascinated.bat.command; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; +import lombok.*; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.interactions.IntegrationType; import net.dv8tion.jda.api.interactions.InteractionContextType; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.internal.interactions.CommandDataImpl; +import org.codehaus.plexus.util.cli.Arg; import java.util.Collections; import java.util.EnumSet; @@ -143,4 +142,56 @@ public abstract class BatCommand { } return null; } + + /** + * Get an argument from the command. + * + * @param argumentIndex the index of the argument in the command + * @param option the option to get from the slash command + * @param arguments the arguments of the invoked command + * @param event the event that invoked the command + * @return the argument + */ + public Argument getArgument(int argumentIndex, String option, String[] arguments, SlashCommandInteraction event) { + return new Argument(argumentIndex, option, arguments, event); + } + + @AllArgsConstructor + public static class Argument { + /** + * The index of the argument in the command. + */ + private final int argumentIndex; + + /** + * The option to get from the slash command. + */ + private final String option; + + /** + * The arguments of the invoked command. + */ + private final String[] arguments; + + /** + * The event that invoked the command. + */ + private final SlashCommandInteraction event; + + /** + * Get the argument from the command. + * + * @return the argument + */ + public String getAsString() { + if (event != null) { + OptionMapping option = event.getOption(this.option); + if (option == null) { + return null; + } + return option.getAsString(); + } + return arguments[argumentIndex]; + } + } } \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/common/EmbedDescriptionBuilder.java b/src/main/java/cc/fascinated/bat/common/DescriptionBuilder.java similarity index 71% rename from src/main/java/cc/fascinated/bat/common/EmbedDescriptionBuilder.java rename to src/main/java/cc/fascinated/bat/common/DescriptionBuilder.java index 77d8c91..830ec18 100644 --- a/src/main/java/cc/fascinated/bat/common/EmbedDescriptionBuilder.java +++ b/src/main/java/cc/fascinated/bat/common/DescriptionBuilder.java @@ -5,13 +5,13 @@ import lombok.NonNull; /** * @author Fascinated (fascinated7) */ -public class EmbedDescriptionBuilder { +public class DescriptionBuilder { /** * Where the description is stored */ private final StringBuilder builder = new StringBuilder(); - public EmbedDescriptionBuilder(String title) { + public DescriptionBuilder(String title) { if (title == null) { return; } @@ -19,19 +19,19 @@ public class EmbedDescriptionBuilder { } @NonNull - public EmbedDescriptionBuilder appendLine(@NonNull String line, boolean arrow) { + public DescriptionBuilder appendLine(@NonNull String line, boolean arrow) { builder.append(arrow ? "➜ " : "").append(line).append("\n"); return this; } @NonNull - public EmbedDescriptionBuilder appendSubtitle(@NonNull String title) { + public DescriptionBuilder appendSubtitle(@NonNull String title) { builder.append("**").append(title).append("**").append("\n"); return this; } @NonNull - public EmbedDescriptionBuilder emptyLine() { + public DescriptionBuilder emptyLine() { builder.append("\n"); return this; } diff --git a/src/main/java/cc/fascinated/bat/common/RoleUtils.java b/src/main/java/cc/fascinated/bat/common/RoleUtils.java index 5c2c126..53cd74c 100644 --- a/src/main/java/cc/fascinated/bat/common/RoleUtils.java +++ b/src/main/java/cc/fascinated/bat/common/RoleUtils.java @@ -26,6 +26,17 @@ public class RoleUtils { return member.getRoles().stream().anyMatch(r -> r.getPosition() > role.getPosition()); } + /** + * Checks if a member has a higher role than the specified role + * + * @param member the member to check + * @param targetMember the member to check against + * @return if the member has a higher role + */ + public static boolean hasHigherRole(Member member, Member targetMember) { + return member.getRoles().stream().anyMatch(r -> targetMember.getRoles().stream().anyMatch(tr -> tr.getPosition() < r.getPosition())); + } + /** * Gets the formatted permissions of a role * diff --git a/src/main/java/cc/fascinated/bat/features/autorole/command/SyncSubCommand.java b/src/main/java/cc/fascinated/bat/features/autorole/command/SyncSubCommand.java index 5c7eeb4..c7736d5 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/command/SyncSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/command/SyncSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.autorole.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile; import cc.fascinated.bat.model.BatGuild; @@ -90,7 +90,7 @@ public class SyncSubCommand extends BatCommand { // We're finished giving all the roles if (finished == members.size()) { - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder( + DescriptionBuilder description = new DescriptionBuilder( "Successfully gave auto roles to `%s` member%s".formatted( members.size(), members.size() == 1 ? "" : "s" diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java index f2ff0ca..4bf2598 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java @@ -9,7 +9,6 @@ import cc.fascinated.bat.model.BatUser; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; import net.dv8tion.jda.api.interactions.commands.build.OptionData; @@ -50,9 +49,12 @@ public class EightBallCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { - OptionMapping questionOption = event.getOption("question"); - assert questionOption != null; - String question = questionOption.getAsString(); + String question = super.getArgument(0, "question", null, event).getAsString(); + if (question == null) { + // todo: reply + return; + } + String response = responses[(int) (Math.random() * responses.length)]; event.replyEmbeds(EmbedUtils.successEmbed() diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/fun/PPSizeCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/fun/PPSizeCommand.java index 765e67c..3f60a15 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/fun/PPSizeCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/fun/PPSizeCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.base.commands.fun; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.MathUtils; import cc.fascinated.bat.model.BatGuild; @@ -41,7 +41,7 @@ public class PPSizeCommand extends BatCommand { int size = (int) MathUtils.random(1, 12); event.replyEmbeds(EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("PP Size") + .setDescription(new DescriptionBuilder("PP Size") .appendLine(""" The size of %s's pp is %s inches **8%sD** diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/general/BotStatsCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/general/BotStatsCommand.java index 66a341e..8767b68 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/general/BotStatsCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/general/BotStatsCommand.java @@ -43,7 +43,7 @@ public class BotStatsCommand extends BatCommand { long memoryUsed = (runtime.totalMemory() - runtime.freeMemory()); event.replyEmbeds(EmbedUtils.genericEmbed().setDescription( - new EmbedDescriptionBuilder("Bat Statistics") + new DescriptionBuilder("Bat Statistics") .appendLine("Guilds: **%s**".formatted(NumberFormatter.format(jda.getGuilds().size())), true) .appendLine("Users: **%s**".formatted(NumberFormatter.format(jda.getUsers().size())), true) .appendLine("Gateway Ping: **%sms**".formatted(jda.getGatewayPing()), true) diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java index 4515abe..13132b4 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.base.commands.general; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; @@ -26,7 +26,7 @@ public class VoteCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Vote Links"); + DescriptionBuilder description = new DescriptionBuilder("Vote Links"); description.appendLine("Vote for the bot on the following websites to support us!", false); for (String link : VOTE_LINKS) { description.appendLine(link, true); diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/utility/PastebinCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/utility/PastebinCommand.java index ce2d964..6718b20 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/utility/PastebinCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/utility/PastebinCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.base.commands.utility; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.PasteUtils; import cc.fascinated.bat.model.BatGuild; @@ -43,7 +43,7 @@ public class PastebinCommand extends BatCommand { // Upload the text to pastebin String url = PasteUtils.uploadPaste(text).getUrl(); event.replyEmbeds(EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("The text has been uploaded to Paste!") + .setDescription(new DescriptionBuilder("The text has been uploaded to Paste!") .appendLine("URL: %s".formatted(url), true) .build()) .build()) diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/utility/lookup/UserSubCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/utility/lookup/UserSubCommand.java index 7af6398..a3b1763 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/utility/lookup/UserSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/utility/lookup/UserSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.base.commands.utility.lookup; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.LongUtils; import cc.fascinated.bat.model.BatGuild; @@ -61,7 +61,7 @@ public class UserSubCommand extends BatCommand { } String name = target.getGlobalName() == null ? target.getName() : target.getGlobalName().replaceAll("`", ""); target.retrieveProfile().queue(profile -> event.replyEmbeds(EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("User Lookup") + .setDescription(new DescriptionBuilder("User Lookup") .appendLine("Name: `%s`".formatted(name), true) .appendLine("Username: `%s`".formatted(target.getName()), true) .appendLine("ID: `%s`".formatted(target.getId()), true) diff --git a/src/main/java/cc/fascinated/bat/features/leveling/command/CurrentSubCommand.java b/src/main/java/cc/fascinated/bat/features/leveling/command/CurrentSubCommand.java index 80b0bb2..6a52a48 100644 --- a/src/main/java/cc/fascinated/bat/features/leveling/command/CurrentSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/leveling/command/CurrentSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.leveling.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.features.leveling.LevelingFeature; @@ -47,7 +47,7 @@ public class CurrentSubCommand extends BatCommand { LevelingProfile profile = guild.getLevelingProfile(); UserLevel level = profile.getUserLevel(target.getId()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Current Level"); + DescriptionBuilder description = new DescriptionBuilder("Current Level"); description.appendLine("User: %s".formatted(target.getDiscordUser().getAsMention()), true); description.appendLine("Level: `%s`".formatted(level.getLevel()), true); description.appendLine("XP: `%s`/`%s`".formatted( diff --git a/src/main/java/cc/fascinated/bat/features/logging/LogCategory.java b/src/main/java/cc/fascinated/bat/features/logging/LogCategory.java index 40e1862..2c3568f 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/LogCategory.java +++ b/src/main/java/cc/fascinated/bat/features/logging/LogCategory.java @@ -14,7 +14,8 @@ public enum LogCategory { MESSAGE(Emoji.fromUnicode("📩")), MEMBER(Emoji.fromUnicode("👤")), CHANNEL(Emoji.fromUnicode("📺")), - GUILD(Emoji.fromUnicode("🏰")); + GUILD(Emoji.fromUnicode("🏰")), + MODERATION(Emoji.fromUnicode("🛡️")); /** * The emoji of the log category diff --git a/src/main/java/cc/fascinated/bat/features/logging/LogFeature.java b/src/main/java/cc/fascinated/bat/features/logging/LogFeature.java index bf77163..c2b13e1 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/LogFeature.java +++ b/src/main/java/cc/fascinated/bat/features/logging/LogFeature.java @@ -18,9 +18,12 @@ import org.springframework.stereotype.Component; */ @Component public class LogFeature extends Feature { + public static LogFeature INSTANCE; + @Autowired public LogFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { super("Logging", FeatureProfile.FeatureState.DISABLED, true); + INSTANCE = this; super.registerCommand(commandService, context.getBean(LogsCommand.class)); } diff --git a/src/main/java/cc/fascinated/bat/features/logging/LogType.java b/src/main/java/cc/fascinated/bat/features/logging/LogType.java index d50fd7e..c3cfd98 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/LogType.java +++ b/src/main/java/cc/fascinated/bat/features/logging/LogType.java @@ -60,7 +60,14 @@ public enum LogType { STICKER_REMOVE(LogCategory.GUILD), STICKER_NAME_UPDATED(LogCategory.GUILD), BOOST_TIER_UPDATED(LogCategory.GUILD), - GUILD_CONFIGURATION(LogCategory.GUILD); + GUILD_CONFIGURATION(LogCategory.GUILD), + + /** + * Moderation Events + */ + PUNISHMENT_ISSUED(LogCategory.MODERATION), + PUNISHMENT_REMOVED_OR_EXPIRED(LogCategory.MODERATION), + PURGE(LogCategory.MODERATION); /** * The category of the log type diff --git a/src/main/java/cc/fascinated/bat/features/logging/command/ListSubCommand.java b/src/main/java/cc/fascinated/bat/features/logging/command/ListSubCommand.java index c1e149f..1fa66cf 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/command/ListSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/logging/command/ListSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.logging.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogCategory; @@ -78,7 +78,7 @@ public class ListSubCommand extends BatCommand implements EventListener { } List logEvents = LogType.getLogTypesByCategory(category.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder(null); + DescriptionBuilder description = new DescriptionBuilder(null); description.appendLine("Log channels for the `%s` category".formatted(category.getName()), false); description.emptyLine(); for (LogType logType : logEvents) { @@ -97,7 +97,7 @@ public class ListSubCommand extends BatCommand implements EventListener { * @return the help message */ public MessageEmbed getHelpMessage() { - return EmbedUtils.genericEmbed().setDescription(new EmbedDescriptionBuilder(null).appendLine( + return EmbedUtils.genericEmbed().setDescription(new DescriptionBuilder(null).appendLine( """ Set the log channel for: - A specific event, use `/logs set ` diff --git a/src/main/java/cc/fascinated/bat/features/logging/command/RemoveSubCommand.java b/src/main/java/cc/fascinated/bat/features/logging/command/RemoveSubCommand.java index 67b6afc..1705cce 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/command/RemoveSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/logging/command/RemoveSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.logging.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.logging.LogCategory; import cc.fascinated.bat.features.logging.LogProfile; @@ -44,7 +44,7 @@ public class RemoveSubCommand extends BatCommand { for (LogType logType : LogType.values()) { profile.removeLogChannel(logType); } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder(null); + DescriptionBuilder description = new DescriptionBuilder(null); description.appendLine("%s Successfully removed the log channel from `%s` log events".formatted( Emojis.CHECK_MARK_EMOJI, LogType.values().length @@ -62,7 +62,7 @@ public class RemoveSubCommand extends BatCommand { for (LogType logType : category) { profile.removeLogChannel(logType); } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder(null); + DescriptionBuilder description = new DescriptionBuilder(null); description.appendLine("%s Successfully removed the log channel from `%s` `%s` log events".formatted( Emojis.CHECK_MARK_EMOJI, category.size(), @@ -85,7 +85,7 @@ public class RemoveSubCommand extends BatCommand { return; } profile.removeLogChannel(logType); - event.replyEmbeds(EmbedUtils.successEmbed().setDescription(new EmbedDescriptionBuilder(null) + event.replyEmbeds(EmbedUtils.successEmbed().setDescription(new DescriptionBuilder(null) .appendLine("%s Successfully removed the log channel from `%s`".formatted( Emojis.CHECK_MARK_EMOJI, logType.getName() diff --git a/src/main/java/cc/fascinated/bat/features/logging/command/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/logging/command/SetSubCommand.java index e0fb942..c87d66f 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/command/SetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/logging/command/SetSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.logging.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.logging.LogCategory; import cc.fascinated.bat.features.logging.LogProfile; @@ -51,7 +51,7 @@ public class SetSubCommand extends BatCommand { for (LogType logType : LogType.values()) { profile.setLogChannel(logType, targetChannel); } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder(null); + DescriptionBuilder description = new DescriptionBuilder(null); description.appendLine("%s Successfully set the log channel for `%s` log events to %s".formatted( Emojis.CHECK_MARK_EMOJI, LogType.values().length, @@ -70,7 +70,7 @@ public class SetSubCommand extends BatCommand { for (LogType logType : category) { profile.setLogChannel(logType, targetChannel); } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder(null); + DescriptionBuilder description = new DescriptionBuilder(null); description.appendLine("%s Successfully set the log channel for `%s` `%s` log events to %s".formatted( Emojis.CHECK_MARK_EMOJI, category.size(), @@ -94,7 +94,7 @@ public class SetSubCommand extends BatCommand { return; } profile.setLogChannel(logType, targetChannel); - event.replyEmbeds(EmbedUtils.successEmbed().setDescription(new EmbedDescriptionBuilder(null) + event.replyEmbeds(EmbedUtils.successEmbed().setDescription(new DescriptionBuilder(null) .appendLine("%s Successfully set the log channel for `%s` to %s".formatted( Emojis.CHECK_MARK_EMOJI, logType.getName(), diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index daf4318..63cf5e3 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -84,7 +84,7 @@ public class ChannelListener implements EventListener { String type = formatChannelType(channel); log.info("{} \"{}\" was created in guild \"{}\"", type, event.getChannel().getName(), guild.getName()); logFeature.sendLog(guild, LogType.CHANNEL_CREATE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("%s Created".formatted(type)) + .setDescription(new DescriptionBuilder("%s Created".formatted(type)) .appendLine("%s: %s".formatted(type, event.getChannel().getAsMention()), true) .appendLine("Name: `%s`".formatted(event.getChannel().getName()), true) .build()) @@ -96,7 +96,7 @@ public class ChannelListener implements EventListener { ChannelUnion channel = event.getChannel(); String type = formatChannelType(channel); log.info("{} \"{}\" was deleted in guild \"{}\"", type, event.getChannel().getName(), guild.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Deleted".formatted(type)) + DescriptionBuilder description = new DescriptionBuilder("%s Deleted".formatted(type)) .appendLine("Name: `#%s`".formatted(channel.getName()), true); if (channel instanceof TextChannel) { TextChannel textChannel = channel.asTextChannel(); @@ -125,7 +125,7 @@ public class ChannelListener implements EventListener { // User switched channels if (oldChannel != null && !oldChannel.equals(voiceChannel)) { log.info("User \"{}\" switched from voice channel \"{}\" to \"{}\" in guild \"{}\"", user.getName(), oldChannel.getName(), voiceChannel.getName(), guild.getName()); - String switchDescription = new EmbedDescriptionBuilder("Member Switched Voice Channel") + String switchDescription = new DescriptionBuilder("Member Switched Voice Channel") .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Channel: %s -> %s".formatted(oldChannel.getAsMention(), voiceChannel.getAsMention()), true) .build(); @@ -134,7 +134,7 @@ public class ChannelListener implements EventListener { } log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getName(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName()); - String description = new EmbedDescriptionBuilder("Member %s Voice Channel".formatted(joined ? "Joined" : "Left")) + String description = new DescriptionBuilder("Member %s Voice Channel".formatted(joined ? "Joined" : "Left")) .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Channel: %s".formatted(voiceChannel.getAsMention()), true) .build(); @@ -161,7 +161,7 @@ public class ChannelListener implements EventListener { String target = event.getPermissionOverride().isRoleOverride() ? event.getPermissionOverride().getRole().getAsMention() : event.getPermissionOverride().getMember().getAsMention(); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Channel permissions updated") + DescriptionBuilder description = new DescriptionBuilder("Channel permissions updated") .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) .appendLine("%s: %s".formatted( event.getPermissionOverride().isRoleOverride() ? "Role" : "Member", @@ -189,7 +189,7 @@ public class ChannelListener implements EventListener { String type = formatChannelType(channel); log.info("{} \"{}\" topic was updated to {} in guild \"{}\"", type, newValue, oldValue, guild.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Topic Updated".formatted(type)); + DescriptionBuilder description = new DescriptionBuilder("%s Topic Updated".formatted(type)); description.appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true); description.appendLine("Topic: `%s` -> `%s`".formatted( oldValue == null ? "No Topic" : oldValue, @@ -208,7 +208,7 @@ public class ChannelListener implements EventListener { VoiceChannel channel = event.getChannel().asVoiceChannel(); log.info("Voice channel \"{}\" bitrate was updated to {} in guild \"{}\"", channel.getName(), event.getNewValue(), guild.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Voice Channel Updated") + DescriptionBuilder description = new DescriptionBuilder("Voice Channel Updated") .appendLine("Channel: %s".formatted(channel.getAsMention()), true) .appendLine("Bitrate: `%s` -> `%s`".formatted(NumberFormatter.format(event.getOldValue()), NumberFormatter.format(event.getNewValue())), true); @@ -225,7 +225,7 @@ public class ChannelListener implements EventListener { String type = formatChannelType(channel); log.info("{} \"{}\" name was updated to {} in guild \"{}\"", type, newValue, oldValue, guild.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Name Updated".formatted(type)); + DescriptionBuilder description = new DescriptionBuilder("%s Name Updated".formatted(type)); if (channel.getType() == ChannelType.TEXT || channel.getType() == ChannelType.VOICE) { description.appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true); } @@ -239,7 +239,7 @@ public class ChannelListener implements EventListener { @Override public void onChannelUpdateNSFW(@NonNull BatGuild guild, @NonNull ChannelUpdateNSFWEvent event) { logFeature.sendLog(guild, LogType.CHANNEL_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Channel NSFW Updated") + .setDescription(new DescriptionBuilder("Channel NSFW Updated") .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) .appendLine("NSFW: `%s` -> `%s`".formatted( Boolean.TRUE.equals(event.getOldValue()) ? "Yes" : "No", @@ -257,7 +257,7 @@ public class ChannelListener implements EventListener { VoiceChannel channel = event.getChannel().asVoiceChannel(); log.info("Voice channel \"{}\" user limit was updated to {} in guild \"{}\"", channel.getName(), event.getNewValue(), guild.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Voice Channel User Limit Updated") + DescriptionBuilder description = new DescriptionBuilder("Voice Channel User Limit Updated") .appendLine("Channel: %s".formatted(channel.getAsMention()), true) .appendLine("User Limit: `%s` -> `%s`".formatted( event.getOldValue() == 0 ? "Unlimited" : NumberFormatter.format(event.getOldValue()), @@ -277,7 +277,7 @@ public class ChannelListener implements EventListener { String newRegion = event.getNewValue() == Region.UNKNOWN ? "Automatic" : event.getNewValue().getName(); log.info("Channel \"{}\" region was updated to \"{}\" in guild \"{}\"", event.getChannel().getName(), newRegion, guild.getName()); logFeature.sendLog(guild, LogType.CHANNEL_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Channel Region Updated") + .setDescription(new DescriptionBuilder("Channel Region Updated") .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) .appendLine("Region: `%s` -> `%s`".formatted( event.getOldValue() == Region.UNKNOWN ? "Automatic" : event.getOldValue().getName(), @@ -297,7 +297,7 @@ public class ChannelListener implements EventListener { log.info("Text channel \"{}\" slowmode was updated to {} in guild \"{}\"", event.getChannel().getName(), newSlowmode, guild.getName()); logFeature.sendLog(guild, LogType.CHANNEL_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Channel Slowmode Updated") + .setDescription(new DescriptionBuilder("Channel Slowmode Updated") .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) .appendLine("Slowmode: `%s` -> `%s`".formatted(oldSlowmode, newSlowmode), true) .build()) @@ -308,7 +308,7 @@ public class ChannelListener implements EventListener { public void onChannelUpdateArchived(@NonNull BatGuild guild, @NonNull Channel channel, boolean isArchived, @NonNull ChannelUpdateArchivedEvent event) { log.info("Thread \"{}\" was {} in guild \"{}\"", channel.getName(), isArchived ? "archived" : "unarchived", guild.getName()); logFeature.sendLog(guild, LogType.THREAD_ARCHIVE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Thread %s".formatted(isArchived ? "Archived" : "Unarchived")) + .setDescription(new DescriptionBuilder("Thread %s".formatted(isArchived ? "Archived" : "Unarchived")) .appendLine("Channel: %s".formatted(channel.getAsMention()), true) .build()) .build()); diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/EmojiListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/EmojiListener.java index d292ca0..9276908 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/EmojiListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/EmojiListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogFeature; @@ -32,7 +32,7 @@ public class EmojiListener implements EventListener { public void onEmojiAdd(@NonNull BatGuild guild, @NonNull Emoji emoji, @NonNull EmojiAddedEvent event) { log.info("Emoji \"{}\" was added in guild \"{}\"", emoji.getName(), guild.getName()); logFeature.sendLog(guild, LogType.EMOJI_ADD, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Emoji Added") + .setDescription(new DescriptionBuilder("Emoji Added") .appendLine("Emoji: %s".formatted(emoji.getFormatted()), true) .appendLine("Name: `%s`".formatted(emoji.getName()), true) .build()) @@ -43,7 +43,7 @@ public class EmojiListener implements EventListener { public void onEmojiRemove(@NonNull BatGuild guild, @NonNull Emoji emoji, @NonNull EmojiRemovedEvent event) { log.info("Emoji \"{}\" was removed in guild \"{}\"", emoji.getName(), guild.getName()); logFeature.sendLog(guild, LogType.EMOJI_REMOVE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Emoji Removed") + .setDescription(new DescriptionBuilder("Emoji Removed") .appendLine("Emoji: %s".formatted(emoji.getFormatted()), true) .appendLine("Name: `%s`".formatted(emoji.getName()), true) .build()) @@ -54,7 +54,7 @@ public class EmojiListener implements EventListener { public void onEmojiRename(@NonNull BatGuild guild, @NonNull Emoji emoji, @NonNull String oldName, @NonNull String newName, @NonNull EmojiUpdateNameEvent event) { log.info("Emoji \"{}\" was renamed to \"{}\" in guild \"{}\"", oldName, newName, guild.getName()); logFeature.sendLog(guild, LogType.EMOJI_NAME_UPDATED, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Emoji Renamed") + .setDescription(new DescriptionBuilder("Emoji Renamed") .appendLine("Emoji: %s".formatted(emoji.getFormatted()), true) .appendLine("Name: `%s` -> `%s`".formatted(oldName, newName), true) .build()) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/GuildListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/GuildListener.java index 6678974..8ba62e1 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/GuildListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/GuildListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.EnumUtils; import cc.fascinated.bat.common.TimeUtils; @@ -41,7 +41,7 @@ public class GuildListener implements EventListener { log.info("Invite created in guild \"{}\" with code \"{}\"", guild.getGuild().getName(), invite.getCode()); invite.expand().queue(expandedInvite -> { - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Invite Created"); + DescriptionBuilder description = new DescriptionBuilder("Invite Created"); description.appendLine("Invite: %s".formatted(expandedInvite.getUrl()), true); if (expandedInvite.getChannel() != null) { description.appendLine("Channel: %s".formatted( @@ -60,7 +60,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateName(@NonNull BatGuild guild, String oldName, String newName, @NonNull GuildUpdateNameEvent event) { log.info("Guild name was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldName, newName); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Name Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Name Updated") .appendLine("Name: `%s` -> `%s`".formatted(oldName, newName), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -69,7 +69,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateAfkChannel(@NonNull BatGuild guild, VoiceChannel oldChannel, VoiceChannel newChannel, @NonNull GuildUpdateAfkChannelEvent event) { log.info("Guild AFK channel was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild AFK Channel Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild AFK Channel Updated") .appendLine("Channel: `%s` -> `%s`".formatted( oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName() @@ -82,7 +82,7 @@ public class GuildListener implements EventListener { log.info("Guild AFK timeout was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldTimeout.getSeconds(), newTimeout.getSeconds()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild AFK Timeout Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild AFK Timeout Updated") .appendLine("Timeout: `%s` -> `%s`".formatted( TimeUtils.format(oldTimeout.getSeconds() * 1000L), TimeUtils.format(newTimeout.getSeconds() * 1000L) @@ -94,7 +94,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateBanner(@NonNull BatGuild guild, String oldBannerUrl, String newBannerUrl, @NonNull GuildUpdateBannerEvent event) { log.info("Guild banner was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldBannerUrl, newBannerUrl); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Banner Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Banner Updated") .appendLine("Banner: [click here](%s)".formatted(newBannerUrl), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -103,7 +103,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateDescription(@NonNull BatGuild guild, String oldDescription, String newDescription, @NonNull GuildUpdateDescriptionEvent event) { log.info("Guild description was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldDescription, newDescription); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Description Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Description Updated") .appendLine("Description: `%s` -> `%s`".formatted(oldDescription, newDescription), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -112,7 +112,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateIcon(@NonNull BatGuild guild, String oldIconUrl, String newIconUrl, @NonNull GuildUpdateIconEvent event) { log.info("Guild icon was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldIconUrl, newIconUrl); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Icon Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Icon Updated") .appendLine("Icon: [click here](%s)".formatted(newIconUrl), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -121,7 +121,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateLocale(@NonNull BatGuild guild, DiscordLocale oldLocale, DiscordLocale newLocale, @NonNull GuildUpdateLocaleEvent event) { log.info("Guild primary language was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLocale, newLocale); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Primary Language Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Primary Language Updated") .appendLine("Language: `%s` -> `%s`".formatted( oldLocale.getLanguageName(), newLocale.getLanguageName() @@ -133,7 +133,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateCommunityUpdatesChannel(@NonNull BatGuild guild, TextChannel oldChannel, TextChannel newChannel, @NonNull GuildUpdateCommunityUpdatesChannelEvent event) { log.info("Guild community updates channel was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Community Updates Channel Updated") + DescriptionBuilder description = new DescriptionBuilder("Community Updates Channel Updated") .appendLine("Channel: `%s` -> `%s`".formatted( oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName() @@ -146,7 +146,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateBoostTier(@NonNull BatGuild guild, Guild.BoostTier oldTier, Guild.BoostTier newTier, @NonNull GuildUpdateBoostTierEvent event) { log.info("Guild boost tier was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldTier.getKey(), newTier.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Boost Tier Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Boost Tier Updated") .appendLine("Tier: `%s` -> `%s`".formatted(oldTier.getKey(), newTier.getKey()), true); logFeature.sendLog(guild, LogType.BOOST_TIER_UPDATED, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -155,7 +155,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateMaxMembers(@NonNull BatGuild guild, int oldCount, int newCount, @NonNull GuildUpdateMaxMembersEvent event) { log.info("Guild max members was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldCount, newCount); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Max Members Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Max Members Updated") .appendLine("Members: `%s` -> `%s`".formatted(oldCount, newCount), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -164,7 +164,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateExplicitContentLevel(@NonNull BatGuild guild, Guild.ExplicitContentLevel oldLevel, Guild.ExplicitContentLevel newLevel, @NonNull GuildUpdateExplicitContentLevelEvent event) { log.info("Guild explicit content level was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLevel.getKey(), newLevel.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Explicit Content Level Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Explicit Content Level Updated") .appendLine("Level: `%s` -> `%s`".formatted( EnumUtils.getEnumName(oldLevel), EnumUtils.getEnumName(newLevel) @@ -176,7 +176,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateMFALevel(@NonNull BatGuild guild, Guild.MFALevel oldLevel, Guild.MFALevel newLevel, @NonNull GuildUpdateMFALevelEvent event) { log.info("Guild MFA level was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLevel.getKey(), newLevel.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild MFA Level Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild MFA Level Updated") .appendLine("Level: `%s` -> `%s`".formatted( EnumUtils.getEnumName(oldLevel), EnumUtils.getEnumName(newLevel) @@ -188,7 +188,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateNotificationLevel(@NonNull BatGuild guild, Guild.NotificationLevel oldLevel, Guild.NotificationLevel newLevel, @NonNull GuildUpdateNotificationLevelEvent event) { log.info("Guild notification level was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLevel.getKey(), newLevel.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Notification Level Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Notification Level Updated") .appendLine("Level: `%s` -> `%s`".formatted( EnumUtils.getEnumName(oldLevel), EnumUtils.getEnumName(newLevel) @@ -200,7 +200,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateNSFWLevel(@NonNull BatGuild guild, Guild.NSFWLevel oldLevel, Guild.NSFWLevel newLevel, @NonNull GuildUpdateNSFWLevelEvent event) { log.info("Guild NSFW level was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLevel.getKey(), newLevel.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild NSFW Level Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild NSFW Level Updated") .appendLine("Level: `%s` -> `%s`".formatted( EnumUtils.getEnumName(oldLevel), EnumUtils.getEnumName(newLevel) @@ -212,7 +212,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateOwner(@NonNull BatGuild guild, @NonNull BatUser oldOwner, @NonNull BatUser newOwner, @NonNull GuildUpdateOwnerEvent event) { log.info("Guild owner was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldOwner.getUser().getAsTag(), newOwner.getUser().getAsTag()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Owner Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Owner Updated") .appendLine("Owner: %s -> %s".formatted(oldOwner.getUser().getAsMention(), newOwner.getUser().getAsMention()), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } @@ -221,7 +221,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateRulesChannel(@NonNull BatGuild guild, TextChannel oldChannel, TextChannel newChannel, @NonNull GuildUpdateRulesChannelEvent event) { log.info("Guild rules channel was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Rules Channel Updated") + DescriptionBuilder description = new DescriptionBuilder("Rules Channel Updated") .appendLine("Channel: %s -> %s".formatted( oldChannel == null ? "`None`" : oldChannel.getAsMention(), newChannel == null ? "`None`" : newChannel.getAsMention() @@ -233,7 +233,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateSystemChannel(@NonNull BatGuild guild, TextChannel oldChannel, TextChannel newChannel, @NonNull GuildUpdateSystemChannelEvent event) { log.info("Guild system channel was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldChannel == null ? "None" : oldChannel.getName(), newChannel == null ? "None" : newChannel.getName()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("System Channel Updated") + DescriptionBuilder description = new DescriptionBuilder("System Channel Updated") .appendLine("Channel: %s -> %s".formatted( oldChannel == null ? "`None`" : oldChannel.getAsMention(), newChannel == null ? "`None`" : newChannel.getAsMention() @@ -245,7 +245,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateVanityCode(@NonNull BatGuild guild, String oldCode, String newCode, @NonNull GuildUpdateVanityCodeEvent event) { log.info("Guild vanity code was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldCode, newCode); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Vanity Code Updated") + DescriptionBuilder description = new DescriptionBuilder("Vanity Code Updated") .appendLine("Code: `%s` -> `%s`".formatted( oldCode == null ? "None" : oldCode, newCode == null ? "None" : newCode @@ -257,7 +257,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateVerificationLevel(@NonNull BatGuild guild, Guild.VerificationLevel oldLevel, Guild.VerificationLevel newLevel, @NonNull GuildUpdateVerificationLevelEvent event) { log.info("Guild verification level was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldLevel.getKey(), newLevel.getKey()); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Verification Level Updated") + DescriptionBuilder description = new DescriptionBuilder("Verification Level Updated") .appendLine("Level: `%s` -> `%s`".formatted( EnumUtils.getEnumName(oldLevel), EnumUtils.getEnumName(newLevel) @@ -269,7 +269,7 @@ public class GuildListener implements EventListener { public void onGuildUpdateSplash(@NonNull BatGuild guild, String oldSplashUrl, String newSplashUrl, @NonNull GuildUpdateSplashEvent event) { log.info("Guild splash was updated in guild \"{}\" from \"{}\" to \"{}\"", guild.getGuild().getName(), oldSplashUrl, newSplashUrl); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Guild Splash Updated") + DescriptionBuilder description = new DescriptionBuilder("Guild Splash Updated") .appendLine("Splash: [click here](%s)".formatted(newSplashUrl), true); logFeature.sendLog(guild, LogType.GUILD_CONFIGURATION, EmbedUtils.successEmbed().setDescription(description.build()).build()); } diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 6682938..eabbd13 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogFeature; @@ -53,7 +53,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" joined the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_JOIN, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Joined") + .setDescription(new DescriptionBuilder("Member Joined") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Username: `%s`".formatted(user.getDiscordUser().getName()), true) .appendLine("Joined Discord: ".formatted(user.getDiscordUser().getTimeCreated().toEpochSecond()), true) @@ -68,7 +68,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" left the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_LEAVE, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Left") + .setDescription(new DescriptionBuilder("Member Left") .appendLine("Member: <@%s>".formatted(user.getId()), true) .appendLine("Username: `%s`".formatted(user.getName()), true) .build()) @@ -86,7 +86,7 @@ public class MemberListener implements EventListener { user.getName(), oldNameFormatted, newNameFormatted, guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_NICKNAME_UPDATE, EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Nickname Updated") + .setDescription(new DescriptionBuilder("Member Nickname Updated") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Nickname: `%s` -> `%s`".formatted( oldNameFormatted, @@ -111,7 +111,7 @@ public class MemberListener implements EventListener { if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_GLOBAL_NAME_UPDATE, EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Name Updated") + .setDescription(new DescriptionBuilder("Member Name Updated") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Name: `%s` -> `%s`".formatted( oldNameFormatted, @@ -135,7 +135,7 @@ public class MemberListener implements EventListener { if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Username Updated") + .setDescription(new DescriptionBuilder("Member Username Updated") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Username: `%s` -> `%s`".formatted(oldName, newName), true) .build()) @@ -157,7 +157,7 @@ public class MemberListener implements EventListener { if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Avatar Updated") + .setDescription(new DescriptionBuilder("Member Avatar Updated") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Avatar: %s".formatted(newAvatarUrl == null ? "Removed" : "[click here](%s)".formatted(newAvatarUrl)), true) .build()) @@ -180,7 +180,7 @@ public class MemberListener implements EventListener { String s = rolesAdded.size() > 1 ? "s" : ""; logFeature.sendLog(guild, LogType.MEMBER_ROLE_UPDATE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Role%s Added".formatted(s)) + .setDescription(new DescriptionBuilder("Member Role%s Added".formatted(s)) .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Role%s Added: %s".formatted(s, roles.substring(0, roles.length() - 2)), true) .build()) @@ -201,7 +201,7 @@ public class MemberListener implements EventListener { String s = rolesAdded.size() > 1 ? "s" : ""; logFeature.sendLog(guild, LogType.MEMBER_ROLE_UPDATE, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Role%s Removed".formatted(s)) + .setDescription(new DescriptionBuilder("Member Role%s Removed".formatted(s)) .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Role%s Removed: %s".formatted(s, roles.substring(0, roles.length() - 2)), true) .build()) @@ -216,7 +216,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" was banned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_BAN, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Banned") + .setDescription(new DescriptionBuilder("Member Banned") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .build()) .build()); @@ -230,7 +230,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" was unbanned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_UNBAN, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Unbanned") + .setDescription(new DescriptionBuilder("Member Unbanned") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .build()) .build()); @@ -244,7 +244,7 @@ public class MemberListener implements EventListener { long seconds = timeoutEnd.toInstant().getEpochSecond(); logFeature.sendLog(guild, LogType.MEMBER_TIMEOUT, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Timed Out") + .setDescription(new DescriptionBuilder("Member Timed Out") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Timeout End: ".formatted(seconds), true) .appendLine("Relative End: ".formatted(seconds), true) @@ -261,7 +261,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" boosted the guild \"{}\" until \"{}\"", user.getName(), guild.getDiscordGuild().getName(), newBoostTime); logFeature.sendLog(guild, LogType.MEMBER_BOOSTED, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Boosted") + .setDescription(new DescriptionBuilder("Member Boosted") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .build()) .build()); @@ -279,7 +279,7 @@ public class MemberListener implements EventListener { log.info("User \"{}\" boost expired in the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_BOOST_EXPIRE, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Member Boost Expired") + .setDescription(new DescriptionBuilder("Member Boost Expired") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .build()) .build()); diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java index a47505d..a1578df 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogFeature; @@ -35,7 +35,7 @@ public class MessageListener implements EventListener { log.info("User \"{}\" deleted a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_DELETE, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("Message Deleted") + .setDescription(new DescriptionBuilder("Message Deleted") .appendLine("Author: %s".formatted(message.getAuthor().getAsMention()), true) .appendLine("Channel: %s".formatted(message.getChannel().getAsMention()), true) .appendLine("Content: %s".formatted(logFeature.formatContent(message.getContent())), true) @@ -50,7 +50,7 @@ public class MessageListener implements EventListener { log.info("User \"{}\" edited a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_EDIT, EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Message Edited") + .setDescription(new DescriptionBuilder("Message Edited") .appendLine("Author: %s".formatted(newMessage.getAuthor().getAsMention()), true) .appendLine("Channel: %s".formatted(newMessage.getChannel().getAsMention()), true) .appendLine("Old Content: %s".formatted(logFeature.formatContent(oldMessage.getContent())), true) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/RoleListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/RoleListener.java index d2ed614..6fa072c 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/RoleListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/RoleListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.RoleUtils; import cc.fascinated.bat.event.EventListener; @@ -53,7 +53,7 @@ public class RoleListener implements EventListener { } } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Role Permissions Updated") + DescriptionBuilder description = new DescriptionBuilder("Role Permissions Updated") .appendLine("Role: %s".formatted(event.getRole().getAsMention()), true); if (!allowedPermissions.isEmpty()) { description.appendLine("Allowed Permissions: %s".formatted(allowedPermissions.substring(0, allowedPermissions.length() - 2)), true); @@ -72,7 +72,7 @@ public class RoleListener implements EventListener { Role role = event.getRole(); log.info("Role \"{}\" was created in guild \"{}\"", role.getName(), guild.getName()); logFeature.sendLog(guild, LogType.ROLE_CREATE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Created") + .setDescription(new DescriptionBuilder("Role Created") .appendLine("Role: %s".formatted(role.getAsMention()), true) .appendLine("Color: %s".formatted(RoleUtils.getFormattedColor(role)), true) .appendLine("Permissions: %s".formatted(RoleUtils.getFormattedPermissions(role)), true) @@ -85,7 +85,7 @@ public class RoleListener implements EventListener { Role role = event.getRole(); log.info("Role \"{}\" was deleted in guild \"{}\"", role.getName(), guild.getName()); logFeature.sendLog(guild, LogType.ROLE_DELETE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Deleted") + .setDescription(new DescriptionBuilder("Role Deleted") .appendLine("Role: `%s`".formatted(role.getName()), true) .appendLine("Color: %s".formatted(RoleUtils.getFormattedColor(role)), true) .appendLine("Permissions: %s".formatted(RoleUtils.getFormattedPermissions(role)), true) @@ -99,7 +99,7 @@ public class RoleListener implements EventListener { String newName = event.getNewName(); log.info("Role \"{}\" was renamed to \"{}\" in guild \"{}\"", oldName, newName, guild.getName()); logFeature.sendLog(guild, LogType.ROLE_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Renamed") + .setDescription(new DescriptionBuilder("Role Renamed") .appendLine("Role: %s".formatted(event.getRole().getAsMention()), true) .appendLine("Name: `%s` -> `%s`".formatted(oldName, newName), true) .build()) @@ -113,7 +113,7 @@ public class RoleListener implements EventListener { log.info("Role \"{}\" color was updated in guild \"{}\"", event.getRole().getName(), guild.getName()); logFeature.sendLog(guild, LogType.ROLE_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Color Updated") + .setDescription(new DescriptionBuilder("Role Color Updated") .appendLine("Role: %s".formatted(event.getRole().getAsMention()), true) .appendLine("Color: %s -> %s".formatted( RoleUtils.getFormattedColor(oldColor), @@ -130,7 +130,7 @@ public class RoleListener implements EventListener { log.info("Role \"{}\" icon was updated in guild \"{}\"", event.getRole().getName(), guild.getName()); logFeature.sendLog(guild, LogType.ROLE_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Icon Updated") + .setDescription(new DescriptionBuilder("Role Icon Updated") .appendLine("Role: %s".formatted(event.getRole().getAsMention()), true) .appendLine("Icon: `%s` -> `%s`".formatted( oldIcon == null ? "None" : oldIcon.getEmoji(), @@ -144,7 +144,7 @@ public class RoleListener implements EventListener { public void onRoleUpdateHoisted(@NonNull BatGuild guild, @NonNull Role role, boolean wasHoisted, boolean isHoisted, @NonNull RoleUpdateHoistedEvent event) { log.info("Role \"{}\" hoisted status was updated in guild \"{}\"", role.getName(), guild.getName()); logFeature.sendLog(guild, LogType.ROLE_CONFIGURATION, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Role Hoisted Status Updated") + .setDescription(new DescriptionBuilder("Role Hoisted Status Updated") .appendLine("Role: %s".formatted(role.getAsMention()), true) .appendLine("Hoisted: `%s` -> `%s`".formatted( wasHoisted ? "Yes" : "No", diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/StickerListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/StickerListener.java index 8184b8a..961c62a 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/StickerListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/StickerListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.logging.listeners; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogFeature; @@ -32,7 +32,7 @@ public class StickerListener implements EventListener { public void onGuildStickerAdd(@NonNull BatGuild guild, @NonNull GuildSticker sticker, @NonNull GuildStickerAddedEvent event) { log.info("Sticker \"{}\" was added in guild \"{}\"", sticker.getName(), guild.getName()); logFeature.sendLog(guild, LogType.STICKER_ADD, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Sticker Added") + .setDescription(new DescriptionBuilder("Sticker Added") .appendLine("Sticker: %s".formatted(sticker.getName()), true) .appendLine("URL: %s".formatted(sticker.getIconUrl()), true) .build()) @@ -43,7 +43,7 @@ public class StickerListener implements EventListener { public void onGuildStickerRemove(@NonNull BatGuild guild, @NonNull GuildSticker sticker, @NonNull GuildStickerRemovedEvent event) { log.info("Sticker \"{}\" was removed in guild \"{}\"", sticker.getName(), guild.getName()); logFeature.sendLog(guild, LogType.STICKER_REMOVE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Sticker Removed") + .setDescription(new DescriptionBuilder("Sticker Removed") .appendLine("Sticker: %s".formatted(sticker.getName()), true) .appendLine("URL: %s".formatted(sticker.getIconUrl()), true) .build()) @@ -55,7 +55,7 @@ public class StickerListener implements EventListener { @NonNull String newName, @NonNull GuildStickerUpdateNameEvent event) { log.info("Sticker \"{}\" was renamed in guild \"{}\" from \"{}\" to \"{}\"", sticker.getName(), guild.getName(), oldName, newName); logFeature.sendLog(guild, LogType.STICKER_NAME_UPDATED, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("Sticker Renamed") + .setDescription(new DescriptionBuilder("Sticker Renamed") .appendLine("Sticker: %s".formatted(sticker.getName()), true) .appendLine("Name: `%s` -> `%s`".formatted(oldName, newName), true) .build()) diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java index 1593477..e38e2ba 100644 --- a/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.messagesnipe.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.PasteUtils; import cc.fascinated.bat.features.messagesnipe.MessageSnipeFeature; @@ -36,7 +36,7 @@ public class DeletedSubCommand extends BatCommand { String content = message.getMessage().getContentStripped(); String formattedContent = content.length() > 512 ? PasteUtils.uploadPaste(content).getUrl() : "```\n%s\n```".formatted(content); event.replyEmbeds(EmbedUtils.genericEmbed() - .setDescription(new EmbedDescriptionBuilder("Deleted Message Snipe") + .setDescription(new DescriptionBuilder("Deleted Message Snipe") .appendLine("Author: **%s** (%s)".formatted(author.getAsMention(), author.getId()), true) .appendLine("Deleted: ".formatted(message.getDeletedDate().getTime() / 1000), true) .appendLine("Content: %s".formatted(formattedContent), true) diff --git a/src/main/java/cc/fascinated/bat/features/minecraft/MinecraftProfile.java b/src/main/java/cc/fascinated/bat/features/minecraft/MinecraftProfile.java index cf03cf9..ff94965 100644 --- a/src/main/java/cc/fascinated/bat/features/minecraft/MinecraftProfile.java +++ b/src/main/java/cc/fascinated/bat/features/minecraft/MinecraftProfile.java @@ -86,7 +86,7 @@ public class MinecraftProfile extends Serializable { } server.setLastState(isOnline); EmbedBuilder embedBuilder = isOnline ? EmbedUtils.successEmbed() : EmbedUtils.errorEmbed(); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Server Watcher"); + DescriptionBuilder description = new DescriptionBuilder("Server Watcher"); description.appendLine("%s %s server `%s` is now **%s**".formatted( isOnline ? Emojis.CHECK_MARK_EMOJI : Emojis.CROSS_MARK_EMOJI, EnumUtils.getEnumName(server.getPlatform()), diff --git a/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupPlayerSubCommand.java b/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupPlayerSubCommand.java index ff12224..4833d36 100644 --- a/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupPlayerSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupPlayerSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.minecraft.command.minecraft; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; @@ -46,7 +46,7 @@ public class LookupPlayerSubCommand extends BatCommand { } String headUrl = cachedPlayer.getSkin() != null ? cachedPlayer.getSkin().getParts().get(Skin.SkinPart.HEAD.getName()) : null; - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Player Lookup") + DescriptionBuilder description = new DescriptionBuilder("Player Lookup") .appendLine("Username: `%s`".formatted(cachedPlayer.getUsername()), true) .appendLine("UUID: `%s`".formatted(cachedPlayer.getUniqueId().toString()), true); if (cachedPlayer.getSkin() != null) { diff --git a/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupServerSubCommand.java b/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupServerSubCommand.java index df43db9..43fc9b7 100644 --- a/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupServerSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/minecraft/command/minecraft/LookupServerSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.minecraft.command.minecraft; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; @@ -62,7 +62,7 @@ public class LookupServerSubCommand extends BatCommand { int platformDefaultPort = platform.equalsIgnoreCase("java") ? 25565 : 19132; String hostname = server.getHostname() + (server.getPort() != platformDefaultPort ? ":" + server.getPort() : ""); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Server Lookup [(Raw Data)](%s)".formatted( + DescriptionBuilder description = new DescriptionBuilder("Server Lookup [(Raw Data)](%s)".formatted( "https://api.mcutils.xyz/server/%s/%s".formatted(platform, hostname) )); description.appendLine("Host: `%s`".formatted(hostname), true); diff --git a/src/main/java/cc/fascinated/bat/features/minecraft/command/serverwatcher/ListSubCommand.java b/src/main/java/cc/fascinated/bat/features/minecraft/command/serverwatcher/ListSubCommand.java index d4c94a6..95de921 100644 --- a/src/main/java/cc/fascinated/bat/features/minecraft/command/serverwatcher/ListSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/minecraft/command/serverwatcher/ListSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.minecraft.command.serverwatcher; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.EnumUtils; import cc.fascinated.bat.features.minecraft.MinecraftProfile; @@ -38,7 +38,7 @@ public class ListSubCommand extends BatCommand { for (ServerWatcher server : profile.getServerWatchers()) { watchers.computeIfAbsent(server.getPlatform(), k -> new ArrayList<>()).add(server); } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Server Watcher"); + DescriptionBuilder description = new DescriptionBuilder("Server Watcher"); description.appendLine("Here is a list of all the servers being watched", false); description.emptyLine(); diff --git a/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java b/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java index fba6f3a..e05bf90 100644 --- a/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java +++ b/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java @@ -1,23 +1,111 @@ package cc.fascinated.bat.features.moderation; +import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.FeatureProfile; -import cc.fascinated.bat.features.moderation.command.PurgeCommand; +import cc.fascinated.bat.features.moderation.command.*; +import cc.fascinated.bat.features.moderation.punish.Punishment; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.CommandService; +import cc.fascinated.bat.service.DiscordService; +import cc.fascinated.bat.service.GuildService; +import cc.fascinated.bat.service.UserService; import lombok.NonNull; +import lombok.extern.log4j.Log4j2; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.unions.ChannelUnion; +import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.time.Instant; +import java.util.List; +import java.util.Map; + /** * @author Fascinated (fascinated7) */ @Component -public class ModerationFeature extends Feature { +@Log4j2 +public class ModerationFeature extends Feature implements EventListener { + private final GuildService guildService; + private final UserService userService; + @Autowired - public ModerationFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { + public ModerationFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService, @NonNull GuildService guildService, + @NonNull UserService userService) { super("Moderation", FeatureProfile.FeatureState.DISABLED, true); + this.guildService = guildService; + this.userService = userService; super.registerCommand(commandService, context.getBean(PurgeCommand.class)); + super.registerCommand(commandService, context.getBean(WarnCommand.class)); + super.registerCommand(commandService, context.getBean(KickCommand.class)); + super.registerCommand(commandService, context.getBean(BanCommand.class)); + super.registerCommand(commandService, context.getBean(MuteCommand.class)); + super.registerCommand(commandService, context.getBean(UnbanCommand.class)); + super.registerCommand(commandService, context.getBean(UnmuteCommand.class)); + super.registerCommand(commandService, context.getBean(PunishHistoryCommand.class)); + } + + /** + * This method is called every minute to check + * the status of temporary punishments + */ + @Scheduled(cron = "0 * * * * *") + public void checkTemporaryPunishments() { + for (Guild guild : DiscordService.JDA.getGuilds()) { + BatGuild batGuild = guildService.getGuild(guild.getId()); + if (batGuild.getFeatureProfile().isFeatureDisabled(this)) { // Check if the feature is disabled + continue; + } + + PunishmentProfile profile = batGuild.getPunishmentProfile(); + + for (Map.Entry> entry : profile.getPunishments().entrySet()) { + BatUser user = userService.getUser(entry.getKey()); + if (user == null) { // This should never happen + continue; + } + + for (Punishment punishment : entry.getValue()) { + // Check if the punishment is not temporary and has not expired + if (punishment.getEndDate() == null + || punishment.isExpired() + || punishment.getEndDate().toInstant().isAfter(Instant.now())) { + continue; + } + BatUser issuer = userService.getUser(punishment.getIssuer()); + punishment.setExpired(true); + profile.removePunishment( + user, + issuer, + batGuild, + punishment.getType(), + punishment.getReason() + ); + log.info("Expired punishment for user {}", user.getDiscordUser().getEffectiveName()); + } + } + } + } + + @Override + public void onChannelCreate(@NonNull BatGuild guild, @NonNull ChannelCreateEvent event) { + if (guild.getFeatureProfile().isFeatureDisabled(this)) { // Check if the feature is disabled + return; + } + + PunishmentProfile profile = guild.getPunishmentProfile(); + ChannelUnion channelUnion = event.getChannel(); + if (channelUnion.getType() != ChannelType.TEXT) { + return; + } + profile.upsetMutedRolePermissions(guild, channelUnion.asGuildChannel()); } } diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/BanCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/BanCommand.java new file mode 100644 index 0000000..1d1aa6e --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/BanCommand.java @@ -0,0 +1,75 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.TimeUtils; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "ban", + description = "Bans a member", + requiredPermissions = Permission.BAN_MEMBERS +) +public class BanCommand extends BatCommand { + private final UserService userService; + + @Autowired + public BanCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to ban", true), + new OptionData(OptionType.STRING, "reason", "The reason for the ban", false), + new OptionData(OptionType.STRING, "length", "The length of the ban", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + OptionMapping lengthOption = event.getOption("length"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + long length = lengthOption == null ? -1 : TimeUtils.fromString(lengthOption.getAsString()); + + if (lengthOption != null && length == -1) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("Invalid length provided") + .build() + ).queue(); + return; + } + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot ban this user") + .build() + ).queue(); + return; + } + + profile.temporaryPunish(targetUser, user, guild, PunishmentType.BAN, reason, length); + profile.punishmentResponse(event, PunishmentType.BAN, targetUser, reason, false, length); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/KickCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/KickCommand.java new file mode 100644 index 0000000..3686ef1 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/KickCommand.java @@ -0,0 +1,65 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.RoleUtils; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "kick", + description = "Kicks a member", + requiredPermissions = Permission.KICK_MEMBERS +) +public class KickCommand extends BatCommand { + private final UserService userService; + + @Autowired + public KickCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to kick", true), + new OptionData(OptionType.STRING, "reason", "The reason for the kick", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + assert event.getGuild() != null; + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot kick this user") + .build() + ).queue(); + return; + } + + profile.punishMember(targetUser, user, guild, PunishmentType.KICK, reason); + profile.punishmentResponse(event, PunishmentType.BAN, targetUser, reason, false, -1); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/MuteCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/MuteCommand.java new file mode 100644 index 0000000..5fab7a6 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/MuteCommand.java @@ -0,0 +1,75 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.TimeUtils; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "mute", + description = "Mutes a member", + requiredPermissions = Permission.MANAGE_CHANNEL +) +public class MuteCommand extends BatCommand { + private final UserService userService; + + @Autowired + public MuteCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to mute", true), + new OptionData(OptionType.STRING, "reason", "The reason for the mute", false), + new OptionData(OptionType.STRING, "length", "The length of the mute", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + OptionMapping lengthOption = event.getOption("length"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + long length = lengthOption == null ? -1 : TimeUtils.fromString(lengthOption.getAsString()); + + if (lengthOption != null && length == -1) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("Invalid length provided") + .build() + ).queue(); + return; + } + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot mute this user") + .build() + ).queue(); + return; + } + + profile.temporaryPunish(targetUser, user, guild, PunishmentType.MUTE, reason, length); + profile.punishmentResponse(event, PunishmentType.MUTE, targetUser, reason, false, length); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/PunishHistoryCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/PunishHistoryCommand.java new file mode 100644 index 0000000..7392d52 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/PunishHistoryCommand.java @@ -0,0 +1,102 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.DescriptionBuilder; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.moderation.punish.Punishment; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import com.github.ygimenez.method.Pages; +import com.github.ygimenez.model.InteractPage; +import com.github.ygimenez.model.Page; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "punish-history", + description = "View the punishment history of a member", + requiredPermissions = Permission.MANAGE_SERVER +) +public class PunishHistoryCommand extends BatCommand { + private static final int PUNISHMENTS_PER_PAGE = 10; + private final UserService userService; + + @Autowired + public PunishHistoryCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to view the punishment history of", true) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + + PunishmentProfile profile = guild.getPunishmentProfile(); + List punishments = profile.getPunishments(targetUser); + + List pages = new ArrayList<>(); + int totalPages = (int) Math.ceil((double) punishments.size() / PUNISHMENTS_PER_PAGE); + + if (totalPages >= 1) { + for (int i = 0; i < totalPages; i++) { + int fromIndex = i * PUNISHMENTS_PER_PAGE; + int toIndex = Math.min(fromIndex + PUNISHMENTS_PER_PAGE, punishments.size()); + List subList = punishments.subList(fromIndex, toIndex); + DescriptionBuilder history = new DescriptionBuilder("Punishment history for %s".formatted(targetUser.getDiscordUser().getAsMention())); + + for (Punishment punishment : subList) { + BatUser issuer = userService.getUser(punishment.getIssuer()); + history.appendLine("> **[%s%s]** Reason: `%s` | Issuer: %s%s".formatted( + punishment.getEndDate() != null ? "TEMP-" : "", + punishment.getType().name(), + punishment.getIssuedDate().toInstant().getEpochSecond(), + punishment.getReason() == null ? "N/A" : punishment.getReason(), + issuer.getDiscordUser().getAsMention(), + punishment.isExpired() ? " **(Expired)**" : "" + ), false); + } + + pages.add(InteractPage.of(EmbedUtils.successEmbed() + .setDescription(history.build()) + .setFooter("Page %d/%d".formatted(i + 1, totalPages)) + .build())); + } + } else { + pages.add(InteractPage.of(EmbedUtils.successEmbed() + .setDescription("No punishments found for %s".formatted(targetUser.getDiscordUser().getAsMention())) + .build())); + } + + event.replyEmbeds((MessageEmbed) pages.get(0).getContent()).queue(success -> { + if (pages.size() < 2) { // If there is only one page, we don't need to paginate + return; + } + success.retrieveOriginal().queue(message -> { + Pages.paginate(message, pages, true, (interactedUser) -> interactedUser.getIdLong() == user.getDiscordUser().getIdLong()); + }); + }); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java index ac7c712..5159f3a 100644 --- a/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java @@ -3,7 +3,11 @@ package cc.fascinated.bat.features.moderation.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.NumberFormatter; +import cc.fascinated.bat.features.logging.LogFeature; +import cc.fascinated.bat.features.logging.LogType; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import lombok.NonNull; @@ -16,6 +20,9 @@ import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @@ -28,8 +35,11 @@ import java.util.concurrent.TimeUnit; @CommandInfo(name = "purge", description = "Purge messages from a channel", requiredPermissions = Permission.MESSAGE_MANAGE, category = Category.MODERATION) public class PurgeCommand extends BatCommand { private final long MESSAGE_DELETE_DELAY = TimeUnit.SECONDS.toMillis(10); + private final LogFeature logFeature; - public PurgeCommand() { + @Autowired + public PurgeCommand(@NonNull LogFeature logFeature) { + this.logFeature = logFeature; super.addOptions(new OptionData(OptionType.INTEGER, "amount", "The amount of messages to remove", true)); } @@ -55,12 +65,21 @@ public class PurgeCommand extends BatCommand { then.retrieveOriginal().queue(original -> { if (original == null) return; List toRemove = messages.stream().filter(message -> !original.getId().equals(message.getId())).toList(); - textChannel.deleteMessages(toRemove).queue(done -> then.editOriginalEmbeds(EmbedUtils.successEmbed() - .setDescription("Successfully purged `%s` messages\n\n*This message will be removed *".formatted( - amount, - (System.currentTimeMillis() + MESSAGE_DELETE_DELAY) / 1000 - )) - .build()).queue(message -> message.delete().queueAfter(MESSAGE_DELETE_DELAY, TimeUnit.MILLISECONDS))); + textChannel.deleteMessages(toRemove).queue(done -> { + then.editOriginalEmbeds(EmbedUtils.successEmbed() + .setDescription("Successfully purged `%s` messages\n\n*This message will be removed *".formatted( + amount, + (System.currentTimeMillis() + MESSAGE_DELETE_DELAY) / 1000 + )) + .build()).queue(message -> message.delete().queueAfter(MESSAGE_DELETE_DELAY, TimeUnit.MILLISECONDS)); + logFeature.sendLog(guild, LogType.PURGE, EmbedUtils.successEmbed() + .setDescription(new DescriptionBuilder("Purged Messages") + .appendLine("Amount: `%s`".formatted(NumberFormatter.simpleFormat(amount)), true) + .appendLine("Channel: %s".formatted(textChannel.getAsMention()), true) + .appendLine("Issuer: %s".formatted(member.getAsMention()), true) + .build()) + .build()); + }); }); }); }); diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/UnbanCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/UnbanCommand.java new file mode 100644 index 0000000..00f5d9a --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/UnbanCommand.java @@ -0,0 +1,72 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.moderation.punish.Punishment; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "unban", + description = "Un-bans a member", + requiredPermissions = Permission.BAN_MEMBERS +) +public class UnbanCommand extends BatCommand { + private final UserService userService; + + @Autowired + public UnbanCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.STRING, "member", "The ID of the member you want to un-ban", true), + new OptionData(OptionType.STRING, "reason", "The reason for the un-ban", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsString()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot unban this user") + .build() + ).queue(); + return; + } + + Punishment punishment = profile.removePunishment(targetUser, user, guild, PunishmentType.BAN, reason); + if (punishment == null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("This user is not banned") + .build() + ).queue(); + return; + } + + profile.punishmentResponse(event, PunishmentType.BAN, targetUser, reason, true, -1); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/UnmuteCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/UnmuteCommand.java new file mode 100644 index 0000000..e059a82 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/UnmuteCommand.java @@ -0,0 +1,72 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.moderation.punish.Punishment; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "unmute", + description = "Un-mutes a member", + requiredPermissions = Permission.MANAGE_CHANNEL +) +public class UnmuteCommand extends BatCommand { + private final UserService userService; + + @Autowired + public UnmuteCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to un-mute", true), + new OptionData(OptionType.STRING, "reason", "The reason for the un-mute", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot unmute this user") + .build() + ).queue(); + return; + } + + Punishment punishment = profile.removePunishment(targetUser, user, guild, PunishmentType.MUTE, reason); + if (punishment == null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("This user is not muted") + .build() + ).queue(); + return; + } + + profile.punishmentResponse(event, PunishmentType.MUTE, targetUser, reason, true, -1); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/WarnCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/WarnCommand.java new file mode 100644 index 0000000..df4abd1 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/WarnCommand.java @@ -0,0 +1,63 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.UserService; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo( + name = "warn", + description = "Warns a member", + requiredPermissions = Permission.MANAGE_CHANNEL +) +public class WarnCommand extends BatCommand { + private final UserService userService; + + @Autowired + public WarnCommand(@NonNull UserService userService) { + this.userService = userService; + super.addOptions( + new OptionData(OptionType.USER, "member", "The member you want to warn", true), + new OptionData(OptionType.STRING, "reason", "The reason for the warning", false) + ); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping memberOption = event.getOption("member"); + OptionMapping reasonOption = event.getOption("reason"); + assert memberOption != null; + BatUser targetUser = userService.getUser(memberOption.getAsUser().getId()); + String reason = reasonOption == null ? null : reasonOption.getAsString(); + + PunishmentProfile profile = guild.getPunishmentProfile(); + if (!profile.canPunish(guild, user, targetUser)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You cannot warn this user") + .build() + ).queue(); + return; + } + + profile.punishMember(targetUser, user, guild, PunishmentType.WARN, reason); + profile.punishmentResponse(event, PunishmentType.WARN, targetUser, reason, false, -1); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/punish/Punishment.java b/src/main/java/cc/fascinated/bat/features/moderation/punish/Punishment.java new file mode 100644 index 0000000..2bb1970 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/punish/Punishment.java @@ -0,0 +1,45 @@ +package cc.fascinated.bat.features.moderation.punish; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor +@Getter +@Setter +public class Punishment { + /** + * The type of punishment + */ + private final PunishmentType type; + + /** + * The reason for the punishment + */ + private final String reason; + + /** + * The member who issued out this punishment + */ + private final String issuer; + + /** + * The date the punishment was issued + */ + private final Date issuedDate; + + /** + * The time the punishment will end, if temporary + */ + private Date endDate; + + /** + * If the punishment has expired + */ + private boolean expired; +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentProfile.java b/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentProfile.java new file mode 100644 index 0000000..86fcdb9 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentProfile.java @@ -0,0 +1,395 @@ +package cc.fascinated.bat.features.moderation.punish; + +import cc.fascinated.bat.common.*; +import cc.fascinated.bat.features.logging.LogFeature; +import cc.fascinated.bat.features.logging.LogType; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import com.google.gson.Gson; +import lombok.Getter; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.PermissionOverride; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.bson.Document; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author Fascinated (fascinated7) + */ +@Getter +public class PunishmentProfile extends Serializable { + /** + * The punishments issued in this guild + */ + private final Map> punishments = new HashMap<>(); + + /** + * Punish a member + * + * @param user The user to punish + * @param issuer The issuer of the punishment + * @param guild The guild the punishment is being issued in + * @param type The type of punishment + * @param reasonString The reason for the punishment + * @param length The length of the punishment + * @return The punishment issued + */ + private Punishment punishMember(BatUser user, BatUser issuer, BatGuild guild, PunishmentType type, String reasonString, long length) { + Punishment punishment = new Punishment( + type, + reasonString, + issuer.getId(), + new Date(), + length == -1 ? null : new Date(System.currentTimeMillis() + length), + false + ); + List userPunishments = this.punishments.getOrDefault(user.getId(), new ArrayList<>()); + + Punishment previousPunishment = this.getLatestActivePunishment(user, type); + // Expire the previous punishment + if (previousPunishment != null && + (previousPunishment.getType() == PunishmentType.MUTE || previousPunishment.getType() == PunishmentType.BAN)) { + previousPunishment.setExpired(true); + } + userPunishments.add(punishment); + this.punishments.put(user.getId(), userPunishments); + + String reason = reasonString == null ? "No reason provided" : reasonString; + String lengthFormatted = TimeUtils.format(length); + + Guild discordGuild = guild.getDiscordGuild(); + DescriptionBuilder punishmentDescription = new DescriptionBuilder("%s Issued".formatted(EnumUtils.getEnumName(type))) + .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) + .appendLine("Issuer: %s".formatted(issuer.getDiscordUser().getAsMention()), true) + .appendLine("Reason: `%s`".formatted(reason), true); + // Only applicable for Mutes and Bans + if (type == PunishmentType.MUTE || type == PunishmentType.BAN) { + punishmentDescription.appendLine("Length: `%s`".formatted(length == -1 ? "Permanent" : lengthFormatted), true); + } + LogFeature.INSTANCE.sendLog(guild, LogType.PUNISHMENT_ISSUED, EmbedUtils.successEmbed() + .setDescription(punishmentDescription.build()) + .build()); + + String name = EnumUtils.getEnumName(type).endsWith("e") ? EnumUtils.getEnumName(type) + "d" : EnumUtils.getEnumName(type) + "ed"; + user.getDiscordUser().openPrivateChannel().queue(channel -> { + DescriptionBuilder descriptionBuilder = new DescriptionBuilder(null); + descriptionBuilder.appendLine("🛡️ You have been **%s** in **%s**".formatted( + name, + discordGuild.getName() + ), false); + if (length != -1 && (type == PunishmentType.MUTE || type == PunishmentType.BAN)) { + descriptionBuilder.appendLine("Length: %s".formatted(lengthFormatted), true); + } + descriptionBuilder.appendLine("Reason: %s".formatted(reason), true); + try { + channel.sendMessage(descriptionBuilder.build()).complete(); + } catch (Exception ignored) { + } // Ignore since the user has DMs disabled + }); + + switch (type) { + case BAN -> discordGuild.ban(user.getDiscordUser(), 0, TimeUnit.SECONDS).queue(); + case KICK -> discordGuild.kick(user.getDiscordUser()).queue(); + case MUTE -> { + this.ensureMutedPermissionsAreSetup(guild); // Ensure the muted role permissions are set up + Role mutedRole = this.findOrCreateMutedRole(guild); + discordGuild.addRoleToMember(user.getDiscordUser(), mutedRole).queue(); + } + } + return punishment; + } + + /** + * Punish a member + * + * @param user The user to punish + * @param issuer The issuer of the punishment + * @param guild The guild the punishment is being issued in + * @param type The type of punishment + * @param reason The reason for the punishment + * @return The punishment issued + */ + public Punishment punishMember(BatUser user, BatUser issuer, BatGuild guild, PunishmentType type, String reason) { + return this.punishMember(user, issuer, guild, type, reason, -1); + } + + /** + * Temporarily punish a member + * + * @param user The user to punish + * @param issuer The issuer of the punishment + * @param guild The guild the punishment is being issued in + * @param type The type of punishment + * @param reason The reason for the punishment + * @param length The length of the punishment + * @return The punishment issued + */ + public Punishment temporaryPunish(BatUser user, BatUser issuer, BatGuild guild, PunishmentType type, String reason, long length) { + return this.punishMember(user, issuer, guild, type, reason, length); + } + + /** + * Remove a punishment from a user + * + * @param user The user to remove the punishment from + * @param issuer The issuer of the punishment removal + * @param guild The guild the punishment is being removed from + * @param type The type of punishment + * @param reason The reason for the punishment removal + */ + public Punishment removePunishment(BatUser user, BatUser issuer, BatGuild guild, PunishmentType type, String reason) { + Punishment punishment = this.getLatestActivePunishment(user, type); + if (punishment == null && type != PunishmentType.BAN) { + return null; + } + if (punishment == null) { // In case they are unbanning a user that wasn't banned by the bot + punishment = new Punishment(type, reason, issuer.getId(), new Date(), null, false); + } + + switch (type) { + case BAN -> guild.getDiscordGuild().unban(user.getDiscordUser()).queue(); + case MUTE -> { + Role mutedRole = this.findOrCreateMutedRole(guild); + guild.getDiscordGuild().removeRoleFromMember(user.getDiscordUser(), mutedRole).queue(); + } + } + + DescriptionBuilder descriptionBuilder = new DescriptionBuilder("%s Removed".formatted(EnumUtils.getEnumName(type))) + .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) + .appendLine("Issuer: %s".formatted(issuer.getDiscordUser().getAsMention()), true) + .appendLine("Reason: `%s`".formatted(reason), true); + LogFeature.INSTANCE.sendLog(guild, LogType.PUNISHMENT_REMOVED_OR_EXPIRED, EmbedUtils.successEmbed() + .setDescription(descriptionBuilder.build()) + .build()); + + user.getDiscordUser().openPrivateChannel().queue(channel -> { + DescriptionBuilder descriptionBuilder1 = new DescriptionBuilder(null); + descriptionBuilder1.appendLine("🛡️ Your **%s** in **%s** has been removed".formatted( + EnumUtils.getEnumName(type), + guild.getDiscordGuild().getName() + ), false); + try { + channel.sendMessage(descriptionBuilder1.build()).complete(); + } catch (Exception ignored) { + } // Ignore since the user has DMs disabled + }); + + punishment.setExpired(true); // Expire the punishment + return punishment; + } + + /** + * Gets the latest punishment for a user + * + * @param user The user to get the latest punishment for + * @param type The type of punishment + * @return The latest punishment + */ + public Punishment getLatestActivePunishment(BatUser user, PunishmentType type) { + List punishments = this.punishments.get(user.getId()); + if (punishments == null) { + return null; + } + return punishments.stream() + .filter(punishment -> punishment.getType() == type && !punishment.isExpired()) + .max(Comparator.comparing(Punishment::getIssuedDate)) + .orElse(null); + } + + /** + * Gets the punishments for a user + * + * @param user The user to get the punishments for + * @return The punishments + */ + public List getPunishments(BatUser user) { + return this.punishments.getOrDefault(user.getId(), new ArrayList<>()).stream() + .sorted(Comparator.comparing(Punishment::isExpired).reversed().thenComparing(Punishment::getIssuedDate).reversed()) + .toList(); + + } + + /** + * Gets the muted role for the Guild, if it + * doesn't exist the bot will create one + * + * @param guild The guild to get the muted role for + * @return The muted role + */ + public Role findOrCreateMutedRole(BatGuild guild) { + Guild discordGuild = guild.getDiscordGuild(); + Role mutedRole = discordGuild.getRolesByName("Muted", true).stream().findFirst().orElse(null); + if (mutedRole == null) { + return discordGuild.createRole() + .setName("Muted") + .complete(); + } + return mutedRole; + } + + /** + * Sets the muted role permissions for a channel + * + * @param guild the guild to get the muted role from + * @param channel the channel to set the permissions for + */ + public void upsetMutedRolePermissions(BatGuild guild, GuildChannel channel) { + PunishmentProfile profile = guild.getPunishmentProfile(); + Role mutedRole = profile.findOrCreateMutedRole(guild); + assert mutedRole != null; + + if (channel instanceof TextChannel textChannel) { + textChannel.upsertPermissionOverride(mutedRole) + .deny(Permission.MESSAGE_SEND) + .queue(); + return; + } + if (channel instanceof VoiceChannel voiceChannel) { + voiceChannel.upsertPermissionOverride(mutedRole) + .deny(Permission.VOICE_SPEAK) + .queue(); + } + } + + /** + * Ensures that the muted role permissions are + * set up for all channels + * + * @param guild the guild to check + */ + public void ensureMutedPermissionsAreSetup(BatGuild guild) { + Role mutedRole = this.findOrCreateMutedRole(guild); + for (GuildChannel channel : guild.getDiscordGuild().getChannels()) { + for (PermissionOverride override : channel.getPermissionContainer().getRolePermissionOverrides()) { + Role role = override.getRole(); + assert role != null; + if (role.getId().equals(mutedRole.getId())) { + return; + } + } + this.upsetMutedRolePermissions(guild, channel); + } + } + + /** + * Inform the user that the punishment was applied + * + * @param event The event to respond to + * @param type The type of punishment + * @param targetUser The user that was punished + * @param reason The reason for the punishment + * @param length The length of the punishment + */ + public void punishmentResponse(SlashCommandInteraction event, PunishmentType type, BatUser targetUser, String reason, boolean remove, long length) { + String name = EnumUtils.getEnumName(type).endsWith("e") ? EnumUtils.getEnumName(type) + "d" : EnumUtils.getEnumName(type) + "ed"; + DescriptionBuilder description = new DescriptionBuilder("Successfully %s%s %s".formatted( + remove ? "Un-" : "", + name, + targetUser.getDiscordUser().getAsMention() + )); + description.appendLine("Reason: %s".formatted(reason == null ? "No reason provided" : reason), true); + if (length != -1) { + description.appendLine("Length: %s".formatted(TimeUtils.format(length)), true); + } + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription(description.build()) + .build() + ).queue(); + } + + /** + * Check if a user can be punished + * + * @param guild The guild to check + * @param issuer The issuer of the punishment + * @param targetUser The user to punish + * @return If the user can be punished + */ + public boolean canPunish(BatGuild guild, BatUser issuer, BatUser targetUser) { + Member owner = guild.getDiscordGuild().getOwner(); + assert owner != null; + + if (targetUser == null) { + return false; + } + + // Check if the target user is the owner + if (owner.getId().equals(targetUser.getId())) { + return false; + } + + // Check if the target user is the bot + if (targetUser.getId().equals(guild.getDiscordGuild().getSelfMember().getId())) { + return false; + } + + // Check if the target user is the same as the issuer + if (targetUser.getId().equals(issuer.getId())) { + return false; + } + + // Check if the target user has a higher role than the bot + Member member = guild.getDiscordGuild().getMemberById(targetUser.getId()); + assert member != null; + if (RoleUtils.hasHigherRole(member, guild.getDiscordGuild().getSelfMember())) { + return false; + } + + return true; + } + + @Override + public void load(Document document, Gson gson) { + Document punishmentsDocument = (Document) document.getOrDefault("punishments", new Document()); + for (String key : punishmentsDocument.keySet()) { + List punishmentList = punishmentsDocument.getList(key, Document.class, new ArrayList<>()); + List punishments = new ArrayList<>(); + for (Document punishmentDocument : punishmentList) { + punishments.add(new Punishment( + PunishmentType.valueOf(punishmentDocument.getString("type")), + punishmentDocument.getString("reason"), + punishmentDocument.getString("issuer"), + punishmentDocument.getDate("issuedDate"), + punishmentDocument.getDate("endDate"), + punishmentDocument.getBoolean("expired", false) + )); + } + this.punishments.put(key, punishments); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + Document punishmentsDocument = new Document(); + for (String key : this.punishments.keySet()) { + List punishmentList = new ArrayList<>(); + for (Punishment punishment : this.punishments.get(key)) { + Document punishmentDocument = new Document(); + punishmentDocument.append("type", punishment.getType().name()); + punishmentDocument.append("reason", punishment.getReason()); + punishmentDocument.append("issuer", punishment.getIssuer()); + punishmentDocument.append("issuedDate", punishment.getIssuedDate()); + punishmentDocument.append("endDate", punishment.getEndDate()); + punishmentDocument.append("expired", punishment.isExpired()); + punishmentList.add(punishmentDocument); + } + punishmentsDocument.append(key, punishmentList); + } + document.append("punishments", punishmentsDocument); + return document; + } + + @Override + public void reset() { + this.punishments.clear(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentType.java b/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentType.java new file mode 100644 index 0000000..7144ab0 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/punish/PunishmentType.java @@ -0,0 +1,11 @@ +package cc.fascinated.bat.features.moderation.punish; + +/** + * @author Fascinated (fascinated7) + */ +public enum PunishmentType { + KICK, + BAN, + WARN, + MUTE +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java index 010bddb..1794f61 100644 --- a/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.reminder.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.reminder.Reminder; import cc.fascinated.bat.features.reminder.ReminderProfile; @@ -30,7 +30,7 @@ public class ListSubCommand extends BatCommand { return; } - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Active Reminders"); + DescriptionBuilder description = new DescriptionBuilder("Active Reminders"); for (Reminder reminder : profile.getReminders(user.getDiscordUser())) { description.appendLine("%s - %s".formatted( reminder.getReminder(), diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java index 9629f7e..615faa2 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java @@ -122,7 +122,7 @@ public class ScoreSaberCommand extends BatCommand { String timeTaken = TimeUtils.format(System.currentTimeMillis() - before, TimeUtils.BatTimeFormat.FIT, true); message.editOriginalEmbeds(EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("%s's ScoreSaber Account".formatted(user.getDiscordUser().getAsMention())) + .setDescription(new DescriptionBuilder("%s's ScoreSaber Account".formatted(user.getDiscordUser().getAsMention())) .appendLine("Name: `%s`".formatted(name), true) .appendLine("Country: `%s`".formatted(country), true) .appendLine("Rank: `#%s`".formatted(rank), true) diff --git a/src/main/java/cc/fascinated/bat/features/statschannel/command/AddSubCommand.java b/src/main/java/cc/fascinated/bat/features/statschannel/command/AddSubCommand.java index 98a69d3..f83a901 100644 --- a/src/main/java/cc/fascinated/bat/features/statschannel/command/AddSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/statschannel/command/AddSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.statschannel.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.statschannel.StatsChannelProfile; import cc.fascinated.bat.model.BatGuild; @@ -66,7 +66,7 @@ public class AddSubCommand extends BatCommand { profile.refreshChannels(guild); // For the stat channels to be updated event.replyEmbeds(EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("%s The stats channel %s has been created".formatted( + .setDescription(new DescriptionBuilder("%s The stats channel %s has been created".formatted( Emojis.CHECK_MARK_EMOJI, voiceChannel.getAsMention() )) diff --git a/src/main/java/cc/fascinated/bat/features/statschannel/command/CurrentSubCommand.java b/src/main/java/cc/fascinated/bat/features/statschannel/command/CurrentSubCommand.java index d595882..3954100 100644 --- a/src/main/java/cc/fascinated/bat/features/statschannel/command/CurrentSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/statschannel/command/CurrentSubCommand.java @@ -2,7 +2,7 @@ package cc.fascinated.bat.features.statschannel.command; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.statschannel.StatsChannel; import cc.fascinated.bat.features.statschannel.StatsChannelFeature; @@ -30,7 +30,7 @@ public class CurrentSubCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { StatsChannelProfile profile = guild.getStatsChannelProfile(); - EmbedDescriptionBuilder builder = new EmbedDescriptionBuilder("Stats Channels"); + DescriptionBuilder builder = new DescriptionBuilder("Stats Channels"); if (profile.getChannels().isEmpty()) { builder.appendLine("You have no stats channels set up", true); } else { diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java index 02f285f..915d9e6 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.welcomer.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.HexColorUtils; import cc.fascinated.bat.features.welcomer.WelcomerProfile; @@ -74,7 +74,7 @@ public class EmbedSubCommand extends BatCommand { boolean isMessageEnabled = profile.isMessage(); profile.setEmbed(title, description, color, pingBeforeSend); - EmbedDescriptionBuilder successDescription = new EmbedDescriptionBuilder("Welcomer Embed") + DescriptionBuilder successDescription = new DescriptionBuilder("Welcomer Embed") .appendLine("%s Successfully set the welcomer embed!".formatted(Emojis.CHECK_MARK_EMOJI), false); if (isMessageEnabled) { successDescription.appendLine("*This has removed the plain message welcomer*", false); diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java index 83ae477..2fd8a9f 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.welcomer.command; import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; -import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.DescriptionBuilder; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.welcomer.WelcomerPlaceholders; import cc.fascinated.bat.features.welcomer.WelcomerProfile; @@ -39,7 +39,7 @@ public class MessageSubCommand extends BatCommand { boolean isEmbedEnabled = profile.isEmbed(); profile.setMessage(message); - EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Welcomer Message") + DescriptionBuilder description = new DescriptionBuilder("Welcomer Message") .appendLine("%s Set the message to `%s`".formatted(Emojis.CHECK_MARK_EMOJI, message), false); if (isEmbedEnabled) { description.appendLine("*This has removed the embed welcomer*", false); diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index 5748f4b..2fc9725 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -9,6 +9,7 @@ import cc.fascinated.bat.features.counter.CounterProfile; import cc.fascinated.bat.features.leveling.LevelingProfile; import cc.fascinated.bat.features.logging.LogProfile; import cc.fascinated.bat.features.minecraft.MinecraftProfile; +import cc.fascinated.bat.features.moderation.punish.PunishmentProfile; import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile; import cc.fascinated.bat.features.reminder.ReminderProfile; import cc.fascinated.bat.features.statschannel.StatsChannelProfile; @@ -190,6 +191,15 @@ public class BatGuild extends ProfileHolder { return getProfile(StatsChannelProfile.class); } + /** + * Gets the punishment profile + * + * @return the punishment profile + */ + public PunishmentProfile getPunishmentProfile() { + return getProfile(PunishmentProfile.class); + } + /** * Saves the user */ diff --git a/src/main/java/cc/fascinated/bat/service/DiscordService.java b/src/main/java/cc/fascinated/bat/service/DiscordService.java index b483042..c66e6b5 100644 --- a/src/main/java/cc/fascinated/bat/service/DiscordService.java +++ b/src/main/java/cc/fascinated/bat/service/DiscordService.java @@ -4,6 +4,8 @@ import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.common.TimerUtils; import cc.fascinated.bat.config.Config; import cc.fascinated.bat.event.EventListener; +import com.github.ygimenez.method.Pages; +import com.github.ygimenez.model.PaginatorBuilder; import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; @@ -60,6 +62,7 @@ public class DiscordService implements EventListener { CacheFlag.ONLINE_STATUS ).build() .awaitReady(); + Pages.activate(PaginatorBuilder.createSimplePaginator(JDA)); // Activate the paginator log.info("Connected to Discord as {}", JDA.getSelfUser().getEffectiveName()); TimerUtils.scheduleRepeating(this::updateActivity, 0, 1000 * 60 * 2); }