1
0
mirror of https://github.com/sciwhiz12/Janitor.git synced 2024-11-10 02:21:25 +00:00

Improve and add more config options, add reload command to console

This commit is contained in:
Arnold Alejo Nunag 2020-10-01 05:22:40 +08:00
parent cbf57fb585
commit 934fbeb2f4
Signed by: sciwhiz12
GPG Key ID: 622CF446534317E1
12 changed files with 129 additions and 21 deletions

View File

@ -34,14 +34,25 @@ public class BotConsole {
public void parseCommand(String input) {
String[] parts = input.split(" ");
outer:
switch (parts[0]) {
case "shutdown": {
running = false;
bot.shutdown();
break;
}
case "reload": {
if (parts.length >= 2)
switch (parts[1]) {
case "translations": {
CONSOLE.info("Reloading translations");
bot.getTranslations().loadTranslations();
break outer;
}
}
}
default:
CONSOLE.warn("Unknown command: " + input);
CONSOLE.warn("Unknown command: {}", input);
}
}
@ -60,7 +71,8 @@ public class BotConsole {
while (!scanner.hasNextLine()) {
try {
Thread.sleep(150);
} catch (InterruptedException e) {
}
catch (InterruptedException e) {
CONSOLE.warn("Console thread is interrupted");
continue outer;
}
@ -72,7 +84,8 @@ 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);
}
}

View File

@ -62,6 +62,11 @@ public class GuildStorage {
}
public void save() {
save(false);
}
public void save(boolean isAutosave) {
if (!isAutosave)
Logging.JANITOR.debug("Saving guild storage to files under {}...", mainFolder);
boolean anySaved = false;
for (Guild guild : guildStorage.keySet()) {
@ -111,8 +116,8 @@ public class GuildStorage {
@Override
public void run() {
while (running) {
storage.save();
try { Thread.sleep(10000); }
storage.save(true);
try { Thread.sleep(storage.getBot().getConfig().AUTOSAVE_INTERVAL.get() * 1000); }
catch (InterruptedException ignored) {}
}
}

View File

@ -3,6 +3,7 @@ package sciwhiz12.janitor.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import sciwhiz12.janitor.JanitorBot;
import sciwhiz12.janitor.config.BotConfig;
import sciwhiz12.janitor.msg.Messages;
public abstract class BaseCommand {
@ -24,5 +25,9 @@ public abstract class BaseCommand {
return getBot().getMessages();
}
protected BotConfig config() {
return getBot().getConfig();
}
public abstract LiteralArgumentBuilder<MessageReceivedEvent> getNode();
}

View File

@ -48,9 +48,7 @@ public class CommandRegistry implements EventListener {
addCommand(new WarnCommand(this));
addCommand(new WarnListCommand(this));
addCommand(new UnwarnCommand(this));
if (bot.getConfig().getOwnerID().isPresent()) {
addCommand(new ShutdownCommand(this, bot.getConfig().getOwnerID().get()));
}
addCommand(new ShutdownCommand(this));
}
public CommandDispatcher<MessageReceivedEvent> getDispatcher() {

View File

@ -11,17 +11,16 @@ import static sciwhiz12.janitor.Logging.JANITOR;
import static sciwhiz12.janitor.commands.util.CommandHelper.literal;
public class ShutdownCommand extends BaseCommand {
private final long ownerID;
public ShutdownCommand(CommandRegistry registry, long ownerID) {
public ShutdownCommand(CommandRegistry registry) {
super(registry);
this.ownerID = ownerID;
}
@Override
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
return literal("shutdown")
.requires(ctx -> ctx.getAuthor().getIdLong() == ownerID)
.requires(ctx -> getBot().getConfig().getOwnerID().map(
id -> id == ctx.getAuthor().getIdLong()).orElse(false)
)
.executes(this::run);
}
@ -33,7 +32,8 @@ public class ShutdownCommand extends BaseCommand {
.submit()
.whenComplete(Util.handle(
success -> JANITOR.debug("Sent shutdown message to channel {}", Util.toString(ctx.getSource().getAuthor())),
err -> JANITOR.error("Error while sending ping message to bot owner {}", Util.toString(ctx.getSource().getAuthor()))
err -> JANITOR
.error("Error while sending ping message to bot owner {}", Util.toString(ctx.getSource().getAuthor()))
)
)
.join();

View File

@ -31,6 +31,7 @@ public class UnwarnCommand extends BaseCommand {
@Override
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
return literal("unwarn")
.requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get())
.then(argument("caseId", IntegerArgumentType.integer(1))
.executes(this::run)
);
@ -59,10 +60,16 @@ public class UnwarnCommand extends BaseCommand {
final WarningStorage storage = WarningStorage.get(getBot().getStorage(), guild);
@Nullable
final WarningEntry entry = storage.getWarning(caseID);
Member temp;
if (entry == null)
messages().MODERATION.noWarnWithID(channel, performer, caseID).queue();
else if (entry.getWarned().getIdLong() == performer.getIdLong())
else if (entry.getWarned().getIdLong() == performer.getIdLong()
&& !config().WARNINGS_REMOVE_SELF_WARNINGS.get())
messages().MODERATION.cannotUnwarnSelf(channel, performer, caseID, entry).queue();
else if (config().WARNINGS_RESPECT_MOD_ROLES.get()
&& (temp = guild.getMember(entry.getPerformer())) != null
&& !performer.canInteract(temp))
messages().MODERATION.cannotRemoveHigherModerated(channel, performer, caseID, entry).queue();
else {
storage.removeWarning(caseID);
messages().MODERATION.unwarn(channel, performer, caseID, entry).queue();

View File

@ -36,6 +36,7 @@ public class WarnCommand extends BaseCommand {
@Override
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
return literal("warn")
.requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get())
.then(argument("member", member())
.then(argument("reason", greedyString())
.executes(ctx -> this.run(ctx, getString(ctx, "reason")))
@ -70,6 +71,8 @@ public class WarnCommand extends BaseCommand {
messages().MODERATION.performerInsufficientPermissions(channel, performer, WARN_PERMISSION).queue();
else if (!performer.canInteract(target))
messages().MODERATION.cannotModerate(channel, performer, target).queue();
else if (target.hasPermission(WARN_PERMISSION) && config().WARNINGS_PREVENT_WARNING_MODS.get())
messages().MODERATION.cannotWarnMods(channel, performer, target).queue();
else
target.getUser().openPrivateChannel()
.flatMap(dm -> messages().MODERATION.warnDM(dm, performer, target, reason, dateTime))

View File

@ -36,6 +36,7 @@ public class WarnListCommand extends BaseCommand {
@Override
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
return literal("warnlist")
.requires(ctx -> getBot().getConfig().WARNINGS_ENABLE.get())
.then(literal("target")
.then(argument("target", member())
.then(literal("mod")

View File

@ -18,10 +18,19 @@ public class BotConfig {
private final CommentedConfigSpec.ConfigValue<String> CLIENT_TOKEN;
private final CommentedConfigSpec.LongValue OWNER_ID;
public final CommentedConfigSpec.ConfigValue<String> STORAGE_PATH;
public final CommentedConfigSpec.IntValue AUTOSAVE_INTERVAL;
public final CommentedConfigSpec.ConfigValue<String> CUSTOM_TRANSLATION_FILE;
public final CommentedConfigSpec.ConfigValue<String> COMMAND_PREFIX;
public final CommentedConfigSpec.BooleanValue WARNINGS_ENABLE;
public final CommentedConfigSpec.BooleanValue WARNINGS_RESPECT_MOD_ROLES;
public final CommentedConfigSpec.BooleanValue WARNINGS_PREVENT_WARNING_MODS;
public final CommentedConfigSpec.BooleanValue WARNINGS_REMOVE_SELF_WARNINGS;
private final BotOptions options;
private final Path configPath;
private final CommentedConfigSpec spec;
@ -32,24 +41,55 @@ public class BotConfig {
final CommentedConfigSpec.Builder builder = new CommentedConfigSpec.Builder();
builder.push("discord");
CLIENT_TOKEN = builder
.comment("The client secret/token for the bot user", "This must be set, or the application will not start up.")
.define("discord.client_token", "");
.define("client_token", "");
OWNER_ID = builder
.comment("The id of the bot owner; used for sending status messages and for bot administration commands.",
"If 0, then the bot has no owner set.")
.defineInRange("discord.owner_id", 0L, Long.MIN_VALUE, Long.MAX_VALUE);
.defineInRange("owner_id", 0L, Long.MIN_VALUE, Long.MAX_VALUE);
builder.pop();
builder.push("storage");
STORAGE_PATH = builder
.comment("The folder where per-guild storage is kept.")
.define("storage.main_path", "guild_storage");
.define("main_path", "guild_storage");
AUTOSAVE_INTERVAL = builder
.comment("The interval between storage autosave checks, in seconds.")
.defineInRange("autosave_internal", 20, 1, Integer.MAX_VALUE);
builder.pop();
CUSTOM_TRANSLATION_FILE = builder
.comment("A file which contains custom translation keys to load for messages.",
"If blank, no file shall be loaded.")
.define("messages.custom_translations", "");
COMMAND_PREFIX = builder
.comment("The prefix for commands.")
.define("commands.prefix", "!");
builder.comment("Moderation settings").push("moderation");
{
builder.comment("Settings for the warnings system").push("warnings");
WARNINGS_ENABLE = builder
.comment("Whether to enable the warnings system. If disabled, the related commands are force-disabled.")
.define("enable", true);
WARNINGS_RESPECT_MOD_ROLES = builder
.comment(
"Whether to prevent lower-ranked moderators (in the role hierarchy) from removing warnings issued by " +
"higher-ranked moderators.")
.define("respect_mod_roles", false);
WARNINGS_PREVENT_WARNING_MODS = builder
.comment("Whether to prevent moderators from issuing warnings against other moderators.")
.define("warn_other_moderators", false);
WARNINGS_REMOVE_SELF_WARNINGS = builder
.comment("Whether to allow moderators to remove warnings from themselves.")
.define("remove_self_warnings", false);
builder.pop();
}
builder.pop();
spec = builder.build();
this.configPath = options.getConfigPath().orElse(DEFAULT_CONFIG_PATH);

View File

@ -312,6 +312,33 @@ public class Messages {
embed.addField(translate("moderation.unwarn.field.reason"), entry.getReason(), false);
return channel.sendMessage(embed.build());
}
public MessageAction cannotWarnMods(MessageChannel channel, Member performer, Member target) {
final EmbedBuilder embed = new EmbedBuilder()
.setTitle(translate("moderation.warn.cannot_warn_mods.title"), null)
.setColor(General.FAILURE_COLOR)
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()))
.setDescription(translate("moderation.warn.cannot_warn_mods.desc"))
.addField(translate("moderation.warn.cannot_warn_mods.field.performer"),
performer.getAsMention(), true)
.addField(translate("moderation.warn.cannot_warn_mods.field.target"),
target.getAsMention(), true);
return channel.sendMessage(embed.build());
}
public MessageAction cannotRemoveHigherModerated(MessageChannel channel, Member performer, int caseID, WarningEntry entry) {
final EmbedBuilder embed = new EmbedBuilder()
.setTitle(translate("moderation.unwarn.cannot_remove_higher_mod.title"), null)
.setColor(General.FAILURE_COLOR)
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()))
.setDescription(translate("moderation.unwarn.cannot_remove_higher_mod.desc"))
.addField(translate("moderation.unwarn.cannot_remove_higher_mod.field.performer"),
performer.getUser().getAsMention(), true)
.addField(translate("moderation.unwarn.cannot_remove_higher_mod.field.original_performer"),
entry.getPerformer().getAsMention(), true)
.addField(translate("moderation.unwarn.cannot_remove_higher_mod.field.case_id"), String.valueOf(caseID), true);
return channel.sendMessage(embed.build());
}
}
}

View File

@ -32,7 +32,7 @@ public class Translations {
loadTranslations();
}
void loadTranslations() {
public void loadTranslations() {
if (translationsFile == null) {
JANITOR.info(TRANSLATIONS, "No translation file given, using default english translations");
loadDefaultTranslations();

View File

@ -72,5 +72,14 @@
"moderation.unwarn.cannot_unwarn_self.desc": "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.unwarn.cannot_unwarn_self.field.case_id": "Case ID",
"moderation.warn.cannot_warn_mods.title": "Cannot warn moderators.",
"moderation.warn.cannot_warn_mods.desc": "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.desc": "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"
}