From 3570b7ddabaf2d31a4555d9f7fd99757535aea91 Mon Sep 17 00:00:00 2001 From: James Martin Date: Wed, 25 Nov 2020 11:18:09 -0800 Subject: [PATCH] Improve the way commutations, appeals, and clears work. Specifically, commutations now create a new infraction, and all three set a repeal reason/issuer/type. This makes the system more flexible and makes for a better audit log. --- README.md | 32 ++-- .../wasteland/modtools/ModToolsState.java | 26 +--- .../modtools/commands/CommandBan.java | 10 +- .../modtools/commands/CommandBans.java | 15 -- .../commands/CommandIssueInfraction.java | 16 +- .../modtools/commands/CommandKick.java | 10 +- .../modtools/commands/CommandMute.java | 10 +- .../modtools/commands/CommandMutes.java | 15 -- .../commands/CommandRemoveInfraction.java | 46 ------ .../modtools/commands/CommandUnban.java | 15 -- .../modtools/commands/CommandUnmute.java | 15 -- .../modtools/commands/CommandWarn.java | 10 +- .../modtools/infraction/Duration.java | 12 ++ .../modtools/infraction/Infraction.java | 103 +++++++++++-- .../infraction/InfractionProvider.java | 27 +++- .../modtools/infraction/InfractionStore.java | 32 +++- .../modtools/infraction/NewInfraction.java | 145 ++++++++++++++++++ .../wasteland/modtools/infraction/Repeal.java | 33 ++++ .../modtools/infraction/RepealType.java | 11 ++ ...{InfractionType.java => SentenceType.java} | 4 +- ...LogProvider.java => AuditLogProvider.java} | 42 +++-- .../{ModLogStore.java => AuditLogStore.java} | 3 +- ...ommandModLog.java => CommandAuditLog.java} | 2 +- modtools/src/main/resources/plugin.yml | 58 ++----- 24 files changed, 448 insertions(+), 244 deletions(-) delete mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java delete mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java delete mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java delete mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java delete mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java create mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/NewInfraction.java create mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Repeal.java create mode 100644 modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/RepealType.java rename modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/{InfractionType.java => SentenceType.java} (78%) rename modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/{ModLogProvider.java => AuditLogProvider.java} (59%) rename modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/{ModLogStore.java => AuditLogStore.java} (53%) rename modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/{CommandModLog.java => CommandAuditLog.java} (86%) diff --git a/README.md b/README.md index ca03f1c..9ea79cd 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ This plugin provides tools which both help moderators track what rule infraction and help server administrators hold moderators accountable through an audit log. This plugin provides these basic commands: -* `/ban` and `/unban` +* `/ban` * `/kick` -* `/mute` and `/unmute` +* `/mute` * `/warn` All bans, kicks, mutes, and warnings are logged, @@ -43,21 +43,24 @@ and to help server administrators hold moderators accountable through an audit l It is also possible to set the maximum length of bans or mutes that a moderator can issue in the configuration file. -You may view the currently active bans and mutes using `/bans` and `/mutes` respectively, -or see the history of infractions a player has committed using `/infractions`. +You may view the currently active sentences against any player, +the infractions that a moderator has issued, +or see the history of infractions a player has committed using `/infractions query`. +This command does not include infractions that have been cleared from a player's record, +or old versions of infractions from before they were commuted. -You can remove an infraction from a player's account using commands like `/unwarn`. -Removing an infraction from a player's account will not remove the infraction from the audit log, -and in fact will just add that the infraction was removed to the audit log. +You can commute, extend, or update a sentence using `/infractions commute`, +remove and clear an infraction from a player's record using `/infractions clear` +or remove a sentence without clearing the infraction from the player's record using `/infractions appeal`. +These commands do not remove the infraction from the audit log, and in fact create a new entry in the audit log. You may view the audit log using `/auditlog`. +The audit log includes infractions that have been cleared, appealed, or commuted, +the history of those actions. For more information on how to use these commands please see the in game `/help` or the `plugin.yml` For more information on how to configure this plugin, please see the default `config.yml`. -### Infraction histories & audit logs -A set of moderator tools which logs all moderator actions, - ### Manuals There are two built-in manuals: `/rules` and `/faq`. These manuals provide both brief overviews and more detail which players may view if they wish. @@ -66,12 +69,3 @@ It is also possible for moderators to (forcibly) show players portions of the ru as a brief reminder of the rules or to quickly answer a question they were asking. Please see the in-game `/help` menu or `plugin.yml` for more information on how to use these commands. - -## Current Features -* Tracks how many zombies or husks a player kills. -* Supports a ranking system for players based on the U.S. Marines' ranks. - -## Planned Features -* Make zombies horde more intelligently. -* Special world effects. -* A lot of stuff, generally, but it's been a few months so I don't remember it all. I'll add it here when work begins again. diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java index dc77b8f..eb486dd 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java @@ -4,17 +4,13 @@ import org.bukkit.plugin.java.JavaPlugin; import me.jamestmartin.wasteland.manual.ManualState; import me.jamestmartin.wasteland.modtools.commands.CommandBan; -import me.jamestmartin.wasteland.modtools.commands.CommandBans; import me.jamestmartin.wasteland.modtools.commands.CommandInfractions; import me.jamestmartin.wasteland.modtools.commands.CommandKick; import me.jamestmartin.wasteland.modtools.commands.CommandMute; -import me.jamestmartin.wasteland.modtools.commands.CommandMutes; -import me.jamestmartin.wasteland.modtools.commands.CommandUnban; -import me.jamestmartin.wasteland.modtools.commands.CommandUnmute; import me.jamestmartin.wasteland.modtools.commands.CommandWarn; import me.jamestmartin.wasteland.modtools.config.ModToolsConfig; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.log.CommandModLog; +import me.jamestmartin.wasteland.modtools.log.CommandAuditLog; import me.jamestmartin.wasteland.offlineplayer.CommandLastSeen; import me.jamestmartin.wasteland.offlineplayer.CommandUUID; @@ -22,15 +18,11 @@ class ModToolsState { private final ManualState manualState; private final CommandBan commandBan; - private final CommandBans commandBans; private final CommandInfractions commandInfractions; private final CommandKick commandKick; private final CommandLastSeen commandLastSeen; - private final CommandModLog commandModLog; + private final CommandAuditLog commandAuditLog; private final CommandMute commandMute; - private final CommandMutes commandMutes; - private final CommandUnban commandUnban; - private final CommandUnmute commandUnmute; private final CommandUUID commandUUID; private final CommandWarn commandWarn; @@ -41,15 +33,11 @@ class ModToolsState { InfractionStore store = null; this.commandBan = new CommandBan(store, config.getDurations().getBansConfig()); - this.commandBans = new CommandBans(); this.commandInfractions = new CommandInfractions(); this.commandKick = new CommandKick(store); this.commandLastSeen = new CommandLastSeen(); - this.commandModLog = new CommandModLog(); + this.commandAuditLog = new CommandAuditLog(); this.commandMute = new CommandMute(store, config.getDurations().getMutesConfig()); - this.commandMutes = new CommandMutes(); - this.commandUnban = new CommandUnban(); - this.commandUnmute = new CommandUnmute(); this.commandUUID = new CommandUUID(); this.commandWarn = new CommandWarn(store); } @@ -58,15 +46,11 @@ class ModToolsState { manualState.register(plugin); plugin.getCommand("ban").setExecutor(commandBan); - plugin.getCommand("bans").setExecutor(commandBans); plugin.getCommand("infractions").setExecutor(commandInfractions); plugin.getCommand("kick").setExecutor(commandKick); plugin.getCommand("lastseen").setExecutor(commandLastSeen); - plugin.getCommand("modlog").setExecutor(commandModLog); + plugin.getCommand("auditlog").setExecutor(commandAuditLog); plugin.getCommand("mute").setExecutor(commandMute); - plugin.getCommand("mutes").setExecutor(commandMutes); - plugin.getCommand("unban").setExecutor(commandUnban); - plugin.getCommand("unmute").setExecutor(commandUnmute); plugin.getCommand("uuid").setExecutor(commandUUID); plugin.getCommand("warn").setExecutor(commandWarn); } @@ -79,7 +63,7 @@ class ModToolsState { plugin.getCommand("infractions").setExecutor(null); plugin.getCommand("kick").setExecutor(null); plugin.getCommand("lastseen").setExecutor(null); - plugin.getCommand("modlog").setExecutor(null); + plugin.getCommand("auditlog").setExecutor(null); plugin.getCommand("mute").setExecutor(null); plugin.getCommand("mutes").setExecutor(null); plugin.getCommand("unban").setExecutor(null); diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java index c1dff67..fb8faf9 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java @@ -4,9 +4,9 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import me.jamestmartin.wasteland.modtools.config.DurationsConfig; -import me.jamestmartin.wasteland.modtools.infraction.Infraction; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.NewInfraction; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; public class CommandBan extends CommandIssueInfraction { public CommandBan(InfractionStore store, DurationsConfig durations) { @@ -14,12 +14,12 @@ public class CommandBan extends CommandIssueInfraction { } @Override - protected InfractionType getType() { - return InfractionType.BAN; + protected SentenceType getType() { + return SentenceType.BAN; } @Override - protected void applyInfraction(CommandSender sender, Infraction infraction) { + protected void applyInfraction(CommandSender sender, NewInfraction infraction) { Player recipient = infraction.getRecipient().getPlayer(); if (recipient != null) { recipient.kickPlayer(infraction.getMessage()); diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java deleted file mode 100644 index f74b620..0000000 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jamestmartin.wasteland.modtools.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -public class CommandBans implements CommandExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java index dd2b404..2c3d4b9 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java @@ -10,9 +10,9 @@ import org.bukkit.entity.Player; import me.jamestmartin.wasteland.modtools.config.DurationsConfig; import me.jamestmartin.wasteland.modtools.infraction.Duration; -import me.jamestmartin.wasteland.modtools.infraction.Infraction; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.NewInfraction; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; abstract class CommandIssueInfraction implements CommandExecutor { protected final InfractionStore store; @@ -41,13 +41,13 @@ abstract class CommandIssueInfraction implements CommandExecutor { } Player issuer = sender instanceof Player ? (Player) sender : null; - Optional maybe = parseArgs(getType(), issuer, args); + Optional maybe = parseArgs(getType(), issuer, args); if (maybe.isEmpty()) { // TOOD: better error messages sender.sendMessage("Invalid syntax."); return false; } - Infraction infraction = maybe.get(); + NewInfraction infraction = maybe.get(); if (infraction.getDuration().compareTo(maxDuration) == 1) { sender.sendMessage("You are not allowed you issue an infraction of duration " + infraction.getDuration() + "."); @@ -57,15 +57,15 @@ abstract class CommandIssueInfraction implements CommandExecutor { } applyInfraction(sender, infraction); - store.addInfraction(infraction); + store.issueInfraction(infraction); return false; } - protected abstract InfractionType getType(); + protected abstract SentenceType getType(); - protected abstract void applyInfraction(CommandSender sender, Infraction infraction); + protected abstract void applyInfraction(CommandSender sender, NewInfraction infraction); - private static Optional parseArgs(InfractionType type, OfflinePlayer issuer, String[] args) { + private static Optional parseArgs(SentenceType type, OfflinePlayer issuer, String[] args) { // TODO return null; } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java index c494ed6..1a24fbc 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java @@ -3,9 +3,9 @@ package me.jamestmartin.wasteland.modtools.commands; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.NewInfraction; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; public class CommandKick extends CommandIssueInfraction { public CommandKick(InfractionStore store) { @@ -13,12 +13,12 @@ public class CommandKick extends CommandIssueInfraction { } @Override - protected InfractionType getType() { - return InfractionType.KICK; + protected SentenceType getType() { + return SentenceType.KICK; } @Override - protected void applyInfraction(CommandSender sender, Infraction infraction) { + protected void applyInfraction(CommandSender sender, NewInfraction infraction) { Player player = infraction.getRecipient().getPlayer(); if (player == null) { sender.sendMessage("That player is not online!"); diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java index bd00b22..0e70c7b 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java @@ -4,9 +4,9 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import me.jamestmartin.wasteland.modtools.config.DurationsConfig; -import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.NewInfraction; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; public class CommandMute extends CommandIssueInfraction { public CommandMute(InfractionStore store, DurationsConfig durations) { @@ -14,12 +14,12 @@ public class CommandMute extends CommandIssueInfraction { } @Override - protected InfractionType getType() { - return InfractionType.MUTE; + protected SentenceType getType() { + return SentenceType.MUTE; } @Override - protected void applyInfraction(CommandSender sender, Infraction infraction) { + protected void applyInfraction(CommandSender sender, NewInfraction infraction) { Player player = infraction.getRecipient().getPlayer(); if (player != null) { player.sendMessage(infraction.getMessage()); diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java deleted file mode 100644 index e1b9597..0000000 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jamestmartin.wasteland.modtools.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -public class CommandMutes implements CommandExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java deleted file mode 100644 index 19cfdcf..0000000 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.jamestmartin.wasteland.modtools.commands; - -import java.util.Optional; - -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import me.jamestmartin.wasteland.modtools.infraction.Infraction; -import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; - -public abstract class CommandRemoveInfraction implements CommandExecutor { - protected final InfractionStore store; - - public CommandRemoveInfraction(InfractionStore store) { - this.store = store; - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - Player issuer = sender instanceof Player ? (Player) sender : null; - Optional maybe = parseArgs(getType(), issuer, args); - if (maybe.isEmpty()) { - // TOOD: better error messages - sender.sendMessage("Invalid syntax."); - return false; - } - Infraction infraction = maybe.get(); - - applyInfraction(sender, infraction); - store.addInfraction(infraction); - return false; - } - - protected abstract InfractionType getType(); - - protected abstract void applyInfraction(CommandSender sender, Infraction infraction); - - private static Optional parseArgs(InfractionType type, OfflinePlayer issuer, String[] args) { - // TODO - return null; - } -} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java deleted file mode 100644 index 499261b..0000000 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jamestmartin.wasteland.modtools.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -public class CommandUnban implements CommandExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java deleted file mode 100644 index d85337b..0000000 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jamestmartin.wasteland.modtools.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -public class CommandUnmute implements CommandExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java index c8ad5f5..a0c5249 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java @@ -3,9 +3,9 @@ package me.jamestmartin.wasteland.modtools.commands; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.NewInfraction; import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; public class CommandWarn extends CommandIssueInfraction { public CommandWarn(InfractionStore store) { @@ -13,12 +13,12 @@ public class CommandWarn extends CommandIssueInfraction { } @Override - protected InfractionType getType() { - return InfractionType.WARN; + protected SentenceType getType() { + return SentenceType.WARN; } @Override - protected void applyInfraction(CommandSender sender, Infraction infraction) { + protected void applyInfraction(CommandSender sender, NewInfraction infraction) { Player player = infraction.getRecipient().getPlayer(); if (player != null) { player.sendMessage(infraction.getMessage()); diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java index fdff271..0f42321 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java @@ -1,6 +1,7 @@ package me.jamestmartin.wasteland.modtools.infraction; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Optional; @@ -170,4 +171,15 @@ public class Duration implements Comparable { return Long.compare(getSeconds().get(), other.getSeconds().get()); } + + public static Duration fromDates(Date begin, Date end) { + return new Duration(end.getTime() - begin.getTime()); + } + + public static Duration fromDates(Date begin, Optional end) { + if (end.isEmpty()) { + return INFINITY; + } + return fromDates(begin, end.get()); + } } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java index 649085e..53b894c 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java @@ -1,56 +1,139 @@ package me.jamestmartin.wasteland.modtools.infraction; import java.util.Date; +import java.util.Optional; import org.bukkit.OfflinePlayer; public class Infraction { - private final InfractionType type; - private final OfflinePlayer issuer; + /** The unique identifier of this infraction. */ + private final int id; + /** The type of sentence the player received: ban, kick, mute, or warning. */ + private final SentenceType type; + /** The moderator who issued the sentence. (Or empty, if it was issued by the console.) */ + private final Optional issuer; + /** The player who committed the infraction. */ private final OfflinePlayer recipient; + /** The time that the sentence was issued. */ private final Date issued; - private final Duration duration; + /** The time that the sentence takes effect. */ + private final Date start; + /** The time that the sentence naturally expires, if ever. */ + private final Optional expiry; + /** The information about this infraction's repeal, if it was repealed. */ + private final Optional repeal; + /** If this sentence was commuted, the identifier for the original infraction. */ + private final Optional original; + /** The section identifier for the rule that was violated. */ private final String rule; + /** The reason that an infraction was issued. */ private final String reason; - public Infraction(InfractionType type, OfflinePlayer issuer, OfflinePlayer recipient, Date issued, Duration duration, String rule, String reason) { + public Infraction( + int id, + SentenceType type, + Optional issuer, + OfflinePlayer recipient, + Date issued, + Date start, + Optional expiry, + Optional repeal, + Optional original, + String rule, + String reason + ) { + this.id = id; this.type = type; this.issuer = issuer; this.recipient = recipient; this.issued = issued; - this.duration = duration; + this.start = start; + this.expiry = expiry; + this.repeal = repeal; + this.original = original; this.rule = rule; this.reason = reason; } - public InfractionType getType() { + /** @return The unique identifier for this infraction. */ + public int getId() { + return id; + } + + /** @return The {@link SentenceType type of sentence} the player received: ban, kick, mute, or warning. */ + public SentenceType getType() { return type; } - public OfflinePlayer getIssuer() { + /** @return The moderator who issued the sentence. (Or empty, if it was issued by the console.) */ + public Optional getIssuer() { return issuer; } - + + /** @return The player who committed the infraction. */ public OfflinePlayer getRecipient() { return recipient; } + /** @return The time the sentence was issued. */ public Date getIssued() { return issued; } - public Duration getDuration() { - return duration; + /** + * @return + *

The time that the sentence first takes effect. + *

+ * Generally, this will be the same time that it was issued; + * however, if a sentence is commuted, the new infraction starts at the same time, + * but will actually have a time issued *after* the sentence started! + */ + public Date getStart() { + return start; } + /** @return The time the infraction naturally expires if not repealed, if ever. */ + public Optional getExpiry() { + return expiry; + } + + /** + * @return The duration that the sentence would last if not repealed. + * @see #getActualDuration() + */ + public Duration getOriginalDuration() { + return Duration.fromDates(getStart(), getExpiry()); + } + + /** @return The information about this infraction's repeal, if it was repealed. */ + public Optional getRepeal() { + return repeal; + } + + /** @return If this sentence was commuted, the identifier for the original infraction. */ + public Optional getOriginal() { + return original; + } + + /** + * @return The duration the sentence would last if it has been repealed, or otherwise the original duration. + * @see #getOriginalDuration() + */ + public Duration getActualDuration() { + return Duration.fromDates(getStart(), getRepeal().map(Repeal::getIssued).or(() -> getExpiry())); + } + + /** @return The rule that was violated. */ public String getRule() { return rule; } + /** @return The reason that the infraction was issued. */ public String getReason() { return reason; } + /** @return The message that the player will get sent with information about their sentence. */ public String getMessage() { // TODO return null; diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java index 663e656..6e798f6 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java @@ -5,21 +5,42 @@ import java.util.Set; import java.util.UUID; public interface InfractionProvider { - Set getActiveInfractions(Optional player, Optional type); + /** + * @param player The player who committed the infractions, or any player. + * @param type The type of sentence given, or any sentence type. + * @return The un-expired, un-repealed sentences matching the provide criteria. + */ + Set getActiveInfractions(Optional player, Optional type); + /** @return All un-expired, un-repealed sentences. */ default Set getActiveInfractions() { return getActiveInfractions(Optional.empty(), Optional.empty()); } + /** + * @param player The player who committed the infractions. + * @return The player's un-expired, un-repealed sentences. + */ default Set getActiveInfractions(UUID player) { return getActiveInfractions(Optional.of(player), Optional.empty()); } - default Set getActiveInfractions(UUID player, InfractionType type) { + /** + * @param player The player who committed the infractions. + * @param type The type of sentence given. + * @return The player's un-expired, un-repealed sentences of the given type. + */ + default Set getActiveInfractions(UUID player, SentenceType type) { return getActiveInfractions(Optional.of(player), Optional.of(type)); } - default Set getActiveInfractions(InfractionType type) { + /** + * @param type The type of sentence given. + * @return All un-expired, un-repealed sentences of the given type. + */ + default Set getActiveInfractions(SentenceType type) { return getActiveInfractions(Optional.empty(), Optional.of(type)); } + + // TODO: Provide *in*active infractions which were never cleared. } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java index e250704..017ed7b 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java @@ -1,8 +1,36 @@ package me.jamestmartin.wasteland.modtools.infraction; +import java.util.Optional; + import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; public interface InfractionStore extends InfractionProvider { - void addInfraction(Infraction infraction); - void removeInfractions(OfflinePlayer player, InfractionType type); + /** + * @param infraction The new infraction to add to the database. + * @see NewInfraction#NewInfraction(SentenceType, java.util.Optional, OfflinePlayer, Duration, String, String) Create a new infraction. + * @see NewInfraction#NewInfraction(java.util.Optional, Duration, Infraction) Commute an old infraction. + * @see NewInfraction#NewInfraction(SentenceType, java.util.Optional, OfflinePlayer, java.util.Optional, Duration, java.util.Optional, String, String) Update an old infraction. + */ + void issueInfraction(NewInfraction infraction); + + /** + *

Clear a previously-issued infraction. + *

This will clear the infraction from the player's record, but not from the audit log. + * @param id The identifier of the infraction to clear. + * @param issuer The moderator who cleared the infraction. + * @see RepealType#CLEARED + * @see #appealInfraction(OfflinePlayer, SentenceType) + */ + void clearInfraction(int id, Optional issuer); + + /** + *

Accept an appeal for a previously-issued infraction. + *

This will remove the sentence from the player, but not remove it from their record. + * @param id The identifier of the infraction which was appealed. + * @param issuer The moderator who accepted the appeal. + * @see RepealType#APPEALED + * @see #clearInfraction(int, Optional) + */ + void appealInfraction(int id, Optional issuer); } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/NewInfraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/NewInfraction.java new file mode 100644 index 0000000..655afeb --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/NewInfraction.java @@ -0,0 +1,145 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import java.util.Date; +import java.util.Optional; + +import org.bukkit.OfflinePlayer; + +public class NewInfraction { + /** The type of sentence the player received: ban, kick, mute, or warning. */ + private final SentenceType type; + /** The moderator who issued the sentence. (Or empty, if it was issued by the console.) */ + private final Optional issuer; + /** The player who committed the infraction. */ + private final OfflinePlayer recipient; + /** The time that the sentence takes effect, or empty if it starts immediately. */ + private final Optional start; + /** The duration of the sentence. */ + private final Duration duration; + /** If this sentence was commuted, the identifier for the original infraction. */ + private final Optional original; + /** The section identifier for the rule that was violated. */ + private final String rule; + /** The reason that an infraction was issued. */ + private final String reason; + + public NewInfraction( + SentenceType type, + Optional issuer, + OfflinePlayer recipient, + Optional start, + Duration duration, + Optional original, + String rule, + String reason + ) { + this.type = type; + this.issuer = issuer; + this.recipient = recipient; + this.start = start; + this.duration = duration; + this.original = original; + this.rule = rule; + this.reason = reason; + } + + public NewInfraction( + SentenceType type, + Optional issuer, + OfflinePlayer recipient, + Duration duration, + String rule, + String reason + ) { + this.type = type; + this.issuer = issuer; + this.recipient = recipient; + this.start = Optional.empty(); + this.duration = duration; + this.original = Optional.empty(); + this.rule = rule; + this.reason = reason; + } + + /** Update an old infraction with a new expiry. */ + public NewInfraction( + Optional issuer, + Duration duration, + Infraction original + ) { + this.type = original.getType(); + this.issuer = issuer; + this.recipient = original.getRecipient(); + this.start = Optional.of(original.getStart()); + this.duration = duration; + this.original = Optional.of(original.getId()); + this.rule = original.getRule(); + this.reason = original.getReason(); + } + + /** Update an old infraction with a new expiry and reason. */ + public NewInfraction( + Optional issuer, + Duration duration, + Infraction original, + String rule, + String reason + ) { + this.type = original.getType(); + this.issuer = issuer; + this.recipient = original.getRecipient(); + this.start = Optional.of(original.getStart()); + this.duration = duration; + this.original = Optional.of(original.getId()); + this.rule = rule; + this.reason = reason; + } + + /** @return The {@link SentenceType type of sentence} the player received: ban, kick, mute, or warning. */ + public SentenceType getType() { + return type; + } + + /** @return The moderator who issued the sentence. (Or empty, if it was issued by the console.) */ + public Optional getIssuer() { + return issuer; + } + + /** @return The player who committed the infraction. */ + public OfflinePlayer getRecipient() { + return recipient; + } + + /** + * @return The time that the sentence first takes effect, or empty if it starts immediately. + */ + public Optional getStart() { + return start; + } + + /** @return The time the infraction naturally expires if not repealed, if ever. */ + public Duration getDuration() { + return duration; + } + + /** @return If this sentence was commuted, the identifier for the original infraction. */ + public Optional getOriginal() { + return original; + } + + /** @return The rule that was violated. */ + public String getRule() { + return rule; + } + + /** @return The reason that the infraction was issued. */ + public String getReason() { + return reason; + } + + /** @return The message that the player will get sent with information about their sentence. */ + public String getMessage() { + // TODO + return null; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Repeal.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Repeal.java new file mode 100644 index 0000000..1d403d8 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Repeal.java @@ -0,0 +1,33 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import java.util.Date; +import java.util.Optional; + +import org.bukkit.OfflinePlayer; + +public class Repeal { + private final RepealType type; + private final Optional issuer; + private final Date issued; + + public Repeal(RepealType type, Optional issuer, Date issued) { + this.type = type; + this.issuer = issuer; + this.issued = issued; + } + + /** The way in which the infraction was repealed. */ + public RepealType getType() { + return type; + } + + /** The player who issued the repeal. */ + public Optional getIssuer() { + return issuer; + } + + /** The time the repeal was issued. */ + public Date getIssued() { + return issued; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/RepealType.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/RepealType.java new file mode 100644 index 0000000..2dad403 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/RepealType.java @@ -0,0 +1,11 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +/** The way in which which an infraction was removed. */ +public enum RepealType { + /** The player was cleared of wrongdoing, and this infraction will be removed from their record. */ + CLEARED, + /** The player's sentence was reduced, and replaced with another infraction. */ + COMMUTED, + /** The player's sentence was removed based on appeal, but the infraction will remain on their record. */ + APPEALED; +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/SentenceType.java similarity index 78% rename from modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java rename to modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/SentenceType.java index d5e746b..e6930ca 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/SentenceType.java @@ -1,6 +1,6 @@ package me.jamestmartin.wasteland.modtools.infraction; -public enum InfractionType { +public enum SentenceType { BAN(true), KICK(false), MUTE(true), @@ -8,7 +8,7 @@ public enum InfractionType { private final boolean hasduration; - private InfractionType(boolean hasDuration) { + private SentenceType(boolean hasDuration) { this.hasduration = hasDuration; } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogProvider.java similarity index 59% rename from modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java rename to modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogProvider.java index 1e8d870..b4aea58 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogProvider.java @@ -6,37 +6,60 @@ import java.util.UUID; import me.jamestmartin.wasteland.modtools.infraction.Duration; import me.jamestmartin.wasteland.modtools.infraction.Infraction; -import me.jamestmartin.wasteland.modtools.infraction.InfractionType; +import me.jamestmartin.wasteland.modtools.infraction.SentenceType; -public interface ModLogProvider { +public interface AuditLogProvider { + /** + * @param duration The maximum time ago that an infraction was issued or repealed. + * @param issuer The moderator who issued an infraction. + * @param recipient The player who committed the infraction. + * @param type The type of sentence issued. + * @return All infractions that were issued or repealed fitting the provided criteria. + */ Set getInfractions( Duration duration, Optional issuer, Optional recipient, - Optional type + Optional type ); + /** All infractions that have ever been issued. */ default Set getInfractions() { return getInfractions(Duration.INFINITY); } - default Set getInfractions(InfractionType type) { + /** + * @param type The type of sentence issued. + * @return All sentences of the given type that have ever been issued. + */ + default Set getInfractions(SentenceType type) { return getInfractions(Duration.INFINITY, type); } + /** + * @param duration The maximum time ago that an infraction was issued or repealed. + * @return All sentences that have ever been issued or repealed within the duration provided. + */ default Set getInfractions(Duration duration) { return getInfractions(duration, Optional.empty(), Optional.empty(), Optional.empty()); } - default Set getInfractions(Duration duration, InfractionType type) { + /** + * @param duration The maximum time ago that an infraction was issued or repealed. + * @param type The type of sentence issued. + * @return All sentences of the given type that have ever been issued or repealed within the duration provided. + */ + default Set getInfractions(Duration duration, SentenceType type) { return getInfractions(duration, Optional.empty(), Optional.empty(), Optional.of(type)); } + // TODO: Javadoc for all these variants. + default Set getInfractionsIssuedTo(UUID player) { return getInfractionsIssuedTo(Duration.INFINITY, player); } - default Set getInfractionsIssuedTo(UUID player, InfractionType type) { + default Set getInfractionsIssuedTo(UUID player, SentenceType type) { return getInfractionsIssuedTo(Duration.INFINITY, player, type); } @@ -44,7 +67,7 @@ public interface ModLogProvider { return getInfractions(duration, Optional.empty(), Optional.of(player), Optional.empty()); } - default Set getInfractionsIssuedTo(Duration duration, UUID player, InfractionType type) { + default Set getInfractionsIssuedTo(Duration duration, UUID player, SentenceType type) { return getInfractions(duration, Optional.empty(), Optional.of(player), Optional.of(type)); } @@ -52,7 +75,7 @@ public interface ModLogProvider { return getInfractionsIssuedBy(Duration.INFINITY, player); } - default Set getInfractionsIssuedBy(UUID player, InfractionType type) { + default Set getInfractionsIssuedBy(UUID player, SentenceType type) { return getInfractionsIssuedBy(Duration.INFINITY, player, type); } @@ -60,8 +83,7 @@ public interface ModLogProvider { return getInfractions(duration, Optional.of(player), Optional.empty(), Optional.empty()); } - default Set getInfractionsIssuedBy(Duration duration, UUID player, InfractionType type) { + default Set getInfractionsIssuedBy(Duration duration, UUID player, SentenceType type) { return getInfractions(duration, Optional.of(player), Optional.empty(), Optional.of(type)); } - } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogStore.java similarity index 53% rename from modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java rename to modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogStore.java index a2c53c9..6841239 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/AuditLogStore.java @@ -1,7 +1,8 @@ package me.jamestmartin.wasteland.modtools.log; import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; -public interface ModLogStore extends ModLogProvider { +public interface AuditLogStore extends AuditLogProvider, InfractionStore { void addInfraction(Infraction infraction); } diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandAuditLog.java similarity index 86% rename from modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java rename to modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandAuditLog.java index a2fffc3..a1a1721 100644 --- a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandAuditLog.java @@ -4,7 +4,7 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -public class CommandModLog implements CommandExecutor { +public class CommandAuditLog implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { diff --git a/modtools/src/main/resources/plugin.yml b/modtools/src/main/resources/plugin.yml index f172d65..3edceb1 100644 --- a/modtools/src/main/resources/plugin.yml +++ b/modtools/src/main/resources/plugin.yml @@ -5,14 +5,19 @@ version: 0.1.0 api-version: 1.16 commands: - modlog: + auditlog: description: See the list of recent actions taken by moderators. usage: "Usage: / []" permission: wasteland.modtools.log - permission-message: You do not have permission to view the moderator log. + permission-message: You do not have permission to view the aduit log. infractions: description: See the list of infractions against the rules a player has committed. - usage: "Usage: / []" + usage: | + Usage: + / query [] + / commute [] [ ...] + / clear + / appeal permission: wasteland.modtools.infractions permission-message: You do not have permission to view players' infractions against the rules. @@ -43,16 +48,6 @@ commands: usage: "Usage: / [] [ ...]" permission: wasteland.modtools.ban.issue permission-message: You do not have permission to ban players. - unban: - description: Unban a player, allowing them to join again. - usage: "Usage: / [ ...]" - permission: wasteland.modtools.ban.pardon - permission-message: You do not have permission to unban players. - bans: - description: See the list of all players currently banned from the server. - usage: "Usage: / []" - permission: wasteland.modtools.ban.list - permission-message: You do not have permission to list banned players. kick: description: Kick a player from the server. @@ -65,16 +60,6 @@ commands: usage: "Usage: / [] [ ...]" permission: wasteland.modtools.mute.issue permission-message: You do not have permission to mute players. - unmute: - description: Unmute a player, allowing them to talk again. - usage: "Usage: / [ ...]" - permission: wasteland.modtools.mute.pardon - permission-message: You do not have permission to unmute players. - mutes: - description: See the list of all players currently muted on the server. - usage: "Usage: / []" - permission: wasteland.modtools.mutes.list - permission-message: You do not have permission to list muted players. warn: description: Give a player an official (logged) warning. @@ -97,12 +82,12 @@ permissions: default: op children: wasteland.modtools.infractions: true - wasteland.modtools.ban.list: true - wasteland.modtools.mute.list: true - wasteland.modtools.warn.list: true wasteland.modtools.infractions: description: Allows you to see the list of infractions against the rules a player has committed. default: op + wasteland.modtools.infractions.clear: + description: Allows you to clear infractions from players' permanent records. + default: op wasteland.modtools.uuid: description: Allows you to see the UUIDs of players with a given name on this server. @@ -151,20 +136,16 @@ permissions: wasteland.manual.faq: true wasteland.modtools.ban: - description: Allows you to ban or unban a player, or list active bans. + description: Allows you to ban or unban a player. default: op children: wasteland.modtools.ban.issue: true - wasteland.modtools.ban.list: true wasteland.modtools.ban.pardon: true wasteland.modtools.ban.issue: description: Allows you to issue bans. default: op - wasteland.modtools.ban.list: - description: Allows you to list all active bans. - default: op - wasteland.modtools.ban.pardon: - description: Allows you to remove bans. + wasteland.modtools.ban.commute: + description: Allows you to commute bans. default: op wasteland.modtools.kick: @@ -172,20 +153,15 @@ permissions: default: op wasteland.modtools.mute: - description: Allows you to mute or unmute a player, or list active mutes. - default: op + description: Allows you to mute or unmute a player. children: wasteland.modtools.mute.issue: true - wasteland.modtools.mute.list: true wasteland.modtools.mute.pardon: true wasteland.modtools.mute.issue: description: Allows you to issue mutes. default: op - wasteland.modtools.mute.list: - description: Allows you to list active mutes. - default: op - wasteland.modtools.mute.pardon: - description: Allows you to remove mutes. + wasteland.modtools.mute.commute: + description: Allows you to commute mutes. default: op wasteland.modtools.warn: