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);
}