mirror of
https://github.com/sciwhiz12/Janitor.git
synced 2024-11-10 04:31:26 +00:00
Add warnings system and commands, and per-guild storage
This commit is contained in:
parent
8f9601a9c7
commit
412c499cfc
120
src/main/java/sciwhiz12/janitor/GuildStorage.java
Normal file
120
src/main/java/sciwhiz12/janitor/GuildStorage.java
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
package sciwhiz12.janitor;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import sciwhiz12.janitor.storage.IStorage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static java.nio.file.StandardOpenOption.*;
|
||||||
|
|
||||||
|
public class GuildStorage {
|
||||||
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
|
||||||
|
|
||||||
|
private final JanitorBot bot;
|
||||||
|
private final Path mainFolder;
|
||||||
|
private final Map<Guild, Map<String, IStorage>> guildStorage = new IdentityHashMap<>();
|
||||||
|
|
||||||
|
public GuildStorage(JanitorBot bot, Path mainFolder) {
|
||||||
|
Preconditions.checkArgument(Files.isDirectory(mainFolder) || Files.notExists(mainFolder));
|
||||||
|
this.bot = bot;
|
||||||
|
this.mainFolder = mainFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JanitorBot getBot() {
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends IStorage> T getOrCreate(Guild guild, String key, Supplier<T> defaultSupplier) {
|
||||||
|
final Map<String, IStorage> storageMap = guildStorage.computeIfAbsent(guild, g -> new HashMap<>());
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) storageMap.computeIfAbsent(key, k -> load(guild, key, defaultSupplier.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path getFile(Guild guild, String key) {
|
||||||
|
final Path guildFolder = makeFolder(guild);
|
||||||
|
final Path file = Path.of(key + ".json");
|
||||||
|
return mainFolder.resolve(guildFolder).resolve(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends IStorage> T load(Guild guild, String key, T storage) {
|
||||||
|
final Path file = getFile(guild, key);
|
||||||
|
if (Files.notExists(file)) return storage;
|
||||||
|
|
||||||
|
Logging.JANITOR.debug("Loading storage {} for guild {}", key, guild);
|
||||||
|
try (Reader reader = Files.newBufferedReader(file)) {
|
||||||
|
storage.read(reader);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Logging.JANITOR.error("Error while loading storage {} for guild {}", key, guild, e);
|
||||||
|
}
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
Logging.JANITOR.debug("Saving guild storage to files under {}...", mainFolder);
|
||||||
|
boolean anySaved = false;
|
||||||
|
for (Guild guild : guildStorage.keySet()) {
|
||||||
|
final Map<String, IStorage> storageMap = guildStorage.get(guild);
|
||||||
|
for (String key : storageMap.keySet()) {
|
||||||
|
final IStorage storage = storageMap.get(key);
|
||||||
|
if (storage.dirty()) {
|
||||||
|
final Path file = getFile(guild, key);
|
||||||
|
try {
|
||||||
|
if (Files.notExists(file.getParent())) Files.createDirectories(file.getParent());
|
||||||
|
if (Files.notExists(file)) Files.createFile(file);
|
||||||
|
try (Writer writer = Files
|
||||||
|
.newBufferedWriter(file, CREATE, WRITE, TRUNCATE_EXISTING)) {
|
||||||
|
storage.write(writer);
|
||||||
|
anySaved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Logging.JANITOR.error("Error while writing storage {} for guild {}", key, guild, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anySaved)
|
||||||
|
Logging.JANITOR.info("Saved guild storage to files under {}", mainFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path makeFolder(Guild guild) {
|
||||||
|
return Path.of(Long.toHexString(guild.getIdLong()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SavingThread extends Thread {
|
||||||
|
private final GuildStorage storage;
|
||||||
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
public SavingThread(GuildStorage storage) {
|
||||||
|
this.storage = storage;
|
||||||
|
this.setName("GuildStorage-Saving-Thread");
|
||||||
|
this.setDaemon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopThread() {
|
||||||
|
running = false;
|
||||||
|
this.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (running) {
|
||||||
|
storage.save();
|
||||||
|
try { Thread.sleep(10000); }
|
||||||
|
catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,12 +22,15 @@ public class JanitorBot {
|
||||||
private final BotConfig config;
|
private final BotConfig config;
|
||||||
private final Messages messages;
|
private final Messages messages;
|
||||||
private BotConsole console;
|
private BotConsole console;
|
||||||
|
private final GuildStorage storage;
|
||||||
|
private final GuildStorage.SavingThread storageSavingThread;
|
||||||
private CommandRegistry cmdRegistry;
|
private CommandRegistry cmdRegistry;
|
||||||
private Translations translations;
|
private Translations translations;
|
||||||
|
|
||||||
public JanitorBot(JDA discord, BotConfig config) {
|
public JanitorBot(JDA discord, BotConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.console = new BotConsole(this, System.in);
|
this.console = new BotConsole(this, System.in);
|
||||||
|
this.storage = new GuildStorage(this, config.getStoragePath());
|
||||||
this.cmdRegistry = new CommandRegistry(this, config.getCommandPrefix());
|
this.cmdRegistry = new CommandRegistry(this, config.getCommandPrefix());
|
||||||
this.discord = discord;
|
this.discord = discord;
|
||||||
this.translations = new Translations(this, config.getTranslationsFile());
|
this.translations = new Translations(this, config.getTranslationsFile());
|
||||||
|
@ -47,6 +50,8 @@ public class JanitorBot {
|
||||||
error -> JANITOR.error(STATUS, "Error while sending ready message to owner", error)
|
error -> JANITOR.error(STATUS, "Error while sending ready message to owner", error)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
storageSavingThread = new GuildStorage.SavingThread(storage);
|
||||||
|
storageSavingThread.start();
|
||||||
console.start();
|
console.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +65,8 @@ public class JanitorBot {
|
||||||
|
|
||||||
public Messages getMessages() { return this.messages; }
|
public Messages getMessages() { return this.messages; }
|
||||||
|
|
||||||
|
public GuildStorage getStorage() { return this.storage; }
|
||||||
|
|
||||||
public CommandRegistry getCommandRegistry() {
|
public CommandRegistry getCommandRegistry() {
|
||||||
return this.cmdRegistry;
|
return this.cmdRegistry;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +77,6 @@ public class JanitorBot {
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
JANITOR.info(STATUS, "Shutting down!");
|
JANITOR.info(STATUS, "Shutting down!");
|
||||||
console.stop();
|
|
||||||
getConfig().getOwnerID()
|
getConfig().getOwnerID()
|
||||||
.map(discord::retrieveUserById)
|
.map(discord::retrieveUserById)
|
||||||
.map(owner ->
|
.map(owner ->
|
||||||
|
@ -90,5 +96,8 @@ public class JanitorBot {
|
||||||
))
|
))
|
||||||
).ifPresent(CompletableFuture::join);
|
).ifPresent(CompletableFuture::join);
|
||||||
discord.shutdown();
|
discord.shutdown();
|
||||||
|
storageSavingThread.stopThread();
|
||||||
|
storage.save();
|
||||||
|
console.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ public class Logging {
|
||||||
public static final Marker STATUS = MarkerFactory.getMarker("STATUS");
|
public static final Marker STATUS = MarkerFactory.getMarker("STATUS");
|
||||||
public static final Marker COMMANDS = MarkerFactory.getMarker("COMMANDS");
|
public static final Marker COMMANDS = MarkerFactory.getMarker("COMMANDS");
|
||||||
public static final Marker TRANSLATIONS = MarkerFactory.getMarker("TRANSLATIONS");
|
public static final Marker TRANSLATIONS = MarkerFactory.getMarker("TRANSLATIONS");
|
||||||
|
public static final Marker STORAGE = MarkerFactory.getMarker("STORAGE");
|
||||||
|
|
||||||
public static final Logger JANITOR = LoggerFactory.getLogger("janitor");
|
public static final Logger JANITOR = LoggerFactory.getLogger("janitor");
|
||||||
public static final Logger CONSOLE = LoggerFactory.getLogger("janitor.console");
|
public static final Logger CONSOLE = LoggerFactory.getLogger("janitor.console");
|
||||||
|
|
|
@ -16,6 +16,9 @@ import sciwhiz12.janitor.commands.misc.PingCommand;
|
||||||
import sciwhiz12.janitor.commands.moderation.BanCommand;
|
import sciwhiz12.janitor.commands.moderation.BanCommand;
|
||||||
import sciwhiz12.janitor.commands.moderation.KickCommand;
|
import sciwhiz12.janitor.commands.moderation.KickCommand;
|
||||||
import sciwhiz12.janitor.commands.moderation.UnbanCommand;
|
import sciwhiz12.janitor.commands.moderation.UnbanCommand;
|
||||||
|
import sciwhiz12.janitor.commands.moderation.UnwarnCommand;
|
||||||
|
import sciwhiz12.janitor.commands.moderation.WarnCommand;
|
||||||
|
import sciwhiz12.janitor.commands.moderation.WarnListCommand;
|
||||||
import sciwhiz12.janitor.utils.Util;
|
import sciwhiz12.janitor.utils.Util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -42,6 +45,9 @@ public class CommandRegistry implements EventListener {
|
||||||
addCommand(new KickCommand(this));
|
addCommand(new KickCommand(this));
|
||||||
addCommand(new BanCommand(this));
|
addCommand(new BanCommand(this));
|
||||||
addCommand(new UnbanCommand(this));
|
addCommand(new UnbanCommand(this));
|
||||||
|
addCommand(new WarnCommand(this));
|
||||||
|
addCommand(new WarnListCommand(this));
|
||||||
|
addCommand(new UnwarnCommand(this));
|
||||||
if (bot.getConfig().getOwnerID().isPresent()) {
|
if (bot.getConfig().getOwnerID().isPresent()) {
|
||||||
addCommand(new ShutdownCommand(this, bot.getConfig().getOwnerID().get()));
|
addCommand(new ShutdownCommand(this, bot.getConfig().getOwnerID().get()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package sciwhiz12.janitor.commands.moderation;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.dv8tion.jda.api.Permission;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import sciwhiz12.janitor.commands.BaseCommand;
|
||||||
|
import sciwhiz12.janitor.commands.CommandRegistry;
|
||||||
|
import sciwhiz12.janitor.moderation.warns.WarningEntry;
|
||||||
|
import sciwhiz12.janitor.moderation.warns.WarningStorage;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.argument;
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.literal;
|
||||||
|
|
||||||
|
public class UnwarnCommand extends BaseCommand {
|
||||||
|
public static final EnumSet<Permission> WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS);
|
||||||
|
|
||||||
|
public UnwarnCommand(CommandRegistry registry) {
|
||||||
|
super(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
|
||||||
|
return literal("unwarn")
|
||||||
|
.then(argument("caseId", IntegerArgumentType.integer(1))
|
||||||
|
.executes(this::run)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int run(CommandContext<MessageReceivedEvent> ctx) {
|
||||||
|
realRun(ctx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void realRun(CommandContext<MessageReceivedEvent> ctx) {
|
||||||
|
MessageChannel channel = ctx.getSource().getChannel();
|
||||||
|
if (!ctx.getSource().isFromGuild()) {
|
||||||
|
messages().GENERAL.guildOnlyCommand(channel).queue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Guild guild = ctx.getSource().getGuild();
|
||||||
|
final Member performer = Objects.requireNonNull(ctx.getSource().getMember());
|
||||||
|
int caseID = IntegerArgumentType.getInteger(ctx, "caseId");
|
||||||
|
|
||||||
|
final OffsetDateTime dateTime = OffsetDateTime.now();
|
||||||
|
|
||||||
|
if (!performer.hasPermission(WARN_PERMISSION))
|
||||||
|
messages().MODERATION.performerInsufficientPermissions(channel, performer, WARN_PERMISSION).queue();
|
||||||
|
else {
|
||||||
|
final WarningStorage storage = WarningStorage.get(getBot().getStorage(), guild);
|
||||||
|
@Nullable
|
||||||
|
final WarningEntry entry = storage.getWarning(caseID);
|
||||||
|
if (entry == null)
|
||||||
|
messages().MODERATION.noWarnWithID(channel, performer, caseID).queue();
|
||||||
|
else if (entry.getWarned().getIdLong() == performer.getIdLong())
|
||||||
|
messages().MODERATION.cannotUnwarnSelf(channel, performer, caseID, entry).queue();
|
||||||
|
else {
|
||||||
|
storage.removeWarning(caseID);
|
||||||
|
messages().MODERATION.unwarn(channel, performer, caseID, entry).queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package sciwhiz12.janitor.commands.moderation;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import net.dv8tion.jda.api.Permission;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
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 java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||||
|
import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.getMembers;
|
||||||
|
import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.member;
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.argument;
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.literal;
|
||||||
|
|
||||||
|
public class WarnCommand extends BaseCommand {
|
||||||
|
public static final EnumSet<Permission> WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS);
|
||||||
|
|
||||||
|
public WarnCommand(CommandRegistry registry) {
|
||||||
|
super(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
|
||||||
|
return literal("warn")
|
||||||
|
.then(argument("member", member())
|
||||||
|
.then(argument("reason", greedyString())
|
||||||
|
.executes(ctx -> this.run(ctx, getString(ctx, "reason")))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int run(CommandContext<MessageReceivedEvent> ctx, String reason) throws CommandSyntaxException {
|
||||||
|
realRun(ctx, reason);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void realRun(CommandContext<MessageReceivedEvent> ctx, String reason) throws CommandSyntaxException {
|
||||||
|
MessageChannel channel = ctx.getSource().getChannel();
|
||||||
|
if (!ctx.getSource().isFromGuild()) {
|
||||||
|
messages().GENERAL.guildOnlyCommand(channel).queue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Guild guild = ctx.getSource().getGuild();
|
||||||
|
final Member performer = Objects.requireNonNull(ctx.getSource().getMember());
|
||||||
|
|
||||||
|
final List<Member> members = getMembers("member", ctx).fromGuild(performer.getGuild());
|
||||||
|
if (members.size() < 1) return;
|
||||||
|
final Member target = members.get(0);
|
||||||
|
|
||||||
|
final OffsetDateTime dateTime = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
|
if (guild.getSelfMember().equals(target))
|
||||||
|
messages().GENERAL.cannotActionSelf(channel).queue();
|
||||||
|
else if (performer.equals(target))
|
||||||
|
messages().GENERAL.cannotActionPerformer(channel, performer).queue();
|
||||||
|
else if (!performer.hasPermission(WARN_PERMISSION))
|
||||||
|
messages().MODERATION.performerInsufficientPermissions(channel, performer, WARN_PERMISSION).queue();
|
||||||
|
else if (!performer.canInteract(target))
|
||||||
|
messages().MODERATION.cannotModerate(channel, performer, target).queue();
|
||||||
|
else
|
||||||
|
target.getUser().openPrivateChannel()
|
||||||
|
.flatMap(dm -> messages().MODERATION.warnDM(dm, performer, target, reason, dateTime))
|
||||||
|
.mapToResult()
|
||||||
|
.flatMap(res -> {
|
||||||
|
int caseId = WarningStorage.get(getBot().getStorage(), guild)
|
||||||
|
.addWarning(new WarningEntry(target.getUser(), performer.getUser(), dateTime, reason));
|
||||||
|
return messages().MODERATION
|
||||||
|
.warnUser(channel, performer, target, reason, dateTime, caseId, res.isSuccess());
|
||||||
|
})
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
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;
|
||||||
|
import net.dv8tion.jda.api.Permission;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
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 java.time.OffsetDateTime;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.getMembers;
|
||||||
|
import static sciwhiz12.janitor.commands.arguments.GuildMemberArgument.member;
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.argument;
|
||||||
|
import static sciwhiz12.janitor.commands.util.CommandHelper.literal;
|
||||||
|
|
||||||
|
public class WarnListCommand extends BaseCommand {
|
||||||
|
public static final EnumSet<Permission> WARN_PERMISSION = EnumSet.of(Permission.KICK_MEMBERS);
|
||||||
|
|
||||||
|
public WarnListCommand(CommandRegistry registry) {
|
||||||
|
super(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiteralArgumentBuilder<MessageReceivedEvent> getNode() {
|
||||||
|
return literal("warnlist")
|
||||||
|
.then(literal("target")
|
||||||
|
.then(argument("target", member())
|
||||||
|
.then(literal("mod")
|
||||||
|
.then(argument("moderator", member())
|
||||||
|
.executes(ctx -> this.run(ctx, true, true))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.executes(ctx -> this.run(ctx, true, false))
|
||||||
|
)
|
||||||
|
).then(literal("mod")
|
||||||
|
.then(argument("moderator", member())
|
||||||
|
.executes(ctx -> this.run(ctx, false, true))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.executes(ctx -> this.run(ctx, false, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int run(CommandContext<MessageReceivedEvent> ctx, boolean filterTarget, boolean filterModerator)
|
||||||
|
throws CommandSyntaxException {
|
||||||
|
realRun(ctx, filterTarget, filterModerator);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void realRun(CommandContext<MessageReceivedEvent> ctx, boolean filterTarget, boolean filterModerator)
|
||||||
|
throws CommandSyntaxException {
|
||||||
|
MessageChannel channel = ctx.getSource().getChannel();
|
||||||
|
if (!ctx.getSource().isFromGuild()) {
|
||||||
|
messages().GENERAL.guildOnlyCommand(channel).queue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Guild guild = ctx.getSource().getGuild();
|
||||||
|
final Member performer = Objects.requireNonNull(ctx.getSource().getMember());
|
||||||
|
Predicate<Map.Entry<Integer, WarningEntry>> predicate = e -> true;
|
||||||
|
|
||||||
|
if (filterTarget) {
|
||||||
|
final List<Member> members = getMembers("target", ctx).fromGuild(performer.getGuild());
|
||||||
|
if (members.size() < 1) return;
|
||||||
|
final Member target = members.get(0);
|
||||||
|
if (guild.getSelfMember().equals(target)) {
|
||||||
|
messages().GENERAL.cannotActionSelf(channel).queue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
predicate = predicate.and(e -> e.getValue().getWarned().getIdLong() == target.getIdLong());
|
||||||
|
}
|
||||||
|
if (filterModerator) {
|
||||||
|
final List<Member> members = getMembers("moderator", ctx).fromGuild(performer.getGuild());
|
||||||
|
if (members.size() < 1) return;
|
||||||
|
final Member mod = members.get(0);
|
||||||
|
predicate = predicate.and(e -> e.getValue().getPerformer().getIdLong() == mod.getIdLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
final OffsetDateTime dateTime = OffsetDateTime.now();
|
||||||
|
|
||||||
|
if (!performer.hasPermission(WARN_PERMISSION))
|
||||||
|
messages().MODERATION.performerInsufficientPermissions(channel, performer, WARN_PERMISSION).queue();
|
||||||
|
else
|
||||||
|
messages().MODERATION.warnList(channel, WarningStorage.get(getBot().getStorage(), guild)
|
||||||
|
.getWarnings()
|
||||||
|
.entrySet().stream()
|
||||||
|
.filter(predicate)
|
||||||
|
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue))
|
||||||
|
).queue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,10 @@ import static sciwhiz12.janitor.Logging.JANITOR;
|
||||||
|
|
||||||
public class BotConfig {
|
public class BotConfig {
|
||||||
public static final Path DEFAULT_CONFIG_PATH = Path.of("config.toml");
|
public static final Path DEFAULT_CONFIG_PATH = Path.of("config.toml");
|
||||||
|
public static final Path DEFAULT_STORAGE_PATH = Path.of("guild_storage");
|
||||||
public static final String CLIENT_TOKEN = "discord.client_token";
|
public static final String CLIENT_TOKEN = "discord.client_token";
|
||||||
public static final String OWNER_ID = "discord.owner_id";
|
public static final String OWNER_ID = "discord.owner_id";
|
||||||
|
public static final String STORAGE_PATH = "storage.main_path";
|
||||||
public static final String TRANSLATION_FILE_PATH = "messages.translation_file";
|
public static final String TRANSLATION_FILE_PATH = "messages.translation_file";
|
||||||
public static final String COMMAND_PREFIX = "commands.prefix";
|
public static final String COMMAND_PREFIX = "commands.prefix";
|
||||||
|
|
||||||
|
@ -52,6 +54,10 @@ public class BotConfig {
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getStoragePath() {
|
||||||
|
return config.<String>getOptional(STORAGE_PATH).map(Path::of).orElse(DEFAULT_STORAGE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<String> getToken() {
|
public Optional<String> getToken() {
|
||||||
return options.getToken().or(() -> config.getOptional(CLIENT_TOKEN));
|
return options.getToken().or(() -> config.getOptional(CLIENT_TOKEN));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package sciwhiz12.janitor.moderation.warns;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
import sciwhiz12.janitor.JanitorBot;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class WarningEntry {
|
||||||
|
private final User performer;
|
||||||
|
private final User warned;
|
||||||
|
private final OffsetDateTime dateTime;
|
||||||
|
@Nullable
|
||||||
|
private final String reason;
|
||||||
|
|
||||||
|
public WarningEntry(User warned, User performer, OffsetDateTime dateTime, @Nullable String reason) {
|
||||||
|
this.performer = performer;
|
||||||
|
this.warned = warned;
|
||||||
|
this.dateTime = dateTime;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getPerformer() {
|
||||||
|
return performer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getWarned() {
|
||||||
|
return warned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getDateTime() {
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
WarningEntry that = (WarningEntry) o;
|
||||||
|
return getPerformer().equals(that.getPerformer()) &&
|
||||||
|
getWarned().equals(that.getWarned()) &&
|
||||||
|
getDateTime().equals(that.getDateTime()) &&
|
||||||
|
Objects.equals(getReason(), that.getReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getPerformer(), getWarned(), getDateTime(), getReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Serializer implements JsonDeserializer<WarningEntry>, JsonSerializer<WarningEntry> {
|
||||||
|
private final JanitorBot bot;
|
||||||
|
|
||||||
|
public Serializer(JanitorBot bot) {
|
||||||
|
this.bot = bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WarningEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
final JsonObject obj = json.getAsJsonObject();
|
||||||
|
final User warned = bot.getDiscord().retrieveUserById(obj.get("warned").getAsLong()).complete();
|
||||||
|
final User performer = bot.getDiscord().retrieveUserById(obj.get("performer").getAsLong()).complete();
|
||||||
|
final OffsetDateTime dateTime = OffsetDateTime.parse(obj.get("dateTime").getAsString());
|
||||||
|
@Nullable
|
||||||
|
final String reason = obj.has("reason") ? obj.get("reason").getAsString() : null;
|
||||||
|
return new WarningEntry(warned, performer, dateTime, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(WarningEntry src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
final JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("warned", src.getWarned().getId());
|
||||||
|
obj.addProperty("performer", src.getPerformer().getId());
|
||||||
|
obj.addProperty("dateTime", src.getDateTime().toString());
|
||||||
|
if (src.getReason() != null) {
|
||||||
|
obj.addProperty("reason", src.getReason());
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package sciwhiz12.janitor.moderation.warns;
|
||||||
|
|
||||||
|
import com.electronwill.nightconfig.core.utils.ObservedMap;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import sciwhiz12.janitor.GuildStorage;
|
||||||
|
import sciwhiz12.janitor.JanitorBot;
|
||||||
|
import sciwhiz12.janitor.storage.JsonStorage;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WarningStorage extends JsonStorage {
|
||||||
|
private static final Type WARNING_MAP_TYPE = new TypeToken<Map<Integer, WarningEntry>>() {}.getType();
|
||||||
|
public static final String STORAGE_KEY = "warnings";
|
||||||
|
|
||||||
|
public static WarningStorage get(GuildStorage storage, Guild guild) {
|
||||||
|
return storage.getOrCreate(guild, STORAGE_KEY, () -> new WarningStorage(storage.getBot()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final JanitorBot bot;
|
||||||
|
private int lastID = 1;
|
||||||
|
private final Map<Integer, WarningEntry> warnings = new ObservedMap<>(new HashMap<>(), this::markDirty);
|
||||||
|
|
||||||
|
public WarningStorage(JanitorBot bot) {
|
||||||
|
this.bot = bot;
|
||||||
|
this.gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(WarningEntry.class, new WarningEntry.Serializer(bot))
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JanitorBot getBot() {
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addWarning(WarningEntry entry) {
|
||||||
|
int id = lastID++;
|
||||||
|
warnings.put(id, entry);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public WarningEntry getWarning(int caseID) {
|
||||||
|
return warnings.get(caseID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarningEntry removeWarning(int caseID) {
|
||||||
|
return warnings.remove(caseID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, WarningEntry> getWarnings() {
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement save() {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("lastCaseID", lastID);
|
||||||
|
obj.add("warnings", gson.toJsonTree(warnings));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonElement in) {
|
||||||
|
final JsonObject obj = in.getAsJsonObject();
|
||||||
|
lastID = obj.get("lastCaseID").getAsInt();
|
||||||
|
final Map<Integer, WarningEntry> loaded = gson.fromJson(obj.get("warnings"), WARNING_MAP_TYPE);
|
||||||
|
warnings.clear();
|
||||||
|
warnings.putAll(loaded);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,12 +11,18 @@ import net.dv8tion.jda.api.requests.RestAction;
|
||||||
import net.dv8tion.jda.api.requests.restaction.MessageAction;
|
import net.dv8tion.jda.api.requests.restaction.MessageAction;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import sciwhiz12.janitor.JanitorBot;
|
import sciwhiz12.janitor.JanitorBot;
|
||||||
|
import sciwhiz12.janitor.moderation.warns.WarningEntry;
|
||||||
|
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
|
||||||
|
|
||||||
public class Messages {
|
public class Messages {
|
||||||
private final JanitorBot bot;
|
private final JanitorBot bot;
|
||||||
public final General GENERAL;
|
public final General GENERAL;
|
||||||
|
@ -212,6 +218,100 @@ public class Messages {
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MessageAction warnUser(MessageChannel channel, Member performer, Member target, String reason,
|
||||||
|
OffsetDateTime dateTime, int caseID, boolean sentDM) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setAuthor(translate("moderation.warn.info.author"), null, GAVEL_ICON_URL)
|
||||||
|
.addField(translate("moderation.warn.info.field.performer"), performer.getUser().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.warn.info.field.target"), target.getUser().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.warn.info.field.sent_private_message"), sentDM ? "✅" : "❌", true)
|
||||||
|
.addField(translate("moderation.warn.info.field.case_id"), String.valueOf(caseID), true)
|
||||||
|
.addField(translate("moderation.warn.info.field.date_time"),
|
||||||
|
dateTime.format(RFC_1123_DATE_TIME), true)
|
||||||
|
.addField(translate("moderation.warn.info.field.reason"), reason, false);
|
||||||
|
return channel
|
||||||
|
.sendMessage(embed.setColor(MODERATION_COLOR).setTimestamp(OffsetDateTime.now(Clock.systemUTC())).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAction warnDM(MessageChannel channel, Member performer, Member target, String reason,
|
||||||
|
OffsetDateTime dateTime) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setAuthor(performer.getGuild().getName(), null, performer.getGuild().getIconUrl())
|
||||||
|
.setTitle(translate("moderation.warn.dm.title"))
|
||||||
|
.addField(translate("moderation.warn.dm.field.performer"), performer.getUser().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.warn.dm.field.date_time"),
|
||||||
|
dateTime.format(RFC_1123_DATE_TIME), true)
|
||||||
|
.addField(translate("moderation.warn.dm.field.reason"), reason, false);
|
||||||
|
return channel.sendMessage(embed.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAction warnList(MessageChannel channel, Map<Integer, WarningEntry> displayWarnings) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setAuthor(translate("moderation.warnlist.author"), null, GAVEL_ICON_URL)
|
||||||
|
.setColor(MODERATION_COLOR)
|
||||||
|
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()));
|
||||||
|
String warningsDesc = 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");
|
||||||
|
embed.setDescription(warningsDesc);
|
||||||
|
return channel.sendMessage(embed.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAction noWarnWithID(MessageChannel channel, Member performer, int caseID) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setTitle(translate("moderation.unwarn.no_case_found.title"), null)
|
||||||
|
.setColor(General.FAILURE_COLOR)
|
||||||
|
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()))
|
||||||
|
.setDescription(translate("moderation.unwarn.no_case_found.desc"))
|
||||||
|
.addField(translate("moderation.unwarn.no_case_found.field.performer"), performer.getUser().getAsMention(),
|
||||||
|
true)
|
||||||
|
.addField(translate("moderation.unwarn.no_case_found.field.case_id"), String.valueOf(caseID), true);
|
||||||
|
return channel.sendMessage(embed.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAction cannotUnwarnSelf(MessageChannel channel, Member performer, int caseID, WarningEntry entry) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setTitle(translate("moderation.unwarn.cannot_unwarn_self.title"), null)
|
||||||
|
.setColor(General.FAILURE_COLOR)
|
||||||
|
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()))
|
||||||
|
.setDescription(translate("moderation.unwarn.cannot_unwarn_self.desc"))
|
||||||
|
.addField(translate("moderation.unwarn.cannot_unwarn_self.field.performer"),
|
||||||
|
performer.getUser().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.unwarn.cannot_unwarn_self.field.original_performer"),
|
||||||
|
entry.getPerformer().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.unwarn.cannot_unwarn_self.field.case_id"), String.valueOf(caseID), true);
|
||||||
|
return channel.sendMessage(embed.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAction unwarn(MessageChannel channel, Member performer, int caseID, WarningEntry entry) {
|
||||||
|
final EmbedBuilder embed = new EmbedBuilder()
|
||||||
|
.setAuthor(translate("moderation.unwarn.author"), null, GAVEL_ICON_URL)
|
||||||
|
.setColor(MODERATION_COLOR)
|
||||||
|
.setTimestamp(OffsetDateTime.now(Clock.systemUTC()))
|
||||||
|
.addField(translate("moderation.unwarn.field.performer"), performer.getUser().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.unwarn.field.case_id"), String.valueOf(caseID), true)
|
||||||
|
.addField(translate("moderation.unwarn.field.original_target"), entry.getWarned().getAsMention(), true)
|
||||||
|
.addField(translate("moderation.unwarn.field.original_performer"), entry.getPerformer().getAsMention(),
|
||||||
|
true)
|
||||||
|
.addField(translate("moderation.unwarn.field.date_time"),
|
||||||
|
entry.getDateTime().format(RFC_1123_DATE_TIME), true);
|
||||||
|
if (entry.getReason() != null)
|
||||||
|
embed.addField(translate("moderation.unwarn.field.reason"), entry.getReason(), false);
|
||||||
|
return channel.sendMessage(embed.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
22
src/main/java/sciwhiz12/janitor/storage/AbstractStorage.java
Normal file
22
src/main/java/sciwhiz12/janitor/storage/AbstractStorage.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package sciwhiz12.janitor.storage;
|
||||||
|
|
||||||
|
public abstract class AbstractStorage implements IStorage {
|
||||||
|
private boolean dirty;
|
||||||
|
|
||||||
|
public boolean isDirty() {
|
||||||
|
return dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dirty() {
|
||||||
|
if (dirty) {
|
||||||
|
dirty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markDirty() {
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/sciwhiz12/janitor/storage/IStorage.java
Normal file
13
src/main/java/sciwhiz12/janitor/storage/IStorage.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package sciwhiz12.janitor.storage;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
public interface IStorage {
|
||||||
|
|
||||||
|
boolean dirty();
|
||||||
|
|
||||||
|
void write(Writer output);
|
||||||
|
|
||||||
|
void read(Reader input);
|
||||||
|
}
|
30
src/main/java/sciwhiz12/janitor/storage/JsonStorage.java
Normal file
30
src/main/java/sciwhiz12/janitor/storage/JsonStorage.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package sciwhiz12.janitor.storage;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
public abstract class JsonStorage extends AbstractStorage {
|
||||||
|
public static final Gson GSON = new GsonBuilder()
|
||||||
|
.serializeNulls()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
public abstract JsonElement save();
|
||||||
|
|
||||||
|
public abstract void load(JsonElement object);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Writer input) {
|
||||||
|
GSON.toJson(save(), input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(Reader input) {
|
||||||
|
load(JsonParser.parseReader(input));
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,5 +41,36 @@
|
||||||
"moderation.ban.dm.field.reason": "Reason",
|
"moderation.ban.dm.field.reason": "Reason",
|
||||||
"moderation.unban.info.author": "Unbanned user from server.",
|
"moderation.unban.info.author": "Unbanned user from server.",
|
||||||
"moderation.unban.info.field.performer": "Performer",
|
"moderation.unban.info.field.performer": "Performer",
|
||||||
"moderation.unban.info.field.target": "Target"
|
"moderation.unban.info.field.target": "Target",
|
||||||
|
"moderation.warn.info.author": "Warned user.",
|
||||||
|
"moderation.warn.info.field.performer": "Performer",
|
||||||
|
"moderation.warn.info.field.target": "Target",
|
||||||
|
"moderation.warn.info.field.sent_private_message": "Sent DM",
|
||||||
|
"moderation.warn.info.field.case_id": "Case ID",
|
||||||
|
"moderation.warn.info.field.date_time": "Date & Time",
|
||||||
|
"moderation.warn.info.field.reason": "Reason",
|
||||||
|
"moderation.warn.dm.title": "You were warned by a moderator.",
|
||||||
|
"moderation.warn.dm.field.performer": "Moderator",
|
||||||
|
"moderation.warn.dm.field.date_time": "Date & Time",
|
||||||
|
"moderation.warn.dm.field.reason": "Reason",
|
||||||
|
"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": "Performer",
|
||||||
|
"moderation.unwarn.field.original_target": "Original Target",
|
||||||
|
"moderation.unwarn.field.original_performer": "Original Performer",
|
||||||
|
"moderation.unwarn.field.case_id": "Case ID",
|
||||||
|
"moderation.unwarn.field.date_time": "Date & Time",
|
||||||
|
"moderation.unwarn.field.reason": "Reason",
|
||||||
|
"moderation.unwarn.no_case_found.title": "No warning found.",
|
||||||
|
"moderation.unwarn.no_case_found.desc": "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.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"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user