From 42adb8238c66a2ca998ff6e78b514d32dfc7bcfa Mon Sep 17 00:00:00 2001 From: Arnold Alejo Nunag Date: Thu, 12 Nov 2020 01:17:09 +0800 Subject: [PATCH] Refactor, remove translations, add guild config system --- .../java/sciwhiz12/janitor/BotConsole.java | 5 - .../java/sciwhiz12/janitor/JanitorBot.java | 18 +- .../janitor/commands/BaseCommand.java | 11 +- .../janitor/commands/CommandRegistry.java | 26 ++- .../commands/moderation/BanCommand.java | 2 +- .../commands/moderation/KickCommand.java | 2 +- .../commands/moderation/NoteCommand.java | 13 +- .../commands/moderation/UnwarnCommand.java | 8 +- .../commands/moderation/WarnCommand.java | 8 +- .../commands/moderation/WarnListCommand.java | 14 +- .../sciwhiz12/janitor/config/BotConfig.java | 67 ++----- .../sciwhiz12/janitor/config/BotOptions.java | 20 +- .../janitor/config/ConfigManager.java | 44 +++++ .../sciwhiz12/janitor/config/GuildConfig.java | 183 ++++++++++++++++++ .../janitor/msg/ListingMessageBuilder.java | 25 +-- .../sciwhiz12/janitor/msg/MessageHelper.java | 23 +-- .../java/sciwhiz12/janitor/msg/Messages.java | 4 +- .../janitor/msg/RegularMessageBuilder.java | 14 +- .../sciwhiz12/janitor/msg/TranslationMap.java | 84 -------- .../janitor/msg/json/ListingMessage.java | 23 +-- .../janitor/msg/json/RegularMessage.java | 21 +- .../msg/substitution/CustomSubstitutions.java | 6 +- ...tutions.java => ICustomSubstitutions.java} | 2 +- .../msg/substitution/ISubstitutor.java | 5 +- .../msg/substitution/SubstitutionMap.java | 23 ++- src/main/resources/english.json | 117 ----------- .../general/error/ambiguous_member.json | 4 +- .../error/cannot_action_performer.json | 10 +- .../general/error/cannot_action_self.json | 3 +- .../general/error/cannot_interact.json | 5 +- .../general/error/guild_only_command.json | 3 +- .../error/insufficient_permissions.json | 5 +- .../resources/messages/moderation/ban/dm.json | 8 +- .../messages/moderation/ban/info.json | 16 +- .../moderation/error/cannot_interact.json | 10 +- .../error/insufficient_permissions.json | 10 +- .../error/note/max_amount_of_notes.json | 12 +- .../moderation/error/note/no_note_found.json | 15 +- .../unwarn/cannot_remove_higher_mod.json | 12 +- .../error/unwarn/cannot_unwarn_self.json | 12 +- .../error/unwarn/no_case_found.json | 15 +- .../error/warn/cannot_warn_mods.json | 10 +- .../messages/moderation/kick/dm.json | 8 +- .../messages/moderation/kick/info.json | 12 +- .../messages/moderation/note/add.json | 12 +- .../messages/moderation/note/list.json | 6 +- .../messages/moderation/note/remove.json | 14 +- .../messages/moderation/unban/info.json | 6 +- .../messages/moderation/unwarn/info.json | 16 +- .../messages/moderation/warn/dm.json | 10 +- .../messages/moderation/warn/info.json | 16 +- .../messages/moderation/warn/list.json | 6 +- 52 files changed, 473 insertions(+), 551 deletions(-) create mode 100644 src/main/java/sciwhiz12/janitor/config/ConfigManager.java create mode 100644 src/main/java/sciwhiz12/janitor/config/GuildConfig.java delete mode 100644 src/main/java/sciwhiz12/janitor/msg/TranslationMap.java rename src/main/java/sciwhiz12/janitor/msg/substitution/{IHasCustomSubstitutions.java => ICustomSubstitutions.java} (72%) delete mode 100644 src/main/resources/english.json diff --git a/src/main/java/sciwhiz12/janitor/BotConsole.java b/src/main/java/sciwhiz12/janitor/BotConsole.java index ebb83c5..fbf8c4e 100644 --- a/src/main/java/sciwhiz12/janitor/BotConsole.java +++ b/src/main/java/sciwhiz12/janitor/BotConsole.java @@ -44,11 +44,6 @@ public class BotConsole { case "reload": { if (parts.length >= 2) switch (parts[1]) { - case "translations": { - CONSOLE.info("Reloading translations"); - bot.getTranslations().loadTranslations(); - break outer; - } case "messages": { CONSOLE.info("Reloading messages"); bot.getMessages().loadMessages(); diff --git a/src/main/java/sciwhiz12/janitor/JanitorBot.java b/src/main/java/sciwhiz12/janitor/JanitorBot.java index 232e5fe..db44184 100644 --- a/src/main/java/sciwhiz12/janitor/JanitorBot.java +++ b/src/main/java/sciwhiz12/janitor/JanitorBot.java @@ -8,8 +8,8 @@ import net.dv8tion.jda.api.entities.PrivateChannel; import net.dv8tion.jda.api.entities.User; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.config.BotConfig; +import sciwhiz12.janitor.config.ConfigManager; import sciwhiz12.janitor.msg.Messages; -import sciwhiz12.janitor.msg.TranslationMap; import sciwhiz12.janitor.msg.emote.ReactionManager; import sciwhiz12.janitor.msg.substitution.SubstitutionMap; import sciwhiz12.janitor.storage.GuildStorage; @@ -27,8 +27,8 @@ public class JanitorBot { private final BotConsole console; private final GuildStorage storage; private final GuildStorage.SavingThread storageSavingThread; + private final ConfigManager configManager; private final CommandRegistry cmdRegistry; - private final TranslationMap translations; private final SubstitutionMap substitutions; private final Messages messages; private final ReactionManager reactions; @@ -38,10 +38,10 @@ public class JanitorBot { this.discord = discord; this.console = new BotConsole(this, System.in); this.storage = new GuildStorage(this, Path.of(config.STORAGE_PATH.get())); - this.cmdRegistry = new CommandRegistry(this, config.getCommandPrefix()); - this.translations = new TranslationMap(this, config.getTranslationsFile()); + this.configManager = new ConfigManager(this, config.getConfigsFolder()); + this.cmdRegistry = new CommandRegistry(this); this.substitutions = new SubstitutionMap(this); - this.messages = new Messages(this, config.getTranslationsFile()); + this.messages = new Messages(this, config.getMessagesFolder()); this.reactions = new ReactionManager(this); // TODO: find which of these can be loaded in parallel before the bot JDA is ready discord.addEventListener(cmdRegistry, reactions); @@ -78,14 +78,12 @@ public class JanitorBot { public GuildStorage getStorage() { return this.storage; } + public ConfigManager getConfigManager() { return configManager; } + public CommandRegistry getCommandRegistry() { return this.cmdRegistry; } - public TranslationMap getTranslations() { - return this.translations; - } - public ReactionManager getReactionManager() { return this.reactions; } @@ -113,6 +111,8 @@ public class JanitorBot { discord.shutdown(); storageSavingThread.stopThread(); storage.save(); + configManager.save(); + configManager.close(); console.stop(); } diff --git a/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java b/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java index 334e362..e892d8c 100644 --- a/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java @@ -1,9 +1,10 @@ package sciwhiz12.janitor.commands; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.JanitorBot; -import sciwhiz12.janitor.config.BotConfig; +import sciwhiz12.janitor.config.GuildConfig; import sciwhiz12.janitor.msg.Messages; public abstract class BaseCommand { @@ -25,9 +26,11 @@ public abstract class BaseCommand { return getBot().getMessages(); } - protected BotConfig config() { - return getBot().getConfig(); - } + protected GuildConfig config(MessageReceivedEvent event) { return config(event.getGuild().getIdLong()); } + + protected GuildConfig config(Guild guild) { return config(guild.getIdLong()); } + + protected GuildConfig config(long guildID) { return getBot().getConfigManager().getConfig(guildID); } public abstract LiteralArgumentBuilder getNode(); } diff --git a/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java b/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java index f833510..e510748 100644 --- a/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java +++ b/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java @@ -20,6 +20,7 @@ import sciwhiz12.janitor.commands.moderation.UnbanCommand; import sciwhiz12.janitor.commands.moderation.UnwarnCommand; import sciwhiz12.janitor.commands.moderation.WarnCommand; import sciwhiz12.janitor.commands.moderation.WarnListCommand; +import sciwhiz12.janitor.config.GuildConfig; import sciwhiz12.janitor.utils.Util; import java.util.HashMap; @@ -30,13 +31,11 @@ import static sciwhiz12.janitor.Logging.JANITOR; public class CommandRegistry implements EventListener { private final JanitorBot bot; - private final String prefix; private final Map registry = new HashMap<>(); private final CommandDispatcher dispatcher; - public CommandRegistry(JanitorBot bot, String prefix) { + public CommandRegistry(JanitorBot bot) { this.bot = bot; - this.prefix = prefix; this.dispatcher = new CommandDispatcher<>(); addCommand(new PingCommand(this, "ping", "Pong!")); @@ -69,17 +68,28 @@ public class CommandRegistry implements EventListener { public void onEvent(@NotNull GenericEvent genericEvent) { if (!(genericEvent instanceof MessageReceivedEvent)) return; MessageReceivedEvent event = (MessageReceivedEvent) genericEvent; + if (event.getAuthor().isBot()) return; + final String prefix; + if (event.isFromGuild()) { + prefix = getBot().getConfigManager().getConfig(event.getGuild().getIdLong()) + .forGuild(GuildConfig.COMMAND_PREFIX); + } else { + prefix = getBot().getConfig().getCommandPrefix(); + } + String msg = event.getMessage().getContentRaw(); - if (!msg.startsWith(this.prefix)) return; + if (!msg.startsWith(prefix)) return; JANITOR.debug(COMMANDS, "Received message starting with valid command prefix. Author: {}, full message: {}", Util.toString(event.getAuthor()), msg); try { - StringReader command = new StringReader(msg.substring(this.prefix.length())); + StringReader command = new StringReader(msg.substring(prefix.length())); ParseResults parseResults = this.dispatcher.parse(command, event); if (parseResults.getReader().canRead()) { - // Parsing did not succeed, i.e. command not found - // TODO: add separate code path when insufficient permissions / requires fails - JANITOR.error(COMMANDS, "Error while parsing command: {}", parseResults.getExceptions().values()); + if (parseResults.getExceptions().isEmpty()) { + JANITOR.info(COMMANDS, "Command not found."); + } else { + JANITOR.error(COMMANDS, "Error while parsing command: {}", parseResults.getExceptions().values()); + } return; } JANITOR.debug(COMMANDS, "Executing command."); diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java index 4c624db..58da11d 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java @@ -124,7 +124,7 @@ public class BanCommand extends BaseCommand { .flatMap(v -> messages().getRegularMessage("moderation/ban/info") .apply(MessageHelper.member("performer", performer)) .apply(MessageHelper.member("target", target)) - .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .with("private_message", () -> res.isSuccess() ? "\u2705" : "\u274C") .with("delete_duration", () -> String.valueOf(days)) .with("reason", () -> reason) .send(getBot(), channel) diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java index 71d392b..e2cb129 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java @@ -110,7 +110,7 @@ public class KickCommand extends BaseCommand { .flatMap(v -> messages().getRegularMessage("moderation/kick/info") .apply(MessageHelper.member("performer", performer)) .apply(MessageHelper.member("target", target)) - .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .with("private_message", () -> res.isSuccess() ? "\u2705" : "\u274C") .with("reason", () -> reason) .send(getBot(), channel) ) diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java index 7bde650..835ce11 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java @@ -34,6 +34,8 @@ import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.member; import static sciwhiz12.janitor.commands.moderation.NoteCommand.ModeratorFilter.*; import static sciwhiz12.janitor.commands.util.CommandHelper.argument; import static sciwhiz12.janitor.commands.util.CommandHelper.literal; +import static sciwhiz12.janitor.config.GuildConfig.ENABLE_NOTES; +import static sciwhiz12.janitor.config.GuildConfig.MAX_NOTES_PER_MOD; import static sciwhiz12.janitor.msg.MessageHelper.*; public class NoteCommand extends BaseCommand { @@ -46,7 +48,7 @@ public class NoteCommand extends BaseCommand { @Override public LiteralArgumentBuilder getNode() { return literal("note") - .requires(ctx -> config().NOTES_ENABLE.get()) + .requires(event -> config(event).forGuild(ENABLE_NOTES)) .then(literal("add") .then(argument("target", member()) .then(argument("contents", greedyString()) @@ -126,7 +128,7 @@ public class NoteCommand extends BaseCommand { } else { final NoteStorage storage = NoteStorage.get(getBot().getStorage(), guild); - final int maxAmount = config().NOTES_MAX_AMOUNT_PER_MOD.get(); + final int maxAmount = config(ctx.getSource()).forGuild(MAX_NOTES_PER_MOD); if (storage.getAmountOfNotes(target.getUser()) >= maxAmount) { messages().getRegularMessage("moderation/error/insufficient_permissions") .apply(MessageHelper.member("performer", performer)) @@ -201,13 +203,8 @@ public class NoteCommand extends BaseCommand { } else { messages().>getListingMessage("moderation/note/list") .apply(MessageHelper.member("performer", performer)) - .amountPerPage(8) .setEntryApplier((entry, subs) -> subs - .with("note_entry.note_id", () -> String.valueOf(entry.getKey())) - .apply(user("note_entry.performer", entry.getValue().getPerformer())) - .apply(user("note_entry.target", entry.getValue().getTarget())) - .with("note_entry.date_time", () -> entry.getValue().getDateTime().format(DATE_TIME_FORMAT)) - .with("note_entry.contents", entry.getValue()::getContents) + .apply(noteEntry("note_entry", entry.getKey(), entry.getValue())) ) .build(channel, getBot(), ctx.getSource().getMessage(), NoteStorage.get(getBot().getStorage(), guild) diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java index 0790e0b..0c44209 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; +import sciwhiz12.janitor.config.GuildConfig; import sciwhiz12.janitor.moderation.warns.WarningEntry; import sciwhiz12.janitor.moderation.warns.WarningStorage; import sciwhiz12.janitor.msg.MessageHelper; @@ -20,6 +21,7 @@ import javax.annotation.Nullable; import static sciwhiz12.janitor.commands.util.CommandHelper.argument; import static sciwhiz12.janitor.commands.util.CommandHelper.literal; +import static sciwhiz12.janitor.config.GuildConfig.*; public class UnwarnCommand extends BaseCommand { public static final EnumSet WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS); @@ -31,7 +33,7 @@ public class UnwarnCommand extends BaseCommand { @Override public LiteralArgumentBuilder getNode() { return literal("unwarn") - .requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get()) + .requires(ctx -> config(ctx).forGuild(ENABLE_WARNS)) .then(argument("caseId", IntegerArgumentType.integer(1)) .executes(this::run) ); @@ -73,13 +75,13 @@ public class UnwarnCommand extends BaseCommand { .send(getBot(), channel).queue(); } else if (entry.getWarned().getIdLong() == performer.getIdLong() - && !config().WARNINGS_REMOVE_SELF_WARNINGS.get()) { + && !config(guild).forGuild(ALLOW_REMOVE_SELF_WARNINGS)) { messages().getRegularMessage("moderation/error/unwarn/cannot_unwarn_self") .apply(MessageHelper.member("performer", performer)) .apply(MessageHelper.warningEntry("warning_entry", caseID, entry)) .send(getBot(), channel).queue(); - } else if (config().WARNINGS_RESPECT_MOD_ROLES.get() + } else if (config(guild).forGuild(WARNS_RESPECT_MOD_ROLES) && (temp = guild.getMember(entry.getPerformer())) != null && !performer.canInteract(temp)) { messages().getRegularMessage("moderation/error/unwarn/cannot_remove_higher_mod") .apply(MessageHelper.member("performer", performer)) diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java index c0288a3..40f5b8e 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; +import sciwhiz12.janitor.config.GuildConfig; import sciwhiz12.janitor.moderation.warns.WarningEntry; import sciwhiz12.janitor.moderation.warns.WarningStorage; import sciwhiz12.janitor.msg.MessageHelper; @@ -26,6 +27,7 @@ import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.getMember import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.member; import static sciwhiz12.janitor.commands.util.CommandHelper.argument; import static sciwhiz12.janitor.commands.util.CommandHelper.literal; +import static sciwhiz12.janitor.config.GuildConfig.ALLOW_WARN_OTHER_MODERATORS; public class WarnCommand extends BaseCommand { public static final EnumSet WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS); @@ -37,7 +39,7 @@ public class WarnCommand extends BaseCommand { @Override public LiteralArgumentBuilder getNode() { return literal("warn") - .requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get()) + .requires(ctx -> config(ctx).forGuild(GuildConfig.ENABLE_WARNS)) .then(argument("member", member()) .then(argument("reason", greedyString()) .executes(ctx -> this.run(ctx, getString(ctx, "reason"))) @@ -84,7 +86,7 @@ public class WarnCommand extends BaseCommand { .apply(MessageHelper.member("target", target)) .send(getBot(), channel).queue(); - } else if (target.hasPermission(WARN_PERMISSION) && config().WARNINGS_PREVENT_WARNING_MODS.get()) { + } else if (target.hasPermission(WARN_PERMISSION) && config(guild).forGuild(ALLOW_WARN_OTHER_MODERATORS)) { messages().getRegularMessage("moderation/error/warn/cannot_warn_mods") .apply(MessageHelper.member("performer", performer)) .apply(MessageHelper.member("target", target)) @@ -104,7 +106,7 @@ public class WarnCommand extends BaseCommand { .flatMap(res -> messages().getRegularMessage("moderation/warn/info") .apply(MessageHelper.member("performer", performer)) .apply(MessageHelper.warningEntry("warning_entry", caseId, entry)) - .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .with("private_message", () -> res.isSuccess() ? "\u2705" : "\u274C") .send(getBot(), channel) ) .queue(); diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java index 0439c6e..c7ed366 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java @@ -26,8 +26,7 @@ import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.getMember import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.member; import static sciwhiz12.janitor.commands.util.CommandHelper.argument; import static sciwhiz12.janitor.commands.util.CommandHelper.literal; -import static sciwhiz12.janitor.msg.MessageHelper.DATE_TIME_FORMAT; -import static sciwhiz12.janitor.msg.MessageHelper.user; +import static sciwhiz12.janitor.config.GuildConfig.ENABLE_WARNS; public class WarnListCommand extends BaseCommand { public static final EnumSet WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS); @@ -39,7 +38,7 @@ public class WarnListCommand extends BaseCommand { @Override public LiteralArgumentBuilder getNode() { return literal("warnlist") - .requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get()) + .requires(ctx -> config(ctx).forGuild(ENABLE_WARNS)) .then(literal("target") .then(argument("target", member()) .then(literal("mod") @@ -100,13 +99,8 @@ public class WarnListCommand extends BaseCommand { } else { messages().>getListingMessage("moderation/warn/list") .apply(MessageHelper.member("performer", performer)) - .amountPerPage(8) - .setEntryApplier((entry, subs) -> subs - .with("warning_entry.case_id", () -> String.valueOf(entry.getKey())) - .apply(user("warning_entry.performer", entry.getValue().getPerformer())) - .apply(user("warning_entry.warned", entry.getValue().getWarned())) - .with("warning_entry.date_time", () -> entry.getValue().getDateTime().format(DATE_TIME_FORMAT)) - .with("warning_entry.reason", entry.getValue()::getReason) + .setEntryApplier((entry, subs) -> + subs.apply(MessageHelper.warningEntry("warning_entry", entry.getKey(), entry.getValue())) ) .build(channel, getBot(), ctx.getSource().getMessage(), WarningStorage.get(getBot().getStorage(), guild) diff --git a/src/main/java/sciwhiz12/janitor/config/BotConfig.java b/src/main/java/sciwhiz12/janitor/config/BotConfig.java index 6dc0fb7..37d8d9d 100644 --- a/src/main/java/sciwhiz12/janitor/config/BotConfig.java +++ b/src/main/java/sciwhiz12/janitor/config/BotConfig.java @@ -19,22 +19,15 @@ public class BotConfig { private final CommentedConfigSpec.ConfigValue CLIENT_TOKEN; private final CommentedConfigSpec.LongValue OWNER_ID; + public final CommentedConfigSpec.ConfigValue CONFIGS_PATH; + public final CommentedConfigSpec.ConfigValue STORAGE_PATH; public final CommentedConfigSpec.IntValue AUTOSAVE_INTERVAL; - public final CommentedConfigSpec.ConfigValue CUSTOM_TRANSLATION_FILE; public final CommentedConfigSpec.ConfigValue CUSTOM_MESSAGES_DIRECTORY; public final CommentedConfigSpec.ConfigValue COMMAND_PREFIX; - public final CommentedConfigSpec.BooleanValue WARNINGS_ENABLE; - public final CommentedConfigSpec.BooleanValue WARNINGS_RESPECT_MOD_ROLES; - public final CommentedConfigSpec.BooleanValue WARNINGS_PREVENT_WARNING_MODS; - public final CommentedConfigSpec.BooleanValue WARNINGS_REMOVE_SELF_WARNINGS; - - public final CommentedConfigSpec.IntValue NOTES_MAX_AMOUNT_PER_MOD; - public final CommentedConfigSpec.BooleanValue NOTES_ENABLE; - private final BotOptions options; private final Path configPath; private final CommentedConfigSpec spec; @@ -55,6 +48,10 @@ public class BotConfig { .defineInRange("owner_id", 0L, Long.MIN_VALUE, Long.MAX_VALUE); builder.pop(); + CONFIGS_PATH = builder + .comment("The folder where guild configs are kept.") + .define("configs_path", "configs"); + builder.push("storage"); STORAGE_PATH = builder .comment("The folder where per-guild storage is kept.") @@ -64,10 +61,6 @@ public class BotConfig { .defineInRange("autosave_internal", 20, 1, Integer.MAX_VALUE); builder.pop(); - CUSTOM_TRANSLATION_FILE = builder - .comment("A file which contains custom translation keys to load for messages.", - "If blank, no file shall be loaded.") - .define("messages.custom_translations", ""); CUSTOM_MESSAGES_DIRECTORY = builder .comment("A folder containing custom messages, with a 'messages.json' key file.", "If blank, no folder shall be loaded and defaults will be used.") @@ -77,36 +70,6 @@ public class BotConfig { .comment("The prefix for commands.") .define("commands.prefix", "!"); - builder.comment("Moderation settings").push("moderation"); - { - builder.comment("Settings for the warnings system").push("warnings"); - WARNINGS_ENABLE = builder - .comment("Whether to enable the warnings system. If disabled, the related commands are force-disabled.") - .define("enable", true); - WARNINGS_RESPECT_MOD_ROLES = builder - .comment( - "Whether to prevent lower-ranked moderators (in the role hierarchy) from removing warnings issued by " + - "higher-ranked moderators.") - .define("respect_mod_roles", false); - WARNINGS_PREVENT_WARNING_MODS = builder - .comment("Whether to prevent moderators from issuing warnings against other moderators.") - .define("warn_other_moderators", false); - WARNINGS_REMOVE_SELF_WARNINGS = builder - .comment("Whether to allow moderators to remove warnings from themselves.") - .define("remove_self_warnings", false); - builder.pop(); - - builder.comment("Settings for the notes system").push("notes"); - NOTES_ENABLE = builder - .comment("Whether to enable the notes system. If disabled, the related commands are force-disabled.") - .define("enable", true); - NOTES_MAX_AMOUNT_PER_MOD = builder - .comment("The max amount of notes for a user per moderator.") - .defineInRange("max_amount", Integer.MAX_VALUE, 0, Integer.MAX_VALUE); - builder.pop(); - } - builder.pop(); - spec = builder.build(); this.configPath = options.getConfigPath().orElse(DEFAULT_CONFIG_PATH); @@ -129,15 +92,6 @@ public class BotConfig { return config; } - @Nullable - public Path getTranslationsFile() { - return options.getTranslationsFile(). - or(() -> CUSTOM_TRANSLATION_FILE.get().isBlank() ? - Optional.empty() : - Optional.of(Path.of(CUSTOM_TRANSLATION_FILE.get()))) - .orElse(null); - } - @Nullable public Path getMessagesFolder() { return options.getMessagesFolder(). @@ -147,6 +101,15 @@ public class BotConfig { .orElse(null); } + @Nullable + public Path getConfigsFolder() { + return options.getConfigsFolder(). + or(() -> CONFIGS_PATH.get().isBlank() ? + Optional.empty() : + Optional.of(Path.of(CONFIGS_PATH.get()))) + .orElse(null); + } + public String getToken() { return options.getToken().orElse(CLIENT_TOKEN.get()); } diff --git a/src/main/java/sciwhiz12/janitor/config/BotOptions.java b/src/main/java/sciwhiz12/janitor/config/BotOptions.java index ff51f26..477c7f3 100644 --- a/src/main/java/sciwhiz12/janitor/config/BotOptions.java +++ b/src/main/java/sciwhiz12/janitor/config/BotOptions.java @@ -13,8 +13,8 @@ import static joptsimple.util.PathProperties.*; public class BotOptions { private final OptionSet options; private final ArgumentAcceptingOptionSpec configPath; - private final ArgumentAcceptingOptionSpec translationsPath; private final ArgumentAcceptingOptionSpec messagesFolder; + private final ArgumentAcceptingOptionSpec configsFolder; private final ArgumentAcceptingOptionSpec token; private final ArgumentAcceptingOptionSpec prefix; private final ArgumentAcceptingOptionSpec owner; @@ -25,12 +25,12 @@ public class BotOptions { .accepts("config", "The path to the config file; defaults to 'config.toml'") .withRequiredArg() .withValuesConvertedBy(new PathConverter(FILE_EXISTING, READABLE, WRITABLE)); - this.translationsPath = parser - .accepts("translations", "The path to the translations file") - .withRequiredArg() - .withValuesConvertedBy(new PathConverter(FILE_EXISTING, READABLE)); this.messagesFolder = parser - .accepts("translations", "The path to the custom messages folder") + .accepts("messages", "The path to the custom messages folder") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter(DIRECTORY_EXISTING, READABLE)); + this.configsFolder = parser + .accepts("guildConfigs", "The path to the guild configs folder") .withRequiredArg() .withValuesConvertedBy(new PathConverter(DIRECTORY_EXISTING, READABLE)); this.token = parser @@ -50,14 +50,14 @@ public class BotOptions { return configPath.valueOptional(options); } - public Optional getTranslationsFile() { - return translationsPath.valueOptional(options); - } - public Optional getMessagesFolder() { return messagesFolder.valueOptional(options); } + public Optional getConfigsFolder() { + return configsFolder.valueOptional(options); + } + public Optional getToken() { return token.valueOptional(options); } diff --git a/src/main/java/sciwhiz12/janitor/config/ConfigManager.java b/src/main/java/sciwhiz12/janitor/config/ConfigManager.java new file mode 100644 index 0000000..4e14d9c --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/config/ConfigManager.java @@ -0,0 +1,44 @@ +package sciwhiz12.janitor.config; + +import sciwhiz12.janitor.JanitorBot; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class ConfigManager { + private final JanitorBot bot; + private final Path configPath; + private final Map configMap = new HashMap<>(); + + public ConfigManager(JanitorBot bot, Path configPath) { + this.bot = bot; + this.configPath = configPath; + } + + public GuildConfig getConfig(long guildID) { + return configMap.computeIfAbsent(guildID, (id) -> new GuildConfig(id, getFile(guildID))); + } + + public JanitorBot getBot() { + return bot; + } + + public void save() { + configMap.values().forEach(GuildConfig::save); + } + + public void close() { + configMap.values().forEach(GuildConfig::close); + for (Iterator iterator = configMap.values().iterator(); iterator.hasNext(); ) { + iterator.next().close(); + iterator.remove(); + } + } + + private Path getFile(long guildID) { + final Path file = Path.of(Long.toHexString(guildID) + ".toml"); + return configPath.resolve(file); + } +} diff --git a/src/main/java/sciwhiz12/janitor/config/GuildConfig.java b/src/main/java/sciwhiz12/janitor/config/GuildConfig.java new file mode 100644 index 0000000..26078f1 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/config/GuildConfig.java @@ -0,0 +1,183 @@ +package sciwhiz12.janitor.config; + +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import com.electronwill.nightconfig.core.file.FileNotFoundAction; +import com.electronwill.nightconfig.core.file.FileWatcher; +import com.electronwill.nightconfig.toml.TomlFormat; +import com.google.common.base.Joiner; +import net.dv8tion.jda.api.entities.GuildChannel; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static sciwhiz12.janitor.Logging.CONFIG; +import static sciwhiz12.janitor.Logging.JANITOR; + +public class GuildConfig { + private static final Joiner NEWLINE = Joiner.on("\n"); + + private final long guild; + private final CommentedFileConfig config; + private boolean closed = false; + + public static final ConfigNode ENABLE = new ConfigNode<>( + "enable", () -> true, + "Whether the bot is enabled for this guild.", + "Can be used to temporarily disable the bot in emergency situations."); + + public static final ConfigNode COMMAND_PREFIX = new ConfigNode<>( + "commands.prefix", () -> "!", + "The prefix for all commands."); + + public static final ConfigNode ENABLE_WARNS = new ConfigNode<>( + "moderation.warns.enable", () -> true, + "Whether to enable the warnings system. If disabled, the related commands are force-disabled."); + + public static final ConfigNode WARNS_RESPECT_MOD_ROLES = new ConfigNode<>( + "moderation.warns.respect_mod_roles", () -> false, + "Whether to prevent lower-ranked moderators (in the role hierarchy) from removing warnings " + + "issued by higher-ranked moderators."); + public static final ConfigNode ALLOW_WARN_OTHER_MODERATORS = new ConfigNode<>( + "moderation.warns.warn_other_moderators", () -> true, + "Whether to allow moderators to issue warnings against other moderators."); + public static final ConfigNode ALLOW_REMOVE_SELF_WARNINGS = new ConfigNode<>( + "moderation.warns.remove_self_warnings", () -> false, + "Whether to allow moderators to remove warnings from themselves."); + + public static final ConfigNode ENABLE_NOTES = new ConfigNode<>( + "moderation.notes.enable", () -> true, + "Whether to enable the notes system. If disabled, the related commands are force-disabled."); + public static final ConfigNode MAX_NOTES_PER_MOD = new ConfigNode<>( + "moderation.notes.max_amount", () -> Integer.MAX_VALUE, + "The max amount of notes for a user per moderator."); + + GuildConfig(long guild, Path configPath) { + this.guild = guild; + this.config = CommentedFileConfig.builder(configPath, TomlFormat.instance()) + .onFileNotFound(FileNotFoundAction.CREATE_EMPTY) + .preserveInsertionOrder() + .autosave() + .build(); + try { + CONFIG.info("Building guild config for {} from {}", Long.toHexString(this.guild), configPath); + config.load(); + FileWatcher.defaultInstance().addWatch(configPath, this::onFileChange); + ConfigNode.nodes.forEach(this::forGuild); + save(); + } catch (IOException ex) { + JANITOR.error("Error while building config from file {}", configPath, ex); + } + } + + protected CommentedConfig getChannelOverrides() { + final String channelOverridesID = "channel_overrides"; + CommentedConfig channelConfigs = config.get(channelOverridesID); + if (channelConfigs == null) { + channelConfigs = config.createSubConfig(); + config.set(channelOverridesID, channelConfigs); + config.setComment(channelOverridesID, "Channel overrides for certain configuration options"); + } + return channelConfigs; + } + + public CommentedConfig getChannelConfig(GuildChannel channel) { + final String id = channel.getId(); + CommentedConfig overrides = getChannelOverrides(); + CommentedConfig channelOverride = overrides.get(id); + if (channelOverride == null) { + channelOverride = overrides.createSubConfig(); + overrides.set(id, channelOverride); + overrides.setComment(id, "Channel overrides for channel with name " + channel.getName()); + } + return channelOverride; + } + + private static void ensureComment(CommentedConfig config, String path, String expectedComment) { + if (!Objects.equals(config.getComment(path), expectedComment)) { + config.setComment(path, expectedComment); + } + } + + public T forGuild(ConfigNode node) { + ensureComment(config, node.path, node.comment); + T value = config.get(node.path); + if (value == null) { + value = node.defaultValue.get(); + config.set(node.path, value); + } + return value; + } + + public void forGuild(ConfigNode node, T newValue) { + ensureComment(config, node.path, node.comment); + config.set(node.path, newValue); + } + + public T forChannel(GuildChannel channel, ConfigNode node) { + CommentedConfig channelConfig = getChannelConfig(channel); + ensureComment(channelConfig, node.path, node.comment); + T value = channelConfig.getRaw(node.path); + if (value == null) { + value = node.defaultValue.get(); + channelConfig.set(node.path, node.defaultValue.get()); + } + return value; + } + + public void forChannel(GuildChannel channel, ConfigNode node, T newValue) { + CommentedConfig channelConfig = getChannelConfig(channel); + ensureComment(channelConfig, node.path, node.comment); + channelConfig.set(node.path, newValue); + } + + public long getGuildID() { + return guild; + } + + public CommentedFileConfig getRawConfig() { + return config; + } + + public void save() { + if (!closed) { + config.save(); + } + } + + public void close() { + if (!closed) { + closed = true; + config.close(); + } + } + + void onFileChange() { + if (closed) return; + try { + CONFIG.info("Reloading config due to file change {}", config.getNioPath()); + config.load(); + } catch (Exception ex) { + CONFIG.error("Error while reloading config from {}", config.getNioPath(), ex); + } + } + + public static class ConfigNode { + static final List> nodes = new ArrayList<>(); + + public final String path; + final String comment; + final Supplier defaultValue; + + ConfigNode(String path, Supplier defaultValue, String... comment) { + this.path = path; + this.defaultValue = defaultValue; + this.comment = NEWLINE.join(comment); + nodes.add(this); + } + } +} diff --git a/src/main/java/sciwhiz12/janitor/msg/ListingMessageBuilder.java b/src/main/java/sciwhiz12/janitor/msg/ListingMessageBuilder.java index 855b4ab..f8fb969 100644 --- a/src/main/java/sciwhiz12/janitor/msg/ListingMessageBuilder.java +++ b/src/main/java/sciwhiz12/janitor/msg/ListingMessageBuilder.java @@ -9,7 +9,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import sciwhiz12.janitor.JanitorBot; import sciwhiz12.janitor.msg.json.ListingMessage; import sciwhiz12.janitor.msg.substitution.CustomSubstitutions; -import sciwhiz12.janitor.msg.substitution.IHasCustomSubstitutions; +import sciwhiz12.janitor.msg.substitution.ICustomSubstitutions; import sciwhiz12.janitor.msg.substitution.SubstitutionMap; import java.util.HashMap; @@ -20,10 +20,10 @@ import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; -public class ListingMessageBuilder implements IHasCustomSubstitutions> { +public class ListingMessageBuilder implements ICustomSubstitutions> { private final ListingMessage message; private final Map> customSubstitutions; - private int amountPerPage = 10; + private int amountPerPage = 6; private BiConsumer entryApplier = (entry, sub) -> {}; public ListingMessageBuilder(ListingMessage message, Map> customSubstitutions) { @@ -55,22 +55,24 @@ public class ListingMessageBuilder implements IHasCustomSubstitutions entries) { + public void build(MessageChannel channel, + SubstitutionMap globalSubstitutions, + Message triggerMessage, + List entries) { final CustomSubstitutions customSubs = globalSubstitutions.with(customSubstitutions); final ImmutableList list = ImmutableList.copyOf(entries); final PagedMessage pagedMessage = new PagedMessage(message, list, amountPerPage); - channel.sendMessage(pagedMessage.createMessage(translations, customSubs, entryApplier)) - .queue(listMsg -> translations.getBot().getReactionManager().newMessage(listMsg) + channel.sendMessage(pagedMessage.createMessage(customSubs, entryApplier)) + .queue(listMsg -> globalSubstitutions.getBot().getReactionManager().newMessage(listMsg) .owner(triggerMessage.getAuthor().getIdLong()) .removeEmotes(true) .add("\u2b05", (msg, event) -> { // PREVIOUS if (pagedMessage.advancePage(PageDirection.PREVIOUS)) { event.retrieveMessage() .flatMap(eventMsg -> eventMsg.editMessage( - pagedMessage.createMessage(translations, customSubs, entryApplier)) + pagedMessage.createMessage(customSubs, entryApplier)) ) .queue(); } @@ -88,7 +90,7 @@ public class ListingMessageBuilder implements IHasCustomSubstitutions eventMsg.editMessage( - pagedMessage.createMessage(translations, customSubs, entryApplier)) + pagedMessage.createMessage(customSubs, entryApplier)) ) .queue(); } @@ -98,7 +100,7 @@ public class ListingMessageBuilder implements IHasCustomSubstitutions entries) { - build(channel, bot.getTranslations(), bot.getSubstitutions(), triggerMessage, entries); + build(channel, bot.getSubstitutions(), triggerMessage, entries); } class PagedMessage { @@ -136,11 +138,10 @@ public class ListingMessageBuilder implements IHasCustomSubstitutions applier) { if (currentPage != lastPage) { cachedMessage = message.create( - translations, substitutions.with(new HashMap<>()) .with("page.max", () -> String.valueOf(maxPages + 1)) .with("page.current", () -> String.valueOf(currentPage + 1)), diff --git a/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java b/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java index 2a54033..59eb603 100644 --- a/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java +++ b/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java @@ -8,10 +8,11 @@ import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.User; import sciwhiz12.janitor.moderation.notes.NoteEntry; import sciwhiz12.janitor.moderation.warns.WarningEntry; -import sciwhiz12.janitor.msg.substitution.IHasCustomSubstitutions; +import sciwhiz12.janitor.msg.substitution.ICustomSubstitutions; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.util.Objects; import java.util.function.Consumer; import static java.time.temporal.ChronoField.*; @@ -19,19 +20,19 @@ import static java.time.temporal.ChronoField.*; public class MessageHelper { private MessageHelper() {} - public static > Consumer snowflake(String head, ISnowflake snowflake) { + public static > Consumer snowflake(String head, ISnowflake snowflake) { return builder -> builder .with(head + ".id", snowflake::getId) .with(head + ".creation_datetime", () -> snowflake.getTimeCreated().format(DATE_TIME_FORMAT)); } - public static > Consumer mentionable(String head, IMentionable mentionable) { - return builder -> builder + public static > Consumer mentionable(String head, IMentionable mentionable) { + return builder -> builder .apply(snowflake(head, mentionable)) .with(head + ".mention", mentionable::getAsMention); } - public static > Consumer role(String head, Role role) { + public static > Consumer role(String head, Role role) { return builder -> builder .apply(mentionable(head, role)) .with(head + ".color_hex", () -> Integer.toHexString(role.getColorRaw())) @@ -39,7 +40,7 @@ public class MessageHelper { .with(head + ".permissions", role.getPermissions()::toString); } - public static > Consumer user(String head, User user) { + public static > Consumer user(String head, User user) { return builder -> builder .apply(mentionable(head, user)) .with(head + ".name", user::getName) @@ -48,7 +49,7 @@ public class MessageHelper { .with(head + ".flags", user.getFlags()::toString); } - public static > Consumer guild(String head, Guild guild) { + public static > Consumer guild(String head, Guild guild) { return builder -> builder .apply(snowflake(head, guild)) .with(head + ".name", guild::getName) @@ -58,10 +59,10 @@ public class MessageHelper { .with(head + ".boost.count", () -> String.valueOf(guild.getBoostCount())) .with(head + ".locale", guild.getLocale()::toString) .with(head + ".verification_level", guild.getVerificationLevel()::toString) - .with(head + ".icon_url", guild::getIconUrl); + .with(head + ".icon_url", () -> Objects.toString(guild.getIconUrl(), "")); } - public static > Consumer member(String head, Member member) { + public static > Consumer member(String head, Member member) { return builder -> builder .apply(user(head, member.getUser())) .apply(guild(head + ".guild", member.getGuild())) @@ -71,7 +72,7 @@ public class MessageHelper { .with(head + ".color", () -> String.valueOf(member.getColorRaw())); } - public static > Consumer warningEntry(String head, int caseID, WarningEntry entry) { + public static > Consumer warningEntry(String head, int caseID, WarningEntry entry) { return builder -> builder .with(head + ".case_id", () -> String.valueOf(caseID)) .apply(user(head + ".performer", entry.getPerformer())) @@ -80,7 +81,7 @@ public class MessageHelper { .with(head + ".reason", entry::getReason); } - public static > Consumer noteEntry(String head, int noteID, NoteEntry entry) { + public static > Consumer noteEntry(String head, int noteID, NoteEntry entry) { return builder -> builder .with(head + ".note_id", () -> String.valueOf(noteID)) .apply(user(head + ".performer", entry.getPerformer())) diff --git a/src/main/java/sciwhiz12/janitor/msg/Messages.java b/src/main/java/sciwhiz12/janitor/msg/Messages.java index cfbde61..5cf47da 100644 --- a/src/main/java/sciwhiz12/janitor/msg/Messages.java +++ b/src/main/java/sciwhiz12/janitor/msg/Messages.java @@ -127,8 +127,8 @@ public class Messages { public static final RegularMessage UNKNOWN_REGULAR_MESSAGE = new RegularMessage( "UNKNOWN MESSAGE!", null, - "A regular message was tried to be looked up, but was not found. Please report this to your bot " + - "maintainer/administrator.", + "A regular message was tried to be looked up, but was not found. " + + "Please report this to your bot maintainer/administrator.", String.valueOf(0xFF0000), null, null, diff --git a/src/main/java/sciwhiz12/janitor/msg/RegularMessageBuilder.java b/src/main/java/sciwhiz12/janitor/msg/RegularMessageBuilder.java index 37cad71..43a3370 100644 --- a/src/main/java/sciwhiz12/janitor/msg/RegularMessageBuilder.java +++ b/src/main/java/sciwhiz12/janitor/msg/RegularMessageBuilder.java @@ -5,7 +5,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.requests.restaction.MessageAction; import sciwhiz12.janitor.JanitorBot; import sciwhiz12.janitor.msg.json.RegularMessage; -import sciwhiz12.janitor.msg.substitution.IHasCustomSubstitutions; +import sciwhiz12.janitor.msg.substitution.ICustomSubstitutions; import sciwhiz12.janitor.msg.substitution.SubstitutionMap; import java.util.HashMap; @@ -13,7 +13,7 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; -public class RegularMessageBuilder implements IHasCustomSubstitutions { +public class RegularMessageBuilder implements ICustomSubstitutions { private final RegularMessage message; private final Map> customSubstitutions; @@ -26,10 +26,6 @@ public class RegularMessageBuilder implements IHasCustomSubstitutions()); } - public RegularMessageBuilder(RegularMessageBuilder copy) { - this(copy.message, new HashMap<>(copy.customSubstitutions)); - } - public RegularMessageBuilder apply(Consumer consumer) { consumer.accept(this); return this; @@ -40,12 +36,12 @@ public class RegularMessageBuilder implements IHasCustomSubstitutions", CASE_INSENSITIVE); - private static final String DEFAULT_TRANSLATIONS_RESOURCE = "english.json"; - private static final TypeReference> MAP_TYPE = new TypeReference<>() {}; - - private final JanitorBot bot; - private final Path translationsFile; - private final Map translations = new HashMap<>(); - private final ObjectMapper jsonMapper = new ObjectMapper(); - - public TranslationMap(JanitorBot bot, Path translationsFile) { - this.bot = bot; - this.translationsFile = translationsFile; - loadTranslations(); - } - - public void loadTranslations() { - if (translationsFile == null) { - JANITOR.info(TRANSLATIONS, "No translation file given, using default english translations"); - loadDefaultTranslations(); - return; - } - try { - JANITOR.debug(TRANSLATIONS, "Loading translations from file {}", translationsFile); - Map trans = jsonMapper.readValue(Files.newBufferedReader(translationsFile), MAP_TYPE); - translations.clear(); - translations.putAll(trans); - JANITOR.info(TRANSLATIONS, "Loaded {} translations from file {}", translations.size(), translationsFile); - } catch (Exception e) { - JANITOR.error(TRANSLATIONS, "Error while loading translations from file {}", translationsFile, e); - loadDefaultTranslations(); - } - } - - void loadDefaultTranslations() { - try { - JANITOR.debug(TRANSLATIONS, "Loading default english translations"); - // noinspection UnstableApiUsage - Map trans = jsonMapper.readValue( - new InputStreamReader(Resources.getResource(DEFAULT_TRANSLATIONS_RESOURCE).openStream()), - MAP_TYPE); - translations.clear(); - translations.putAll(trans); - JANITOR.info(TRANSLATIONS, "Loaded {} default english translations", translations.size()); - } catch (Exception e) { - JANITOR.error(TRANSLATIONS, "Error while loading default english translations", e); - } - } - - public Map getTranslationMap() { - return Collections.unmodifiableMap(translations); - } - - public String translate(String text) { - final Matcher matcher = TRANSLATION_REGEX.matcher(text); - return matcher.replaceAll( - matchResult -> quoteReplacement(translations.getOrDefault(matchResult.group(1), matchResult.group(0)))); - } - - public JanitorBot getBot() { - return bot; - } -} diff --git a/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java b/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java index 50365f2..a7b6ff7 100644 --- a/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java +++ b/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java @@ -6,7 +6,6 @@ import joptsimple.internal.Strings; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.Role; -import sciwhiz12.janitor.msg.TranslationMap; import sciwhiz12.janitor.msg.substitution.CustomSubstitutions; import sciwhiz12.janitor.msg.substitution.ISubstitutor; @@ -142,27 +141,25 @@ public class ListingMessage { } public EmbedBuilder create( - TranslationMap translations, ISubstitutor global, Iterable iterable, BiConsumer entryApplier ) { - final Function func = str -> str != null ? global.substitute(translations.translate(str)) : null; final EmbedBuilder builder = new EmbedBuilder(); - builder.setTitle(func.apply(title), func.apply(url)); + builder.setTitle(global.substitute(title), global.substitute(url)); builder.setColor(parseColor(global.substitute(color))); - builder.setAuthor(func.apply(authorName), func.apply(authorUrl), func.apply(authorIconUrl)); - builder.setDescription(func.apply(description)); - builder.setImage(func.apply(imageUrl)); - builder.setThumbnail(func.apply(thumbnailUrl)); + builder.setAuthor(global.substitute(authorName), global.substitute(authorUrl), global.substitute(authorIconUrl)); + builder.setDescription(global.substitute(description)); + builder.setImage(global.substitute(imageUrl)); + builder.setThumbnail(global.substitute(thumbnailUrl)); builder.setTimestamp(OffsetDateTime.now(ZoneOffset.UTC)); - builder.setFooter(func.apply(footerText), func.apply(footerIconUrl)); + builder.setFooter(global.substitute(footerText), global.substitute(footerIconUrl)); for (MessageEmbed.Field field : beforeFields) { - builder.addField(func.apply(field.getName()), func.apply(field.getValue()), field.isInline()); + builder.addField(global.substitute(field.getName()), global.substitute(field.getValue()), field.isInline()); } final CustomSubstitutions entrySubs = new CustomSubstitutions(); - final Function entryFunc = str -> str != null ? entrySubs.substitute(func.apply(str)) : null; + final Function entryFunc = str -> str != null ? entrySubs.substitute(global.substitute(str)) : null; int count = 0; for (T listEntry : iterable) { entryApplier.accept(listEntry, entrySubs); @@ -181,11 +178,11 @@ public class ListingMessage { count++; } if (count < 1) { - builder.getDescriptionBuilder().append(func.apply(emptyText)); + builder.getDescriptionBuilder().append(global.substitute(emptyText)); } for (MessageEmbed.Field field : afterFields) { - builder.addField(func.apply(field.getName()), func.apply(field.getValue()), field.isInline()); + builder.addField(global.substitute(field.getName()), global.substitute(field.getValue()), field.isInline()); } return builder; } diff --git a/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java index 10472d6..ff96769 100644 --- a/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java +++ b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java @@ -6,7 +6,6 @@ import joptsimple.internal.Strings; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.Role; -import sciwhiz12.janitor.msg.TranslationMap; import sciwhiz12.janitor.msg.substitution.ISubstitutor; import java.time.OffsetDateTime; @@ -16,7 +15,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.StringJoiner; -import java.util.function.Function; import javax.annotation.Nullable; @JsonDeserialize(using = RegularMessageDeserializer.class) @@ -176,19 +174,18 @@ public class RegularMessage { thumbnailUrl, fields); } - public EmbedBuilder create(TranslationMap translations, ISubstitutor substitutions) { - final Function func = str -> str != null ? substitutions.substitute(translations.translate(str)) : null; + public EmbedBuilder create(ISubstitutor subs) { final EmbedBuilder builder = new EmbedBuilder(); - builder.setTitle(func.apply(title), func.apply(url)); - builder.setColor(parseColor(substitutions.substitute(color))); - builder.setAuthor(func.apply(authorName), func.apply(authorUrl), func.apply(authorIconUrl)); - builder.setDescription(func.apply(description)); - builder.setImage(func.apply(imageUrl)); - builder.setThumbnail(func.apply(thumbnailUrl)); + builder.setTitle(subs.substitute(title), subs.substitute(url)); + builder.setColor(parseColor(subs.substitute(color))); + builder.setAuthor(subs.substitute(authorName), subs.substitute(authorUrl), subs.substitute(authorIconUrl)); + builder.setDescription(subs.substitute(description)); + builder.setImage(subs.substitute(imageUrl)); + builder.setThumbnail(subs.substitute(thumbnailUrl)); builder.setTimestamp(OffsetDateTime.now(ZoneOffset.UTC)); - builder.setFooter(func.apply(footerText), func.apply(footerIconUrl)); + builder.setFooter(subs.substitute(footerText), subs.substitute(footerIconUrl)); for (MessageEmbed.Field field : fields) { - builder.addField(func.apply(field.getName()), func.apply(field.getValue()), field.isInline()); + builder.addField(subs.substitute(field.getName()), subs.substitute(field.getValue()), field.isInline()); } return builder; } diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java b/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java index bcbf9d0..a69f90e 100644 --- a/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java @@ -7,8 +7,9 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; +import javax.annotation.Nullable; -public class CustomSubstitutions implements ISubstitutor, IHasCustomSubstitutions { +public class CustomSubstitutions implements ISubstitutor, ICustomSubstitutions { private final Map> map; public CustomSubstitutions(Map> map) { @@ -20,7 +21,8 @@ public class CustomSubstitutions implements ISubstitutor, IHasCustomSubstitution } @Override - public String substitute(String text) { + @Nullable + public String substitute(@Nullable String text) { return SubstitutionMap.substitute(text, map); } diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/IHasCustomSubstitutions.java b/src/main/java/sciwhiz12/janitor/msg/substitution/ICustomSubstitutions.java similarity index 72% rename from src/main/java/sciwhiz12/janitor/msg/substitution/IHasCustomSubstitutions.java rename to src/main/java/sciwhiz12/janitor/msg/substitution/ICustomSubstitutions.java index 93f772c..b0a1098 100644 --- a/src/main/java/sciwhiz12/janitor/msg/substitution/IHasCustomSubstitutions.java +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/ICustomSubstitutions.java @@ -3,7 +3,7 @@ package sciwhiz12.janitor.msg.substitution; import java.util.function.Consumer; import java.util.function.Supplier; -public interface IHasCustomSubstitutions> { +public interface ICustomSubstitutions> { T with(String argument, Supplier value); T apply(Consumer consumer); diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java b/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java index 907b51d..cb13d3b 100644 --- a/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java @@ -1,5 +1,8 @@ package sciwhiz12.janitor.msg.substitution; +import javax.annotation.Nullable; + public interface ISubstitutor { - String substitute(String text); + @Nullable + String substitute(@Nullable String text); } diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java b/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java index 00c2d5d..8b95d27 100644 --- a/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java @@ -11,8 +11,8 @@ import java.util.Map; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Nullable; -import static java.util.regex.Matcher.quoteReplacement; import static java.util.regex.Pattern.CASE_INSENSITIVE; import static sciwhiz12.janitor.msg.MessageHelper.DATE_TIME_FORMAT; @@ -20,18 +20,24 @@ public class SubstitutionMap implements ISubstitutor { public static final Pattern ARGUMENT_REGEX = Pattern.compile("\\$\\{(.+?)}", CASE_INSENSITIVE); public static final Pattern NULL_ARGUMENT_REGEX = Pattern.compile("nullcheck;(.+?);(.+)", CASE_INSENSITIVE); - public static String substitute(String text, Map> arguments) { + private static String quote(@Nullable String input) { + return input != null ? Matcher.quoteReplacement(input) : ""; + } + + @Nullable + public static String substitute(@Nullable String text, Map> arguments) { + if (text == null || text.isBlank()) return null; final Matcher matcher = ARGUMENT_REGEX.matcher(text); return matcher.replaceAll(matchResult -> { final Matcher nullMatcher = NULL_ARGUMENT_REGEX.matcher(matchResult.group(1)); if (nullMatcher.matches()) { final String grp1 = nullMatcher.group(1); - final String str = arguments.containsKey(grp1) ? arguments.get(grp1).get() : null; - return str != null ? - quoteReplacement(str) : - quoteReplacement(arguments.getOrDefault(nullMatcher.group(2), () -> nullMatcher.group(2)).get()); + return quote(arguments.getOrDefault( + grp1, + () -> arguments.getOrDefault(nullMatcher.group(2), () -> nullMatcher.group(2)).get() + ).get()); } - return quoteReplacement(arguments.getOrDefault(matchResult.group(1), () -> matchResult.group(0)).get()); + return quote(arguments.getOrDefault(matchResult.group(1), () -> matchResult.group(0)).get()); }); } @@ -51,7 +57,8 @@ public class SubstitutionMap implements ISubstitutor { return bot; } - public String substitute(String text) { + @Nullable + public String substitute(@Nullable String text) { return SubstitutionMap.substitute(text, defaultSubstitutions); } diff --git a/src/main/resources/english.json b/src/main/resources/english.json deleted file mode 100644 index 1803669..0000000 --- a/src/main/resources/english.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "general.error.guild_only_command.title": "Guild only command!", - "general.error.guild_only_command.description": "This command can only be run in a guild channel.", - "general.error.ambiguous_member.title": "Ambiguous member argument!", - "general.error.ambiguous_member.description": "The name you have specified is too ambiguous (leads to more than 1 member)!\nPlease narrow down the specified name until it can uniquely identify a member of this guild.", - "general.error.insufficient_permissions.title": "I have insufficient permissions!", - "general.error.insufficient_permissions.description": "I do not have sufficient permissions to carry out this action!\nPlease contact your server admins if you believe this is in error.", - "general.error.insufficient_permissions.field.permissions": "Required permissions", - "general.error.cannot_interact.title": "Member is higher than me!", - "general.error.cannot_interact.description": "Cannot perform action on the given member, likely due to me being lower in the role hierarchy.", - "general.error.cannot_interact.field.target": "Target", - "general.error.cannot_action_self.title": "Cannot act against myself!", - "general.error.cannot_action_self.description": "Cannot perform action against myself, as that would be counter-intuitive.", - "general.error.cannot_action_performer.title": "Performer cannot act against self!", - "general.error.cannot_action_performer.description": "You cannot perform this action against yourself.", - "general.error.cannot_action_performer.field.performer": "Performer/Target", - "moderation.insufficient_permissions.title": "Insufficient permissions.", - "moderation.insufficient_permissions.description": "The performer of this command has insufficient permissions to use this command.", - "moderation.insufficient_permissions.field.performer": "Performer", - "moderation.insufficient_permissions.field.permissions": "Required permissions", - "moderation.cannot_interact.title": "Cannot moderate Target.", - "moderation.cannot_interact.description": "The performer of this command cannot moderate the target user, likely due to being lower in the role hierarchy.", - "moderation.cannot_interact.field.performer": "Performer", - "moderation.cannot_interact.field.target": "Target", - "moderation.kick.info.author": "Kicked user from server.", - "moderation.kick.info.field.performer": "Performer", - "moderation.kick.info.field.target": "Target", - "moderation.kick.info.field.private_message": "Sent DM", - "moderation.kick.info.field.reason.name": "Reason", - "moderation.kick.info.field.reason.value": "${nullcheck;reason;_No reason specified._}", - "moderation.kick.dm.title": "You were kicked from this server.", - "moderation.kick.dm.field.performer": "Moderator", - "moderation.kick.dm.field.reason.name": "Reason", - "moderation.kick.dm.field.reason.value": "${nullcheck;reason;_No reason specified._}", - "moderation.ban.info.author": "Banned user from server.", - "moderation.ban.info.field.performer": "Performer", - "moderation.ban.info.field.target": "Target", - "moderation.ban.info.field.private_message": "Sent DM", - "moderation.ban.info.field.delete_duration.name": "Message Deletion", - "moderation.ban.info.field.delete_duration.value": "${delete_duration} day(s)", - "moderation.ban.info.field.reason.name": "Reason", - "moderation.ban.info.field.reason.value": "${nullcheck;reason;_No reason specified._}", - "moderation.ban.dm.title": "You were banned from this server.", - "moderation.ban.dm.field.performer": "Moderator", - "moderation.ban.dm.field.reason.name": "Reason", - "moderation.ban.dm.field.reason.value": "${nullcheck;reason;_No reason specified._}", - "moderation.unban.info.author": "Unbanned user from server.", - "moderation.unban.info.field.performer": "Performer", - "moderation.unban.info.field.target": "Target", - "moderation.warn.info.author": "Warned user.", - "moderation.warn.info.field.performer": "Performer", - "moderation.warn.info.field.target": "Target", - "moderation.warn.info.field.case_id": "Case ID", - "moderation.warn.info.field.reason.name": "Reason", - "moderation.warn.info.field.reason.value": "${nullcheck;warning_entry.reason;_No reason specified._}", - "moderation.warn.info.field.private_message": "Sent DM", - "moderation.warn.info.field.date_time": "Date & Time", - "moderation.warn.dm.title": "You were warned by a moderator.", - "moderation.warn.dm.field.performer": "Moderator", - "moderation.warn.dm.field.date_time": "Date & Time", - "moderation.warn.dm.field.reason.name": "Reason", - "moderation.warn.dm.field.reason.value": "${nullcheck;warning_entry.reason;_No reason specified._}", - "moderation.unwarn.info.author": "Removed warning from user.", - "moderation.unwarn.info.field.performer": "Performer", - "moderation.unwarn.info.field.original_target": "Original Target", - "moderation.unwarn.info.field.original_performer": "Original Performer", - "moderation.unwarn.info.field.case_id": "Case ID", - "moderation.unwarn.info.field.date_time": "Date & Time", - "moderation.unwarn.info.field.reason.name": "Reason", - "moderation.unwarn.info.field.reason.value": "${nullcheck;warning_entry.reason;_No reason specified._}", - "moderation.unwarn.no_case_found.title": "No warning found.", - "moderation.unwarn.no_case_found.description": "No warning with that case ID was found.", - "moderation.unwarn.no_case_found.field.performer": "Performer", - "moderation.unwarn.no_case_found.field.case_id": "Case ID", - "moderation.unwarn.cannot_unwarn_self.title": "Cannot remove warning from self.", - "moderation.unwarn.cannot_unwarn_self.description": "Performer cannot remove a warning from themselves.", - "moderation.unwarn.cannot_unwarn_self.field.performer": "Performer/Original Target", - "moderation.unwarn.cannot_unwarn_self.field.original_performer": "Original Performer", - "moderation.unwarn.cannot_unwarn_self.field.case_id": "Case ID", - "moderation.warn.cannot_warn_mods.title": "Cannot warn moderators.", - "moderation.warn.cannot_warn_mods.description": "Moderators cannot issue warnings to other moderators.", - "moderation.warn.cannot_warn_mods.field.performer": "Performer", - "moderation.warn.cannot_warn_mods.field.target": "Target", - "moderation.warn.cannot_remove_higher_mod.title": "Cannot remove warning issued by higher-ranked moderator.", - "moderation.warn.cannot_remove_higher_mod.description": "The performer cannot remove this warning, as this was issued by a higher-ranking moderator.", - "moderation.warn.cannot_remove_higher_mod.field.performer": "Performer", - "moderation.warn.cannot_remove_higher_mod.field.original_performer": "Original Performer", - "moderation.warn.cannot_remove_higher_mod.field.case_id": "Case ID", - "moderation.note.max_amount_of_notes.title": "Max notes reached.", - "moderation.note.max_amount_of_notes.description": "The performer has reached the maximum amount of notes for the target user.", - "moderation.note.max_amount_of_notes.field.performer": "Performer", - "moderation.note.max_amount_of_notes.field.target": "Target", - "moderation.note.max_amount_of_notes.field.amount": "(Max.) Amount", - "moderation.note.no_note_found.title": "No note found.", - "moderation.note.no_note_found.description": "No note with that note ID was found.", - "moderation.note.no_note_found.field.performer": "Performer", - "moderation.note.no_note_found.field.note_id": "Note ID", - "moderation.note.add.author": "Recorded note for user.", - "moderation.note.add.field.performer": "Performer", - "moderation.note.add.field.target": "Target", - "moderation.note.add.field.note_id": "Note ID", - "moderation.note.add.field.date_time": "Date & Time", - "moderation.note.add.field.contents": "Text", - "moderation.note.remove.author": "Removed note.", - "moderation.note.remove.field.performer": "Performer", - "moderation.note.remove.field.original_performer": "Original Performer", - "moderation.note.remove.field.original_target": "Original Target", - "moderation.note.remove.field.note_id": "Note ID", - "moderation.note.remove.field.date_time": "Date & Time", - "moderation.note.remove.field.contents": "Text", - "moderation.warnlist.author": "Listing of Warnings", - "moderation.warnlist.empty": "**_No warnings logged matching your query._**", - "moderation.warnlist.entry": "**Case #${warning_entry.case_id}**: Warned ${warning_entry.warned.mention} by ${warning_entry.performer.mention} \n - _Date & Time:_ ${warning_entry.date_time} \n - _Reason:_ ${nullcheck;warning_entry.reason;_No reason specified._}", - "moderation.note.list.author": "Listing of Notes (Page ${page.current}/${page.max})", - "moderation.note.list.empty": "**_No recorded notes matching your query._**", - "moderation.note.list.entry": "**#${note_entry.note_id}**: for ${note_entry.target.mention} by ${note_entry.performer.mention} \n - _Date & Time:_ ${note_entry.date_time} \n - _Text:_ ${note_entry.contents}" -} \ No newline at end of file diff --git a/src/main/resources/messages/general/error/ambiguous_member.json b/src/main/resources/messages/general/error/ambiguous_member.json index f078f45..fd9db2f 100644 --- a/src/main/resources/messages/general/error/ambiguous_member.json +++ b/src/main/resources/messages/general/error/ambiguous_member.json @@ -1,5 +1,5 @@ { "color": "${general.error.color}", - "title": "", - "description": "" + "title": "Ambiguous member argument!", + "description": "The name you have specified is too ambiguous (leads to more than 1 member)!\nPlease narrow down the specified name until it can uniquely identify a member of this guild." } \ No newline at end of file diff --git a/src/main/resources/messages/general/error/cannot_action_performer.json b/src/main/resources/messages/general/error/cannot_action_performer.json index 8913518..b5a248a 100644 --- a/src/main/resources/messages/general/error/cannot_action_performer.json +++ b/src/main/resources/messages/general/error/cannot_action_performer.json @@ -1,12 +1,4 @@ { "color": "${general.error.color}", - "title": "", - "description": "", - "fields": [ - { - "name": "", - "value": "${performer.mention}", - "inline": true - } - ] + "title": "Performer cannot act against self." } \ No newline at end of file diff --git a/src/main/resources/messages/general/error/cannot_action_self.json b/src/main/resources/messages/general/error/cannot_action_self.json index a43ec63..428d2e0 100644 --- a/src/main/resources/messages/general/error/cannot_action_self.json +++ b/src/main/resources/messages/general/error/cannot_action_self.json @@ -1,5 +1,4 @@ { "color": "${general.error.color}", - "title": "", - "description": "" + "title": "Cannot perform this action against myself." } \ No newline at end of file diff --git a/src/main/resources/messages/general/error/cannot_interact.json b/src/main/resources/messages/general/error/cannot_interact.json index a4eea52..4f89e26 100644 --- a/src/main/resources/messages/general/error/cannot_interact.json +++ b/src/main/resources/messages/general/error/cannot_interact.json @@ -1,10 +1,9 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "description": "Cannot perform action on the given member, likely due to me being lower in the role hierarchy.", "fields": [ { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true } diff --git a/src/main/resources/messages/general/error/guild_only_command.json b/src/main/resources/messages/general/error/guild_only_command.json index b46d90c..0b4d385 100644 --- a/src/main/resources/messages/general/error/guild_only_command.json +++ b/src/main/resources/messages/general/error/guild_only_command.json @@ -1,5 +1,4 @@ { "color": "${general.error.color}", - "title": "", - "description": "" + "title": "Guild only command!" } \ No newline at end of file diff --git a/src/main/resources/messages/general/error/insufficient_permissions.json b/src/main/resources/messages/general/error/insufficient_permissions.json index 1d3f29c..7c8ffb0 100644 --- a/src/main/resources/messages/general/error/insufficient_permissions.json +++ b/src/main/resources/messages/general/error/insufficient_permissions.json @@ -1,10 +1,9 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "description": "I do not have sufficient permissions to carry out this action.\nPlease contact your server administrators if you believe this is in error.", "fields": [ { - "name": "", + "name": "Required permissions", "value": "${required_permissions}", "inline": true } diff --git a/src/main/resources/messages/moderation/ban/dm.json b/src/main/resources/messages/moderation/ban/dm.json index 3798ed0..6f83c61 100644 --- a/src/main/resources/messages/moderation/ban/dm.json +++ b/src/main/resources/messages/moderation/ban/dm.json @@ -4,16 +4,16 @@ "name": "${performer.guild.name}", "icon_url": "${performer.guild.icon_url}" }, - "title": "", + "title": "You were banned from this server.", "fields": [ { - "name": "", + "name": "Moderator", "value": "${performer.mention}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;reason;_No reason specified._}", "inline": true } ] diff --git a/src/main/resources/messages/moderation/ban/info.json b/src/main/resources/messages/moderation/ban/info.json index 306ee27..5cccc64 100644 --- a/src/main/resources/messages/moderation/ban/info.json +++ b/src/main/resources/messages/moderation/ban/info.json @@ -1,33 +1,33 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Banned user from server.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true }, { - "name": "", + "name": "Sent DM", "value": "${private_message}", "inline": true }, { - "name": "", - "value": "", + "name": "Message Deletion", + "value": "${delete_duration} day(s)", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;reason;_No reason specified._}", "inline": false } ] diff --git a/src/main/resources/messages/moderation/error/cannot_interact.json b/src/main/resources/messages/moderation/error/cannot_interact.json index 63cb40a..daab16a 100644 --- a/src/main/resources/messages/moderation/error/cannot_interact.json +++ b/src/main/resources/messages/moderation/error/cannot_interact.json @@ -1,15 +1,9 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "description": "The performer of this command cannot moderate the target user, likely due to being lower in the role hierarchy.", "fields": [ { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true } diff --git a/src/main/resources/messages/moderation/error/insufficient_permissions.json b/src/main/resources/messages/moderation/error/insufficient_permissions.json index a2479f2..e2044bd 100644 --- a/src/main/resources/messages/moderation/error/insufficient_permissions.json +++ b/src/main/resources/messages/moderation/error/insufficient_permissions.json @@ -1,15 +1,9 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "description": "The performer of this command has insufficient permissions to use this command.", "fields": [ { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", + "name": "Required permissions", "value": "${required_permissions}", "inline": true } diff --git a/src/main/resources/messages/moderation/error/note/max_amount_of_notes.json b/src/main/resources/messages/moderation/error/note/max_amount_of_notes.json index a451a0d..5ac9daf 100644 --- a/src/main/resources/messages/moderation/error/note/max_amount_of_notes.json +++ b/src/main/resources/messages/moderation/error/note/max_amount_of_notes.json @@ -1,20 +1,14 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "description": "The performer has reached the maximum amount of notes for the target user.", "fields": [ { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true }, { - "name": "", + "name": "(Max.) Amount", "value": "${notes_amount}", "inline": true } diff --git a/src/main/resources/messages/moderation/error/note/no_note_found.json b/src/main/resources/messages/moderation/error/note/no_note_found.json index 70b2bf3..f4beb0d 100644 --- a/src/main/resources/messages/moderation/error/note/no_note_found.json +++ b/src/main/resources/messages/moderation/error/note/no_note_found.json @@ -1,17 +1,4 @@ { "color": "${general.error.color}", - "title": "", - "description": "", - "fields": [ - { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", - "value": "${note_id}", - "inline": true - } - ] + "description": "No note with that note ID was found." } \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json b/src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json index fd3982d..631305a 100644 --- a/src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json +++ b/src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json @@ -1,22 +1,16 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "title": "Cannot remove warning issued by higher-ranked moderator.", "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Issuer", "value": "${warning_entry.performer.mention}", "inline": true - }, - { - "name": "", - "value": "${warning_entry.case_id}", - "inline": true } ] } \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json b/src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json index 69f09a3..26cfad0 100644 --- a/src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json +++ b/src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json @@ -1,22 +1,16 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "title": "Cannot remove warning from self.", "fields": [ { - "name": "", + "name": "Performer/Target", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Issuer", "value": "${warning_entry.performer.mention}", "inline": true - }, - { - "name": "", - "value": "${warning_entry.case_id}", - "inline": true } ] } \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/unwarn/no_case_found.json b/src/main/resources/messages/moderation/error/unwarn/no_case_found.json index 2914238..9e6409a 100644 --- a/src/main/resources/messages/moderation/error/unwarn/no_case_found.json +++ b/src/main/resources/messages/moderation/error/unwarn/no_case_found.json @@ -1,17 +1,4 @@ { "color": "${general.error.color}", - "title": "", - "description": "", - "fields": [ - { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", - "value": "${case_id}", - "inline": true - } - ] + "description": "No warning with that case ID was found." } \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json b/src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json index 4b2f418..aa93be5 100644 --- a/src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json +++ b/src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json @@ -1,15 +1,9 @@ { "color": "${general.error.color}", - "title": "", - "description": "", + "title": "Cannot warn other moderators.", "fields": [ { - "name": "", - "value": "${performer.mention}", - "inline": true - }, - { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true } diff --git a/src/main/resources/messages/moderation/kick/dm.json b/src/main/resources/messages/moderation/kick/dm.json index 89a7ca0..9f5fe51 100644 --- a/src/main/resources/messages/moderation/kick/dm.json +++ b/src/main/resources/messages/moderation/kick/dm.json @@ -4,16 +4,16 @@ "name": "${performer.guild.name}", "icon_url": "${performer.guild.icon_url}" }, - "title": "", + "title": "You were kicked from this server.", "fields": [ { - "name": "", + "name": "Moderator", "value": "${performer.mention}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;reason;_No reason specified._}", "inline": true } ] diff --git a/src/main/resources/messages/moderation/kick/info.json b/src/main/resources/messages/moderation/kick/info.json index f3288b8..27de619 100644 --- a/src/main/resources/messages/moderation/kick/info.json +++ b/src/main/resources/messages/moderation/kick/info.json @@ -1,28 +1,28 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Kicked user from server.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true }, { - "name": "", + "name": "Sent DM", "value": "${private_message}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;reason;_No reason specified._}", "inline": false } ] diff --git a/src/main/resources/messages/moderation/note/add.json b/src/main/resources/messages/moderation/note/add.json index 71fc360..bcbaf82 100644 --- a/src/main/resources/messages/moderation/note/add.json +++ b/src/main/resources/messages/moderation/note/add.json @@ -1,32 +1,32 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Recorded note for user.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${note_entry.performer.mention}", "inline": true }, { - "name": "", + "name": "Target", "value": "${note_entry.target.mention}", "inline": true }, { - "name": "", + "name": "Note ID", "value": "${note_entry.note_id}", "inline": true }, { - "name": "", + "name": "Date & Time", "value": "${note_entry.date_time}", "inline": true }, { - "name": "", + "name": "Text", "value": "${note_entry.contents}", "inline": false } diff --git a/src/main/resources/messages/moderation/note/list.json b/src/main/resources/messages/moderation/note/list.json index db23518..7aa2946 100644 --- a/src/main/resources/messages/moderation/note/list.json +++ b/src/main/resources/messages/moderation/note/list.json @@ -2,12 +2,12 @@ "type": "listing", "color": "${moderation.color}", "author": { - "name": "", + "name": "Listing of Notes (Page ${page.current}/${page.max})", "icon_url": "${moderation.icon_url}" }, "entry": { "type": "description", - "text": "" + "text": "**#${note_entry.note_id}**: ${note_entry.target.mention} by ${note_entry.performer.mention}\n - _${note_entry.date_time}_\n${note_entry.contents}" }, - "empty": "" + "empty": "**_No recorded notes matching your query._**" } \ No newline at end of file diff --git a/src/main/resources/messages/moderation/note/remove.json b/src/main/resources/messages/moderation/note/remove.json index 69b176b..3733dd0 100644 --- a/src/main/resources/messages/moderation/note/remove.json +++ b/src/main/resources/messages/moderation/note/remove.json @@ -1,37 +1,37 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Removed note.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Original Performer", "value": "${note_entry.performer.mention}", "inline": true }, { - "name": "", + "name": "Original Target", "value": "${note_entry.target.mention}", "inline": true }, { - "name": "", + "name": "Note ID", "value": "${note_entry.note_id}", "inline": true }, { - "name": "", + "name": "Date & Time", "value": "${note_entry.date_time}", "inline": true }, { - "name": "", + "name": "Text", "value": "${note_entry.contents}", "inline": false } diff --git a/src/main/resources/messages/moderation/unban/info.json b/src/main/resources/messages/moderation/unban/info.json index 6efe8a3..aa0ecf0 100644 --- a/src/main/resources/messages/moderation/unban/info.json +++ b/src/main/resources/messages/moderation/unban/info.json @@ -1,17 +1,17 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Unbanned user from server.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Target", "value": "${target.mention}", "inline": true } diff --git a/src/main/resources/messages/moderation/unwarn/info.json b/src/main/resources/messages/moderation/unwarn/info.json index 6d2b347..6b6efa5 100644 --- a/src/main/resources/messages/moderation/unwarn/info.json +++ b/src/main/resources/messages/moderation/unwarn/info.json @@ -1,38 +1,38 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Removed warning from user.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${performer.mention}", "inline": true }, { - "name": "", + "name": "Original Target", "value": "${warning_entry.target.mention}", "inline": true }, { - "name": "", + "name": "Original Performer", "value": "${warning_entry.performer.mention}", "inline": true }, { - "name": "", + "name": "Case ID", "value": "${warning_entry.case_id}", "inline": true }, { - "name": "", + "name": "Date & Time", "value": "${warning_entry.date_time}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;warning_entry.reason;_No reason specified._}", "inline": false } ] diff --git a/src/main/resources/messages/moderation/warn/dm.json b/src/main/resources/messages/moderation/warn/dm.json index 1139d25..511d01b 100644 --- a/src/main/resources/messages/moderation/warn/dm.json +++ b/src/main/resources/messages/moderation/warn/dm.json @@ -4,21 +4,21 @@ "name": "${performer.guild.name}", "icon_url": "${performer.guild.icon_url}" }, - "title": "", + "title": "You were warned by a moderator.", "fields": [ { - "name": "", + "name": "Moderator", "value": "${warning_entry.performer.mention}", "inline": true }, { - "name": "", + "name": "Date & Time", "value": "${warning_entry.date_time}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;warning_entry.reason;_No reason specified._}", "inline": false } ] diff --git a/src/main/resources/messages/moderation/warn/info.json b/src/main/resources/messages/moderation/warn/info.json index ed55bb7..c7bbec6 100644 --- a/src/main/resources/messages/moderation/warn/info.json +++ b/src/main/resources/messages/moderation/warn/info.json @@ -1,38 +1,38 @@ { "color": "${moderation.color}", "author": { - "name": "", + "name": "Warned user.", "icon_url": "${moderation.icon_url}" }, "fields": [ { - "name": "", + "name": "Performer", "value": "${warning_entry.performer.mention}", "inline": true }, { - "name": "", + "name": "Target", "value": "${warning_entry.target.mention}", "inline": true }, { - "name": "", + "name": "Case ID", "value": "${warning_entry.case_id}", "inline": true }, { - "name": "", + "name": "Sent DM", "value": "${private_message}", "inline": true }, { - "name": "", + "name": "Date & Time", "value": "${warning_entry.date_time}", "inline": true }, { - "name": "", - "value": "", + "name": "Reason", + "value": "${nullcheck;warning_entry.reason;_No reason specified._}", "inline": false } ] diff --git a/src/main/resources/messages/moderation/warn/list.json b/src/main/resources/messages/moderation/warn/list.json index b915a59..3a2b7a3 100644 --- a/src/main/resources/messages/moderation/warn/list.json +++ b/src/main/resources/messages/moderation/warn/list.json @@ -2,12 +2,12 @@ "type": "listing", "color": "${moderation.color}", "author": { - "name": "", + "name": "Listing of Warnings (Page ${page.current}/${page.max})", "icon_url": "${moderation.icon_url}" }, "entry": { "type": "description", - "text": "" + "text": "**Case #${warning_entry.case_id}**: Warned ${warning_entry.target.mention} by ${warning_entry.performer.mention} \n - _Date & Time:_ ${warning_entry.date_time} \n - _Reason:_ ${warning_entry.reason}" }, - "empty": "" + "empty": "**_No warnings logged matching your query._**" } \ No newline at end of file