mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-10-02 08:37:35 +02:00
Fixed subcommand aliases. Added admin tp command.
While writing the admin tp command, I realized that subcommand aliases were not working. Also, it was not possible to tell what alias had been used for a command. I added that capability. i.e., if the alias is used, then the label of that command is set to the alias.
This commit is contained in:
parent
c3c0a87dbb
commit
f6ca7f7866
@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
@ -31,14 +32,14 @@ import us.tastybento.bskyblock.util.Util;
|
||||
public abstract class CompositeCommand extends Command implements PluginIdentifiableCommand, BSBCommand {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
/**
|
||||
* This is the command level. 0 is the top, 1 is the first level sub command.
|
||||
*/
|
||||
private final int subCommandLevel;
|
||||
/**
|
||||
* True if the command is for the player only (not for the console)
|
||||
*/
|
||||
private boolean onlyPlayer = false;
|
||||
/**
|
||||
* The parameters string for this command. It is the commands followed by a locale reference.
|
||||
*/
|
||||
private String parameters = "";
|
||||
/**
|
||||
* The parent command to this one. If this is a top-level command it will be empty.
|
||||
*/
|
||||
@ -47,14 +48,19 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
* The permission required to execute this command
|
||||
*/
|
||||
private String permission = "";
|
||||
/**
|
||||
* This is the command level. 0 is the top, 1 is the first level sub command.
|
||||
*/
|
||||
private final int subCommandLevel;
|
||||
/**
|
||||
* Map of sub commands
|
||||
*/
|
||||
private Map<String, CompositeCommand> subCommands;
|
||||
|
||||
/**
|
||||
* The parameters string for this command. It is the commands followed by a locale reference.
|
||||
* Map of aliases for subcommands
|
||||
*/
|
||||
private String parameters = "";
|
||||
private Map<String, CompositeCommand> subCommandAliases;
|
||||
/**
|
||||
* The command chain from the very top, e.g., island team promote
|
||||
*/
|
||||
@ -70,6 +76,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
setUsage("");
|
||||
this.subCommandLevel = 0; // Top level
|
||||
this.subCommands = new LinkedHashMap<>();
|
||||
this.subCommandAliases = new LinkedHashMap<>();
|
||||
this.setup();
|
||||
if (!this.getSubCommand("help").isPresent() && !label.equals("help"))
|
||||
new DefaultHelpCommand(this);
|
||||
@ -91,6 +98,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
parent.getSubCommands().put(label, this);
|
||||
this.setAliases(new ArrayList<>(Arrays.asList(aliases)));
|
||||
this.subCommands = new LinkedHashMap<>();
|
||||
this.subCommandAliases = new LinkedHashMap<>();
|
||||
// Add aliases to the parent for this command
|
||||
for (String alias : aliases) {
|
||||
parent.subCommandAliases.put(alias, this);
|
||||
}
|
||||
setUsage("");
|
||||
this.setup();
|
||||
// If this command does not define its own help class, then use the default help command
|
||||
@ -104,17 +116,18 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
/**
|
||||
* This is the top-level command constructor for commands that have no parent.
|
||||
* @param label - string for this command
|
||||
* @param string - aliases for this command
|
||||
* @param aliases - aliases for this command
|
||||
*/
|
||||
public CompositeCommand(String label, String... string) {
|
||||
public CompositeCommand(String label, String... aliases) {
|
||||
super(label);
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: top level command registering..." + label);
|
||||
this.setAliases(new ArrayList<>(Arrays.asList(string)));
|
||||
this.setAliases(new ArrayList<>(Arrays.asList(aliases)));
|
||||
this.parent = null;
|
||||
setUsage("");
|
||||
this.subCommandLevel = 0; // Top level
|
||||
this.subCommands = new LinkedHashMap<>();
|
||||
this.subCommandAliases = new LinkedHashMap<>();
|
||||
// Register command if it is not already registered
|
||||
if (getPlugin().getCommand(label) == null) {
|
||||
getPlugin().getCommandsManager().registerCommand(this);
|
||||
@ -160,7 +173,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
if (event.isCancelled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Execute and trim args
|
||||
return cmd.execute(user, Arrays.asList(args).subList(cmd.subCommandLevel, args.length));
|
||||
}
|
||||
@ -174,7 +187,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
CompositeCommand subCommand = this;
|
||||
// Run through any arguments
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: Running through args: " + args.toString());
|
||||
Bukkit.getLogger().info("DEBUG: Running through args: " + Arrays.asList(args).toString());
|
||||
if (args.length > 0) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (DEBUG)
|
||||
@ -188,6 +201,8 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
subCommand = subCommand.getSubCommand(args[i]).get();
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: Moved to " + subCommand.getLabel());
|
||||
// Set the label
|
||||
subCommand.setLabel(args[i]);
|
||||
} else {
|
||||
return subCommand;
|
||||
}
|
||||
@ -219,6 +234,13 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
return subCommandLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Logger
|
||||
*/
|
||||
public Logger getLogger() {
|
||||
return getPlugin().getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to obtain team members
|
||||
* @param user
|
||||
@ -251,12 +273,13 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
protected PlayersManager getPlayers() {
|
||||
return getPlugin().getPlayers();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BSkyBlock getPlugin() {
|
||||
return BSkyBlock.getInstance();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Settings object
|
||||
*/
|
||||
@ -266,18 +289,26 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
|
||||
|
||||
/**
|
||||
* Returns the CompositeCommand object refering to this command label
|
||||
* Returns the CompositeCommand object referring to this command label
|
||||
* @param label - command label or alias
|
||||
* @return CompositeCommand or null if none found
|
||||
*/
|
||||
public Optional<CompositeCommand> getSubCommand(String label) {
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: label = " + label);
|
||||
for (Map.Entry<String, CompositeCommand> entry : subCommands.entrySet()) {
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: " + entry.getKey());
|
||||
if (entry.getKey().equalsIgnoreCase(label)) return Optional.of(subCommands.get(label));
|
||||
else if (entry.getValue().getAliases().contains(label)) return Optional.of(subCommands.get(entry.getValue().getLabel()));
|
||||
}
|
||||
// Try aliases
|
||||
for (Map.Entry<String, CompositeCommand> entry : subCommandAliases.entrySet()) {
|
||||
if (DEBUG)
|
||||
Bukkit.getLogger().info("DEBUG: alias " + entry.getKey());
|
||||
if (entry.getKey().equalsIgnoreCase(label)) return Optional.of(subCommandAliases.get(label));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Map of sub commands for this command
|
||||
@ -294,22 +325,22 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
protected UUID getTeamLeader(User user) {
|
||||
return getPlugin().getIslands().getTeamLeader(user.getUniqueId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/" + usage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if this command has a specific sub command
|
||||
* @param subCommand
|
||||
* @return true if this command has this sub command
|
||||
*/
|
||||
private boolean hasSubCommand(String subCommand) {
|
||||
return subCommands.containsKey(subCommand);
|
||||
return subCommands.containsKey(subCommand) || subCommandAliases.containsKey(subCommand);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if this command has any sub commands
|
||||
* @return true if this command has subcommands
|
||||
@ -352,6 +383,10 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
this.onlyPlayer = onlyPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command parameters to be shown in help
|
||||
* @param parameters
|
||||
*/
|
||||
public void setParameters(String parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
@ -360,7 +395,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
public void setPermission(String permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This creates the full linking chain of commands
|
||||
*/
|
||||
@ -376,7 +411,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
this.usage = this.usage.trim();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args) {
|
||||
List<String> options = new ArrayList<>();
|
||||
|
@ -6,6 +6,7 @@ import us.tastybento.bskyblock.Constants;
|
||||
import us.tastybento.bskyblock.api.commands.CompositeCommand;
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
import us.tastybento.bskyblock.commands.admin.AdminReloadCommand;
|
||||
import us.tastybento.bskyblock.commands.admin.AdminTeleportCommand;
|
||||
import us.tastybento.bskyblock.commands.admin.AdminVersionCommand;
|
||||
|
||||
public class AdminCommand extends CompositeCommand {
|
||||
@ -21,6 +22,7 @@ public class AdminCommand extends CompositeCommand {
|
||||
this.setDescription("admin.help.description");
|
||||
new AdminVersionCommand(this);
|
||||
new AdminReloadCommand(this);
|
||||
new AdminTeleportCommand(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,57 @@
|
||||
package us.tastybento.bskyblock.commands.admin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import us.tastybento.bskyblock.Constants;
|
||||
import us.tastybento.bskyblock.api.commands.CompositeCommand;
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
import us.tastybento.bskyblock.util.SafeSpotTeleport;
|
||||
|
||||
public class AdminTeleportCommand extends CompositeCommand {
|
||||
|
||||
public AdminTeleportCommand(CompositeCommand parent) {
|
||||
super(parent, "tp", "tpnether", "tpend");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission(Constants.PERMPREFIX + "admin.tp");
|
||||
this.setOnlyPlayer(true);
|
||||
this.setDescription("commands.admin.tp.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, List<String> args) {
|
||||
if (args.isEmpty()) {
|
||||
user.sendMessage("commands.admin.tp.help");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert name to a UUID
|
||||
final UUID targetUUID = getPlayers().getUUID(args.get(0));
|
||||
if (targetUUID == null) {
|
||||
user.sendMessage("errors.unknown-player");
|
||||
return true;
|
||||
} else {
|
||||
if (getPlayers().hasIsland(targetUUID) || getPlayers().inTeam(targetUUID)) {
|
||||
Location warpSpot = getIslands().getIslandLocation(targetUUID).toVector().toLocation(getPlugin().getIslandWorldManager().getIslandWorld());
|
||||
if (this.getLabel().equals("tpnether")) {
|
||||
warpSpot = getIslands().getIslandLocation(targetUUID).toVector().toLocation(getPlugin().getIslandWorldManager().getNetherWorld());
|
||||
} else if (this.getLabel().equals("tpend")) {
|
||||
warpSpot = getIslands().getIslandLocation(targetUUID).toVector().toLocation(getPlugin().getIslandWorldManager().getEndWorld());
|
||||
}
|
||||
// Other wise, go to a safe spot
|
||||
String failureMessage = user.getTranslation("commands.admin.tp.manual", "[location]", warpSpot.getBlockX() + " " + warpSpot.getBlockY() + " "
|
||||
+ warpSpot.getBlockZ());
|
||||
new SafeSpotTeleport(getPlugin(), user.getPlayer(), warpSpot, failureMessage);
|
||||
return true;
|
||||
}
|
||||
user.sendMessage("command.admin.tp.no-island");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,7 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.Constants;
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
import us.tastybento.bskyblock.database.BSBDatabase;
|
||||
import us.tastybento.bskyblock.database.objects.Island;
|
||||
import us.tastybento.bskyblock.database.objects.Players;
|
||||
@ -29,6 +30,7 @@ public class PlayersManager{
|
||||
|
||||
private HashMap<UUID, Players> playerCache;
|
||||
private Set<UUID> inTeleport;
|
||||
private HashMap<String, UUID> nameCache;
|
||||
|
||||
/**
|
||||
* Provides a memory cache of online player information
|
||||
@ -47,6 +49,7 @@ public class PlayersManager{
|
||||
inTeleport = new HashSet<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load all players - not normally used as to load all players into memory will be wasteful
|
||||
*/
|
||||
@ -317,27 +320,19 @@ public class PlayersManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a UUID for a given player's name. Only uses online or cached information.
|
||||
* Attempts to return a UUID for a given player's name.
|
||||
* @param string
|
||||
* @return UUID of player or null if unknown
|
||||
*/
|
||||
public UUID getUUID(String string) {
|
||||
return getUUID(string, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to return a UUID for a given player's name
|
||||
* @param string
|
||||
* @param adminCheck - if made via an admin call, this will go out to the 'net and grab - may cause lag
|
||||
* @return UUID of player or null if unknown
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public UUID getUUID(String string, boolean adminCheck) {
|
||||
// Look in the database if it ready
|
||||
// TODO: finish this!
|
||||
public UUID getUUID(String string) {
|
||||
// See if this is a UUID
|
||||
try {
|
||||
UUID uuid = UUID.fromString(string);
|
||||
return uuid;
|
||||
} catch (Exception e) {}
|
||||
// Look in the name cache
|
||||
return Bukkit.getOfflinePlayer(string).getUniqueId();
|
||||
|
||||
//return database.getUUID(string, adminCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,12 +340,11 @@ public class PlayersManager{
|
||||
* @param uniqueId
|
||||
* @param name
|
||||
*/
|
||||
public void setPlayerName(UUID uniqueId, String name) {
|
||||
public void setPlayerName(User user) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Setting player name to " + name + " for " + uniqueId);
|
||||
addPlayer(uniqueId);
|
||||
playerCache.get(uniqueId).setPlayerName(name);
|
||||
//database.savePlayerName(name, uniqueId);
|
||||
plugin.getLogger().info("DEBUG: Setting player name to " + user.getName() + " for " + user.getUniqueId());
|
||||
addPlayer(user.getUniqueId());
|
||||
playerCache.get(user.getUniqueId()).setPlayerName(user.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -600,7 +594,7 @@ public class PlayersManager{
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: saving player by uuid " + player.getPlayerName() + " " + playerUUID + " saved");
|
||||
handler.saveObject(player);
|
||||
|
||||
|
||||
} catch (IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException | SecurityException
|
||||
| InstantiationException | NoSuchMethodException
|
||||
@ -613,5 +607,11 @@ public class PlayersManager{
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isKnown(String string) {
|
||||
UUID uuid = this.getUUID(string);
|
||||
if (uuid == null) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package us.tastybento.bskyblock.database.objects;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
|
||||
/**
|
||||
* A bean to hold name to UUID lookup
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class NameToUUID implements DataObject {
|
||||
|
||||
public HashMap<String, UUID> namesToUUID;
|
||||
|
||||
public NameToUUID() {}
|
||||
|
||||
/**
|
||||
* @return the namesToUUID
|
||||
*/
|
||||
public HashMap<String, UUID> getNamesToUUID() {
|
||||
return namesToUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param namesToUUID the namesToUUID to set
|
||||
*/
|
||||
public void setNamesToUUID(HashMap<String, UUID> namesToUUID) {
|
||||
this.namesToUUID = namesToUUID;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.objects.DataObject#getUniqueId()
|
||||
*/
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return "names-uuid";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.objects.DataObject#setUniqueId(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update a name
|
||||
* @param user
|
||||
*/
|
||||
public void addName(User user) {
|
||||
this.namesToUUID.put(user.getName(), user.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UUID for name
|
||||
* @param name
|
||||
* @return UUID or null if not found
|
||||
*/
|
||||
public UUID getUUID(String name) {
|
||||
return this.namesToUUID.get(name);
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package us.tastybento.bskyblock.listeners;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -31,15 +30,14 @@ public class JoinLeaveListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (player == null) {
|
||||
if (event.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
if (playerUUID == null) {
|
||||
User user = User.getInstance(event.getPlayer());
|
||||
if (user.getUniqueId() == null) {
|
||||
return;
|
||||
}
|
||||
User user = User.getInstance(player);
|
||||
UUID playerUUID = user.getUniqueId();
|
||||
if (plugin.getPlayers().isKnown(playerUUID)) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: known player");
|
||||
@ -52,10 +50,10 @@ public class JoinLeaveListener implements Listener {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Setting player's name");
|
||||
// Set the player's name (it may have changed), but only if it isn't empty
|
||||
if (!player.getName().isEmpty()) {
|
||||
if (!user.getName().isEmpty()) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Player name is " + player.getName());
|
||||
players.setPlayerName(playerUUID, player.getName());
|
||||
plugin.getLogger().info("DEBUG: Player name is " + user.getName());
|
||||
players.setPlayerName(user);
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Saving player");
|
||||
players.save(playerUUID);
|
||||
@ -65,19 +63,19 @@ public class JoinLeaveListener implements Listener {
|
||||
if (plugin.getSettings().isRemoveMobsOnLogin()) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Removing mobs");
|
||||
plugin.getIslands().removeMobs(player.getLocation());
|
||||
plugin.getIslands().removeMobs(user.getLocation());
|
||||
}
|
||||
|
||||
// Check if they logged in to a locked island and expel them or if they are banned
|
||||
Island currentIsland = plugin.getIslands().getIslandAt(player.getLocation());
|
||||
if (currentIsland != null && (currentIsland.isLocked() || plugin.getPlayers().isBanned(currentIsland.getOwner(),player.getUniqueId()))) {
|
||||
Island currentIsland = plugin.getIslands().getIslandAt(user.getLocation());
|
||||
if (currentIsland != null && (currentIsland.isLocked() || plugin.getPlayers().isBanned(currentIsland.getOwner(),user.getUniqueId()))) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: Current island is locked, or player is banned");
|
||||
if (!currentIsland.getMembers().contains(playerUUID) && !player.hasPermission(Constants.PERMPREFIX + "mod.bypassprotect")) {
|
||||
if (!currentIsland.getMembers().contains(playerUUID) && !user.hasPermission(Constants.PERMPREFIX + "mod.bypassprotect")) {
|
||||
if (DEBUG)
|
||||
plugin.getLogger().info("DEBUG: No bypass - teleporting");
|
||||
user.sendMessage("locked.islandlocked");
|
||||
plugin.getIslands().homeTeleport(player);
|
||||
plugin.getIslands().homeTeleport(user.getPlayer());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user