From 9c41ceb5f24ba49a7afa95885dccd0e070fd7ba7 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 25 Jul 2018 09:47:57 -0700 Subject: [PATCH] Added clear resets and clear reset all admin commands. Clear reset all uses a timestamp stored in config.yml. If a player logs in and the last time they logged in was before that timestamp, then their resets are cleared. Note that as opposed to ASkyBlock, the player object stores the number of resets done for a world and not the number of resets left. This is a better design because it means that admins can change the max number of resets and every player file does not have to be adjusted. Location of commit (30,000ft above Nevada desert, just coming into Las Vegas). --- locales/en-US.yml | 8 +- .../bskyblock/commands/AdminCommand.java | 8 +- .../admin/AdminClearResetAllCommand.java | 52 ------ .../admin/AdminClearResetsAllCommand.java | 40 ++++ ...mand.java => AdminClearResetsCommand.java} | 14 +- .../admin/AdminClearResetsAllCommandTest.java | 124 +++++++++++++ .../admin/AdminClearResetsCommandTest.java | 174 ++++++++++++++++++ 7 files changed, 356 insertions(+), 64 deletions(-) delete mode 100644 src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetAllCommand.java create mode 100644 src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommand.java rename src/main/java/us/tastybento/bskyblock/commands/admin/{AdminClearResetCommand.java => AdminClearResetsCommand.java} (79%) create mode 100644 src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommandTest.java create mode 100644 src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommandTest.java diff --git a/locales/en-US.yml b/locales/en-US.yml index 357077c18..3bcf916ef 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -52,6 +52,12 @@ commands: help: parameters: "" description: "admin command" + clearresets: + parameters: "" + description: "clears player reset count for this world" + cleared: "&2Resets cleared" + clearresetsall: + description: "clears all player reset counts for this world" team: add: parameters: " " @@ -115,7 +121,7 @@ commands: owner: "Owner: [owner] ([uuid])" last-login: "Last login: [date]" deaths: "Deaths: [number]" - resets-left: "Resets left: [number]/[total]" + resets-left: "Resets: [number] (Max: [total])" team-members-title: "Team members:" team-owner-format: "&a[name] [rank]" team-member-format: "&b[name] [rank]" diff --git a/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java b/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java index 8b9c187fb..456f28e09 100755 --- a/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java @@ -5,8 +5,8 @@ import us.tastybento.bskyblock.api.commands.CompositeCommand; import us.tastybento.bskyblock.api.localization.TextVariables; import us.tastybento.bskyblock.api.user.User; -import us.tastybento.bskyblock.commands.admin.AdminClearResetAllCommand; -import us.tastybento.bskyblock.commands.admin.AdminClearResetCommand; +import us.tastybento.bskyblock.commands.admin.AdminClearResetsAllCommand; +import us.tastybento.bskyblock.commands.admin.AdminClearResetsCommand; import us.tastybento.bskyblock.commands.admin.AdminGetRankCommand; import us.tastybento.bskyblock.commands.admin.AdminInfoCommand; import us.tastybento.bskyblock.commands.admin.AdminRegisterCommand; @@ -57,8 +57,8 @@ public void setup() { // Range new AdminRangeCommand(this); // Resets - new AdminClearResetCommand(this); - new AdminClearResetAllCommand(this); + new AdminClearResetsCommand(this); + new AdminClearResetsAllCommand(this); } @Override diff --git a/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetAllCommand.java b/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetAllCommand.java deleted file mode 100644 index 7ade3c0ec..000000000 --- a/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetAllCommand.java +++ /dev/null @@ -1,52 +0,0 @@ -package us.tastybento.bskyblock.commands.admin; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.user.User; -import us.tastybento.bskyblock.util.Util; - -public class AdminClearResetAllCommand extends CompositeCommand { - - public AdminClearResetAllCommand(CompositeCommand parent) { - super(parent, "clearresetall"); - } - - @Override - public void setup() { - setPermission("admin.clearresetall"); - setParameters("commands.admin.clearreset.parameters"); - setDescription("commands.admin.clearreset.description"); - } - - @Override - public boolean execute(User user, String label, List args) { - // If args are not right, show help - if (!args.isEmpty()) { - showHelp(this, user); - return false; - } - // Set the reset epoch to now - getIWM().setResetEpoch(getWorld()); - // Reset all current players - Bukkit.getOnlinePlayers().stream().map(Player::getUniqueId).filter(getPlayers()::isKnown).forEach(u -> getPlayers().setResets(getWorld(), u, 0)); - user.sendMessage("general.success"); - return true; - } - - @Override - public Optional> tabComplete(User user, String alias, List args) { - String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; - if (args.isEmpty()) { - // Don't show every player on the server. Require at least the first letter - return Optional.empty(); - } - List options = new ArrayList<>(Util.getOnlinePlayerList(user)); - return Optional.of(Util.tabLimit(options, lastArg)); - } -} \ No newline at end of file diff --git a/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommand.java b/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommand.java new file mode 100644 index 000000000..05efa4fdb --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommand.java @@ -0,0 +1,40 @@ +package us.tastybento.bskyblock.commands.admin; + +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import us.tastybento.bskyblock.api.commands.CompositeCommand; +import us.tastybento.bskyblock.api.user.User; + +public class AdminClearResetsAllCommand extends CompositeCommand { + + public AdminClearResetsAllCommand(CompositeCommand parent) { + super(parent, "clearresetsall"); + } + + @Override + public void setup() { + setPermission("admin.clearresetsall"); + setDescription("commands.admin.clearresetsall.description"); + } + + @Override + public boolean execute(User user, String label, List args) { + // If args are not right, show help + if (!args.isEmpty()) { + showHelp(this, user); + return false; + } + this.askConfirmation(user, () -> { + // Set the reset epoch to now + getIWM().setResetEpoch(getWorld()); + // Reset all current players + Bukkit.getOnlinePlayers().stream().map(Player::getUniqueId).filter(getPlayers()::isKnown).forEach(u -> getPlayers().setResets(getWorld(), u, 0)); + user.sendMessage("general.success"); + }); + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetCommand.java b/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommand.java similarity index 79% rename from src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetCommand.java rename to src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommand.java index 29b01bf5e..7fc7bf3f5 100644 --- a/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommand.java @@ -9,17 +9,17 @@ import us.tastybento.bskyblock.api.user.User; import us.tastybento.bskyblock.util.Util; -public class AdminClearResetCommand extends CompositeCommand { +public class AdminClearResetsCommand extends CompositeCommand { - public AdminClearResetCommand(CompositeCommand parent) { - super(parent, "clearreset"); + public AdminClearResetsCommand(CompositeCommand parent) { + super(parent, "clearresets"); } @Override public void setup() { setPermission("admin.clearreset"); - setParameters("commands.admin.clearreset.parameters"); - setDescription("commands.admin.clearreset.description"); + setParameters("commands.admin.clearresets.parameters"); + setDescription("commands.admin.clearresets.description"); } @Override @@ -40,8 +40,8 @@ public boolean execute(User user, String label, List args) { return false; } // Clear resets - user.sendMessage("commands.admin.clearreset.cleared"); - getPlayers().setResets(getWorld(), user.getUniqueId(), 0); + user.sendMessage("commands.admin.clearresets.cleared"); + getPlayers().setResets(getWorld(), targetUUID, 0); user.sendMessage("general.success"); return true; } diff --git a/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommandTest.java b/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommandTest.java new file mode 100644 index 000000000..ff218ea86 --- /dev/null +++ b/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsAllCommandTest.java @@ -0,0 +1,124 @@ +package us.tastybento.bskyblock.commands.admin; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitScheduler; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.Settings; +import us.tastybento.bskyblock.api.user.User; +import us.tastybento.bskyblock.commands.AdminCommand; +import us.tastybento.bskyblock.managers.CommandsManager; +import us.tastybento.bskyblock.managers.IslandWorldManager; +import us.tastybento.bskyblock.managers.IslandsManager; +import us.tastybento.bskyblock.managers.LocalesManager; +import us.tastybento.bskyblock.managers.PlayersManager; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({Bukkit.class, BSkyBlock.class, User.class }) +public class AdminClearResetsAllCommandTest { + + private AdminCommand ac; + private User user; + private IslandsManager im; + private PlayersManager pm; + private UUID notUUID; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + // Set up plugin + BSkyBlock plugin = mock(BSkyBlock.class); + Whitebox.setInternalState(BSkyBlock.class, "instance", plugin); + + // Command manager + CommandsManager cm = mock(CommandsManager.class); + when(plugin.getCommandsManager()).thenReturn(cm); + + // Settings + Settings s = mock(Settings.class); + when(s.getResetWait()).thenReturn(0L); + when(s.getResetLimit()).thenReturn(3); + when(plugin.getSettings()).thenReturn(s); + + // Player + Player p = mock(Player.class); + // Sometimes use Mockito.withSettings().verboseLogging() + user = mock(User.class); + when(user.isOp()).thenReturn(false); + UUID uuid = UUID.randomUUID(); + notUUID = UUID.randomUUID(); + while(notUUID.equals(uuid)) { + notUUID = UUID.randomUUID(); + } + when(user.getUniqueId()).thenReturn(uuid); + when(user.getPlayer()).thenReturn(p); + when(user.getName()).thenReturn("tastybento"); + User.setPlugin(plugin); + + // Parent command has no aliases + ac = mock(AdminCommand.class); + when(ac.getSubCommandAliases()).thenReturn(new HashMap<>()); + + // Island World Manager + IslandWorldManager iwm = mock(IslandWorldManager.class); + World world = mock(World.class); + when(iwm.getBSBIslandWorld()).thenReturn(world); + when(plugin.getIWM()).thenReturn(iwm); + + + // Player has island to begin with + im = mock(IslandsManager.class); + when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); + when(im.hasIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(true); + when(im.isOwner(Mockito.any(),Mockito.any())).thenReturn(true); + when(im.getTeamLeader(Mockito.any(),Mockito.any())).thenReturn(uuid); + when(plugin.getIslands()).thenReturn(im); + + // Has team + pm = mock(PlayersManager.class); + when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true); + + when(plugin.getPlayers()).thenReturn(pm); + + // Server & Scheduler + BukkitScheduler sch = mock(BukkitScheduler.class); + PowerMockito.mockStatic(Bukkit.class); + when(Bukkit.getScheduler()).thenReturn(sch); + + // Locales + LocalesManager lm = mock(LocalesManager.class); + when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation"); + when(plugin.getLocalesManager()).thenReturn(lm); + } + + /** + * Test method for {@link us.tastybento.bskyblock.commands.admin.AdminClearResetsAllCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + @Test + public void testExecuteCheckConfirm() { + AdminClearResetsAllCommand itl = new AdminClearResetsAllCommand(ac); + assertFalse(itl.execute(user, itl.getLabel(), new ArrayList<>())); + Mockito.verify(user).sendMessage(Mockito.eq("general.confirm"), Mockito.eq("[seconds]"), Mockito.any()); + } + +} diff --git a/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommandTest.java b/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommandTest.java new file mode 100644 index 000000000..ae915ad8e --- /dev/null +++ b/src/test/java/us/tastybento/bskyblock/commands/admin/AdminClearResetsCommandTest.java @@ -0,0 +1,174 @@ +/** + * + */ +package us.tastybento.bskyblock.commands.admin; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitScheduler; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.Settings; +import us.tastybento.bskyblock.api.user.User; +import us.tastybento.bskyblock.commands.AdminCommand; +import us.tastybento.bskyblock.managers.CommandsManager; +import us.tastybento.bskyblock.managers.IslandWorldManager; +import us.tastybento.bskyblock.managers.IslandsManager; +import us.tastybento.bskyblock.managers.LocalesManager; +import us.tastybento.bskyblock.managers.PlayersManager; + +/** + * @author ben + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({Bukkit.class, BSkyBlock.class, User.class }) +public class AdminClearResetsCommandTest { + + private AdminCommand ac; + private User user; + private IslandsManager im; + private PlayersManager pm; + private UUID notUUID; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + // Set up plugin + BSkyBlock plugin = mock(BSkyBlock.class); + Whitebox.setInternalState(BSkyBlock.class, "instance", plugin); + + // Command manager + CommandsManager cm = mock(CommandsManager.class); + when(plugin.getCommandsManager()).thenReturn(cm); + + // Settings + Settings s = mock(Settings.class); + when(s.getResetWait()).thenReturn(0L); + when(s.getResetLimit()).thenReturn(3); + when(plugin.getSettings()).thenReturn(s); + + // Player + Player p = mock(Player.class); + // Sometimes use Mockito.withSettings().verboseLogging() + user = mock(User.class); + when(user.isOp()).thenReturn(false); + UUID uuid = UUID.randomUUID(); + notUUID = UUID.randomUUID(); + while(notUUID.equals(uuid)) { + notUUID = UUID.randomUUID(); + } + when(user.getUniqueId()).thenReturn(uuid); + when(user.getPlayer()).thenReturn(p); + when(user.getName()).thenReturn("tastybento"); + User.setPlugin(plugin); + + // Parent command has no aliases + ac = mock(AdminCommand.class); + when(ac.getSubCommandAliases()).thenReturn(new HashMap<>()); + + // Island World Manager + IslandWorldManager iwm = mock(IslandWorldManager.class); + World world = mock(World.class); + when(iwm.getBSBIslandWorld()).thenReturn(world); + when(plugin.getIWM()).thenReturn(iwm); + + + // Player has island to begin with + im = mock(IslandsManager.class); + when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); + when(im.hasIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(true); + when(im.isOwner(Mockito.any(),Mockito.any())).thenReturn(true); + when(im.getTeamLeader(Mockito.any(),Mockito.any())).thenReturn(uuid); + when(plugin.getIslands()).thenReturn(im); + + // Has team + pm = mock(PlayersManager.class); + when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true); + + when(plugin.getPlayers()).thenReturn(pm); + + // Server & Scheduler + BukkitScheduler sch = mock(BukkitScheduler.class); + PowerMockito.mockStatic(Bukkit.class); + when(Bukkit.getScheduler()).thenReturn(sch); + + // Locales + LocalesManager lm = mock(LocalesManager.class); + when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation"); + when(plugin.getLocalesManager()).thenReturn(lm); + } + + /** + * Test method for {@link us.tastybento.bskyblock.commands.admin.AdminClearResetsCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + @Test + public void testExecuteNoTarget() { + AdminClearResetsCommand itl = new AdminClearResetsCommand(ac); + assertFalse(itl.execute(user, itl.getLabel(), new ArrayList<>())); + // Show help + Mockito.verify(user).sendMessage(Mockito.eq("commands.help.header"), Mockito.eq("[label]"), Mockito.any()); + } + + /** + * Test method for {@link us.tastybento.bskyblock.commands.admin.AdminClearResetsCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + @Test + public void testExecuteUnknownPlayer() { + AdminClearResetsCommand itl = new AdminClearResetsCommand(ac); + String[] name = {"tastybento"}; + when(pm.getUUID(Mockito.any())).thenReturn(null); + assertFalse(itl.execute(user, itl.getLabel(), Arrays.asList(name))); + Mockito.verify(user).sendMessage(Mockito.eq("general.errors.unknown-player")); + } + + /** + * Test method for {@link us.tastybento.bskyblock.commands.admin.AdminClearResetsCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + @Test + public void testExecutePlayerNoIsland() { + AdminClearResetsCommand itl = new AdminClearResetsCommand(ac); + String[] name = {"tastybento"}; + when(pm.getUUID(Mockito.any())).thenReturn(notUUID); + when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false); + assertFalse(itl.execute(user, itl.getLabel(), Arrays.asList(name))); + Mockito.verify(user).sendMessage(Mockito.eq("general.errors.player-has-no-island")); + } + + /** + * Test method for {@link us.AdminClearResetsCommand.tastybento.bskyblock.commands.admin.AdminClearResetCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + @Test + public void testExecuteSuccess() { + String[] name = {"tastybento"}; + when(pm.getUUID(Mockito.any())).thenReturn(notUUID); + + AdminClearResetsCommand itl = new AdminClearResetsCommand(ac); + assertTrue(itl.execute(user, itl.getLabel(), Arrays.asList(name))); + // Add other verifications + Mockito.verify(user).sendMessage("commands.admin.clearresets.cleared"); + Mockito.verify(user).sendMessage(Mockito.eq("general.success")); + } + +}