From 46eff3358e13b3a263a5e8241c9c9db18b2349ad Mon Sep 17 00:00:00 2001 From: Arnold Alejo Nunag Date: Sat, 10 Oct 2020 16:53:05 +0800 Subject: [PATCH] Externalize messages to JSONs For ref.: bot console has "reload messages" command to reload the messages from disk --- .../java/sciwhiz12/janitor/BotConsole.java | 11 +- .../java/sciwhiz12/janitor/JanitorBot.java | 27 +- src/main/java/sciwhiz12/janitor/Logging.java | 1 + .../commands/moderation/BanCommand.java | 89 +++-- .../commands/moderation/KickCommand.java | 77 ++-- .../commands/moderation/NoteCommand.java | 121 +++++-- .../commands/moderation/UnbanCommand.java | 49 ++- .../commands/moderation/UnwarnCommand.java | 57 ++- .../commands/moderation/WarnCommand.java | 83 +++-- .../commands/moderation/WarnListCommand.java | 59 ++-- .../commands/util/ModerationHelper.java | 6 +- .../sciwhiz12/janitor/config/BotConfig.java | 20 +- .../sciwhiz12/janitor/config/BotOptions.java | 10 + .../java/sciwhiz12/janitor/msg/General.java | 75 ---- .../sciwhiz12/janitor/msg/MessageHelper.java | 110 ++++++ .../java/sciwhiz12/janitor/msg/Messages.java | 168 +++++---- .../sciwhiz12/janitor/msg/Moderation.java | 333 ------------------ ...{Translations.java => TranslationMap.java} | 21 +- .../sciwhiz12/janitor/msg/json/IMessage.java | 9 + .../janitor/msg/json/ListingMessage.java | 61 ++++ .../janitor/msg/json/RegularMessage.java | 213 +++++++++++ .../msg/json/RegularMessageDeserializer.java | 93 +++++ .../msg/substitution/CustomSubstitutions.java | 21 ++ .../msg/substitution/ISubstitutor.java | 5 + .../SubstitutionMap.java} | 29 +- src/main/resources/english.json | 240 +++++-------- .../general/error/ambiguous_member.json | 5 + .../error/cannot_action_performer.json | 12 + .../general/error/cannot_action_self.json | 5 + .../general/error/cannot_interact.json | 12 + .../general/error/guild_only_command.json | 5 + .../error/insufficient_permissions.json | 12 + src/main/resources/messages/messages.json | 26 ++ .../resources/messages/moderation/ban/dm.json | 20 ++ .../messages/moderation/ban/info.json | 34 ++ .../moderation/error/cannot_interact.json | 17 + .../error/insufficient_permissions.json | 17 + .../error/note/max_amount_of_notes.json | 22 ++ .../moderation/error/note/no_note_found.json | 17 + .../unwarn/cannot_remove_higher_mod.json | 22 ++ .../error/unwarn/cannot_unwarn_self.json | 22 ++ .../error/unwarn/no_case_found.json | 17 + .../error/warn/cannot_warn_mods.json | 17 + .../messages/moderation/kick/dm.json | 20 ++ .../messages/moderation/kick/info.json | 29 ++ .../messages/moderation/note/add.json | 34 ++ .../messages/moderation/note/remove.json | 39 ++ .../messages/moderation/unban/info.json | 19 + .../messages/moderation/unwarn/info.json | 39 ++ .../messages/moderation/warn/dm.json | 25 ++ .../messages/moderation/warn/info.json | 39 ++ 51 files changed, 1663 insertions(+), 851 deletions(-) delete mode 100644 src/main/java/sciwhiz12/janitor/msg/General.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/MessageHelper.java delete mode 100644 src/main/java/sciwhiz12/janitor/msg/Moderation.java rename src/main/java/sciwhiz12/janitor/msg/{Translations.java => TranslationMap.java} (78%) create mode 100644 src/main/java/sciwhiz12/janitor/msg/json/IMessage.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/json/RegularMessageDeserializer.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java create mode 100644 src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java rename src/main/java/sciwhiz12/janitor/msg/{Substitutions.java => substitution/SubstitutionMap.java} (61%) create mode 100644 src/main/resources/messages/general/error/ambiguous_member.json create mode 100644 src/main/resources/messages/general/error/cannot_action_performer.json create mode 100644 src/main/resources/messages/general/error/cannot_action_self.json create mode 100644 src/main/resources/messages/general/error/cannot_interact.json create mode 100644 src/main/resources/messages/general/error/guild_only_command.json create mode 100644 src/main/resources/messages/general/error/insufficient_permissions.json create mode 100644 src/main/resources/messages/messages.json create mode 100644 src/main/resources/messages/moderation/ban/dm.json create mode 100644 src/main/resources/messages/moderation/ban/info.json create mode 100644 src/main/resources/messages/moderation/error/cannot_interact.json create mode 100644 src/main/resources/messages/moderation/error/insufficient_permissions.json create mode 100644 src/main/resources/messages/moderation/error/note/max_amount_of_notes.json create mode 100644 src/main/resources/messages/moderation/error/note/no_note_found.json create mode 100644 src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json create mode 100644 src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json create mode 100644 src/main/resources/messages/moderation/error/unwarn/no_case_found.json create mode 100644 src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json create mode 100644 src/main/resources/messages/moderation/kick/dm.json create mode 100644 src/main/resources/messages/moderation/kick/info.json create mode 100644 src/main/resources/messages/moderation/note/add.json create mode 100644 src/main/resources/messages/moderation/note/remove.json create mode 100644 src/main/resources/messages/moderation/unban/info.json create mode 100644 src/main/resources/messages/moderation/unwarn/info.json create mode 100644 src/main/resources/messages/moderation/warn/dm.json create mode 100644 src/main/resources/messages/moderation/warn/info.json diff --git a/src/main/java/sciwhiz12/janitor/BotConsole.java b/src/main/java/sciwhiz12/janitor/BotConsole.java index 4f2526a..ebb83c5 100644 --- a/src/main/java/sciwhiz12/janitor/BotConsole.java +++ b/src/main/java/sciwhiz12/janitor/BotConsole.java @@ -49,6 +49,11 @@ public class BotConsole { bot.getTranslations().loadTranslations(); break outer; } + case "messages": { + CONSOLE.info("Reloading messages"); + bot.getMessages().loadMessages(); + break outer; + } } } default: @@ -71,8 +76,7 @@ public class BotConsole { while (!scanner.hasNextLine()) { try { Thread.sleep(150); - } - catch (InterruptedException e) { + } catch (InterruptedException e) { CONSOLE.warn("Console thread is interrupted"); continue outer; } @@ -84,8 +88,7 @@ public class BotConsole { } CONSOLE.debug("Received command: {}", input); BotConsole.this.parseCommand(input); - } - catch (Exception e) { + } catch (Exception e) { CONSOLE.error("Error while running console thread", e); } } diff --git a/src/main/java/sciwhiz12/janitor/JanitorBot.java b/src/main/java/sciwhiz12/janitor/JanitorBot.java index 9e60dfa..5a62a62 100644 --- a/src/main/java/sciwhiz12/janitor/JanitorBot.java +++ b/src/main/java/sciwhiz12/janitor/JanitorBot.java @@ -9,8 +9,8 @@ import net.dv8tion.jda.api.entities.User; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.config.BotConfig; import sciwhiz12.janitor.msg.Messages; -import sciwhiz12.janitor.msg.Substitutions; -import sciwhiz12.janitor.msg.Translations; +import sciwhiz12.janitor.msg.TranslationMap; +import sciwhiz12.janitor.msg.substitution.SubstitutionMap; import sciwhiz12.janitor.utils.Util; import java.nio.file.Path; @@ -22,13 +22,13 @@ import static sciwhiz12.janitor.Logging.STATUS; public class JanitorBot { private final JDA discord; private final BotConfig config; - private final Messages messages; - private BotConsole console; + private final BotConsole console; private final GuildStorage storage; private final GuildStorage.SavingThread storageSavingThread; private final CommandRegistry cmdRegistry; - private final Translations translations; - private final Substitutions substitutions; + private final TranslationMap translations; + private final SubstitutionMap substitutions; + private final Messages messages; public JanitorBot(JDA discord, BotConfig config) { this.config = config; @@ -36,9 +36,10 @@ public class JanitorBot { 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 Translations(this, config.getTranslationsFile()); - this.messages = new Messages(this); - this.substitutions = new Substitutions(this); + this.translations = new TranslationMap(this, config.getTranslationsFile()); + this.substitutions = new SubstitutionMap(this); + this.messages = new Messages(this, config.getTranslationsFile()); + // TODO: find which of these can be loaded in parallel before the bot JDA is ready discord.addEventListener(cmdRegistry); discord.getPresence().setPresence(OnlineStatus.ONLINE, Activity.playing(" n' sweeping n' testing!")); discord.getGuilds().forEach(Guild::loadMembers); @@ -67,7 +68,9 @@ public class JanitorBot { return this.config; } - public Messages getMessages() { return this.messages; } + public Messages getMessages() { + return messages; + } public GuildStorage getStorage() { return this.storage; } @@ -75,7 +78,7 @@ public class JanitorBot { return this.cmdRegistry; } - public Translations getTranslations() { + public TranslationMap getTranslations() { return this.translations; } @@ -105,7 +108,7 @@ public class JanitorBot { console.stop(); } - public Substitutions getSubstitutions() { + public SubstitutionMap getSubstitutions() { return substitutions; } } diff --git a/src/main/java/sciwhiz12/janitor/Logging.java b/src/main/java/sciwhiz12/janitor/Logging.java index dc38a81..90a570e 100644 --- a/src/main/java/sciwhiz12/janitor/Logging.java +++ b/src/main/java/sciwhiz12/janitor/Logging.java @@ -9,6 +9,7 @@ public class Logging { public static final Marker STATUS = MarkerFactory.getMarker("STATUS"); public static final Marker COMMANDS = MarkerFactory.getMarker("COMMANDS"); public static final Marker TRANSLATIONS = MarkerFactory.getMarker("TRANSLATIONS"); + public static final Marker MESSAGES = MarkerFactory.getMarker("MESSAGES"); public static final Marker STORAGE = MarkerFactory.getMarker("STORAGE"); public static final Logger JANITOR = LoggerFactory.getLogger("janitor"); diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java index 322210d..4c624db 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/BanCommand.java @@ -11,6 +11,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.commands.util.ModerationHelper; +import sciwhiz12.janitor.msg.MessageHelper; import java.util.EnumSet; import java.util.List; @@ -60,45 +61,77 @@ public class BanCommand extends BaseCommand { ); } - public int run(CommandContext ctx, int days, @Nullable String reason) throws CommandSyntaxException { - realRun(ctx, days, reason); - return 1; - } - - void realRun(CommandContext ctx, int days, @Nullable String reason) throws CommandSyntaxException { + int run(CommandContext ctx, int days, @Nullable String reason) throws CommandSyntaxException { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); - return; + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + + return 1; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); final List members = getMembers("member", ctx).fromGuild(performer.getGuild()); - if (members.size() < 1) return; + if (members.size() < 1) { return 1; } final Member target = members.get(0); - if (guild.getSelfMember().equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - else if (performer.equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionPerformer(performer).build(getBot())).queue(); - else if (!guild.getSelfMember().hasPermission(BAN_PERMISSION)) - channel.sendMessage(messages().GENERAL.insufficientPermissions(performer, BAN_PERMISSION).build(getBot())).queue(); - else if (!guild.getSelfMember().canInteract(target)) - channel.sendMessage(messages().GENERAL.cannotInteract(performer, target).build(getBot())).queue(); - else if (!performer.hasPermission(BAN_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, BAN_PERMISSION).build(getBot())) - .queue(); - else if (!performer.canInteract(target)) - channel.sendMessage(messages().MODERATION.ERRORS.cannotInteract(performer, target).build(getBot())).queue(); - else + if (guild.getSelfMember().equals(target)) { + messages().getRegularMessage("general/error/cannot_action_self") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (performer.equals(target)) { + messages().getRegularMessage("general/error/cannot_action_performer") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (!guild.getSelfMember().hasPermission(BAN_PERMISSION)) { + messages().getRegularMessage("general/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", BAN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!guild.getSelfMember().canInteract(target)) { + messages().getRegularMessage("general/error/cannot_interact") + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else if (!performer.hasPermission(BAN_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", BAN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!performer.canInteract(target)) { + messages().getRegularMessage("moderation/error/cannot_interact") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else { target.getUser().openPrivateChannel() - .flatMap(dm -> dm.sendMessage(messages().MODERATION.bannedDM(performer, target, reason).build(getBot()))) + .flatMap(dm -> messages().getRegularMessage("moderation/ban/dm") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .with("reason", () -> reason) + .send(getBot(), dm) + ) .mapToResult() - .flatMap(res -> ModerationHelper.banUser(target.getGuild(), performer, target, days, reason) - .flatMap(v -> channel.sendMessage( - messages().MODERATION.banUser(performer, target, reason, days, res.isSuccess()).build(getBot())))) + .flatMap(res -> + ModerationHelper.banUser(target.getGuild(), performer, target, days, reason) + .flatMap(v -> messages().getRegularMessage("moderation/ban/info") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .with("delete_duration", () -> String.valueOf(days)) + .with("reason", () -> reason) + .send(getBot(), channel) + ) + ) .queue(); + } + return 1; } } diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java index 91e3e05..71d392b 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/KickCommand.java @@ -12,6 +12,7 @@ import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.commands.util.CommandHelper; import sciwhiz12.janitor.commands.util.ModerationHelper; +import sciwhiz12.janitor.msg.MessageHelper; import java.util.EnumSet; import java.util.List; @@ -50,40 +51,72 @@ public class KickCommand extends BaseCommand { private int runWithReason(CommandContext ctx, @Nullable String reason) throws CommandSyntaxException { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return 1; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); + final List members = getMembers("member", ctx).fromGuild(performer.getGuild()); - if (members.size() < 1) { - return 1; - } + if (members.size() < 1) { return 1; } final Member target = members.get(0); - if (guild.getSelfMember().equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - else if (performer.equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - else if (!guild.getSelfMember().hasPermission(KICK_PERMISSION)) - channel.sendMessage(messages().GENERAL.insufficientPermissions(performer, KICK_PERMISSION).build(getBot())).queue(); - else if (!guild.getSelfMember().canInteract(target)) - channel.sendMessage(messages().GENERAL.cannotInteract(performer, target).build(getBot())).queue(); - else if (!performer.hasPermission(KICK_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, KICK_PERMISSION).build(getBot())) - .queue(); - else if (!performer.canInteract(target)) - channel.sendMessage(messages().MODERATION.ERRORS.cannotInteract(performer, target).build(getBot())).queue(); - else + + if (guild.getSelfMember().equals(target)) { + messages().getRegularMessage("general/error/cannot_action_self") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (performer.equals(target)) { + messages().getRegularMessage("general/error/cannot_action_performer") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (!guild.getSelfMember().hasPermission(KICK_PERMISSION)) { + messages().getRegularMessage("general/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", KICK_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!guild.getSelfMember().canInteract(target)) { + messages().getRegularMessage("general/error/cannot_interact") + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else if (!performer.hasPermission(KICK_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", KICK_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!performer.canInteract(target)) { + messages().getRegularMessage("moderation/error/cannot_interact") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else { target.getUser().openPrivateChannel() - .flatMap(dm -> dm.sendMessage(messages().MODERATION.kickedDM(performer, target, reason).build(getBot()))) + .flatMap(dm -> messages().getRegularMessage("moderation/kick/dm") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .with("reason", () -> reason) + .send(getBot(), dm) + ) .mapToResult() .flatMap(res -> ModerationHelper.kickUser(target.getGuild(), performer, target, reason) - .flatMap(v -> channel.sendMessage( - messages().MODERATION.kickUser(performer, target, reason, res.isSuccess()).build(getBot())) + .flatMap(v -> messages().getRegularMessage("moderation/kick/info") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .with("reason", () -> reason) + .send(getBot(), channel) ) ) .queue(); + } return 1; } } diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java index 0e4c13c..8a0b9c2 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/NoteCommand.java @@ -1,6 +1,5 @@ package sciwhiz12.janitor.commands.moderation; -import com.google.common.collect.ImmutableMap; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -13,6 +12,7 @@ import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.moderation.notes.NoteEntry; import sciwhiz12.janitor.moderation.notes.NoteStorage; +import sciwhiz12.janitor.msg.MessageHelper; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -92,7 +92,10 @@ public class NoteCommand extends BaseCommand { private int addNote(CommandContext ctx, String noteContents) throws CommandSyntaxException { final MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return 1; } final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); @@ -102,24 +105,41 @@ public class NoteCommand extends BaseCommand { final Member target = members.get(0); final OffsetDateTime dateTime = OffsetDateTime.now(ZoneOffset.UTC); - if (guild.getSelfMember().equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - else if (performer.equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionPerformer(performer).build(getBot())).queue(); - else if (!performer.hasPermission(NOTE_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, NOTE_PERMISSION).build(getBot())) - .queue(); - else { + if (guild.getSelfMember().equals(target)) { + messages().getRegularMessage("general/error/cannot_action_self") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (performer.equals(target)) { + messages().getRegularMessage("general/error/cannot_action_performer") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (!performer.hasPermission(NOTE_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", NOTE_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else { final NoteStorage storage = NoteStorage.get(getBot().getStorage(), guild); final int maxAmount = config().NOTES_MAX_AMOUNT_PER_MOD.get(); if (storage.getAmountOfNotes(target.getUser()) >= maxAmount) { - channel.sendMessage(messages().MODERATION.ERRORS.maxAmountOfNotes(performer, target, maxAmount).build(getBot())) - .queue(); + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .with("notes_amount", () -> String.valueOf(maxAmount)) + .send(getBot(), channel).queue(); + } else { final NoteEntry entry = new NoteEntry(performer.getUser(), target.getUser(), dateTime, noteContents); int noteID = storage.addNote(entry); - channel.sendMessage(messages().MODERATION.addNote(performer, noteID, entry).build(getBot())).queue(); + + messages().getRegularMessage("moderation/note/add") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.noteEntry("note_entry", noteID, entry)) + .send(getBot(), channel).queue(); + } } return 1; @@ -133,7 +153,10 @@ public class NoteCommand extends BaseCommand { throws CommandSyntaxException { final MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return 1; } final Guild guild = ctx.getSource().getGuild(); @@ -145,7 +168,10 @@ public class NoteCommand extends BaseCommand { if (members.size() < 1) return 1; final Member target = members.get(0); if (guild.getSelfMember().equals(target)) { - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); + messages().getRegularMessage("general/error/cannot_interact") + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + return 1; } predicate = predicate.and(e -> e.getValue().getTarget().getIdLong() == target.getIdLong()); @@ -163,43 +189,62 @@ public class NoteCommand extends BaseCommand { case NONE: {} } - if (!performer.hasPermission(NOTE_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, NOTE_PERMISSION).build(getBot())) - .queue(); - else - channel.sendMessage(messages().MODERATION.noteList( - NoteStorage.get(getBot().getStorage(), guild) - .getNotes() - .entrySet().stream() - .filter(predicate) - .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)) - ).build(getBot())).queue(); + if (!performer.hasPermission(NOTE_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", NOTE_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else { + // channel.sendMessage(messages().MODERATION.noteList( + // NoteStorage.get(getBot().getStorage(), guild) + // .getNotes() + // .entrySet().stream() + // .filter(predicate) + // .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)) + // ).build(getBot())).queue(); + messages().getRegularMessage("moderation/note/list") + .send(getBot(), channel).queue(); + // TODO: fix this + } return 1; } private int removeNote(CommandContext ctx, int noteID) { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return 1; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); - if (!performer.hasPermission(NOTE_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, NOTE_PERMISSION).build(getBot())) - .queue(); - else { + if (!performer.hasPermission(NOTE_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", NOTE_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else { final NoteStorage storage = NoteStorage.get(getBot().getStorage(), guild); @Nullable final NoteEntry entry = storage.getNote(noteID); - if (entry == null) - channel.sendMessage(messages().MODERATION.ERRORS.noNoteFound(performer, noteID).build(getBot())).queue(); - else { + if (entry == null) { + messages().getRegularMessage("moderation/note/add") + .apply(MessageHelper.member("performer", performer)) + .with("note_id", () -> String.valueOf(noteID)) + .send(getBot(), channel).queue(); + + } else { storage.removeNote(noteID); - channel.sendMessage(messages().MODERATION.removeNote(performer, noteID, entry).build(getBot())).queue(); + + messages().getRegularMessage("moderation/note/remove") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.noteEntry("note_entry", noteID, entry)) + .send(getBot(), channel).queue(); } } return 1; diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/UnbanCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/UnbanCommand.java index 3dcee75..7cdcfa8 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/UnbanCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/UnbanCommand.java @@ -12,6 +12,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.commands.util.ModerationHelper; +import sciwhiz12.janitor.msg.MessageHelper; import java.util.EnumSet; import java.util.Locale; @@ -49,7 +50,10 @@ public class UnbanCommand extends BaseCommand { void realNamedRun(CommandContext ctx) { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return; } final Guild guild = ctx.getSource().getGuild(); @@ -62,10 +66,14 @@ public class UnbanCommand extends BaseCommand { .startsWith(username)) .collect(Collectors.toList())) .queue(bans -> { - if (bans.size() > 1) - channel.sendMessage(messages().GENERAL.ambiguousMember(performer).build(getBot())).queue(); - else if (bans.size() == 1) + if (bans.size() > 1) { + messages().getRegularMessage("general/error/ambiguous_member") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + + } else if (bans.size() == 1) { tryUnban(channel, guild, performer, bans.get(0).getUser()); + } }); } @@ -77,7 +85,10 @@ public class UnbanCommand extends BaseCommand { void realIdRun(CommandContext ctx) { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return; } final Guild guild = ctx.getSource().getGuild(); @@ -97,16 +108,26 @@ public class UnbanCommand extends BaseCommand { } void tryUnban(MessageChannel channel, Guild guild, Member performer, User target) { - if (!guild.getSelfMember().hasPermission(UNBAN_PERMISSION)) - channel.sendMessage(messages().GENERAL.insufficientPermissions(performer, UNBAN_PERMISSION).build(getBot())) - .queue(); - else if (!performer.hasPermission(UNBAN_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, UNBAN_PERMISSION).build(getBot())) - .queue(); - else + if (!guild.getSelfMember().hasPermission(UNBAN_PERMISSION)) { + messages().getRegularMessage("general/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", UNBAN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!performer.hasPermission(UNBAN_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", UNBAN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else { ModerationHelper.unbanUser(guild, target) - .flatMap(v -> channel.sendMessage(messages().MODERATION.unbanUser(performer, target).build(getBot()))) + .flatMap(v -> messages().getRegularMessage("moderation/unban/info") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.user("target", target)) + .send(getBot(), channel) + ) .queue(); + } } } diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java index b03b1d0..0790e0b 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/UnwarnCommand.java @@ -12,6 +12,7 @@ import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.moderation.warns.WarningEntry; import sciwhiz12.janitor.moderation.warns.WarningStorage; +import sciwhiz12.janitor.msg.MessageHelper; import java.util.EnumSet; import java.util.Objects; @@ -44,36 +45,54 @@ public class UnwarnCommand extends BaseCommand { void realRun(CommandContext ctx) { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + return; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); int caseID = IntegerArgumentType.getInteger(ctx, "caseId"); - if (!performer.hasPermission(WARN_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, WARN_PERMISSION).build(getBot())) - .queue(); - else { + if (!performer.hasPermission(WARN_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", WARN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else { final WarningStorage storage = WarningStorage.get(getBot().getStorage(), guild); @Nullable final WarningEntry entry = storage.getWarning(caseID); Member temp; - if (entry == null) - channel.sendMessage(messages().MODERATION.ERRORS.noWarnWithID(performer, caseID).build(getBot())).queue(); - else if (entry.getWarned().getIdLong() == performer.getIdLong() - && !config().WARNINGS_REMOVE_SELF_WARNINGS.get()) - channel.sendMessage(messages().MODERATION.ERRORS.cannotUnwarnSelf(performer, caseID, entry).build(getBot())) - .queue(); - else if (config().WARNINGS_RESPECT_MOD_ROLES.get() - && (temp = guild.getMember(entry.getPerformer())) != null - && !performer.canInteract(temp)) - channel.sendMessage( - messages().MODERATION.ERRORS.cannotRemoveHigherModerated(performer, caseID, entry).build(getBot())).queue(); - else { + if (entry == null) { + messages().getRegularMessage("moderation/error/unwarn/no_case_found") + .apply(MessageHelper.member("performer", performer)) + .with("case_id", () -> String.valueOf(caseID)) + .send(getBot(), channel).queue(); + + } else if (entry.getWarned().getIdLong() == performer.getIdLong() + && !config().WARNINGS_REMOVE_SELF_WARNINGS.get()) { + 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() + && (temp = guild.getMember(entry.getPerformer())) != null && !performer.canInteract(temp)) { + messages().getRegularMessage("moderation/error/unwarn/cannot_remove_higher_mod") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.warningEntry("warning_entry", caseID, entry)) + .send(getBot(), channel).queue(); + + } else { storage.removeWarning(caseID); - channel.sendMessage(messages().MODERATION.unwarn(performer, caseID, entry).build(getBot())).queue(); + messages().getRegularMessage("moderation/unwarn/info") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.warningEntry("warning_entry", caseID, entry)) + .send(getBot(), channel).queue(); + } } } diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java index 3353d93..c0288a3 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnCommand.java @@ -12,6 +12,7 @@ import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.moderation.warns.WarningEntry; import sciwhiz12.janitor.moderation.warns.WarningStorage; +import sciwhiz12.janitor.msg.MessageHelper; import java.time.OffsetDateTime; import java.time.ZoneOffset; @@ -44,48 +45,70 @@ public class WarnCommand extends BaseCommand { ); } - public int run(CommandContext ctx, String reason) throws CommandSyntaxException { - realRun(ctx, reason); - return 1; - } - - void realRun(CommandContext ctx, String reason) throws CommandSyntaxException { + int run(CommandContext ctx, String reason) throws CommandSyntaxException { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); - return; + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + + return 1; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); final List members = getMembers("member", ctx).fromGuild(performer.getGuild()); - if (members.size() < 1) return; + if (members.size() < 1) { return 1; } final Member target = members.get(0); final OffsetDateTime dateTime = OffsetDateTime.now(ZoneOffset.UTC); - if (guild.getSelfMember().equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - else if (performer.equals(target)) - channel.sendMessage(messages().GENERAL.cannotActionPerformer(performer).build(getBot())).queue(); - else if (!performer.hasPermission(WARN_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, WARN_PERMISSION).build(getBot())) - .queue(); - else if (!performer.canInteract(target)) - channel.sendMessage(messages().MODERATION.ERRORS.cannotInteract(performer, target).build(getBot())).queue(); - else if (target.hasPermission(WARN_PERMISSION) && config().WARNINGS_PREVENT_WARNING_MODS.get()) - channel.sendMessage(messages().MODERATION.ERRORS.cannotWarnMods(performer, target).build(getBot())).queue(); - else + if (guild.getSelfMember().equals(target)) { + messages().getRegularMessage("general/error/cannot_action_self") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (performer.equals(target)) { + messages().getRegularMessage("general/error/cannot_action_performer") + .apply(MessageHelper.member("performer", performer)) + .send(getBot(), channel).queue(); + + } else if (!performer.hasPermission(WARN_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", WARN_PERMISSION::toString) + .send(getBot(), channel).queue(); + + } else if (!performer.canInteract(target)) { + messages().getRegularMessage("moderation/error/cannot_interact") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else if (target.hasPermission(WARN_PERMISSION) && config().WARNINGS_PREVENT_WARNING_MODS.get()) { + messages().getRegularMessage("moderation/error/warn/cannot_warn_mods") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + } else { + WarningEntry entry = new WarningEntry(target.getUser(), performer.getUser(), dateTime, reason); + int caseId = WarningStorage.get(getBot().getStorage(), guild).addWarning(entry); + target.getUser().openPrivateChannel() - .flatMap( - dm -> dm.sendMessage(messages().MODERATION.warnedDM(performer, target, reason, dateTime).build(getBot()))) + .flatMap(dm -> messages().getRegularMessage("moderation/warn/dm") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.warningEntry("warning_entry", caseId, entry)) + .send(getBot(), dm) + ) .mapToResult() - .flatMap(res -> { - WarningEntry entry = new WarningEntry(target.getUser(), performer.getUser(), dateTime, reason); - int caseId = WarningStorage.get(getBot().getStorage(), guild).addWarning(entry); - return channel - .sendMessage(messages().MODERATION.warnUser(performer, caseId, entry, res.isSuccess()).build(getBot())); - }) + .flatMap(res -> messages().getRegularMessage("moderation/warn/info") + .apply(MessageHelper.member("performer", performer)) + .apply(MessageHelper.warningEntry("warning_entry", caseId, entry)) + .with("private_message", () -> res.isSuccess() ? "✅" : "❌") + .send(getBot(), channel) + ) .queue(); + } + return 1; } } diff --git a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java index edc61ab..a30eaf8 100644 --- a/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/moderation/WarnListCommand.java @@ -1,6 +1,5 @@ package sciwhiz12.janitor.commands.moderation; -import com.google.common.collect.ImmutableMap; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -12,7 +11,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import sciwhiz12.janitor.commands.BaseCommand; import sciwhiz12.janitor.commands.CommandRegistry; import sciwhiz12.janitor.moderation.warns.WarningEntry; -import sciwhiz12.janitor.moderation.warns.WarningStorage; +import sciwhiz12.janitor.msg.MessageHelper; import java.util.EnumSet; import java.util.List; @@ -53,18 +52,15 @@ public class WarnListCommand extends BaseCommand { .executes(ctx -> this.run(ctx, false, false)); } - public int run(CommandContext ctx, boolean filterTarget, boolean filterModerator) - throws CommandSyntaxException { - realRun(ctx, filterTarget, filterModerator); - return 1; - } - - void realRun(CommandContext ctx, boolean filterTarget, boolean filterModerator) + int run(CommandContext ctx, boolean filterTarget, boolean filterModerator) throws CommandSyntaxException { MessageChannel channel = ctx.getSource().getChannel(); if (!ctx.getSource().isFromGuild()) { - channel.sendMessage(messages().GENERAL.guildOnlyCommand(ctx.getSource().getAuthor()).build(getBot())).queue(); - return; + messages().getRegularMessage("general/error/guild_only_command") + .apply(MessageHelper.user("performer", ctx.getSource().getAuthor())) + .send(getBot(), channel).queue(); + + return 1; } final Guild guild = ctx.getSource().getGuild(); final Member performer = Objects.requireNonNull(ctx.getSource().getMember()); @@ -72,33 +68,42 @@ public class WarnListCommand extends BaseCommand { if (filterTarget) { final List members = getMembers("target", ctx).fromGuild(performer.getGuild()); - if (members.size() < 1) return; + if (members.size() < 1) return 1; final Member target = members.get(0); if (guild.getSelfMember().equals(target)) { - channel.sendMessage(messages().GENERAL.cannotActionSelf(performer).build(getBot())).queue(); - return; + messages().getRegularMessage("general/error/cannot_interact") + .apply(MessageHelper.member("target", target)) + .send(getBot(), channel).queue(); + + return 1; } predicate = predicate.and(e -> e.getValue().getWarned().getIdLong() == target.getIdLong()); } if (filterModerator) { final List members = getMembers("moderator", ctx).fromGuild(performer.getGuild()); - if (members.size() < 1) return; + if (members.size() < 1) return 1; final Member mod = members.get(0); predicate = predicate.and(e -> e.getValue().getPerformer().getIdLong() == mod.getIdLong()); } - if (!performer.hasPermission(WARN_PERMISSION)) - channel.sendMessage( - messages().MODERATION.ERRORS.performerInsufficientPermissions(performer, WARN_PERMISSION).build(getBot())) - .queue(); - else - channel.sendMessage(messages().MODERATION.warnList( - WarningStorage.get(getBot().getStorage(), guild) - .getWarnings() - .entrySet().stream() - .filter(predicate) - .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)) - ).build(getBot())).queue(); + if (!performer.hasPermission(WARN_PERMISSION)) { + messages().getRegularMessage("moderation/error/insufficient_permissions") + .apply(MessageHelper.member("performer", performer)) + .with("required_permissions", WARN_PERMISSION::toString) + .send(getBot(), channel).queue(); + } else { + // channel.sendMessage(messages().MODERATION.warnList( + // WarningStorage.get(getBot().getStorage(), guild) + // .getWarnings() + // .entrySet().stream() + // .filter(predicate) + // .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)) + // ).build(getBot())).queue(); + messages().getRegularMessage("moderation/warn/list") + .send(getBot(), channel).queue(); + // TODO: fix this + } + return 1; } } diff --git a/src/main/java/sciwhiz12/janitor/commands/util/ModerationHelper.java b/src/main/java/sciwhiz12/janitor/commands/util/ModerationHelper.java index 0895ece..069d503 100644 --- a/src/main/java/sciwhiz12/janitor/commands/util/ModerationHelper.java +++ b/src/main/java/sciwhiz12/janitor/commands/util/ModerationHelper.java @@ -7,9 +7,9 @@ import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import java.time.Instant; import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; import javax.annotation.Nullable; +import static sciwhiz12.janitor.msg.MessageHelper.DATE_TIME_FORMAT; import static sciwhiz12.janitor.utils.Util.nameFor; public class ModerationHelper { @@ -18,7 +18,7 @@ public class ModerationHelper { auditReason.append("Kicked by ") .append(nameFor(performer.getUser())) .append(" on ") - .append(Instant.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.RFC_1123_DATE_TIME)); + .append(Instant.now().atOffset(ZoneOffset.UTC).format(DATE_TIME_FORMAT)); if (reason != null) auditReason.append(" for reason: ").append(reason); return guild.kick(target, auditReason.toString()); @@ -30,7 +30,7 @@ public class ModerationHelper { auditReason.append("Banned by ") .append(nameFor(performer.getUser())) .append(" on ") - .append(Instant.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.RFC_1123_DATE_TIME)); + .append(Instant.now().atOffset(ZoneOffset.UTC).format(DATE_TIME_FORMAT)); if (reason != null) auditReason.append(" for reason: ").append(reason); return guild.ban(target, deleteDuration, auditReason.toString()); diff --git a/src/main/java/sciwhiz12/janitor/config/BotConfig.java b/src/main/java/sciwhiz12/janitor/config/BotConfig.java index 4d5a487..6dc0fb7 100644 --- a/src/main/java/sciwhiz12/janitor/config/BotConfig.java +++ b/src/main/java/sciwhiz12/janitor/config/BotConfig.java @@ -23,6 +23,7 @@ public class BotConfig { 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; @@ -67,6 +68,10 @@ public class BotConfig { .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.") + .define("messages.custom_messages", ""); COMMAND_PREFIX = builder .comment("The prefix for commands.") @@ -115,8 +120,7 @@ public class BotConfig { spec.setConfig(config); // TODO: config spec FileWatcher.defaultInstance().addWatch(configPath, this::onFileChange); - } - catch (IOException ex) { + } catch (IOException ex) { JANITOR.error("Error while building config from file {}", configPath, ex); } } @@ -134,6 +138,15 @@ public class BotConfig { .orElse(null); } + @Nullable + public Path getMessagesFolder() { + return options.getMessagesFolder(). + or(() -> CUSTOM_MESSAGES_DIRECTORY.get().isBlank() ? + Optional.empty() : + Optional.of(Path.of(CUSTOM_MESSAGES_DIRECTORY.get()))) + .orElse(null); + } + public String getToken() { return options.getToken().orElse(CLIENT_TOKEN.get()); } @@ -157,8 +170,7 @@ public class BotConfig { CONFIG.info("Reloading config due to file change {}", configPath); config.load(); spec.setConfig(config); - } - catch (Exception ex) { + } catch (Exception ex) { CONFIG.error("Error while reloading config from {}", configPath, ex); } } diff --git a/src/main/java/sciwhiz12/janitor/config/BotOptions.java b/src/main/java/sciwhiz12/janitor/config/BotOptions.java index a61fb0c..6771b88 100644 --- a/src/main/java/sciwhiz12/janitor/config/BotOptions.java +++ b/src/main/java/sciwhiz12/janitor/config/BotOptions.java @@ -4,6 +4,7 @@ import joptsimple.ArgumentAcceptingOptionSpec; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.util.PathConverter; +import joptsimple.util.PathProperties; import java.nio.file.Path; import java.util.Optional; @@ -14,6 +15,7 @@ public class BotOptions { private final OptionSet options; private final ArgumentAcceptingOptionSpec configPath; private final ArgumentAcceptingOptionSpec translationsPath; + private final ArgumentAcceptingOptionSpec messagesFolder; private final ArgumentAcceptingOptionSpec token; private final ArgumentAcceptingOptionSpec prefix; private final ArgumentAcceptingOptionSpec owner; @@ -28,6 +30,10 @@ public class BotOptions { .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") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter(DIRECTORY_EXISTING, READABLE)); this.token = parser .accepts("token", "The Discord token for the bot user") .withRequiredArg(); @@ -49,6 +55,10 @@ public class BotOptions { return translationsPath.valueOptional(options); } + public Optional getMessagesFolder() { + return messagesFolder.valueOptional(options); + } + public Optional getToken() { return token.valueOptional(options); } diff --git a/src/main/java/sciwhiz12/janitor/msg/General.java b/src/main/java/sciwhiz12/janitor/msg/General.java deleted file mode 100644 index 9ab322b..0000000 --- a/src/main/java/sciwhiz12/janitor/msg/General.java +++ /dev/null @@ -1,75 +0,0 @@ -package sciwhiz12.janitor.msg; - -import net.dv8tion.jda.api.Permission; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.User; - -import java.util.EnumSet; -import java.util.stream.Collectors; - -public final class General { - private final Messages messages; - - General(Messages messages) { - this.messages = messages; - } - - public MessageBuilder guildOnlyCommand(final User performer) { - return messages.failure() - .apply(builder -> messages.user(builder, "performer", performer)) - .embed(embed -> embed - .setTitle("general.guild_only_command.title") - .setDescription("general.guild_only_command.description") - ); - } - - public MessageBuilder ambiguousMember(final Member performer) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .embed(embed -> embed - .setTitle("general.ambiguous_member.title") - .setDescription("general.ambiguous_member.description") - ); - } - - public MessageBuilder insufficientPermissions(final Member performer, final EnumSet permissions) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .with("required_permissions", () -> permissions.stream().map(Permission::getName).collect(Collectors.joining(", "))) - .embed(embed -> embed - .setTitle("general.insufficient_permissions.title") - .setDescription("general.insufficient_permissions.description") - ) - .field("general.insufficient_permissions.field.permissions", true); - } - - public MessageBuilder cannotInteract(final Member performer, final Member target) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .embed(embed -> embed - .setTitle("general.cannot_interact.title") - .setDescription("general.cannot_interact.description") - ) - .field("general.cannot_interact.field.target", true); - } - - public MessageBuilder cannotActionSelf(final Member performer) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .embed(embed -> embed - .setTitle("general.cannot_action_self.title") - .setDescription("general.cannot_action_self.description") - ); - } - - public MessageBuilder cannotActionPerformer(final Member performer) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .embed(embed -> embed - .setTitle("general.cannot_action_performer.title") - .setDescription("general.cannot_action_performer.description") - ) - .field("general.cannot_action_performer.field.performer", true); - } -} diff --git a/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java b/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java new file mode 100644 index 0000000..ab96799 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/MessageHelper.java @@ -0,0 +1,110 @@ +package sciwhiz12.janitor.msg; + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.IMentionable; +import net.dv8tion.jda.api.entities.ISnowflake; +import net.dv8tion.jda.api.entities.Member; +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 java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.function.Consumer; + +import static java.time.temporal.ChronoField.*; + +public class MessageHelper { + private MessageHelper() {} + + 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 + .apply(snowflake(head, mentionable)) + .with(head + ".mention", mentionable::getAsMention); + } + + public static Consumer role(String head, Role role) { + return builder -> builder + .apply(mentionable(head, role)) + .with(head + ".color_hex", () -> Integer.toHexString(role.getColorRaw())) + .with(head + ".name", role::getName) + .with(head + ".permissions", role.getPermissions()::toString); + } + + public static Consumer user(String head, User user) { + return builder -> builder + .apply(mentionable(head, user)) + .with(head + ".name", user::getName) + .with(head + ".discriminator", user::getDiscriminator) + .with(head + ".tag", user::getAsTag) + .with(head + ".flags", user.getFlags()::toString); + } + + public static Consumer guild(String head, Guild guild) { + return builder -> builder + .apply(snowflake(head, guild)) + .with(head + ".name", guild::getName) + .with(head + ".description", guild::getDescription) + .with(head + ".voice_region", guild.getRegion()::toString) + .with(head + ".boost.tier", guild.getBoostTier()::toString) + .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); + } + + public static Consumer member(String head, Member member) { + return builder -> builder + .apply(user(head, member.getUser())) + .apply(guild(head + ".guild", member.getGuild())) + .with(head + ".nickname", member::getNickname) + .with(head + ".effective_name", member::getEffectiveName) + .with(head + ".join_datetime", () -> member.getTimeJoined().format(DATE_TIME_FORMAT)) + .with(head + ".color", () -> String.valueOf(member.getColorRaw())); + } + + 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())) + .apply(user(head + ".target", entry.getWarned())) + .with(head + ".date_time", () -> entry.getDateTime().format(DATE_TIME_FORMAT)) + .with(head + ".reason", entry::getReason); + } + + 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())) + .apply(user(head + ".target", entry.getTarget())) + .with(head + ".date_time", () -> entry.getDateTime().format(DATE_TIME_FORMAT)) + .with(head + ".contents", entry::getContents); + } + + public static final DateTimeFormatter DATE_TIME_FORMAT = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .parseLenient() + .appendValue(YEAR, 4) // 2 digit year not handled + .appendLiteral('-') + .appendValue(MONTH_OF_YEAR, 2) + .appendLiteral('-') + .appendValue(DAY_OF_MONTH, 2) + .appendLiteral(' ') + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .optionalStart() + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .optionalEnd() + .appendLiteral(' ') + .appendOffset("+HHMM", "GMT") + .toFormatter(); +} diff --git a/src/main/java/sciwhiz12/janitor/msg/Messages.java b/src/main/java/sciwhiz12/janitor/msg/Messages.java index 03b4f53..114e60b 100644 --- a/src/main/java/sciwhiz12/janitor/msg/Messages.java +++ b/src/main/java/sciwhiz12/janitor/msg/Messages.java @@ -1,97 +1,119 @@ package sciwhiz12.janitor.msg; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.IMentionable; -import net.dv8tion.jda.api.entities.ISnowflake; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.dv8tion.jda.api.entities.MessageEmbed; import sciwhiz12.janitor.JanitorBot; +import sciwhiz12.janitor.msg.json.RegularMessage; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; +import static com.google.common.io.Resources.getResource; +import static sciwhiz12.janitor.Logging.JANITOR; +import static sciwhiz12.janitor.Logging.MESSAGES; public class Messages { - public static final int FAILURE_COLOR = 0xF73132; + public static final String JSON_FILE_SUFFIX = ".json"; + public static final String MESSAGES_FILENAME = "messages"; + public static final String DEFAULT_MESSAGES_FOLDER = "messages/"; + public static final TypeReference> LIST_TYPE = new TypeReference<>() {}; private final JanitorBot bot; - public final General GENERAL; - public final Moderation MODERATION; + private final Path messagesFolder; + private final Map regularMessages = new HashMap<>(); + private final ObjectMapper jsonMapper = new ObjectMapper(); - public Messages(JanitorBot bot) { + public Messages(JanitorBot bot, Path messagesFolder) { this.bot = bot; - this.GENERAL = new General(this); - this.MODERATION = new Moderation(this); + this.messagesFolder = messagesFolder; + loadMessages(); } - public JanitorBot getBot() { - return bot; + public void loadMessages() { + boolean success = false; + + if (messagesFolder != null) { + JANITOR.debug(MESSAGES, "Loading messages from folder {}", messagesFolder); + success = loadMessages( + path -> Files.newBufferedReader(messagesFolder.resolve(path + JSON_FILE_SUFFIX)) + ); + } else { + JANITOR.info(MESSAGES, "No custom messages folder specified"); + } + + if (!success) { + JANITOR.info(MESSAGES, "Loading default messages"); + //noinspection UnstableApiUsage + loadMessages( + file -> new InputStreamReader(getResource(DEFAULT_MESSAGES_FOLDER + file + JSON_FILE_SUFFIX).openStream()) + ); + } } - public MessageBuilder message() { - final MessageBuilder builder = new MessageBuilder(); - builder.embed() - .setTimestamp(OffsetDateTime.now(ZoneOffset.UTC)); - return builder; + boolean loadMessages(FileOpener files) { + try (Reader keyReader = files.open(MESSAGES_FILENAME)) { + List keysList = jsonMapper.readValue(keyReader, LIST_TYPE); + regularMessages.clear(); + for (String messageKey : keysList) { + final String path = messageKey.replace("/", FileSystems.getDefault().getSeparator()); + try (Reader reader = files.open(path)) { + final JsonNode tree = jsonMapper.readTree(reader); + if ("regular".equals(tree.path("type").asText("regular"))) { + regularMessages.put(messageKey, jsonMapper.convertValue(tree, RegularMessage.class)); + } else { + JANITOR.warn(MESSAGES, "Unknown message type {} for {}", tree.path("type").asText(), messageKey); + } + } catch (Exception e) { + JANITOR.error(MESSAGES, "Error while loading message {}", path, e); + } + } + JANITOR.info(MESSAGES, "Loaded {} messages", regularMessages.size()); + return true; + } catch (Exception e) { + JANITOR.error(MESSAGES, "Error while loading messages", e); + return false; + } } - public MessageBuilder failure() { - final MessageBuilder builder = message(); - builder.embed() - .setColor(FAILURE_COLOR); - return builder; + public Map getRegularMessages() { + return Collections.unmodifiableMap(regularMessages); } - public MessageBuilder snowflake(MessageBuilder builder, String head, ISnowflake snowflake) { - return builder - .with(head + ".id", snowflake::getId) - .with(head + ".creation_datetime", () -> snowflake.getTimeCreated().format(RFC_1123_DATE_TIME)); + public RegularMessageBuilder getRegularMessage(String messageKey) { + final RegularMessage msg = regularMessages.get(messageKey); + if (msg == null) { + JANITOR.warn(MESSAGES, "Attempted to get unknown message with key {}", messageKey); + return new RegularMessageBuilder(UNKNOWN_MESSAGE).with("key", () -> messageKey); + } + return new RegularMessageBuilder(msg); } - public MessageBuilder mentionable(MessageBuilder builder, String head, IMentionable mentionable) { - return builder - .apply(b -> snowflake(b, head, mentionable)) - .with(head + ".mention", mentionable::getAsMention); + interface FileOpener { + Reader open(String filePath) throws IOException; } - public MessageBuilder role(MessageBuilder builder, String head, Role role) { - return builder - .apply(b -> mentionable(b, head, role)) - .with(head + ".color_hex", () -> Integer.toHexString(role.getColorRaw())) - .with(head + ".name", role::getName) - .with(head + ".permissions", role.getPermissions()::toString); - } - - public MessageBuilder user(MessageBuilder builder, String head, User user) { - return builder - .apply(b -> mentionable(b, head, user)) - .with(head + ".name", user::getName) - .with(head + ".discriminator", user::getDiscriminator) - .with(head + ".tag", user::getAsTag) - .with(head + ".flags", user.getFlags()::toString); - } - - public MessageBuilder guild(MessageBuilder builder, String head, Guild guild) { - return builder - .apply(b -> snowflake(b, head, guild)) - .with(head + ".name", guild::getName) - .with(head + ".description", guild::getDescription) - .with(head + ".voice_region", guild.getRegion()::toString) - .with(head + ".boost.tier", guild.getBoostTier()::toString) - .with(head + ".boost.count", () -> String.valueOf(guild.getBoostCount())) - .with(head + ".locale", guild.getLocale()::toString) - .with(head + ".verification_level", guild.getVerificationLevel()::toString); - } - - public MessageBuilder member(MessageBuilder builder, String head, Member member) { - return builder - .apply(b -> user(b, head, member.getUser())) - .apply(b -> guild(b, head + ".guild", member.getGuild())) - .with(head + ".nickname", member::getNickname) - .with(head + ".effective_name", member::getEffectiveName) - .with(head + ".join_datetime", () -> member.getTimeJoined().format(RFC_1123_DATE_TIME)) - .with(head + ".color", () -> String.valueOf(member.getColorRaw())); - } + public static final RegularMessage UNKNOWN_MESSAGE = new RegularMessage( + "UNKNOWN MESSAGE!", + null, + "A message was tried to be looked up, but was not found. Please report this to your bot maintainer/administrator.", + String.valueOf(0xFF0000), + null, + null, + null, + null, + null, + null, + null, + Collections.singletonList(new MessageEmbed.Field("Message Key", "${key}", false)) + ); } diff --git a/src/main/java/sciwhiz12/janitor/msg/Moderation.java b/src/main/java/sciwhiz12/janitor/msg/Moderation.java deleted file mode 100644 index b4ea21d..0000000 --- a/src/main/java/sciwhiz12/janitor/msg/Moderation.java +++ /dev/null @@ -1,333 +0,0 @@ -package sciwhiz12.janitor.msg; - -import net.dv8tion.jda.api.Permission; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.User; -import sciwhiz12.janitor.moderation.notes.NoteEntry; -import sciwhiz12.janitor.moderation.warns.WarningEntry; - -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.EnumSet; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; - -public final class Moderation { - public static final int MODERATION_COLOR = 0xF1BD25; - public static final String GAVEL_ICON_URL = "https://cdn.discordapp.com/attachments/738478941760782526" + - "/760463743330549760/gavel.png"; - - private final Messages messages; - public final Errors ERRORS; - - Moderation(Messages messages) { - this.messages = messages; - ERRORS = new Errors(); - } - - public MessageBuilder moderation() { - return messages.message() - .embed(embed -> embed - .setColor(MODERATION_COLOR) - .setTimestamp(OffsetDateTime.now(ZoneOffset.UTC)) - ); - } - - public MessageBuilder moderation(String author) { - return moderation() - .embed(embed -> embed.setAuthor(author, null, GAVEL_ICON_URL)); - } - - public class Errors { - private Errors() {} - - public MessageBuilder performerInsufficientPermissions(final Member performer, final EnumSet permissions) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .with("required_permissions", - () -> permissions.stream().map(Permission::getName).collect(Collectors.joining(", "))) - .embed(embed -> embed - .setTitle("moderation.insufficient_permissions.title") - .setDescription("moderation.insufficient_permissions.description") - ) - .field("moderation.insufficient_permissions.field.performer", true) - .field("moderation.insufficient_permissions.field.required_permissions", true); - } - - public MessageBuilder cannotInteract(final Member performer, final Member target) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .embed(embed -> embed - .setTitle("moderation.cannot_interact.title") - .setDescription("moderation.cannot_interact.description") - ) - .field("moderation.cannot_interact.field.performer", true) - .field("moderation.cannot_interact.field.target", true); - } - - public MessageBuilder cannotWarnMods(final Member performer, final Member target) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .embed(embed -> embed - .setTitle("moderation.warn.cannot_warn_mods.title") - .setDescription("moderation.warn.cannot_warn_mods.description") - ) - .field("moderation.warn.cannot_warn_mods.field.performer", true) - .field("moderation.warn.cannot_warn_mods.field.target", true); - } - - public MessageBuilder cannotRemoveHigherModerated(final Member performer, final int caseID, final WarningEntry entry) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> warningEntry(builder, "warning_entry", caseID, entry)) - .embed(embed -> embed - .setTitle("moderation.unwarn.cannot_remove_higher_mod.title") - .setDescription("moderation.unwarn.cannot_remove_higher_mod.description") - ) - .field("moderation.unwarn.cannot_remove_higher_mod.field.performer", true) - .field("moderation.unwarn.cannot_remove_higher_mod.field.target", true); - } - - public MessageBuilder maxAmountOfNotes(final Member performer, final Member target, final int amount) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("notes_amount", () -> String.valueOf(amount)) - .embed(embed -> embed - .setTitle("moderation.note.max_amount_of_notes.title") - .setDescription("moderation.note.max_amount_of_notes.description") - ) - .field("moderation.note.max_amount_of_notes.field.performer", true) - .field("moderation.note.max_amount_of_notes.field.target", true) - .field("moderation.note.max_amount_of_notes.field.amount", true); - } - - public MessageBuilder noNoteFound(final Member performer, final int noteID) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .with("note_id", () -> String.valueOf(noteID)) - .embed(embed -> embed - .setTitle("moderation.note.no_note_found.title") - .setDescription("moderation.note.no_note_found.description") - ) - .field("moderation.note.no_note_found.field.performer", true) - .field("moderation.note.no_note_found.field.note_id", true); - } - - public MessageBuilder noWarnWithID(final Member performer, final int caseID) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .with("case_id", () -> String.valueOf(caseID)) - .embed(embed -> embed - .setTitle("moderation.unwarn.no_case_found.title") - .setDescription("moderation.unwarn.no_case_found.description") - ) - .field("moderation.unwarn.no_case_found.field.performer", true) - .field("moderation.unwarn.no_case_found.field.note_id", true); - } - - public MessageBuilder cannotUnwarnSelf(final Member performer, final int caseID, final WarningEntry entry) { - return messages.failure() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> warningEntry(builder, "warning_entry", caseID, entry)) - .embed(embed -> embed - .setTitle("moderation.unwarn.cannot_unwarn_self.title") - .setDescription("moderation.unwarn.cannot_unwarn_self.description") - ) - .field("moderation.unwarn.cannot_unwarn_self.field.performer", true) - .field("moderation.unwarn.cannot_unwarn_self.field.original_performer", true) - .field("moderation.unwarn.cannot_unwarn_self.field.target", true); - } - } - - public MessageBuilder kickUser(final Member performer, final Member target, final @Nullable String reason, - final boolean sentDM) { - return moderation("moderation.kick.info.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("reason", () -> reason) - .field("moderation.kick.info.field.performer", true) - .field("moderation.kick.info.field.target", true) - .field("moderation.kick.info.field.private_message." + (sentDM ? "sent" : "unsent"), true) - .field("moderation.kick.info.field.reason", true); - } - - public MessageBuilder kickedDM(final Member performer, final Member target, final @Nullable String reason) { - return moderation() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("reason", () -> reason) - .embed(embed -> embed - .setTitle("moderation.kick.dm.title") - .setAuthor("moderation.kick.dm.author", null, performer.getGuild().getIconUrl()) - ) - .field("moderation.kick.dm.field.performer", true) - .field("moderation.kick.dm.field.reason", true); - } - - public MessageBuilder banUser(final Member performer, final Member target, final @Nullable String reason, - final int deletionDays, final boolean sentDM) { - return moderation("moderation.ban.info.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("delete_duration", () -> String.valueOf(deletionDays)) - .with("reason", () -> reason) - .field("moderation.ban.info.field.performer", true) - .field("moderation.ban.info.field.target", true) - .field("moderation.ban.info.field.private_message." + (sentDM ? "sent" : "unsent"), true) - .field("moderation.ban.info.field.delete_duration", true) - .field("moderation.ban.info.field.reason", true); - } - - public MessageBuilder bannedDM(final Member performer, final Member target, @Nullable final String reason) { - return moderation() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("reason", () -> reason) - .embed(embed -> embed - .setTitle("moderation.ban.dm.title") - .setAuthor("moderation.ban.dm.author", null, performer.getGuild().getIconUrl()) - ) - .field("moderation.ban.dm.field.performer", true) - .field("moderation.ban.dm.field.reason", true); - } - - public MessageBuilder unbanUser(final Member performer, final User target) { - return moderation("moderation.unban.info.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.user(builder, "target", target)) - .field("moderation.unban.info.field.performer", true) - .field("moderation.unban.info.field.target", true); - } - - public void warningEntry(MessageBuilder builder, String head, int caseID, WarningEntry entry) { - builder - .with(head + ".case_id", () -> String.valueOf(caseID)) - .apply(b -> messages.user(b, head + ".performer", entry.getPerformer())) - .apply(b -> messages.user(b, head + ".target", entry.getWarned())) - .with(head + ".date_time", () -> entry.getDateTime().format(RFC_1123_DATE_TIME)) - .with(head + ".reason", entry::getReason); - } - - public MessageBuilder warnUser(final Member performer, final int caseID, final WarningEntry entry, final boolean sentDM) { - return moderation("moderation.warn.info.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> warningEntry(builder, "warning_entry", caseID, entry)) - .field("moderation.warn.info.field.performer", true) - .field("moderation.warn.info.field.target", true) - .field("moderation.warn.info.field.private_message." + (sentDM ? "sent" : "unsent"), true) - .field("moderation.warn.info.field.date_time", true) - .field("moderation.warn.info.field.case_id", true) - .field("moderation.warn.info.field.reason", true); - } - - public MessageBuilder warnedDM(final Member performer, final Member target, final String reason, - final OffsetDateTime dateTime) { - return moderation() - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> messages.member(builder, "target", target)) - .with("date_time", () -> dateTime.format(RFC_1123_DATE_TIME)) - .with("reason", () -> reason) - .embed(embed -> embed - .setTitle("moderation.warn.dm.title") - .setAuthor("moderation.warn.dm.author", null, performer.getGuild().getIconUrl()) - ) - .field("moderation.warn.dm.field.performer", true) - .field("moderation.warn.dm.field.date_time", true) - .field("moderation.warn.dm.field.reason", true); - } - - public MessageBuilder warnList(final Map displayWarnings) { - // return channel.sendMessage( - // moderationEmbed(translate("moderation.warnlist.author")) - // .setDescription(displayWarnings.size() > 0 ? displayWarnings.entrySet().stream() - // .sorted(Collections.reverseOrder(Comparator.comparingInt(Map.Entry::getKey))) - // .limit(10) - // .map(entry -> - // translate("moderation.warnlist.entry", - // entry.getKey(), - // entry.getValue().getWarned().getAsMention(), - // entry.getValue().getPerformer().getAsMention(), - // entry.getValue().getDateTime().format(RFC_1123_DATE_TIME), - // entry.getValue().getReason() != null - // ? entry.getValue().getReason() - // : translate("moderation.warnlist.entry.no_reason")) - // ) - // .collect(Collectors.joining("\n")) - // : translate("moderation.warnlist.empty")) - // .build() - // ); - return moderation() - .embed(embed -> embed.setTitle("NO OP, CURRENTLY IN PROGRESS")); - } - - public MessageBuilder unwarn(final Member performer, final int caseID, final WarningEntry entry) { - return moderation("moderation.unwarn.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> warningEntry(builder, "warning_entry", caseID, entry)) - .field("moderation.unwarn.field.performer", true) - .field("moderation.unwarn.field.case_id", true) - .field("moderation.unwarn.field.original_performer", true) - .field("moderation.unwarn.field.original_target", true) - .field("moderation.unwarn.field.date_time", true) - .field("moderation.unwarn.field.reason", true); - } - - public void noteEntry(MessageBuilder builder, String head, int noteID, NoteEntry entry) { - builder - .with(head + ".note_id", () -> String.valueOf(noteID)) - .apply(b -> messages.user(b, head + ".performer", entry.getPerformer())) - .apply(b -> messages.user(b, head + ".target", entry.getTarget())) - .with(head + ".date_time", () -> entry.getDateTime().format(RFC_1123_DATE_TIME)) - .with(head + ".contents", entry::getContents); - } - - public MessageBuilder addNote(final Member performer, final int noteID, final NoteEntry entry) { - return moderation("moderation.note.add.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> noteEntry(builder, "note", noteID, entry)) - .field("moderation.note.add.field.performer", true) - .field("moderation.note.add.field.target", true) - .field("moderation.note.add.field.note_id", true) - .field("moderation.note.add.field.date_time", true) - .field("moderation.note.add.field.contents", true); - } - - public MessageBuilder noteList(final Map displayNotes) { - // return channel.sendMessage(moderationEmbed(translate("moderation.note.list.author")) - // .setDescription(displayNotes.size() > 0 ? displayNotes.entrySet().stream() - // .sorted(Collections.reverseOrder(Comparator.comparingInt(Map.Entry::getKey))) - // .limit(10) - // .map(entry -> - // translate("moderation.note.list.entry", - // entry.getKey(), - // entry.getValue().getTarget().getAsMention(), - // entry.getValue().getPerformer().getAsMention(), - // entry.getValue().getDateTime().format(RFC_1123_DATE_TIME), - // entry.getValue().getContents()) - // ) - // .collect(Collectors.joining("\n")) - // : translate("moderation.note.list.empty")) - // .build() - // ); - return moderation() - .embed(embed -> embed.setTitle("NO OP, CURRENTLY IN PROGRESS")); - } - - public MessageBuilder removeNote(final Member performer, final int noteID, final NoteEntry entry) { - return moderation("moderation.note.remove.author") - .apply(builder -> messages.member(builder, "performer", performer)) - .apply(builder -> noteEntry(builder, "note", noteID, entry)) - .field("moderation.note.remove.field.performer", true) - .field("moderation.note.remove.field.case_id", true) - .field("moderation.note.remove.field.original_performer", true) - .field("moderation.note.remove.field.original_target", true) - .field("moderation.note.remove.field.date_time", true) - .field("moderation.note.remove.field.contents", true); - } -} diff --git a/src/main/java/sciwhiz12/janitor/msg/Translations.java b/src/main/java/sciwhiz12/janitor/msg/TranslationMap.java similarity index 78% rename from src/main/java/sciwhiz12/janitor/msg/Translations.java rename to src/main/java/sciwhiz12/janitor/msg/TranslationMap.java index 0101dd3..d89790d 100644 --- a/src/main/java/sciwhiz12/janitor/msg/Translations.java +++ b/src/main/java/sciwhiz12/janitor/msg/TranslationMap.java @@ -11,11 +11,16 @@ import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import static java.util.regex.Matcher.quoteReplacement; +import static java.util.regex.Pattern.CASE_INSENSITIVE; import static sciwhiz12.janitor.Logging.JANITOR; import static sciwhiz12.janitor.Logging.TRANSLATIONS; -public class Translations { +public class TranslationMap { + public static final Pattern TRANSLATION_REGEX = Pattern.compile("<(.+?)>", CASE_INSENSITIVE); private static final String DEFAULT_TRANSLATIONS_RESOURCE = "english.json"; private static final TypeReference> MAP_TYPE = new TypeReference<>() {}; @@ -24,7 +29,7 @@ public class Translations { private final Map translations = new HashMap<>(); private final ObjectMapper jsonMapper = new ObjectMapper(); - public Translations(JanitorBot bot, Path translationsFile) { + public TranslationMap(JanitorBot bot, Path translationsFile) { this.bot = bot; this.translationsFile = translationsFile; loadTranslations(); @@ -42,8 +47,7 @@ public class Translations { translations.clear(); translations.putAll(trans); JANITOR.info(TRANSLATIONS, "Loaded {} translations from file {}", translations.size(), translationsFile); - } - catch (Exception e) { + } catch (Exception e) { JANITOR.error(TRANSLATIONS, "Error while loading translations from file {}", translationsFile, e); loadDefaultTranslations(); } @@ -59,8 +63,7 @@ public class Translations { translations.clear(); translations.putAll(trans); JANITOR.info(TRANSLATIONS, "Loaded {} default english translations", translations.size()); - } - catch (Exception e) { + } catch (Exception e) { JANITOR.error(TRANSLATIONS, "Error while loading default english translations", e); } } @@ -69,7 +72,9 @@ public class Translations { return Collections.unmodifiableMap(translations); } - public String translate(String key, Object... args) { - return String.format(translations.getOrDefault(key, key), args); + 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)))); } } diff --git a/src/main/java/sciwhiz12/janitor/msg/json/IMessage.java b/src/main/java/sciwhiz12/janitor/msg/json/IMessage.java new file mode 100644 index 0000000..97535d5 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/json/IMessage.java @@ -0,0 +1,9 @@ +package sciwhiz12.janitor.msg.json; + +import net.dv8tion.jda.api.EmbedBuilder; +import sciwhiz12.janitor.msg.substitution.ISubstitutor; +import sciwhiz12.janitor.msg.TranslationMap; + +public interface IMessage { + EmbedBuilder create(TranslationMap translations, ISubstitutor substitutions); +} diff --git a/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java b/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java new file mode 100644 index 0000000..82c39c6 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/json/ListingMessage.java @@ -0,0 +1,61 @@ +package sciwhiz12.janitor.msg.json; + +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import net.dv8tion.jda.api.entities.MessageEmbed; + +import java.time.OffsetDateTime; + +public class ListingMessage { + protected final String url; + protected final String title; + protected final String description; + protected final OffsetDateTime timestamp; + protected final int color; + protected final MessageEmbed.Thumbnail thumbnail; + protected final MessageEmbed.AuthorInfo author; + protected final MessageEmbed.Footer footer; + protected final MessageEmbed.ImageInfo image; + protected final Multimap fields; + + @Deprecated + public ListingMessage() { + this(null, null, null, null, 0, null, null, null, null, null); + } + + public ListingMessage(MessageEmbed embed) { + this(embed.getUrl(), + embed.getTitle(), + embed.getDescription(), + embed.getTimestamp(), + embed.getColorRaw(), + embed.getThumbnail(), + embed.getAuthor(), + embed.getFooter(), + embed.getImage(), + Multimaps.index(embed.getFields(), k -> FieldPlacement.BEFORE)); + } + + public ListingMessage(String url, String title, String description, OffsetDateTime timestamp, int color, + MessageEmbed.Thumbnail thumbnail, MessageEmbed.AuthorInfo author, MessageEmbed.Footer footer, + MessageEmbed.ImageInfo image, Multimap fields) { + this.url = url; + this.title = title; + this.description = description; + this.timestamp = timestamp; + this.color = color; + this.thumbnail = thumbnail; + this.author = author; + this.footer = footer; + this.image = image; + this.fields = fields; + } + + public enum ListingType { + DESCRIPTION, FIELDS + } + + public enum FieldPlacement { + BEFORE, AFTER; + } +} diff --git a/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java new file mode 100644 index 0000000..873b015 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessage.java @@ -0,0 +1,213 @@ +package sciwhiz12.janitor.msg.json; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.common.primitives.Ints; +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.substitution.ISubstitutor; +import sciwhiz12.janitor.msg.TranslationMap; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +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) +public class RegularMessage implements IMessage { + @Nullable + protected final String title; + @Nullable + protected final String url; + @Nullable + protected final String description; + @Nullable + protected final String color; + @Nullable + protected final String authorName; + @Nullable + protected final String authorUrl; + @Nullable + protected final String authorIconUrl; + @Nullable + protected final String footerText; + @Nullable + protected final String footerIconUrl; + @Nullable + protected final String imageUrl; + @Nullable + protected final String thumbnailUrl; + protected final List fields; + + public RegularMessage( + @Nullable String title, + @Nullable String url, + @Nullable String description, + @Nullable String color, + @Nullable String authorName, + @Nullable String authorUrl, + @Nullable String authorIconUrl, + @Nullable String footerText, + @Nullable String footerIconUrl, + @Nullable String imageUrl, + @Nullable String thumbnailUrl, + List fields + ) { + this.title = title; + this.url = url; + this.description = description; + this.color = color; + this.authorName = authorName; + this.authorUrl = authorUrl; + this.authorIconUrl = authorIconUrl; + this.footerText = footerText; + this.footerIconUrl = footerIconUrl; + this.imageUrl = imageUrl; + this.thumbnailUrl = thumbnailUrl; + this.fields = new ArrayList<>(fields); + } + + @Nullable + public String getTitle() { + return title; + } + + @Nullable + public String getUrl() { + return url; + } + + @Nullable + public String getDescription() { + return description; + } + + @Nullable + public String getColor() { + return color; + } + + @Nullable + public String getAuthorName() { + return authorName; + } + + @Nullable + public String getAuthorUrl() { + return authorUrl; + } + + @Nullable + public String getAuthorIconUrl() { + return authorIconUrl; + } + + @Nullable + public String getFooterText() { + return footerText; + } + + @Nullable + public String getFooterIconUrl() { + return footerIconUrl; + } + + @Nullable + public String getImageUrl() { + return imageUrl; + } + + @Nullable + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public List getFields() { + return Collections.unmodifiableList(fields); + } + + @Override + public String toString() { + return new StringJoiner(", ", RegularMessage.class.getSimpleName() + "[", "]") + .add("title='" + title + "'") + .add("url='" + url + "'") + .add("description='" + description + "'") + .add("color='" + color + "'") + .add("authorName='" + authorName + "'") + .add("authorUrl='" + authorUrl + "'") + .add("authorIconUrl='" + authorIconUrl + "'") + .add("footerText='" + footerText + "'") + .add("footerIconUrl='" + footerIconUrl + "'") + .add("imageUrl='" + imageUrl + "'") + .add("thumbnailUrl='" + thumbnailUrl + "'") + .add("fields=" + fields) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RegularMessage that = (RegularMessage) o; + return Objects.equals(title, that.title) && + Objects.equals(url, that.url) && + Objects.equals(description, that.description) && + Objects.equals(color, that.color) && + Objects.equals(authorName, that.authorName) && + Objects.equals(authorUrl, that.authorUrl) && + Objects.equals(authorIconUrl, that.authorIconUrl) && + Objects.equals(footerText, that.footerText) && + Objects.equals(footerIconUrl, that.footerIconUrl) && + Objects.equals(imageUrl, that.imageUrl) && + Objects.equals(thumbnailUrl, that.thumbnailUrl) && + fields.equals(that.fields); + } + + @Override + public int hashCode() { + return Objects + .hash(title, url, description, color, authorName, authorUrl, authorIconUrl, footerText, footerIconUrl, imageUrl, + thumbnailUrl, fields); + } + + @Override + public EmbedBuilder create(TranslationMap translations, ISubstitutor substitutions) { + final Function func = str -> str != null ? substitutions.substitute(translations.translate(str)) : null; + 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.setTimestamp(OffsetDateTime.now(ZoneOffset.UTC)); + builder.setFooter(func.apply(footerText), func.apply(footerIconUrl)); + for (MessageEmbed.Field field : fields) { + builder.addField(func.apply(field.getName()), func.apply(field.getValue()), field.isInline()); + } + return builder; + } + + private static int parseColor(String str) { + if (Strings.isNullOrEmpty(str)) return Role.DEFAULT_COLOR_RAW; + if (str.startsWith("0x")) { + // noinspection UnstableApiUsage + final Integer res = Ints.tryParse(str.substring(2), 16); + if (res != null) { + return res; + } + } + // noinspection UnstableApiUsage + final Integer res = Ints.tryParse(str, 10); + if (res != null) { + return res; + } + return Role.DEFAULT_COLOR_RAW; + } +} diff --git a/src/main/java/sciwhiz12/janitor/msg/json/RegularMessageDeserializer.java b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessageDeserializer.java new file mode 100644 index 0000000..36857e3 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/json/RegularMessageDeserializer.java @@ -0,0 +1,93 @@ +package sciwhiz12.janitor.msg.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import net.dv8tion.jda.api.entities.MessageEmbed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +public class RegularMessageDeserializer extends StdDeserializer { + public RegularMessageDeserializer() { + super(RegularMessage.class); + } + + @Override + public RegularMessage deserialize(JsonParser p, DeserializationContext ctx) + throws IOException { + + final JsonNode node = ctx.readTree(p); + + String title = null; + String url = null; + String description = node.path("description").asText(null); + String color = node.path("color").asText(null); + String authorName = null; + String authorUrl = null; + String authorIconUrl = null; + String footerText = null; + String footerIconUrl = null; + String imageUrl = node.path("image").asText(null); + String thumbnailUrl = node.path("thumbnail").asText(null); + List fields = readFields(node); + + // Title + if (node.path("title").isTextual()) { + title = node.path("title").asText(); + } else if (node.path("title").path("text").isTextual()) { + title = node.path("title").path("text").asText(); + url = node.path("title").path("url").asText(null); + } + + // Author + if (node.path("author").isTextual()) { + authorName = node.path("author").asText(); + } else if (node.path("author").path("name").isTextual()) { + authorName = node.path("author").path("name").asText(); + authorUrl = node.path("author").path("url").asText(null); + authorIconUrl = node.path("author").path("icon_url").asText(null); + } + + // Footer + if (node.path("footer").isTextual()) { + footerText = node.path("footer").asText(); + } else if (node.path("footer").path("text").isTextual()) { + footerText = node.path("footer").path("text").asText(); + footerIconUrl = node.path("footer").path("icon_url").asText(null); + } + + return new RegularMessage(title, url, description, color, authorName, authorUrl, + authorIconUrl, footerText, footerIconUrl, imageUrl, thumbnailUrl, fields); + } + + public static List readFields(JsonNode node) { + if (node.path("fields").isArray()) { + final ArrayList fields = new ArrayList<>(); + for (int i = 0; i < node.path("fields").size(); i++) { + final MessageEmbed.Field field = readField(node.path("fields").path(i)); + if (field != null) { + fields.add(field); + } + } + return fields; + } + return Collections.emptyList(); + } + + @Nullable + public static MessageEmbed.Field readField(JsonNode fieldNode) { + if (fieldNode.path("name").isTextual() && fieldNode.path("value").isTextual()) { + return new MessageEmbed.Field( + fieldNode.path("name").asText(), + fieldNode.path("value").asText(), + fieldNode.path("inline").asBoolean(false) + ); + } + return null; + } +} diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java b/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java new file mode 100644 index 0000000..bc45d6c --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/CustomSubstitutions.java @@ -0,0 +1,21 @@ +package sciwhiz12.janitor.msg.substitution; + +import java.util.Map; +import java.util.function.Supplier; + +public class CustomSubstitutions implements ISubstitutor { + private final Map> map; + + public CustomSubstitutions(Map> map) { + this.map = map; + } + + @Override + public String substitute(String text) { + return SubstitutionMap.substitute(text, map); + } + + public Map> getMap() { + return map; + } +} diff --git a/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java b/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java new file mode 100644 index 0000000..907b51d --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/ISubstitutor.java @@ -0,0 +1,5 @@ +package sciwhiz12.janitor.msg.substitution; + +public interface ISubstitutor { + String substitute(String text); +} diff --git a/src/main/java/sciwhiz12/janitor/msg/Substitutions.java b/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java similarity index 61% rename from src/main/java/sciwhiz12/janitor/msg/Substitutions.java rename to src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java index 75fa7eb..00c2d5d 100644 --- a/src/main/java/sciwhiz12/janitor/msg/Substitutions.java +++ b/src/main/java/sciwhiz12/janitor/msg/substitution/SubstitutionMap.java @@ -1,9 +1,11 @@ -package sciwhiz12.janitor.msg; +package sciwhiz12.janitor.msg.substitution; import org.apache.commons.collections4.TransformerUtils; import org.apache.commons.collections4.map.DefaultedMap; import sciwhiz12.janitor.JanitorBot; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; @@ -12,8 +14,9 @@ import java.util.regex.Pattern; import static java.util.regex.Matcher.quoteReplacement; import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static sciwhiz12.janitor.msg.MessageHelper.DATE_TIME_FORMAT; -public class Substitutions { +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); @@ -22,7 +25,8 @@ public class Substitutions { return matcher.replaceAll(matchResult -> { final Matcher nullMatcher = NULL_ARGUMENT_REGEX.matcher(matchResult.group(1)); if (nullMatcher.matches()) { - final String str = arguments.get(nullMatcher.group(1)).get(); + 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()); @@ -34,8 +38,13 @@ public class Substitutions { private final JanitorBot bot; private final Map> defaultSubstitutions = new HashMap<>(); - public Substitutions(JanitorBot bot) { + public SubstitutionMap(JanitorBot bot) { this.bot = bot; + defaultSubstitutions.put("time.now", () -> OffsetDateTime.now(ZoneOffset.UTC).format(DATE_TIME_FORMAT)); + defaultSubstitutions.put("moderation.color", () -> "0xF1BD25"); + defaultSubstitutions.put("moderation.icon_url", + () -> "https://cdn.discordapp.com/attachments/738478941760782526/760463743330549760/gavel.png"); + defaultSubstitutions.put("general.error.color", () -> "0xF73132"); } public JanitorBot getBot() { @@ -43,17 +52,19 @@ public class Substitutions { } public String substitute(String text) { - return Substitutions.substitute(text, defaultSubstitutions); + return SubstitutionMap.substitute(text, defaultSubstitutions); } public String with(String text, Map> substitutions) { - return Substitutions.substitute( - text, - DefaultedMap.defaultedMap(substitutions, TransformerUtils.mapTransformer(defaultSubstitutions)) - ); + return SubstitutionMap.substitute(text, createDefaultedMap(substitutions)); + } + + public CustomSubstitutions with(Map> customSubstitutions) { + return new CustomSubstitutions(createDefaultedMap(customSubstitutions)); } public Map> createDefaultedMap(Map> custom) { return DefaultedMap.defaultedMap(custom, TransformerUtils.mapTransformer(defaultSubstitutions)); } + } diff --git a/src/main/resources/english.json b/src/main/resources/english.json index abc3289..fef3c78 100644 --- a/src/main/resources/english.json +++ b/src/main/resources/english.json @@ -1,182 +1,118 @@ { - "general.guild_only_command.title": "Guild only command!", - "general.guild_only_command.description": "This command can only be run in a guild channel.", - "general.ambiguous_member.title": "Ambiguous member argument!", - "general.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.insufficient_permissions.title": "I have insufficient permissions!", - "general.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.insufficient_permissions.field.permissions.name": "Required permissions", - "general.insufficient_permissions.field.permissions.value": "${required_permissions}", - "general.cannot_interact.title": "Member is higher than me!", - "general.cannot_interact.description": "Cannot perform action on the given member, likely due to me being lower in the role hierarchy.", - "general.cannot_interact.field.target.name": "Target", - "general.cannot_interact.field.target.value": "${target.mention}", - "general.cannot_action_self.title": "Cannot act against myself!", - "general.cannot_action_self.description": "Cannot perform action against myself, as that would be counter-intuitive.", - "general.cannot_action_performer.title": "Performer cannot act against self!", - "general.cannot_action_performer.description": "You cannot perform this action against yourself.", - "general.cannot_action_performer.field.performer.name": "Performer/Target", - "general.cannot_action_performer.field.performer.value": "${performer.mention}", + "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.name": "Performer", - "moderation.insufficient_permissions.field.performer.value": "${performer.mention}", - "moderation.insufficient_permissions.field.permissions.name": "Required permissions", - "moderation.insufficient_permissions.field.permissions.value": "${required_permissions}", + "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.name": "Performer", - "moderation.cannot_interact.field.performer.value": "${performer.mention}", - "moderation.cannot_interact.field.target.name": "Target", - "moderation.cannot_interact.field.target.value": "${target.mention}", + "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.name": "Performer", - "moderation.kick.info.field.performer.value": "${performer.mention}", - "moderation.kick.info.field.target.name": "Target", - "moderation.kick.info.field.target.value": "${target.mention}", + "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.info.field.private_message.sent.name": "Sent DM", - "moderation.kick.info.field.private_message.sent.value": "✅", - "moderation.kick.info.field.private_message.unsent.name": "Sent DM", - "moderation.kick.info.field.private_message.unsent.value": "❌", - "moderation.kick.dm.author": "${performer.guild.name}", "moderation.kick.dm.title": "You were kicked from this server.", - "moderation.kick.dm.field.performer.name": "Moderator", - "moderation.kick.dm.field.performer.value": "${performer.mention}", + "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.name": "Performer", - "moderation.ban.info.field.performer.value": "${performer.mention}", - "moderation.ban.info.field.target.name": "Target", - "moderation.ban.info.field.target.value": "${target.mention}", - "moderation.ban.info.field.reason.name": "Reason", - "moderation.ban.info.field.reason.value": "${nullcheck;reason;_No reason specified._}", - "moderation.ban.info.field.private_message.sent.name": "Sent DM", - "moderation.ban.info.field.private_message.sent.value": "✅", - "moderation.ban.info.field.private_message.unsent.name": "Sent DM", - "moderation.ban.info.field.private_message.unsent.value": "❌", + "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.dm.author": "${performer.guild.name}", + "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.name": "Moderator", - "moderation.ban.dm.field.performer.value": "${performer.mention}", + "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.name": "Performer", - "moderation.unban.info.field.performer.value": "${performer.mention}", - "moderation.unban.info.field.target.name": "Target", - "moderation.unban.info.field.target.value": "${target.mention}", + "moderation.unban.info.field.performer": "Performer", + "moderation.unban.info.field.target": "Target", "moderation.warn.info.author": "Warned user.", - "moderation.warn.info.field.performer.name": "Performer", - "moderation.warn.info.field.performer.value": "${warning_entry.performer.mention}", - "moderation.warn.info.field.target.name": "Target", - "moderation.warn.info.field.target.value": "${warning_entry.target.mention}", - "moderation.warn.info.field.case_id.name": "Case ID", - "moderation.warn.info.field.case_id.value": "${warning_entry.case_id}", + "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.name": "Sent DM", - "moderation.warn.info.field.private_message.sent.value": "✅", - "moderation.warn.info.field.private_message.unsent.name": "Sent DM", - "moderation.warn.info.field.private_message.unsent.value": "❌", - "moderation.warn.info.field.date_time.name": "Date & Time", - "moderation.warn.info.field.date_time.value": "${warning_entry.date_time}", - "moderation.warn.dm.author": "${performer.guild.name}", + "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.name": "Moderator", - "moderation.warn.dm.field.performer.value": "${performer.mention}", - "moderation.warn.dm.field.date_time.name": "Date & Time", - "moderation.warn.dm.field.date_time.value": "${date_time}", + "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;reason;_No reason specified._}", + "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 #%1$s**: Warned %2$s by %3$s %n - _Date & Time:_ %4$s %n - _Reason:_ %5$s", "moderation.warnlist.entry.no_reason": "_no reason specified_", - "moderation.unwarn.author": "Removed warning from user.", - "moderation.unwarn.field.performer.name": "Performer", - "moderation.unwarn.field.performer.value": "${performer.mention}", - "moderation.unwarn.field.original_target.name": "Original Target", - "moderation.unwarn.field.original_target.value": "${warning_entry.target.mention}", - "moderation.unwarn.field.original_performer.name": "Original Performer", - "moderation.unwarn.field.original_performer.value": "${warning_entry.performer.mention}", - "moderation.unwarn.field.case_id.name": "Case ID", - "moderation.unwarn.field.case_id.value": "${warning_entry.case_id}", - "moderation.unwarn.field.date_time.name": "Date & Time", - "moderation.unwarn.field.date_time.value": "${warning_entry.date_time}", - "moderation.unwarn.field.reason.name": "Reason", - "moderation.unwarn.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.name": "Performer", - "moderation.unwarn.no_case_found.field.performer.value": "${performer.mention}", - "moderation.unwarn.no_case_found.field.case_id.name": "Case ID", - "moderation.unwarn.no_case_found.field.case_id.value": "${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.name": "Performer/Original Target", - "moderation.unwarn.cannot_unwarn_self.field.performer.value": "${performer.mention}", - "moderation.unwarn.cannot_unwarn_self.field.original_performer.name": "Original Performer", - "moderation.unwarn.cannot_unwarn_self.field.original_performer.value": "${warning_entry.performer.mention}", - "moderation.unwarn.cannot_unwarn_self.field.case_id.name": "Case ID", - "moderation.unwarn.cannot_unwarn_self.field.case_id.value": "${warning_entry.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.name": "Performer", - "moderation.warn.cannot_warn_mods.field.performer.value": "${performer.mention}", - "moderation.warn.cannot_warn_mods.field.target.name": "Target", - "moderation.warn.cannot_warn_mods.field.target.value": "${target.mention}", - "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.name": "Performer", - "moderation.warn.cannot_remove_higher_mod.field.performer.value": "${performer.mention}", - "moderation.warn.cannot_remove_higher_mod.field.original_performer.name": "Original Performer", - "moderation.warn.cannot_remove_higher_mod.field.original_performer.value": "${warning_entry.performer.mention}", - "moderation.warn.cannot_remove_higher_mod.field.case_id.name": "Case ID", - "moderation.warn.cannot_remove_higher_mod.field.case_id.value": "${warning_entry.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.name": "Performer", - "moderation.note.max_amount_of_notes.field.performer.value": "${performer.mention}", - "moderation.note.max_amount_of_notes.field.target.name": "Target", - "moderation.note.max_amount_of_notes.field.target.value": "${target.mention}", - "moderation.note.max_amount_of_notes.field.amount.name": "(Max.) Amount", - "moderation.note.max_amount_of_notes.field.amount.value": "${notes_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.name": "Performer", - "moderation.note.no_note_found.field.performer.value": "${performer.mention}", - "moderation.note.no_note_found.field.note_id.name": "Note ID", - "moderation.note.no_note_found.field.note_id.value": "${note_id}", "moderation.note.list.author": "Listing of Notes", "moderation.note.list.empty": "**_No recorded notes matching your query._**", - "moderation.note.list.entry": "**#%1$s**: for %2$s by %3$s %n - _Date & Time:_ %4$s %n - _Text:_ %5$s", - "moderation.note.add.author": "Recorded note for user.", - "moderation.note.add.field.performer.name": "Performer", - "moderation.note.add.field.performer.value": "${note.performer.mention}", - "moderation.note.add.field.target.name": "Target", - "moderation.note.add.field.target.value": "${note.target.mention}", - "moderation.note.add.field.note_id.name": "Note ID", - "moderation.note.add.field.note_id.value": "${note.note_id}", - "moderation.note.add.field.date_time.name": "Date & Time", - "moderation.note.add.field.date_time.value": "${note.date_time}", - "moderation.note.add.field.contents.name": "Text", - "moderation.note.add.field.contents.value": "${note.contents}", - "moderation.note.remove.author": "Removed note.", - "moderation.note.remove.field.performer.name": "Performer", - "moderation.note.remove.field.performer.value": "${performer.mention}", - "moderation.note.remove.field.original_performer.name": "Original Performer", - "moderation.note.remove.field.original_performer.value": "${note.performer.mention}", - "moderation.note.remove.field.original_target.name": "Original Target", - "moderation.note.remove.field.original_target.value": "${note.target.mention}", - "moderation.note.remove.field.note_id.name": "Note ID", - "moderation.note.remove.field.note_id.value": "${note.note_id}", - "moderation.note.remove.field.date_time.name": "Date & Time", - "moderation.note.remove.field.date_time.value": "${note.date_time}", - "moderation.note.remove.field.contents.name": "Text", - "moderation.note.remove.field.contents.value": "${note.contents}" + "moderation.note.list.entry": "**#%1$s**: for %2$s by %3$s %n - _Date & Time:_ %4$s %n - _Text:_ %5$s" } \ 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 new file mode 100644 index 0000000..f078f45 --- /dev/null +++ b/src/main/resources/messages/general/error/ambiguous_member.json @@ -0,0 +1,5 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "" +} \ 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 new file mode 100644 index 0000000..8913518 --- /dev/null +++ b/src/main/resources/messages/general/error/cannot_action_performer.json @@ -0,0 +1,12 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + } + ] +} \ 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 new file mode 100644 index 0000000..a43ec63 --- /dev/null +++ b/src/main/resources/messages/general/error/cannot_action_self.json @@ -0,0 +1,5 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "" +} \ 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 new file mode 100644 index 0000000..a4eea52 --- /dev/null +++ b/src/main/resources/messages/general/error/cannot_interact.json @@ -0,0 +1,12 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${target.mention}", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/general/error/guild_only_command.json b/src/main/resources/messages/general/error/guild_only_command.json new file mode 100644 index 0000000..b46d90c --- /dev/null +++ b/src/main/resources/messages/general/error/guild_only_command.json @@ -0,0 +1,5 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "" +} \ 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 new file mode 100644 index 0000000..1d3f29c --- /dev/null +++ b/src/main/resources/messages/general/error/insufficient_permissions.json @@ -0,0 +1,12 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${required_permissions}", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/messages.json b/src/main/resources/messages/messages.json new file mode 100644 index 0000000..5322c01 --- /dev/null +++ b/src/main/resources/messages/messages.json @@ -0,0 +1,26 @@ +[ + "general/error/ambiguous_member", + "general/error/guild_only_command", + "general/error/insufficient_permissions", + "general/error/cannot_interact", + "general/error/cannot_action_self", + "general/error/cannot_action_performer", + "moderation/error/cannot_interact", + "moderation/error/insufficient_permissions", + "moderation/kick/info", + "moderation/kick/dm", + "moderation/ban/info", + "moderation/ban/dm", + "moderation/unban/info", + "moderation/warn/info", + "moderation/warn/dm", + "moderation/unwarn/info", + "moderation/error/unwarn/no_case_found", + "moderation/error/unwarn/cannot_unwarn_self", + "moderation/error/unwarn/cannot_remove_higher_mod", + "moderation/error/warn/cannot_warn_mods", + "moderation/error/note/max_amount_of_notes", + "moderation/error/note/no_note_found", + "moderation/note/add", + "moderation/note/remove" +] \ No newline at end of file diff --git a/src/main/resources/messages/moderation/ban/dm.json b/src/main/resources/messages/moderation/ban/dm.json new file mode 100644 index 0000000..3798ed0 --- /dev/null +++ b/src/main/resources/messages/moderation/ban/dm.json @@ -0,0 +1,20 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "${performer.guild.name}", + "icon_url": "${performer.guild.icon_url}" + }, + "title": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/ban/info.json b/src/main/resources/messages/moderation/ban/info.json new file mode 100644 index 0000000..306ee27 --- /dev/null +++ b/src/main/resources/messages/moderation/ban/info.json @@ -0,0 +1,34 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + }, + { + "name": "", + "value": "${private_message}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": true + }, + { + "name": "", + "value": "", + "inline": false + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/cannot_interact.json b/src/main/resources/messages/moderation/error/cannot_interact.json new file mode 100644 index 0000000..63cb40a --- /dev/null +++ b/src/main/resources/messages/moderation/error/cannot_interact.json @@ -0,0 +1,17 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/error/insufficient_permissions.json b/src/main/resources/messages/moderation/error/insufficient_permissions.json new file mode 100644 index 0000000..a2479f2 --- /dev/null +++ b/src/main/resources/messages/moderation/error/insufficient_permissions.json @@ -0,0 +1,17 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${required_permissions}", + "inline": true + } + ] +} \ No newline at end of file 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 new file mode 100644 index 0000000..a451a0d --- /dev/null +++ b/src/main/resources/messages/moderation/error/note/max_amount_of_notes.json @@ -0,0 +1,22 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + }, + { + "name": "", + "value": "${notes_amount}", + "inline": true + } + ] +} \ No newline at end of file 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 new file mode 100644 index 0000000..70b2bf3 --- /dev/null +++ b/src/main/resources/messages/moderation/error/note/no_note_found.json @@ -0,0 +1,17 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_id}", + "inline": true + } + ] +} \ 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 new file mode 100644 index 0000000..fd3982d --- /dev/null +++ b/src/main/resources/messages/moderation/error/unwarn/cannot_remove_higher_mod.json @@ -0,0 +1,22 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "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 new file mode 100644 index 0000000..69f09a3 --- /dev/null +++ b/src/main/resources/messages/moderation/error/unwarn/cannot_unwarn_self.json @@ -0,0 +1,22 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "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 new file mode 100644 index 0000000..2914238 --- /dev/null +++ b/src/main/resources/messages/moderation/error/unwarn/no_case_found.json @@ -0,0 +1,17 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${case_id}", + "inline": true + } + ] +} \ 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 new file mode 100644 index 0000000..4b2f418 --- /dev/null +++ b/src/main/resources/messages/moderation/error/warn/cannot_warn_mods.json @@ -0,0 +1,17 @@ +{ + "color": "${general.error.color}", + "title": "", + "description": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/kick/dm.json b/src/main/resources/messages/moderation/kick/dm.json new file mode 100644 index 0000000..89a7ca0 --- /dev/null +++ b/src/main/resources/messages/moderation/kick/dm.json @@ -0,0 +1,20 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "${performer.guild.name}", + "icon_url": "${performer.guild.icon_url}" + }, + "title": "", + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/kick/info.json b/src/main/resources/messages/moderation/kick/info.json new file mode 100644 index 0000000..f3288b8 --- /dev/null +++ b/src/main/resources/messages/moderation/kick/info.json @@ -0,0 +1,29 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + }, + { + "name": "", + "value": "${private_message}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": false + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/note/add.json b/src/main/resources/messages/moderation/note/add.json new file mode 100644 index 0000000..71fc360 --- /dev/null +++ b/src/main/resources/messages/moderation/note/add.json @@ -0,0 +1,34 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${note_entry.performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.target.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.note_id}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.date_time}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.contents}", + "inline": false + } + ] +} \ 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 new file mode 100644 index 0000000..69b176b --- /dev/null +++ b/src/main/resources/messages/moderation/note/remove.json @@ -0,0 +1,39 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.target.mention}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.note_id}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.date_time}", + "inline": true + }, + { + "name": "", + "value": "${note_entry.contents}", + "inline": false + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/unban/info.json b/src/main/resources/messages/moderation/unban/info.json new file mode 100644 index 0000000..6efe8a3 --- /dev/null +++ b/src/main/resources/messages/moderation/unban/info.json @@ -0,0 +1,19 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${target.mention}", + "inline": true + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/unwarn/info.json b/src/main/resources/messages/moderation/unwarn/info.json new file mode 100644 index 0000000..6d2b347 --- /dev/null +++ b/src/main/resources/messages/moderation/unwarn/info.json @@ -0,0 +1,39 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.target.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.case_id}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.date_time}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": false + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/warn/dm.json b/src/main/resources/messages/moderation/warn/dm.json new file mode 100644 index 0000000..1139d25 --- /dev/null +++ b/src/main/resources/messages/moderation/warn/dm.json @@ -0,0 +1,25 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "${performer.guild.name}", + "icon_url": "${performer.guild.icon_url}" + }, + "title": "", + "fields": [ + { + "name": "", + "value": "${warning_entry.performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.date_time}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": false + } + ] +} \ No newline at end of file diff --git a/src/main/resources/messages/moderation/warn/info.json b/src/main/resources/messages/moderation/warn/info.json new file mode 100644 index 0000000..ed55bb7 --- /dev/null +++ b/src/main/resources/messages/moderation/warn/info.json @@ -0,0 +1,39 @@ +{ + "color": "${moderation.color}", + "author": { + "name": "", + "icon_url": "${moderation.icon_url}" + }, + "fields": [ + { + "name": "", + "value": "${warning_entry.performer.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.target.mention}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.case_id}", + "inline": true + }, + { + "name": "", + "value": "${private_message}", + "inline": true + }, + { + "name": "", + "value": "${warning_entry.date_time}", + "inline": true + }, + { + "name": "", + "value": "", + "inline": false + } + ] +} \ No newline at end of file