From 1c500a0c05849129af3019c6fecb37f2547464c5 Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 7 Jan 2020 17:20:04 -0800 Subject: [PATCH] Redstone on islands will operate if mods or ops are present even if the offline redstone flag is active and no team members are online. This enables staff to bypass the "Offline Redstone" feature, which means if staff need to moderate players islands then redstone is an issue. Fixes https://github.com/BentoBoxWorld/BentoBox/issues/1102 --- .../OfflineRedstoneListener.java | 10 +++- .../OfflineRedstoneListenerTest.java | 58 ++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListener.java index 5627c4a0d..6aa654a10 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListener.java @@ -24,15 +24,23 @@ public class OfflineRedstoneListener extends FlagListener { return; } - // Check if island exists and members are online - excludes spawn + // Check if island exists and members are online, or mods or ops are on the island - ignores spawn getIslands().getProtectedIslandAt(e.getBlock().getLocation()) .filter(i -> !i.isSpawn()) .ifPresent(i -> { + // Check team members for (UUID uuid : i.getMemberSet(RanksManager.COOP_RANK)) { if (Bukkit.getPlayer(uuid) != null) { return; } } + // Check mods or Ops on island + if (Bukkit.getOnlinePlayers().parallelStream() + .filter(p -> p.isOp() || p.hasPermission(getIWM().getPermissionPrefix(i.getWorld()) + "mod.bypassprotect")) + .anyMatch(p -> i.onIsland(p.getLocation()))) { + return; + } + // No one there... e.setNewCurrent(0); }); } diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListenerTest.java index 6a4de9e8d..52b9ef8f6 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/OfflineRedstoneListenerTest.java @@ -7,8 +7,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; @@ -23,6 +25,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -43,6 +46,8 @@ import world.bentobox.bentobox.util.Util; @PrepareForTest({BentoBox.class, Util.class, Bukkit.class }) public class OfflineRedstoneListenerTest { + private static final String[] NAMES = {"adam", "ben", "cara", "dave", "ed", "frank", "freddy", "george", "harry", "ian", "joe"}; + @Mock private World world; @Mock @@ -100,6 +105,19 @@ public class OfflineRedstoneListenerTest { when(iwm.getAddon(any())).thenReturn(Optional.empty()); PowerMockito.mockStatic(Bukkit.class); + // Online players + Set onlinePlayers = new HashSet<>(); + for (int j = 0; j < NAMES.length; j++) { + Player p1 = mock(Player.class); + UUID u = UUID.randomUUID(); + when(p1.getUniqueId()).thenReturn(u); + when(p1.getName()).thenReturn(NAMES[j]); + // All ops + when(p1.isOp()).thenReturn(true); + onlinePlayers.add(p1); + } + when(Bukkit.getOnlinePlayers()).then((Answer>) invocation -> onlinePlayers); + } @After @@ -150,7 +168,7 @@ public class OfflineRedstoneListenerTest { OfflineRedstoneListener orl = new OfflineRedstoneListener(); // Offline redstone not allowed Flags.OFFLINE_REDSTONE.setSetting(world, false); - // Members are online + // Members are offline when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null); orl.onBlockRedstone(e); @@ -158,6 +176,44 @@ public class OfflineRedstoneListenerTest { assertEquals(0, e.getNewCurrent()); } + /** + * Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}. + */ + @Test + public void testOnBlockRedstoneMembersOfflineOpsOnlineNotOnIsland() { + // Make an event to give some current to block + BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10); + OfflineRedstoneListener orl = new OfflineRedstoneListener(); + // Offline redstone not allowed + Flags.OFFLINE_REDSTONE.setSetting(world, false); + // Members are offline + when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null); + + orl.onBlockRedstone(e); + // Current will be 0 + assertEquals(0, e.getNewCurrent()); + } + + /** + * Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}. + */ + @Test + public void testOnBlockRedstoneMembersOfflineOpsOnlineOnIsland() { + // Make an event to give some current to block + BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10); + OfflineRedstoneListener orl = new OfflineRedstoneListener(); + // Offline redstone not allowed + Flags.OFFLINE_REDSTONE.setSetting(world, false); + // Members are offline + when(Bukkit.getPlayer(any(UUID.class))).thenReturn(null); + // On island + when(island.onIsland(any())).thenReturn(true); + + orl.onBlockRedstone(e); + // Current remains 10 + assertEquals(10, e.getNewCurrent()); + } + /** * Test method for {@link OfflineRedstoneListener#onBlockRedstone(BlockRedstoneEvent)}. */