diff --git a/src/main/java/world/bentobox/bentobox/Settings.java b/src/main/java/world/bentobox/bentobox/Settings.java index efc0ae698..400b718a4 100644 --- a/src/main/java/world/bentobox/bentobox/Settings.java +++ b/src/main/java/world/bentobox/bentobox/Settings.java @@ -143,6 +143,11 @@ public class Settings implements ConfigObject { @ConfigEntry(path = "island.confirmation.commands.reset") private boolean resetConfirmation = true; + @ConfigComment("Ask the recipient to confirm trust or coop invites.") + @ConfigComment("Team invites will always require confirmation, for safety concerns.") + @ConfigEntry(path = "island.confirmation.invites", since = "1.8.0") + private boolean inviteConfirmation = false; + @ConfigComment("Sets the minimum length an island custom name is required to have.") @ConfigEntry(path = "island.name.min-length") private int nameMinLength = 4; @@ -560,5 +565,19 @@ public class Settings implements ConfigObject { this.clearRadius = clearRadius; } + /** + * @return the inviteConfirmation + * @since 1.8.0 + */ + public boolean isInviteConfirmation() { + return inviteConfirmation; + } -} \ No newline at end of file + /** + * @param inviteConfirmation the inviteConfirmation to set + * @since 1.8.0 + */ + public void setInviteConfirmation(boolean inviteConfirmation) { + this.inviteConfirmation = inviteConfirmation; + } +} diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/Invite.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/Invite.java new file mode 100644 index 000000000..b31c1b04d --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/Invite.java @@ -0,0 +1,84 @@ +package world.bentobox.bentobox.api.commands.island.team; + +import java.util.Objects; +import java.util.UUID; + +/** + * Represents an invite + * @author tastybento + * @since 1.8.0 + */ +public class Invite { + + /** + * Type of invitation + * + */ + public enum Type { + COOP, + TEAM, + TRUST + } + + private final Type type; + private final UUID inviter; + private final UUID invitee; + + /** + * @param type + * @param inviter + * @param invitee + */ + public Invite(Type type, UUID inviter, UUID invitee) { + this.type = type; + this.inviter = inviter; + this.invitee = invitee; + } + + /** + * @return the type + */ + public Type getType() { + return type; + } + + /** + * @return the inviter + */ + public UUID getInviter() { + return inviter; + } + + /** + * @return the invitee + */ + public UUID getInvitee() { + return invitee; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return Objects.hash(invitee, inviter, type); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Invite)) { + return false; + } + Invite other = (Invite) obj; + return Objects.equals(invitee, other.invitee) && Objects.equals(inviter, other.inviter) && type == other.type; + } +} diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java index 85557f67c..ccfa57560 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java @@ -1,11 +1,15 @@ package world.bentobox.bentobox.api.commands.island.team; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; @@ -14,10 +18,17 @@ import world.bentobox.bentobox.api.user.User; public class IslandTeamCommand extends CompositeCommand { + /** + * Invited list. Key is the invited party, value is the invite. + * @since 1.8.0 + */ + private Map inviteList; + private IslandTeamInviteCommand inviteCommand; public IslandTeamCommand(CompositeCommand parent) { super(parent, "team"); + inviteList = new HashMap<>(); } @Override @@ -81,10 +92,54 @@ public class IslandTeamCommand extends CompositeCommand { } /** - * @return the inviteCommand + * + * @param type + * @param inviter + * @param invitee + * @since 1.8.0 */ - public IslandTeamInviteCommand getInviteCommand() { - return inviteCommand; + public void addInvite(Invite.Type type, @NonNull UUID inviter, @NonNull UUID invitee) { + inviteList.put(invitee, new Invite(type, inviter, invitee)); } + /** + * + * @param invitee + * @return + * @since 1.8.0 + */ + public boolean isInvited(@NonNull UUID invitee) { + return inviteList.containsKey(invitee); + } + + /** + * Get whoever invited invitee + * @param invitee - uuid + * @return UUID of inviter, or null if invitee has not been invited + * @since 1.8.0 + */ + @Nullable + public UUID getInviter(UUID invitee) { + return isInvited(invitee) ? inviteList.get(invitee).getInviter() : null; + } + + /** + * Gets the invite for an invitee. + * @param invitee - UUID of invitee + * @return invite or null if none + * @since 1.8.0 + */ + @Nullable + public Invite getInvite(UUID invitee) { + return inviteList.get(invitee); + } + + /** + * Removes a pending invite. + * @param uniqueId - UUID of invited user + * @since 1.8.0 + */ + public void removeInvite(@NonNull UUID uniqueId) { + inviteList.remove(uniqueId); + } } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommand.java index 61bb99cb5..5e6830540 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommand.java @@ -7,6 +7,7 @@ import java.util.UUID; import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -20,10 +21,12 @@ import world.bentobox.bentobox.util.Util; */ public class IslandTeamCoopCommand extends CompositeCommand { + private IslandTeamCommand itc; private @Nullable UUID targetUUID; - public IslandTeamCoopCommand(CompositeCommand parentCommand) { + public IslandTeamCoopCommand(IslandTeamCommand parentCommand) { super(parentCommand, "coop"); + this.itc = parentCommand; } @Override @@ -72,6 +75,11 @@ public class IslandTeamCoopCommand extends CompositeCommand { user.sendMessage("commands.island.team.coop.already-has-rank"); return false; } + if (itc.isInvited(targetUUID) && itc.getInviter(targetUUID).equals(user.getUniqueId()) && itc.getInvite(targetUUID).getType().equals(Type.COOP)) { + // Prevent spam + user.sendMessage("commands.island.team.invite.errors.you-have-already-invited"); + return false; + } return true; } @@ -80,9 +88,19 @@ public class IslandTeamCoopCommand extends CompositeCommand { User target = User.getInstance(targetUUID); Island island = getIslands().getIsland(getWorld(), user.getUniqueId()); if (island != null) { - island.setRank(target, RanksManager.COOP_RANK); - user.sendMessage("commands.island.team.coop.success", TextVariables.NAME, target.getName()); - target.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, user.getName()); + if (getPlugin().getSettings().isInviteConfirmation()) { + // Put the invited player (key) onto the list with inviter (value) + // If someone else has invited a player, then this invite will overwrite the previous invite! + itc.addInvite(Invite.Type.COOP, user.getUniqueId(), target.getUniqueId()); + user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, target.getName()); + // Send message to online player + target.sendMessage("commands.island.team.coop.name-has-invited-you", TextVariables.NAME, user.getName()); + target.sendMessage("commands.island.team.invite.to-accept-or-reject", TextVariables.LABEL, getTopLabel()); + } else { + island.setRank(target, RanksManager.COOP_RANK); + user.sendMessage("commands.island.team.coop.success", TextVariables.NAME, target.getName()); + target.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, user.getName()); + } return true; } else { // Should not happen diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java index 003822415..46b57d97b 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java @@ -6,14 +6,14 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.GameMode; -import com.google.common.collect.BiMap; - import world.bentobox.bentobox.api.commands.ConfirmableCommand; +import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.managers.RanksManager; /** * @author tastybento @@ -40,8 +40,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand { public boolean canExecute(User user, String label, List args) { playerUUID = user.getUniqueId(); // Check if player has been invited - BiMap inviteList = itc.getInviteCommand().getInviteList(); - if (!inviteList.containsKey(playerUUID)) { + if (!itc.isInvited(playerUUID)) { user.sendMessage("commands.island.team.invite.errors.none-invited-you"); return false; } @@ -51,71 +50,116 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand { return false; } // Get the island owner - prospectiveOwnerUUID = inviteList.get(playerUUID); + prospectiveOwnerUUID = itc.getInviter(playerUUID); if (!getIslands().hasIsland(getWorld(), prospectiveOwnerUUID)) { user.sendMessage("commands.island.team.invite.errors.invalid-invite"); - inviteList.remove(playerUUID); + itc.removeInvite(playerUUID); return false; } - // Fire event so add-ons can run commands, etc. - IslandBaseEvent event = TeamEvent.builder() - .island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID)) - .reason(TeamEvent.Reason.JOIN) - .involvedPlayer(playerUUID) - .build(); - Bukkit.getPluginManager().callEvent(event); - return !event.isCancelled(); + Invite invite = itc.getInvite(playerUUID); + if (invite.getType().equals(Type.TEAM)) { + // Fire event so add-ons can run commands, etc. + IslandBaseEvent event = TeamEvent.builder() + .island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID)) + .reason(TeamEvent.Reason.JOIN) + .involvedPlayer(playerUUID) + .build(); + Bukkit.getPluginManager().callEvent(event); + return !event.isCancelled(); + } + return true; } @Override public boolean execute(User user, String label, List args) { - askConfirmation(user, user.getTranslation("commands.island.team.invite.accept.confirmation"), () -> { - // Remove the invite - itc.getInviteCommand().getInviteList().remove(playerUUID); - // Put player into Spectator mode - user.setGameMode(GameMode.SPECTATOR); - // Get the player's island - may be null if the player has no island - Island island = getIslands().getIsland(getWorld(), playerUUID); - // Get the team's island - Island teamIsland = getIslands().getIsland(getWorld(), prospectiveOwnerUUID); - // Remove player as owner of the old island - getIslands().removePlayer(getWorld(), playerUUID); - // Remove money inventory etc. for leaving - cleanPlayer(user); - // Add the player as a team member of the new island - getIslands().setJoinTeam(teamIsland, playerUUID); - //Move player to team's island - getPlayers().clearHomeLocations(getWorld(), playerUUID); - getIslands().homeTeleport(getWorld(), user.getPlayer()); - // Delete the old island - if (island != null) { - getIslands().deleteIsland(island, true, user.getUniqueId()); - } - // Reset deaths - if (getIWM().isTeamJoinDeathReset(getWorld())) { - getPlayers().setDeaths(getWorld(), playerUUID, 0); - } - // Put player back into normal mode - user.setGameMode(getIWM().getDefaultGameMode(getWorld())); - - user.sendMessage("commands.island.team.invite.accept.you-joined-island", TextVariables.LABEL, getTopLabel()); - User inviter = User.getInstance(itc.getInviteCommand().getInviteList().get(playerUUID)); - if (inviter != null) { - inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME, user.getName()); - } - getIslands().save(teamIsland); - // Fire event - IslandBaseEvent e = TeamEvent.builder() - .island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID)) - .reason(TeamEvent.Reason.JOINED) - .involvedPlayer(playerUUID) - .build(); - Bukkit.getServer().getPluginManager().callEvent(e); - }); - + // Get the invite + Invite invite = itc.getInvite(playerUUID); + switch (invite.getType()) { + case COOP: + askConfirmation(user, () -> acceptCoopInvite(user, invite)); + break; + case TRUST: + askConfirmation(user, () -> acceptTrustInvite(user, invite)); + break; + default: + askConfirmation(user, user.getTranslation("commands.island.team.invite.accept.confirmation"), () -> acceptTeamInvite(user, invite)); + } return true; } + private void acceptTrustInvite(User user, Invite invite) { + // Remove the invite + itc.removeInvite(playerUUID); + User inviter = User.getInstance(invite.getInviter()); + if (inviter != null) { + Island island = getIslands().getIsland(getWorld(), inviter); + if (island != null) { + island.setRank(user, RanksManager.TRUSTED_RANK); + inviter.sendMessage("commands.island.team.trust.success", TextVariables.NAME, user.getName()); + user.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, inviter.getName()); + } + } + } + + private void acceptCoopInvite(User user, Invite invite) { + // Remove the invite + itc.removeInvite(playerUUID); + User inviter = User.getInstance(invite.getInviter()); + if (inviter != null) { + Island island = getIslands().getIsland(getWorld(), inviter); + if (island != null) { + island.setRank(user, RanksManager.COOP_RANK); + inviter.sendMessage("commands.island.team.coop.success", TextVariables.NAME, user.getName()); + user.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, inviter.getName()); + } + } + } + + private void acceptTeamInvite(User user, Invite invite) { + // Remove the invite + itc.removeInvite(playerUUID); + // Put player into Spectator mode + user.setGameMode(GameMode.SPECTATOR); + // Get the player's island - may be null if the player has no island + Island island = getIslands().getIsland(getWorld(), playerUUID); + // Get the team's island + Island teamIsland = getIslands().getIsland(getWorld(), prospectiveOwnerUUID); + // Remove player as owner of the old island + getIslands().removePlayer(getWorld(), playerUUID); + // Remove money inventory etc. for leaving + cleanPlayer(user); + // Add the player as a team member of the new island + getIslands().setJoinTeam(teamIsland, playerUUID); + //Move player to team's island + getPlayers().clearHomeLocations(getWorld(), playerUUID); + getIslands().homeTeleport(getWorld(), user.getPlayer()); + // Delete the old island + if (island != null) { + getIslands().deleteIsland(island, true, user.getUniqueId()); + } + // Reset deaths + if (getIWM().isTeamJoinDeathReset(getWorld())) { + getPlayers().setDeaths(getWorld(), playerUUID, 0); + } + // Put player back into normal mode + user.setGameMode(getIWM().getDefaultGameMode(getWorld())); + + user.sendMessage("commands.island.team.invite.accept.you-joined-island", TextVariables.LABEL, getTopLabel()); + User inviter = User.getInstance(invite.getInviter()); + if (inviter != null) { + inviter.sendMessage("commands.island.team.invite.accept.name-joined-your-island", TextVariables.NAME, user.getName()); + } + getIslands().save(teamIsland); + // Fire event + IslandBaseEvent e = TeamEvent.builder() + .island(getIslands().getIsland(getWorld(), prospectiveOwnerUUID)) + .reason(TeamEvent.Reason.JOINED) + .involvedPlayer(playerUUID) + .build(); + Bukkit.getServer().getPluginManager().callEvent(e); + + } + private void cleanPlayer(User user) { if (getIWM().isOnLeaveResetEnderChest(getWorld()) || getIWM().isOnJoinResetEnderChest(getWorld())) { user.getPlayer().getEnderChest().clear(); diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java index d4dc084e5..0feeff109 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java @@ -7,12 +7,9 @@ import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.localization.TextVariables; @@ -22,10 +19,11 @@ import world.bentobox.bentobox.util.Util; public class IslandTeamInviteCommand extends CompositeCommand { - private BiMap inviteList; + private IslandTeamCommand itc; - public IslandTeamInviteCommand(CompositeCommand islandCommand) { - super(islandCommand, "invite"); + public IslandTeamInviteCommand(IslandTeamCommand parent) { + super(parent, "invite"); + itc = parent; } @Override @@ -33,7 +31,6 @@ public class IslandTeamInviteCommand extends CompositeCommand { setPermission("island.team"); setOnlyPlayer(true); setDescription("commands.island.team.invite.description"); - inviteList = HashBiMap.create(); setConfigurableRankCommand(); } @@ -53,10 +50,21 @@ public class IslandTeamInviteCommand extends CompositeCommand { } UUID playerUUID = user.getUniqueId(); if (args.isEmpty() || args.size() > 1) { - // Invite label with no name, i.e., /island invite - tells the player who has invited them so far - if (inviteList.containsKey(playerUUID)) { - OfflinePlayer inviter = Bukkit.getServer().getOfflinePlayer(inviteList.get(playerUUID)); - user.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, inviter.getName()); + // Invite label with no name, i.e., /island invite - tells the player who has invited them so far and why + if (itc.isInvited(playerUUID)) { + Invite invite = itc.getInvite(playerUUID); + String name = getPlayers().getName(playerUUID); + switch (invite.getType()) { + case COOP: + user.sendMessage("commands.island.team.invite.name-has-invited-you.coop", TextVariables.NAME, name); + break; + case TRUST: + user.sendMessage("commands.island.team.invite.name-has-invited-you.trust", TextVariables.NAME, name); + break; + default: + user.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, name); + break; + } return true; } // Show help @@ -95,6 +103,11 @@ public class IslandTeamInviteCommand extends CompositeCommand { user.sendMessage("commands.island.team.invite.errors.already-on-team"); return false; } + if (itc.isInvited(invitedPlayerUUID) && itc.getInviter(invitedPlayerUUID).equals(user.getUniqueId()) && itc.getInvite(invitedPlayerUUID).getType().equals(Type.TEAM)) { + // Prevent spam + user.sendMessage("commands.island.team.invite.errors.you-have-already-invited"); + return false; + } return invite(user,invitedPlayer); } @@ -106,8 +119,8 @@ public class IslandTeamInviteCommand extends CompositeCommand { if (teamMembers.size() < maxSize) { // If that player already has an invite out then retract it. // Players can only have one invite one at a time - interesting - if (inviteList.containsValue(user.getUniqueId())) { - inviteList.inverse().remove(user.getUniqueId()); + if (itc.isInvited(user.getUniqueId())) { + itc.removeInvite(user.getUniqueId()); user.sendMessage("commands.island.team.invite.removing-invite"); } // Fire event so add-ons can run commands, etc. @@ -122,7 +135,7 @@ public class IslandTeamInviteCommand extends CompositeCommand { } // Put the invited player (key) onto the list with inviter (value) // If someone else has invited a player, then this invite will overwrite the previous invite! - inviteList.put(invitedPlayer.getUniqueId(), user.getUniqueId()); + itc.addInvite(Invite.Type.TEAM, invitedPlayer.getUniqueId(), user.getUniqueId()); user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, invitedPlayer.getName()); // Send message to online player invitedPlayer.sendMessage("commands.island.team.invite.name-has-invited-you", TextVariables.NAME, user.getName()); @@ -148,14 +161,6 @@ public class IslandTeamInviteCommand extends CompositeCommand { return Optional.of(Util.tabLimit(options, lastArg)); } - /** - * Order is Invited, Inviter - * @return the inviteList - */ - public BiMap getInviteList() { - return inviteList; - } - /** * Gets the maximum team size for this player in this game based on the permission or the world's setting * @param user user diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteRejectCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteRejectCommand.java index 96f79137f..71b6a2513 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteRejectCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteRejectCommand.java @@ -31,11 +31,11 @@ public class IslandTeamInviteRejectCommand extends CompositeCommand { public boolean execute(User user, String label, List args) { UUID playerUUID = user.getUniqueId(); // Reject /island reject - if (itc.getInviteCommand().getInviteList().containsKey(playerUUID)) { + if (itc.isInvited(playerUUID)) { // Fire event so add-ons can run commands, etc. IslandBaseEvent event = TeamEvent.builder() .island(getIslands() - .getIsland(getWorld(), itc.getInviteCommand().getInviteList().get(playerUUID))) + .getIsland(getWorld(), itc.getInviter(playerUUID))) .reason(TeamEvent.Reason.REJECT) .involvedPlayer(playerUUID) .build(); @@ -45,10 +45,10 @@ public class IslandTeamInviteRejectCommand extends CompositeCommand { } // Remove this player from the global invite list - itc.getInviteCommand().getInviteList().remove(user.getUniqueId()); + itc.removeInvite(user.getUniqueId()); user.sendMessage("commands.island.team.invite.reject.you-rejected-invite"); - User inviter = User.getInstance(itc.getInviteCommand().getInviteList().get(playerUUID)); + User inviter = User.getInstance(itc.getInviter(playerUUID)); if (inviter != null) { inviter.sendMessage("commands.island.team.invite.reject.name-rejected-your-invite", TextVariables.NAME, user.getName()); } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java index 670796624..fbcbd1230 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java @@ -4,7 +4,10 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import org.eclipse.jdt.annotation.Nullable; + import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -18,8 +21,12 @@ import world.bentobox.bentobox.util.Util; */ public class IslandTeamTrustCommand extends CompositeCommand { - public IslandTeamTrustCommand(CompositeCommand parentCommand) { + IslandTeamCommand itc; + private @Nullable UUID targetUUID; + + public IslandTeamTrustCommand(IslandTeamCommand parentCommand) { super(parentCommand, "trust"); + this.itc = parentCommand; } @Override @@ -32,7 +39,7 @@ public class IslandTeamTrustCommand extends CompositeCommand { } @Override - public boolean execute(User user, String label, List args) { + public boolean canExecute(User user, String label, List args) { if (args.size() != 1) { // Show help showHelp(this, user); @@ -50,22 +57,18 @@ public class IslandTeamTrustCommand extends CompositeCommand { return false; } // Get target player - UUID targetUUID = getPlayers().getUUID(args.get(0)); + targetUUID = getPlayers().getUUID(args.get(0)); if (targetUUID == null) { user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); return false; } - return (getSettings().getTrustCooldown() <= 0 || !checkCooldown(user, island.getUniqueId(), targetUUID.toString())) && trustCmd(user, targetUUID); - } - - private boolean trustCmd(User user, UUID targetUUID) { - // Player cannot trust themselves - if (user.getUniqueId().equals(targetUUID)) { - user.sendMessage("commands.island.team.trust.trust-in-yourself"); + // Check cooldown + if (getSettings().getTrustCooldown() > 0 && checkCooldown(user, island.getUniqueId(), targetUUID.toString())) { return false; } - if (getIslands().getMembers(getWorld(), user.getUniqueId()).contains(targetUUID)) { - user.sendMessage("commands.island.team.trust.members-trusted"); + // Player cannot coop themselves + if (user.getUniqueId().equals(targetUUID)) { + user.sendMessage("commands.island.team.trust.trust-in-yourself"); return false; } User target = User.getInstance(targetUUID); @@ -74,11 +77,32 @@ public class IslandTeamTrustCommand extends CompositeCommand { user.sendMessage("commands.island.team.trust.player-already-trusted"); return false; } + if (itc.isInvited(targetUUID) && itc.getInviter(targetUUID).equals(user.getUniqueId()) && itc.getInvite(targetUUID).getType().equals(Type.TRUST)) { + // Prevent spam + user.sendMessage("commands.island.team.invite.errors.you-have-already-invited"); + return false; + } + return true; + } + + @Override + public boolean execute(User user, String label, List args) { + User target = User.getInstance(targetUUID); Island island = getIslands().getIsland(getWorld(), user.getUniqueId()); if (island != null) { - island.setRank(target, RanksManager.TRUSTED_RANK); - user.sendMessage("commands.island.team.trust.success", TextVariables.NAME, target.getName()); - target.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, user.getName()); + if (getPlugin().getSettings().isInviteConfirmation()) { + // Put the invited player (key) onto the list with inviter (value) + // If someone else has invited a player, then this invite will overwrite the previous invite! + itc.addInvite(Type.TRUST, user.getUniqueId(), target.getUniqueId()); + user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, target.getName()); + // Send message to online player + target.sendMessage("commands.island.team.trust.name-has-invited-you", TextVariables.NAME, user.getName()); + target.sendMessage("commands.island.team.invite.to-accept-or-reject", TextVariables.LABEL, getTopLabel()); + } else { + island.setRank(target, RanksManager.TRUSTED_RANK); + user.sendMessage("commands.island.team.trust.success", TextVariables.NAME, target.getName()); + target.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, user.getName()); + } return true; } else { // Should not happen @@ -87,6 +111,35 @@ public class IslandTeamTrustCommand extends CompositeCommand { } } + /* + Island island = getIslands().getIsland(getWorld(), user.getUniqueId()); + if (island != null) { + if (getPlugin().getSettings().isInviteConfirmation()) { + if (itc.isInvited(targetUUID) && itc.getInviter(targetUUID).equals(user.getUniqueId()) && itc.getInvite(targetUUID).getType().equals(Type.TRUST)) { + // Prevent spam + user.sendMessage("commands.island.team.invite.errors.you-have-already-invited"); + return false; + } + // Put the invited player (key) onto the list with inviter (value) + // If someone else has invited a player, then this invite will overwrite the previous invite! + itc.addInvite(Type.TRUST, user.getUniqueId(), target.getUniqueId()); + user.sendMessage("commands.island.team.invite.invitation-sent", TextVariables.NAME, target.getName()); + // Send message to online player + target.sendMessage("commands.island.team.trust.name-has-invited-you", TextVariables.NAME, user.getName()); + target.sendMessage("commands.island.team.invite.to-accept-or-reject", TextVariables.LABEL, getTopLabel()); + } else { + island.setRank(target, RanksManager.TRUSTED_RANK); + user.sendMessage("commands.island.team.trust.success", TextVariables.NAME, target.getName()); + target.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, user.getName()); + } + return true; + } else { + // Should not happen + user.sendMessage("general.errors.general"); + return false; + } + }*/ + @Override public Optional> tabComplete(User user, String alias, List args) { if (args.isEmpty()) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e389fd893..0e6211aa7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -78,6 +78,8 @@ island: kick: true leave: true reset: true + # Ask the recipient to confirm trust or coop invites. Team invites always require confirmation. + invite: false delay: # Time in seconds that players have to stand still before teleport commands activate, e.g. island go. time: 0 diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 56b11406c..6e9d48fc7 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -480,6 +480,7 @@ commands: already-has-rank: "&cPlayer already has a rank!" you-are-a-coop-member: "&2You were cooped by [name]" success: "&aYou cooped &b[name]." + name-has-invited-you: "&a[name] has invited you to join be a coop member of their island." uncoop: description: "remove a coop rank from player" parameters: "" @@ -493,7 +494,7 @@ commands: description: "give a player trusted rank on your island" parameters: "" trust-in-yourself: "&cTrust in yourself!" - members-trusted: "&cMembers are already trusted" + name-has-invited-you: "&a[name] has invited you to join be a trusted member of their island." player-already-trusted: "&cPlayer is already trusted!" you-are-trusted: "&2You are trusted by &b[name]&a!" success: "&aYou trusted &b[name]&a." @@ -520,6 +521,7 @@ commands: you-already-are-in-team: "&cYou are already on a team!" already-on-team: "&cThat player is already on a team!" invalid-invite: "&cThat invite is no longer valid, sorry." + you-have-already-invited: "&cYou have already invited that player!" parameters: "" you-can-invite: "&aYou can invite [number] more players." accept: diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommandTest.java index dc15144ed..25ee9e432 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCoopCommandTest.java @@ -5,9 +5,9 @@ package world.bentobox.bentobox.api.commands.island.team; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -33,7 +33,6 @@ import org.powermock.reflect.Whitebox; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; -import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -54,7 +53,7 @@ import world.bentobox.bentobox.managers.RanksManager; public class IslandTeamCoopCommandTest { @Mock - private CompositeCommand ic; + private IslandTeamCommand ic; private UUID uuid; @Mock private User user; @@ -219,18 +218,6 @@ public class IslandTeamCoopCommandTest { verify(user).sendMessage(eq("commands.island.team.coop.already-has-rank")); } - /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamCoopCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. - */ - @Test - public void testCanExecuteCoolDownActive() { - when(s.getCoopCooldown()).thenReturn(10); - when(pm.getUUID(any())).thenReturn(uuid); - IslandTeamCoopCommand itl = new IslandTeamCoopCommand(ic); - itl.setCooldown(uuid, uuid, 10); - assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); - } - /** * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamCoopCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommandTest.java index 1bb05c49d..cb141d548 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommandTest.java @@ -3,8 +3,12 @@ package world.bentobox.bentobox.api.commands.island.team; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Collections; @@ -20,17 +24,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -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 com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; - import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; +import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.events.team.TeamEvent.TeamEventBuilder; @@ -51,19 +52,26 @@ import world.bentobox.bentobox.managers.RanksManager; @PrepareForTest({Bukkit.class, BentoBox.class, User.class, TeamEvent.class }) public class IslandTeamInviteAcceptCommandTest { - private IslandTeamCommand ic; + @Mock + private IslandTeamCommand itc; private UUID uuid; + @Mock private User user; + @Mock private IslandsManager im; + @Mock private PlayersManager pm; private UUID notUUID; @Mock private Settings s; + @Mock private Island island; + @Mock private IslandTeamInviteAcceptCommand c; - private BiMap biMap; - private IslandTeamInviteCommand inviteCommand; + @Mock private PluginManager pim; + @Mock + private Invite invite; /** * @throws java.lang.Exception @@ -84,7 +92,6 @@ public class IslandTeamInviteAcceptCommandTest { // Player Player p = mock(Player.class); // Sometimes use Mockito.withSettings().verboseLogging() - user = mock(User.class); when(user.isOp()).thenReturn(false); uuid = UUID.randomUUID(); notUUID = UUID.randomUUID(); @@ -97,53 +104,48 @@ public class IslandTeamInviteAcceptCommandTest { User.setPlugin(plugin); // Parent command has no aliases - ic = mock(IslandTeamCommand.class); - when(ic.getSubCommandAliases()).thenReturn(new HashMap<>()); - when(ic.getPermissionPrefix()).thenReturn("bskyblock."); - inviteCommand = mock(IslandTeamInviteCommand.class); - biMap = HashBiMap.create(); - when(inviteCommand.getInviteList()).thenReturn(biMap); - when(ic.getInviteCommand()).thenReturn(inviteCommand); + when(itc.getSubCommandAliases()).thenReturn(new HashMap<>()); + when(itc.getPermissionPrefix()).thenReturn("bskyblock."); + when(itc.getInvite(any())).thenReturn(invite); // Player has island to begin with - im = mock(IslandsManager.class); - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); - when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); - when(im.isOwner(Mockito.any(), Mockito.any())).thenReturn(true); - when(im.getOwner(Mockito.any(), Mockito.any())).thenReturn(uuid); - island = mock(Island.class); - when(island.getRank(Mockito.any())).thenReturn(RanksManager.OWNER_RANK); - when(im.getIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(island); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); + when(im.inTeam(any(), any(UUID.class))).thenReturn(true); + when(im.isOwner(any(), any())).thenReturn(true); + when(im.getOwner(any(), any())).thenReturn(uuid); + // Island + when(island.getRank(any())).thenReturn(RanksManager.OWNER_RANK); + when(im.getIsland(any(), any(User.class))).thenReturn(island); when(plugin.getIslands()).thenReturn(im); // Has team - when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true); + when(im.inTeam(any(), eq(uuid))).thenReturn(true); // Player Manager - pm = mock(PlayersManager.class); - when(plugin.getPlayers()).thenReturn(pm); // Server & Scheduler BukkitScheduler sch = mock(BukkitScheduler.class); PowerMockito.mockStatic(Bukkit.class); when(Bukkit.getScheduler()).thenReturn(sch); - pim = mock(PluginManager.class); when(Bukkit.getPluginManager()).thenReturn(pim); // Locales LocalesManager lm = mock(LocalesManager.class); - when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation"); + when(lm.get(any(), any())).thenReturn("mock translation"); when(plugin.getLocalesManager()).thenReturn(lm); - when(user.getTranslation(Mockito.anyString())).thenReturn("mock translation2"); + when(user.getTranslation(anyString())).thenReturn("mock translation2"); // IWM friendly name IslandWorldManager iwm = mock(IslandWorldManager.class); - when(iwm.getFriendlyName(Mockito.any())).thenReturn("BSkyBlock"); + when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); when(plugin.getIWM()).thenReturn(iwm); + // Invite + when(invite.getType()).thenReturn(Invite.Type.TEAM); + // Team invite accept command - c = new IslandTeamInviteAcceptCommand(ic); + c = new IslandTeamInviteAcceptCommand(itc); } /** @@ -178,7 +180,7 @@ public class IslandTeamInviteAcceptCommandTest { @Test public void testCanExecuteNoInvite() { assertFalse(c.canExecute(user, "accept", Collections.emptyList())); - Mockito.verify(user).sendMessage("commands.island.team.invite.errors.none-invited-you"); + verify(user).sendMessage("commands.island.team.invite.errors.none-invited-you"); } /** @@ -186,10 +188,10 @@ public class IslandTeamInviteAcceptCommandTest { */ @Test public void testCanExecuteInTeam() { - biMap.put(uuid, notUUID); - when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(true); + when(itc.isInvited(any())).thenReturn(true); + when(im.inTeam(any(), any())).thenReturn(true); assertFalse(c.canExecute(user, "accept", Collections.emptyList())); - Mockito.verify(user).sendMessage("commands.island.team.invite.errors.you-already-are-in-team"); + verify(user).sendMessage("commands.island.team.invite.errors.you-already-are-in-team"); } /** @@ -197,12 +199,11 @@ public class IslandTeamInviteAcceptCommandTest { */ @Test public void testCanExecuteInvalidInvite() { - biMap.put(uuid, notUUID); - when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false); - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false); + when(itc.isInvited(any())).thenReturn(true); + when(im.inTeam(any(), any())).thenReturn(false); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(false); assertFalse(c.canExecute(user, "accept", Collections.emptyList())); - Mockito.verify(user).sendMessage("commands.island.team.invite.errors.invalid-invite"); - Mockito.verify(inviteCommand).getInviteList(); + verify(user).sendMessage("commands.island.team.invite.errors.invalid-invite"); } /** @@ -210,11 +211,45 @@ public class IslandTeamInviteAcceptCommandTest { */ @Test public void testCanExecuteOkay() { - biMap.put(uuid, notUUID); - when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false); - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); + when(itc.isInvited(any())).thenReturn(true); + when(itc.getInviter(any())).thenReturn(notUUID); + when(itc.getInvite(any())).thenReturn(invite); + when(im.inTeam(any(), any())).thenReturn(false); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); assertTrue(c.canExecute(user, "accept", Collections.emptyList())); - Mockito.verify(pim).callEvent(Mockito.any()); + verify(pim).callEvent(any()); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamInviteAcceptCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteOkayTrust() { + when(itc.isInvited(any())).thenReturn(true); + when(itc.getInviter(any())).thenReturn(notUUID); + when(itc.getInvite(any())).thenReturn(invite); + when(invite.getType()).thenReturn(Type.TRUST); + when(im.inTeam(any(), any())).thenReturn(false); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); + assertTrue(c.canExecute(user, "accept", Collections.emptyList())); + // No event + verify(pim, never()).callEvent(any()); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamInviteAcceptCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteOkayCoop() { + when(itc.isInvited(any())).thenReturn(true); + when(itc.getInviter(any())).thenReturn(notUUID); + when(itc.getInvite(any())).thenReturn(invite); + when(invite.getType()).thenReturn(Invite.Type.COOP); + when(im.inTeam(any(), any())).thenReturn(false); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); + assertTrue(c.canExecute(user, "accept", Collections.emptyList())); + // No event + verify(pim, never()).callEvent(any()); } /** @@ -222,9 +257,11 @@ public class IslandTeamInviteAcceptCommandTest { */ @Test public void testCanExecuteEventBlocked() { - biMap.put(uuid, notUUID); - when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(false); - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); + when(itc.isInvited(any())).thenReturn(true); + when(itc.getInviter(any())).thenReturn(notUUID); + when(itc.getInvite(any())).thenReturn(invite); + when(im.inTeam(any(), any())).thenReturn(false); + when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); // Block event PowerMockito.mockStatic(TeamEvent.class); TeamEventBuilder teb = mock(TeamEventBuilder.class); @@ -236,7 +273,7 @@ public class IslandTeamInviteAcceptCommandTest { when(teb.build()).thenReturn(ibe); when(TeamEvent.builder()).thenReturn(teb); assertFalse(c.canExecute(user, "accept", Collections.emptyList())); - Mockito.verify(pim).callEvent(Mockito.any()); + verify(pim).callEvent(any()); } /** @@ -244,8 +281,31 @@ public class IslandTeamInviteAcceptCommandTest { */ @Test public void testExecuteUserStringListOfString() { + // Team assertTrue(c.execute(user, "accept", Collections.emptyList())); - Mockito.verify(user).getTranslation("commands.island.team.invite.accept.confirmation"); + verify(user).getTranslation("commands.island.team.invite.accept.confirmation"); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamInviteAcceptCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringCoop() { + // Coop + when(invite.getType()).thenReturn(Invite.Type.COOP); + assertTrue(c.execute(user, "accept", Collections.emptyList())); + verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0"); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamInviteAcceptCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringTrust() { + // Trust + when(invite.getType()).thenReturn(Invite.Type.TRUST); + assertTrue(c.execute(user, "accept", Collections.emptyList())); + verify(user).sendMessage("commands.confirmation.confirm", "[seconds]", "0"); } } diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommandTest.java index 05e49cb7e..d53fe74de 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommandTest.java @@ -1,10 +1,7 @@ -/** - * - */ package world.bentobox.bentobox.api.commands.island.team; import static org.junit.Assert.assertFalse; -import static org.mockito.Matchers.anyString; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -28,7 +25,6 @@ import org.powermock.reflect.Whitebox; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; -import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.CommandsManager; @@ -46,14 +42,19 @@ import world.bentobox.bentobox.managers.RanksManager; @PrepareForTest({Bukkit.class, BentoBox.class, User.class }) public class IslandTeamInviteCommandTest { - private CompositeCommand ic; + @Mock + private IslandTeamCommand ic; private UUID uuid; + @Mock private User user; + @Mock private IslandsManager im; + @Mock private PlayersManager pm; private UUID notUUID; @Mock private Settings s; + @Mock private Island island; /** @@ -75,7 +76,6 @@ public class IslandTeamInviteCommandTest { // Player Player p = mock(Player.class); // Sometimes use Mockito.withSettings().verboseLogging() - user = mock(User.class); when(user.isOp()).thenReturn(false); uuid = UUID.randomUUID(); notUUID = UUID.randomUUID(); @@ -88,16 +88,13 @@ public class IslandTeamInviteCommandTest { User.setPlugin(plugin); // Parent command has no aliases - ic = mock(CompositeCommand.class); when(ic.getSubCommandAliases()).thenReturn(new HashMap<>()); // Player has island to begin with - im = mock(IslandsManager.class); when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); when(im.isOwner(Mockito.any(), Mockito.any())).thenReturn(true); when(im.getOwner(Mockito.any(), Mockito.any())).thenReturn(uuid); - island = mock(Island.class); when(island.getRank(Mockito.any())).thenReturn(RanksManager.OWNER_RANK); when(im.getIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(island); when(plugin.getIslands()).thenReturn(im); @@ -106,8 +103,6 @@ public class IslandTeamInviteCommandTest { when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true); // Player Manager - pm = mock(PlayersManager.class); - when(plugin.getPlayers()).thenReturn(pm); // Server & Scheduler diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommandTest.java index ae60ab91e..ff1d28a06 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommandTest.java @@ -1,15 +1,15 @@ -/** - * - */ package world.bentobox.bentobox.api.commands.island.team; import static org.junit.Assert.assertFalse; -import static org.mockito.Matchers.anyString; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.UUID; @@ -17,6 +17,7 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,13 +30,14 @@ import org.powermock.reflect.Whitebox; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; -import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.RanksManager; @@ -47,14 +49,19 @@ import world.bentobox.bentobox.managers.RanksManager; @PrepareForTest({Bukkit.class, BentoBox.class, User.class }) public class IslandTeamTrustCommandTest { - private CompositeCommand ic; + @Mock + private IslandTeamCommand ic; private UUID uuid; + @Mock private User user; + @Mock private IslandsManager im; + @Mock private PlayersManager pm; private UUID notUUID; @Mock private Settings s; + @Mock private Island island; /** @@ -70,13 +77,11 @@ public class IslandTeamTrustCommandTest { CommandsManager cm = mock(CommandsManager.class); when(plugin.getCommandsManager()).thenReturn(cm); - // Settings 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.randomUUID(); notUUID = UUID.randomUUID(); @@ -89,27 +94,23 @@ public class IslandTeamTrustCommandTest { User.setPlugin(plugin); // Parent command has no aliases - ic = mock(CompositeCommand.class); when(ic.getSubCommandAliases()).thenReturn(new HashMap<>()); // Player has island to begin with - im = mock(IslandsManager.class); - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); - when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(true); - when(im.isOwner(Mockito.any(), Mockito.any())).thenReturn(true); - when(im.getOwner(Mockito.any(), Mockito.any())).thenReturn(uuid); - island = mock(Island.class); - when(island.getRank(Mockito.any())).thenReturn(RanksManager.OWNER_RANK); - when(im.getIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(island); - when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island); + when(im.hasIsland(any(), Mockito.any(UUID.class))).thenReturn(true); + when(im.inTeam(any(), Mockito.any(UUID.class))).thenReturn(true); + when(im.isOwner(any(), any())).thenReturn(true); + when(im.getOwner(any(), any())).thenReturn(uuid); + // Island + when(island.getRank(any())).thenReturn(RanksManager.OWNER_RANK); + when(im.getIsland(any(), Mockito.any(User.class))).thenReturn(island); + when(im.getIsland(any(), Mockito.any(UUID.class))).thenReturn(island); when(plugin.getIslands()).thenReturn(im); // Has team - when(im.inTeam(Mockito.any(), Mockito.eq(uuid))).thenReturn(true); + when(im.inTeam(any(), eq(uuid))).thenReturn(true); // Player Manager - pm = mock(PlayersManager.class); - when(plugin.getPlayers()).thenReturn(pm); // Server & Scheduler @@ -119,102 +120,174 @@ public class IslandTeamTrustCommandTest { // Locales LocalesManager lm = mock(LocalesManager.class); - when(lm.get(Mockito.any(), Mockito.any())).thenReturn("mock translation"); + when(lm.get(any(), any())).thenReturn("mock translation"); when(plugin.getLocalesManager()).thenReturn(lm); // IWM friendly name IslandWorldManager iwm = mock(IslandWorldManager.class); - when(iwm.getFriendlyName(Mockito.any())).thenReturn("BSkyBlock"); + when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); when(plugin.getIWM()).thenReturn(iwm); + + PlaceholdersManager phm = mock(PlaceholdersManager.class); + when(phm.replacePlaceholders(any(), any())).thenAnswer(invocation -> invocation.getArgument(1, String.class)); + // Placeholder manager + when(plugin.getPlaceholdersManager()).thenReturn(phm); + } + + @After + public void tearDown() { + User.clearUsers(); } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteNoisland() { - when(im.hasIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false); - when(im.inTeam(Mockito.any(), Mockito.any(UUID.class))).thenReturn(false); + public void testCanExecuteNoisland() { + when(im.hasIsland(any(), Mockito.any(UUID.class))).thenReturn(false); + when(im.inTeam(any(), Mockito.any(UUID.class))).thenReturn(false); IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("bill"))); - Mockito.verify(user).sendMessage(Mockito.eq("general.errors.no-island")); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("bill"))); + verify(user).sendMessage(eq("general.errors.no-island")); } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteLowRank() { - when(island.getRank(Mockito.any())).thenReturn(RanksManager.MEMBER_RANK); + public void testCanExecuteLowRank() { + when(island.getRank(any())).thenReturn(RanksManager.MEMBER_RANK); when(island.getRankCommand(anyString())).thenReturn(RanksManager.OWNER_RANK); IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("bill"))); - Mockito.verify(user).sendMessage(Mockito.eq("general.errors.no-permission")); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("bill"))); + verify(user).sendMessage(eq("general.errors.no-permission")); } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteNoTarget() { + public void testCanExecuteNoTarget() { IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - assertFalse(itl.execute(user, itl.getLabel(), new ArrayList<>())); + assertFalse(itl.canExecute(user, itl.getLabel(), new ArrayList<>())); // Show help } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteUnknownPlayer() { + public void testCanExecuteUnknownPlayer() { IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - when(pm.getUUID(Mockito.any())).thenReturn(null); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("tastybento"))); - Mockito.verify(user).sendMessage("general.errors.unknown-player", "[name]", "tastybento"); + when(pm.getUUID(any())).thenReturn(null); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage("general.errors.unknown-player", "[name]", "tastybento"); } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteSamePlayer() { + public void testCanExecuteSamePlayer() { PowerMockito.mockStatic(User.class); when(User.getInstance(Mockito.any(UUID.class))).thenReturn(user); when(user.isOnline()).thenReturn(true); IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - when(pm.getUUID(Mockito.any())).thenReturn(uuid); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("tastybento"))); - Mockito.verify(user).sendMessage(Mockito.eq("commands.island.team.trust.trust-in-yourself")); + when(pm.getUUID(any())).thenReturn(uuid); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage(eq("commands.island.team.trust.trust-in-yourself")); } /** - * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecutePlayerHasRank() { + public void testCanExecutePlayerHasRank() { PowerMockito.mockStatic(User.class); when(User.getInstance(Mockito.any(UUID.class))).thenReturn(user); when(user.isOnline()).thenReturn(true); IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - when(pm.getUUID(Mockito.any())).thenReturn(notUUID); - when(im.inTeam(Mockito.any(), Mockito.any())).thenReturn(true); - when(im.getMembers(Mockito.any(), Mockito.any())).thenReturn(Collections.singleton(notUUID)); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("bento"))); - Mockito.verify(user).sendMessage(Mockito.eq("commands.island.team.trust.members-trusted")); + when(pm.getUUID(any())).thenReturn(notUUID); + when(im.inTeam(any(), any())).thenReturn(true); + when(im.getMembers(any(), any())).thenReturn(Collections.singleton(notUUID)); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("bento"))); + verify(user).sendMessage(eq("commands.island.team.trust.player-already-trusted")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteCannottrustSelf() { + when(pm.getUUID(any())).thenReturn(uuid); + IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage(eq("commands.island.team.trust.trust-in-yourself")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteCannotAlreadyHasRank() { + UUID other = UUID.randomUUID(); + when(pm.getUUID(any())).thenReturn(other); + when(im.getMembers(any(), any())).thenReturn(Collections.singleton(other)); + IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); + assertFalse(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage(eq("commands.island.team.trust.player-already-trusted")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteSuccess() { + UUID other = UUID.randomUUID(); + when(pm.getUUID(any())).thenReturn(other); + when(im.getMembers(any(), any())).thenReturn(Collections.emptySet()); + when(island.getRank(any())).thenReturn(RanksManager.VISITOR_RANK); + IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); + assertTrue(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); } /** * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test - public void testExecuteCoolDownActive() { - // 10 minutes = 600 seconds - when(s.getInviteCooldown()).thenReturn(10); + public void testExecuteNullIsland() { + // Can execute + when(pm.getUUID(any())).thenReturn(notUUID); + when(im.getMembers(any(), any())).thenReturn(Collections.emptySet()); + when(island.getRank(any())).thenReturn(RanksManager.VISITOR_RANK); IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); - String[] name = {"tastybento"}; - assertFalse(itl.execute(user, itl.getLabel(), Arrays.asList(name))); + assertTrue(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + // Execute + when(im.getIsland(any(), Mockito.any(UUID.class))).thenReturn(null); + assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage(eq("general.errors.general")); } + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamTrustCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteSuccess() { + Player p = mock(Player.class); + when(p.getUniqueId()).thenReturn(notUUID); + User target = User.getInstance(p); + // Can execute + when(pm.getUUID(any())).thenReturn(notUUID); + when(im.getMembers(any(), any())).thenReturn(Collections.emptySet()); + when(island.getRank(any())).thenReturn(RanksManager.VISITOR_RANK); + IslandTeamTrustCommand itl = new IslandTeamTrustCommand(ic); + assertTrue(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); -} + // Execute + when(im.getIsland(any(), Mockito.any(UUID.class))).thenReturn(island); + assertTrue(itl.execute(user, itl.getLabel(), Collections.singletonList("tastybento"))); + verify(user).sendMessage("commands.island.team.trust.success", TextVariables.NAME, null); + verify(island).setRank(target, RanksManager.TRUSTED_RANK); + } +} \ No newline at end of file