mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-24 03:05:17 +01:00
#306 Add command service and set up constructor dependency injection
(work in progress) - Pass all dependencies via constructor - Encapsulate command handling more (e.g. split CommandHandler with new CommandMapper) - Add help command to all base commands at one central point See AccountsCommand or HelpCommand for an example of the advantages - all necessary functions come from CommandService; objects aren't retrieved through a singleton getInstance() method anymore
This commit is contained in:
parent
f785d9d357
commit
8ef1b2ae3e
@ -9,8 +9,12 @@ import fr.xephi.authme.cache.auth.PlayerCache;
|
|||||||
import fr.xephi.authme.cache.backup.JsonCache;
|
import fr.xephi.authme.cache.backup.JsonCache;
|
||||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||||
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.command.CommandDescription;
|
||||||
import fr.xephi.authme.command.CommandHandler;
|
import fr.xephi.authme.command.CommandHandler;
|
||||||
import fr.xephi.authme.command.CommandInitializer;
|
import fr.xephi.authme.command.CommandInitializer;
|
||||||
|
import fr.xephi.authme.command.CommandMapper;
|
||||||
|
import fr.xephi.authme.command.CommandService;
|
||||||
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
import fr.xephi.authme.converter.Converter;
|
import fr.xephi.authme.converter.Converter;
|
||||||
import fr.xephi.authme.converter.ForceFlatToSqlite;
|
import fr.xephi.authme.converter.ForceFlatToSqlite;
|
||||||
import fr.xephi.authme.datasource.CacheDataSource;
|
import fr.xephi.authme.datasource.CacheDataSource;
|
||||||
@ -68,6 +72,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -196,9 +201,12 @@ public class AuthMe extends JavaPlugin {
|
|||||||
plugin = this;
|
plugin = this;
|
||||||
setupConstants();
|
setupConstants();
|
||||||
|
|
||||||
|
// Set up messages
|
||||||
|
messages = Messages.getInstance();
|
||||||
|
|
||||||
// Set up the permissions manager and command handler
|
// Set up the permissions manager and command handler
|
||||||
permsMan = initializePermissionsManager();
|
permsMan = initializePermissionsManager();
|
||||||
commandHandler = new CommandHandler(CommandInitializer.getBaseCommands(), permsMan);
|
commandHandler = initializeCommandHandler(permsMan, messages);
|
||||||
|
|
||||||
// Set up the module manager
|
// Set up the module manager
|
||||||
setupModuleManager();
|
setupModuleManager();
|
||||||
@ -213,8 +221,6 @@ public class AuthMe extends JavaPlugin {
|
|||||||
// Setup otherAccounts file
|
// Setup otherAccounts file
|
||||||
this.otherAccounts = OtherAccounts.getInstance();
|
this.otherAccounts = OtherAccounts.getInstance();
|
||||||
|
|
||||||
// Setup messages
|
|
||||||
this.messages = Messages.getInstance();
|
|
||||||
|
|
||||||
// Set up Metrics
|
// Set up Metrics
|
||||||
setupMetrics();
|
setupMetrics();
|
||||||
@ -405,6 +411,14 @@ public class AuthMe extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages) {
|
||||||
|
HelpProvider helpProvider = new HelpProvider(permissionsManager);
|
||||||
|
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
|
||||||
|
CommandMapper mapper = new CommandMapper(baseCommands, messages, permissionsManager);
|
||||||
|
CommandService commandService = new CommandService(this, mapper, helpProvider, messages);
|
||||||
|
return new CommandHandler(commandService);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the API. This sets up the new and the old API.
|
* Set up the API. This sets up the new and the old API.
|
||||||
*/
|
*/
|
||||||
@ -926,10 +940,6 @@ public class AuthMe extends JavaPlugin {
|
|||||||
return moduleManager;
|
return moduleManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandHandler getCommandHandler() {
|
|
||||||
return this.commandHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Bukkit commands.
|
* Handle Bukkit commands.
|
||||||
*
|
*
|
||||||
|
@ -1,21 +1,10 @@
|
|||||||
package fr.xephi.authme.command;
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.command.executable.HelpCommand;
|
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.command.FoundResultStatus.INCORRECT_ARGUMENTS;
|
|
||||||
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
|
|
||||||
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription}
|
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription}
|
||||||
@ -23,28 +12,13 @@ import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
|
|||||||
*/
|
*/
|
||||||
public class CommandHandler {
|
public class CommandHandler {
|
||||||
|
|
||||||
/**
|
private final CommandService commandService;
|
||||||
* The threshold for suggesting a similar command. If the difference is below this value, we will
|
|
||||||
* ask the player whether he meant the similar command.
|
|
||||||
*/
|
|
||||||
private static final double SUGGEST_COMMAND_THRESHOLD = 0.75;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class of the help command, to which the base label should also be passed in the arguments.
|
|
||||||
*/
|
|
||||||
private static final Class<? extends ExecutableCommand> HELP_COMMAND_CLASS = HelpCommand.class;
|
|
||||||
|
|
||||||
private final Set<CommandDescription> baseCommands;
|
|
||||||
private final PermissionsManager permissionsManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a command handler.
|
* Create a command handler.
|
||||||
*
|
|
||||||
* @param baseCommands The collection of available AuthMe base commands
|
|
||||||
*/
|
*/
|
||||||
public CommandHandler(Set<CommandDescription> baseCommands, PermissionsManager permissionsManager) {
|
public CommandHandler(CommandService commandService) {
|
||||||
this.baseCommands = baseCommands;
|
this.commandService = commandService;
|
||||||
this.permissionsManager = permissionsManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,41 +35,20 @@ public class CommandHandler {
|
|||||||
// Add the Bukkit command label to the front so we get a list like [authme, register, bobby, mysecret]
|
// Add the Bukkit command label to the front so we get a list like [authme, register, bobby, mysecret]
|
||||||
List<String> parts = skipEmptyArguments(bukkitArgs);
|
List<String> parts = skipEmptyArguments(bukkitArgs);
|
||||||
parts.add(0, bukkitCommandLabel);
|
parts.add(0, bukkitCommandLabel);
|
||||||
FoundCommandResult result = mapPartsToCommand(parts);
|
|
||||||
|
|
||||||
switch (result.getResultStatus()) {
|
FoundCommandResult result = commandService.mapPartsToCommand(sender, parts);
|
||||||
case SUCCESS:
|
if (FoundResultStatus.SUCCESS.equals(result.getResultStatus())) {
|
||||||
executeCommandIfAllowed(sender, result.getCommandDescription(), result.getArguments());
|
executeCommand(sender, result);
|
||||||
break;
|
} else {
|
||||||
case MISSING_BASE_COMMAND:
|
commandService.outputMappingError(sender, result);
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Failed to parse " + AuthMe.getPluginName() + " command!");
|
|
||||||
return false;
|
|
||||||
case INCORRECT_ARGUMENTS:
|
|
||||||
sendImproperArgumentsMessage(sender, result);
|
|
||||||
break;
|
|
||||||
case UNKNOWN_LABEL:
|
|
||||||
sendUnknownCommandMessage(sender, result);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unknown result '" + result.getResultStatus() + "'");
|
|
||||||
}
|
}
|
||||||
|
return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void executeCommand(CommandSender sender, FoundCommandResult result) {
|
||||||
* Check a command's permissions and execute it with the given arguments if the check succeeds.
|
ExecutableCommand executableCommand = result.getCommandDescription().getExecutableCommand();
|
||||||
*
|
List<String> arguments = result.getArguments();
|
||||||
* @param sender The command sender
|
executableCommand.executeCommand(sender, arguments, commandService);
|
||||||
* @param command The command to process
|
|
||||||
* @param arguments The arguments to pass to the command
|
|
||||||
*/
|
|
||||||
private void executeCommandIfAllowed(CommandSender sender, CommandDescription command, List<String> arguments) {
|
|
||||||
if (permissionsManager.hasPermission(sender, command)) {
|
|
||||||
command.getExecutableCommand().executeCommand(sender, arguments);
|
|
||||||
} else {
|
|
||||||
sendPermissionDeniedError(sender);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,181 +67,6 @@ public class CommandHandler {
|
|||||||
return cleanArguments;
|
return cleanArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show an "unknown command" to the user and suggests an existing command if its similarity is within
|
|
||||||
* the defined threshold.
|
|
||||||
*
|
|
||||||
* @param sender The command sender
|
|
||||||
* @param result The command that was found during the mapping process
|
|
||||||
*/
|
|
||||||
private static void sendUnknownCommandMessage(CommandSender sender, FoundCommandResult result) {
|
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Unknown command!");
|
|
||||||
|
|
||||||
// Show a command suggestion if available and the difference isn't too big
|
|
||||||
if (result.getDifference() <= SUGGEST_COMMAND_THRESHOLD && result.getCommandDescription() != null) {
|
|
||||||
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD
|
|
||||||
+ CommandUtils.constructCommandPath(result.getCommandDescription()) + ChatColor.YELLOW + "?");
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + result.getLabels().get(0)
|
|
||||||
+ " help" + ChatColor.YELLOW + " to view help.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result) {
|
|
||||||
CommandDescription command = result.getCommandDescription();
|
|
||||||
if (!permissionsManager.hasPermission(sender, command)) {
|
|
||||||
sendPermissionDeniedError(sender);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the command argument help
|
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!");
|
|
||||||
List<String> lines = HelpProvider.printHelp(result, HelpProvider.SHOW_ARGUMENTS);
|
|
||||||
for (String line : lines) {
|
|
||||||
sender.sendMessage(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> labels = result.getLabels();
|
|
||||||
String childLabel = labels.size() >= 2 ? labels.get(1) : "";
|
|
||||||
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE
|
|
||||||
+ "/" + labels.get(0) + " help " + childLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO ljacqu 20151212: Remove me once I am a MessageKey
|
|
||||||
private void sendPermissionDeniedError(CommandSender sender) {
|
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "You don't have permission to use this command!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map incoming command parts to a command. This processes all parts and distinguishes the labels from arguments.
|
|
||||||
*
|
|
||||||
* @param parts The parts to map to commands and arguments
|
|
||||||
* @return The generated {@link FoundCommandResult}
|
|
||||||
*/
|
|
||||||
public FoundCommandResult mapPartsToCommand(final List<String> parts) {
|
|
||||||
if (CollectionUtils.isEmpty(parts)) {
|
|
||||||
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandDescription base = getBaseCommand(parts.get(0));
|
|
||||||
if (base == null) {
|
|
||||||
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefer labels: /register help goes to "Help command", not "Register command" with argument 'help'
|
|
||||||
List<String> remainingParts = parts.subList(1, parts.size());
|
|
||||||
CommandDescription childCommand = getSuitableChild(base, remainingParts);
|
|
||||||
if (childCommand != null) {
|
|
||||||
FoundCommandResult result = new FoundCommandResult(
|
|
||||||
childCommand, parts.subList(0, 2), parts.subList(2, parts.size()));
|
|
||||||
return transformResultForHelp(result);
|
|
||||||
} else if (hasSuitableArgumentCount(base, remainingParts.size())) {
|
|
||||||
return new FoundCommandResult(base, parts.subList(0, 1), parts.subList(1, parts.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return getCommandWithSmallestDifference(base, parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) {
|
|
||||||
// Return the base command with incorrect arg count error if we only have one part
|
|
||||||
if (parts.size() <= 1) {
|
|
||||||
return new FoundCommandResult(base, parts, new ArrayList<String>(), 0.0, INCORRECT_ARGUMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String childLabel = parts.get(1);
|
|
||||||
double minDifference = Double.POSITIVE_INFINITY;
|
|
||||||
CommandDescription closestCommand = null;
|
|
||||||
|
|
||||||
for (CommandDescription child : base.getChildren()) {
|
|
||||||
double difference = getLabelDifference(child, childLabel);
|
|
||||||
if (difference < minDifference) {
|
|
||||||
minDifference = difference;
|
|
||||||
closestCommand = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// base command may have no children, in which case we return the base command with incorrect arguments error
|
|
||||||
if (closestCommand == null) {
|
|
||||||
return new FoundCommandResult(
|
|
||||||
base, parts.subList(0, 1), parts.subList(1, parts.size()), 0.0, INCORRECT_ARGUMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
FoundResultStatus status = (minDifference == 0.0) ? INCORRECT_ARGUMENTS : UNKNOWN_LABEL;
|
|
||||||
final int partsSize = parts.size();
|
|
||||||
List<String> labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize));
|
|
||||||
List<String> arguments = (labels.size() == partsSize)
|
|
||||||
? new ArrayList<String>()
|
|
||||||
: parts.subList(labels.size(), partsSize);
|
|
||||||
|
|
||||||
return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommandDescription getBaseCommand(String label) {
|
|
||||||
String baseLabel = label.toLowerCase();
|
|
||||||
for (CommandDescription command : baseCommands) {
|
|
||||||
if (command.hasLabel(baseLabel)) {
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a child from a base command if the label and the argument count match.
|
|
||||||
*
|
|
||||||
* @param baseCommand The base command whose children should be checked
|
|
||||||
* @param parts The command parts received from the invocation; the first item is the potential label and any
|
|
||||||
* other items are command arguments. The first initial part that led to the base command should not
|
|
||||||
* be present.
|
|
||||||
*
|
|
||||||
* @return A command if there was a complete match (including proper argument count), null otherwise
|
|
||||||
*/
|
|
||||||
private CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
|
|
||||||
if (CollectionUtils.isEmpty(parts)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String label = parts.get(0).toLowerCase();
|
|
||||||
final int argumentCount = parts.size() - 1;
|
|
||||||
|
|
||||||
for (CommandDescription child : baseCommand.getChildren()) {
|
|
||||||
if (child.hasLabel(label) && hasSuitableArgumentCount(child, argumentCount)) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FoundCommandResult transformResultForHelp(FoundCommandResult result) {
|
|
||||||
if (result.getCommandDescription() != null
|
|
||||||
&& HELP_COMMAND_CLASS.isAssignableFrom(result.getCommandDescription().getExecutableCommand().getClass())) {
|
|
||||||
// For "/authme help register" we have labels = [authme, help] and arguments = [register]
|
|
||||||
// But for the help command we want labels = [authme, help] and arguments = [authme, register],
|
|
||||||
// so we can use the arguments as the labels to the command to show help for
|
|
||||||
List<String> arguments = new ArrayList<>(result.getArguments());
|
|
||||||
arguments.add(0, result.getLabels().get(0));
|
|
||||||
return new FoundCommandResult(result.getCommandDescription(), result.getLabels(),
|
|
||||||
arguments, result.getDifference(), result.getResultStatus());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasSuitableArgumentCount(CommandDescription command, int argumentCount) {
|
|
||||||
int minArgs = CommandUtils.getMinNumberOfArguments(command);
|
|
||||||
int maxArgs = CommandUtils.getMaxNumberOfArguments(command);
|
|
||||||
|
|
||||||
return argumentCount >= minArgs && argumentCount <= maxArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double getLabelDifference(CommandDescription command, String givenLabel) {
|
|
||||||
double minDifference = Double.POSITIVE_INFINITY;
|
|
||||||
for (String commandLabel : command.getLabels()) {
|
|
||||||
double difference = StringUtils.getDifference(commandLabel, givenLabel);
|
|
||||||
if (difference < minDifference) {
|
|
||||||
minDifference = difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return minDifference;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand;
|
|||||||
import fr.xephi.authme.command.executable.converter.ConverterCommand;
|
import fr.xephi.authme.command.executable.converter.ConverterCommand;
|
||||||
import fr.xephi.authme.command.executable.email.AddEmailCommand;
|
import fr.xephi.authme.command.executable.email.AddEmailCommand;
|
||||||
import fr.xephi.authme.command.executable.email.ChangeEmailCommand;
|
import fr.xephi.authme.command.executable.email.ChangeEmailCommand;
|
||||||
|
import fr.xephi.authme.command.executable.email.EmailBaseCommand;
|
||||||
import fr.xephi.authme.command.executable.email.RecoverEmailCommand;
|
import fr.xephi.authme.command.executable.email.RecoverEmailCommand;
|
||||||
import fr.xephi.authme.command.executable.login.LoginCommand;
|
import fr.xephi.authme.command.executable.login.LoginCommand;
|
||||||
import fr.xephi.authme.command.executable.logout.LogoutCommand;
|
import fr.xephi.authme.command.executable.logout.LogoutCommand;
|
||||||
@ -36,6 +37,7 @@ import fr.xephi.authme.permission.AdminPermission;
|
|||||||
import fr.xephi.authme.permission.PlayerPermission;
|
import fr.xephi.authme.permission.PlayerPermission;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -47,24 +49,11 @@ import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
|
|||||||
*/
|
*/
|
||||||
public final class CommandInitializer {
|
public final class CommandInitializer {
|
||||||
|
|
||||||
private static Set<CommandDescription> baseCommands;
|
|
||||||
|
|
||||||
private CommandInitializer() {
|
private CommandInitializer() {
|
||||||
// Helper class
|
// Helper class
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<CommandDescription> getBaseCommands() {
|
public static Set<CommandDescription> buildCommands() {
|
||||||
if (baseCommands == null) {
|
|
||||||
initializeCommands();
|
|
||||||
}
|
|
||||||
return baseCommands;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initializeCommands() {
|
|
||||||
// Create a list of help command labels
|
|
||||||
final List<String> helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?");
|
|
||||||
final ExecutableCommand helpCommandExecutable = new HelpCommand();
|
|
||||||
|
|
||||||
// Register the base AuthMe Reloaded command
|
// Register the base AuthMe Reloaded command
|
||||||
final CommandDescription AUTHME_BASE = CommandDescription.builder()
|
final CommandDescription AUTHME_BASE = CommandDescription.builder()
|
||||||
.labels("authme")
|
.labels("authme")
|
||||||
@ -73,16 +62,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new AuthMeCommand())
|
.executableCommand(new AuthMeCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(AUTHME_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the register command
|
// Register the register command
|
||||||
CommandDescription.builder()
|
CommandDescription.builder()
|
||||||
.parent(AUTHME_BASE)
|
.parent(AUTHME_BASE)
|
||||||
@ -301,16 +280,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new LoginCommand())
|
.executableCommand(new LoginCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(LOGIN_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View Help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded login commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base logout command
|
// Register the base logout command
|
||||||
CommandDescription LOGOUT_BASE = CommandDescription.builder()
|
CommandDescription LOGOUT_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
@ -321,16 +290,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new LogoutCommand())
|
.executableCommand(new LogoutCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(LOGOUT_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded logout commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base register command
|
// Register the base register command
|
||||||
final CommandDescription REGISTER_BASE = CommandDescription.builder()
|
final CommandDescription REGISTER_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
@ -343,16 +302,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new RegisterCommand())
|
.executableCommand(new RegisterCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(REGISTER_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded register commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base unregister command
|
// Register the base unregister command
|
||||||
CommandDescription UNREGISTER_BASE = CommandDescription.builder()
|
CommandDescription UNREGISTER_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
@ -364,16 +313,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new UnregisterCommand())
|
.executableCommand(new UnregisterCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(UNREGISTER_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded unregister commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base changepassword command
|
// Register the base changepassword command
|
||||||
final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
|
final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
@ -386,33 +325,13 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new ChangePasswordCommand())
|
.executableCommand(new ChangePasswordCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(CHANGE_PASSWORD_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded changepassword commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base Email command
|
// Register the base Email command
|
||||||
CommandDescription EMAIL_BASE = CommandDescription.builder()
|
CommandDescription EMAIL_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
.labels("email", "mail")
|
.labels("email", "mail")
|
||||||
.description("Email command")
|
.description("Email command")
|
||||||
.detailedDescription("The AuthMeReloaded Email command base.")
|
.detailedDescription("The AuthMeReloaded Email command base.")
|
||||||
.executableCommand(helpCommandExecutable)
|
.executableCommand(new EmailBaseCommand())
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(EMAIL_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded email commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the add command
|
// Register the add command
|
||||||
@ -462,16 +381,6 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new CaptchaCommand())
|
.executableCommand(new CaptchaCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(CAPTCHA_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded captcha commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Register the base converter command
|
// Register the base converter command
|
||||||
CommandDescription CONVERTER_BASE = CommandDescription.builder()
|
CommandDescription CONVERTER_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
@ -484,18 +393,7 @@ public final class CommandInitializer {
|
|||||||
.executableCommand(new ConverterCommand())
|
.executableCommand(new ConverterCommand())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register the help command
|
Set<CommandDescription> baseCommands = ImmutableSet.of(
|
||||||
CommandDescription.builder()
|
|
||||||
.parent(CONVERTER_BASE)
|
|
||||||
.labels(helpCommandLabels)
|
|
||||||
.description("View help")
|
|
||||||
.detailedDescription("View detailed help pages about AuthMeReloaded converter commands.")
|
|
||||||
.withArgument("query", "The command or query to view help for.", true)
|
|
||||||
.executableCommand(helpCommandExecutable)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Add the base commands to the commands array
|
|
||||||
baseCommands = ImmutableSet.of(
|
|
||||||
AUTHME_BASE,
|
AUTHME_BASE,
|
||||||
LOGIN_BASE,
|
LOGIN_BASE,
|
||||||
LOGOUT_BASE,
|
LOGOUT_BASE,
|
||||||
@ -505,5 +403,29 @@ public final class CommandInitializer {
|
|||||||
EMAIL_BASE,
|
EMAIL_BASE,
|
||||||
CAPTCHA_BASE,
|
CAPTCHA_BASE,
|
||||||
CONVERTER_BASE);
|
CONVERTER_BASE);
|
||||||
|
|
||||||
|
setHelpOnAllBases(baseCommands);
|
||||||
|
return baseCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the help command on all base commands, e.g. to register /authme help or /register help.
|
||||||
|
*
|
||||||
|
* @param commands The list of base commands to register a help child command on
|
||||||
|
*/
|
||||||
|
private static void setHelpOnAllBases(Collection<CommandDescription> commands) {
|
||||||
|
final HelpCommand helpCommandExecutable = new HelpCommand();
|
||||||
|
final List<String> helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?");
|
||||||
|
|
||||||
|
for (CommandDescription base : commands) {
|
||||||
|
CommandDescription.builder()
|
||||||
|
.parent(base)
|
||||||
|
.labels(helpCommandLabels)
|
||||||
|
.description("View help")
|
||||||
|
.detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.")
|
||||||
|
.withArgument("query", "The command or query to view help for.", true)
|
||||||
|
.executableCommand(helpCommandExecutable)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
258
src/main/java/fr/xephi/authme/command/CommandMapper.java
Normal file
258
src/main/java/fr/xephi/authme/command/CommandMapper.java
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
|
import fr.xephi.authme.AuthMe;
|
||||||
|
import fr.xephi.authme.command.executable.HelpCommand;
|
||||||
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
|
import fr.xephi.authme.output.Messages;
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.util.CollectionUtils;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.command.FoundResultStatus.INCORRECT_ARGUMENTS;
|
||||||
|
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
|
||||||
|
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AuthMe command handler, responsible for mapping incoming command parts to the correct {@link CommandDescription}
|
||||||
|
* or to display help messages for erroneous invocations (unknown command, no permission, etc.).
|
||||||
|
*/
|
||||||
|
public class CommandMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The threshold for suggesting a similar command. If the difference is below this value, we will
|
||||||
|
* ask the player whether he meant the similar command.
|
||||||
|
*/
|
||||||
|
private static final double SUGGEST_COMMAND_THRESHOLD = 0.75;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class of the help command, to which the base label should also be passed in the arguments.
|
||||||
|
*/
|
||||||
|
private static final Class<? extends ExecutableCommand> HELP_COMMAND_CLASS = HelpCommand.class;
|
||||||
|
|
||||||
|
private final Set<CommandDescription> baseCommands;
|
||||||
|
private final Messages messages;
|
||||||
|
private final PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
public CommandMapper(Set<CommandDescription> baseCommands, Messages messages,
|
||||||
|
PermissionsManager permissionsManager) {
|
||||||
|
this.baseCommands = baseCommands;
|
||||||
|
this.messages = messages;
|
||||||
|
this.permissionsManager = permissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputStandardError(CommandSender sender, FoundCommandResult result) {
|
||||||
|
switch (result.getResultStatus()) {
|
||||||
|
case SUCCESS:
|
||||||
|
// Successful mapping, so no error to output
|
||||||
|
break;
|
||||||
|
case MISSING_BASE_COMMAND:
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "Failed to parse " + AuthMe.getPluginName() + " command!");
|
||||||
|
break;
|
||||||
|
case INCORRECT_ARGUMENTS:
|
||||||
|
sendImproperArgumentsMessage(sender, result);
|
||||||
|
break;
|
||||||
|
case UNKNOWN_LABEL:
|
||||||
|
sendUnknownCommandMessage(sender, result);
|
||||||
|
break;
|
||||||
|
case NO_PERMISSION:
|
||||||
|
sendPermissionDeniedError(sender);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown result status '" + result.getResultStatus() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an "unknown command" message to the user and suggest an existing command if its similarity is within
|
||||||
|
* the defined threshold.
|
||||||
|
*
|
||||||
|
* @param sender The command sender
|
||||||
|
* @param result The command that was found during the mapping process
|
||||||
|
*/
|
||||||
|
private static void sendUnknownCommandMessage(CommandSender sender, FoundCommandResult result) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "Unknown command!");
|
||||||
|
|
||||||
|
// Show a command suggestion if available and the difference isn't too big
|
||||||
|
if (result.getDifference() <= SUGGEST_COMMAND_THRESHOLD && result.getCommandDescription() != null) {
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD
|
||||||
|
+ CommandUtils.constructCommandPath(result.getCommandDescription()) + ChatColor.YELLOW + "?");
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + result.getLabels().get(0)
|
||||||
|
+ " help" + ChatColor.YELLOW + " to view help.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result) {
|
||||||
|
CommandDescription command = result.getCommandDescription();
|
||||||
|
if (!permissionsManager.hasPermission(sender, command)) {
|
||||||
|
sendPermissionDeniedError(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the command argument help
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!");
|
||||||
|
List<String> lines = HelpProvider.printHelp(result, HelpProvider.SHOW_ARGUMENTS);
|
||||||
|
for (String line : lines) {
|
||||||
|
sender.sendMessage(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> labels = result.getLabels();
|
||||||
|
String childLabel = labels.size() >= 2 ? labels.get(1) : "";
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE
|
||||||
|
+ "/" + labels.get(0) + " help " + childLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO ljacqu 20151212: Remove me once I am a MessageKey
|
||||||
|
private static void sendPermissionDeniedError(CommandSender sender) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "You don't have permission to use this command!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map incoming command parts to a command. This processes all parts and distinguishes the labels from arguments.
|
||||||
|
*
|
||||||
|
* @param sender The command sender (null if none applicable)
|
||||||
|
* @param parts The parts to map to commands and arguments
|
||||||
|
* @return The generated {@link FoundCommandResult}
|
||||||
|
*/
|
||||||
|
public FoundCommandResult mapPartsToCommand(CommandSender sender, final List<String> parts) {
|
||||||
|
if (CollectionUtils.isEmpty(parts)) {
|
||||||
|
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandDescription base = getBaseCommand(parts.get(0));
|
||||||
|
if (base == null) {
|
||||||
|
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer labels: /register help goes to "Help command", not "Register command" with argument 'help'
|
||||||
|
List<String> remainingParts = parts.subList(1, parts.size());
|
||||||
|
CommandDescription childCommand = getSuitableChild(base, remainingParts);
|
||||||
|
if (childCommand != null) {
|
||||||
|
FoundResultStatus status = getPermissionAwareStatus(sender, childCommand);
|
||||||
|
FoundCommandResult result = new FoundCommandResult(
|
||||||
|
childCommand, parts.subList(0, 2), parts.subList(2, parts.size()), 0.0, status);
|
||||||
|
return transformResultForHelp(result);
|
||||||
|
} else if (hasSuitableArgumentCount(base, remainingParts.size())) {
|
||||||
|
FoundResultStatus status = getPermissionAwareStatus(sender, base);
|
||||||
|
return new FoundCommandResult(base, parts.subList(0, 1), parts.subList(1, parts.size()), 0.0, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getCommandWithSmallestDifference(base, parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) {
|
||||||
|
// Return the base command with incorrect arg count error if we only have one part
|
||||||
|
if (parts.size() <= 1) {
|
||||||
|
return new FoundCommandResult(base, parts, new ArrayList<String>(), 0.0, INCORRECT_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String childLabel = parts.get(1);
|
||||||
|
double minDifference = Double.POSITIVE_INFINITY;
|
||||||
|
CommandDescription closestCommand = null;
|
||||||
|
|
||||||
|
for (CommandDescription child : base.getChildren()) {
|
||||||
|
double difference = getLabelDifference(child, childLabel);
|
||||||
|
if (difference < minDifference) {
|
||||||
|
minDifference = difference;
|
||||||
|
closestCommand = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// base command may have no children, in which case we return the base command with incorrect arguments error
|
||||||
|
if (closestCommand == null) {
|
||||||
|
return new FoundCommandResult(
|
||||||
|
base, parts.subList(0, 1), parts.subList(1, parts.size()), 0.0, INCORRECT_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
FoundResultStatus status = (minDifference == 0.0) ? INCORRECT_ARGUMENTS : UNKNOWN_LABEL;
|
||||||
|
final int partsSize = parts.size();
|
||||||
|
List<String> labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize));
|
||||||
|
List<String> arguments = (labels.size() == partsSize)
|
||||||
|
? new ArrayList<String>()
|
||||||
|
: parts.subList(labels.size(), partsSize);
|
||||||
|
|
||||||
|
return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandDescription getBaseCommand(String label) {
|
||||||
|
String baseLabel = label.toLowerCase();
|
||||||
|
for (CommandDescription command : baseCommands) {
|
||||||
|
if (command.hasLabel(baseLabel)) {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a child from a base command if the label and the argument count match.
|
||||||
|
*
|
||||||
|
* @param baseCommand The base command whose children should be checked
|
||||||
|
* @param parts The command parts received from the invocation; the first item is the potential label and any
|
||||||
|
* other items are command arguments. The first initial part that led to the base command should not
|
||||||
|
* be present.
|
||||||
|
*
|
||||||
|
* @return A command if there was a complete match (including proper argument count), null otherwise
|
||||||
|
*/
|
||||||
|
private CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
|
||||||
|
if (CollectionUtils.isEmpty(parts)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String label = parts.get(0).toLowerCase();
|
||||||
|
final int argumentCount = parts.size() - 1;
|
||||||
|
|
||||||
|
for (CommandDescription child : baseCommand.getChildren()) {
|
||||||
|
if (child.hasLabel(label) && hasSuitableArgumentCount(child, argumentCount)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FoundCommandResult transformResultForHelp(FoundCommandResult result) {
|
||||||
|
if (result.getCommandDescription() != null
|
||||||
|
&& HELP_COMMAND_CLASS.isAssignableFrom(result.getCommandDescription().getExecutableCommand().getClass())) {
|
||||||
|
// For "/authme help register" we have labels = [authme, help] and arguments = [register]
|
||||||
|
// But for the help command we want labels = [authme, help] and arguments = [authme, register],
|
||||||
|
// so we can use the arguments as the labels to the command to show help for
|
||||||
|
List<String> arguments = new ArrayList<>(result.getArguments());
|
||||||
|
arguments.add(0, result.getLabels().get(0));
|
||||||
|
return new FoundCommandResult(result.getCommandDescription(), result.getLabels(),
|
||||||
|
arguments, result.getDifference(), result.getResultStatus());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FoundResultStatus getPermissionAwareStatus(CommandSender sender, CommandDescription command) {
|
||||||
|
if (sender != null && !permissionsManager.hasPermission(sender, command)) {
|
||||||
|
return FoundResultStatus.NO_PERMISSION;
|
||||||
|
}
|
||||||
|
return FoundResultStatus.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasSuitableArgumentCount(CommandDescription command, int argumentCount) {
|
||||||
|
int minArgs = CommandUtils.getMinNumberOfArguments(command);
|
||||||
|
int maxArgs = CommandUtils.getMaxNumberOfArguments(command);
|
||||||
|
|
||||||
|
return argumentCount >= minArgs && argumentCount <= maxArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double getLabelDifference(CommandDescription command, String givenLabel) {
|
||||||
|
double minDifference = Double.POSITIVE_INFINITY;
|
||||||
|
for (String commandLabel : command.getLabels()) {
|
||||||
|
double difference = StringUtils.getDifference(commandLabel, givenLabel);
|
||||||
|
if (difference < minDifference) {
|
||||||
|
minDifference = difference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minDifference;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
src/main/java/fr/xephi/authme/command/CommandService.java
Normal file
58
src/main/java/fr/xephi/authme/command/CommandService.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
|
import fr.xephi.authme.AuthMe;
|
||||||
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.output.MessageKey;
|
||||||
|
import fr.xephi.authme.output.Messages;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for implementations of {@link ExecutableCommand} to execute some common tasks.
|
||||||
|
* This service basically wraps calls, forwarding them to other classes.
|
||||||
|
*/
|
||||||
|
public class CommandService {
|
||||||
|
|
||||||
|
private final AuthMe authMe;
|
||||||
|
private final Messages messages;
|
||||||
|
private final HelpProvider helpProvider;
|
||||||
|
private final CommandMapper commandMapper;
|
||||||
|
|
||||||
|
public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages) {
|
||||||
|
this.authMe = authMe;
|
||||||
|
this.messages = messages;
|
||||||
|
this.helpProvider = helpProvider;
|
||||||
|
this.commandMapper = commandMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(CommandSender sender, MessageKey messageKey) {
|
||||||
|
messages.send(sender, messageKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FoundCommandResult mapPartsToCommand(CommandSender sender, List<String> commandParts) {
|
||||||
|
return commandMapper.mapPartsToCommand(sender, commandParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputMappingError(CommandSender sender, FoundCommandResult result) {
|
||||||
|
commandMapper.outputStandardError(sender, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTaskAsynchronously(Runnable task) {
|
||||||
|
authMe.getServer().getScheduler().runTaskAsynchronously(authMe, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSource getDataSource() {
|
||||||
|
// TODO ljacqu 20151222: Add getter for .database and rename the field to dataSource
|
||||||
|
return authMe.database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputHelp(CommandSender sender, FoundCommandResult result, int options) {
|
||||||
|
List<String> lines = helpProvider.printHelp(sender, result, options);
|
||||||
|
for (String line : lines) {
|
||||||
|
sender.sendMessage(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,13 +7,15 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Base class for AuthMe commands that can be executed.
|
* Base class for AuthMe commands that can be executed.
|
||||||
*/
|
*/
|
||||||
public abstract class ExecutableCommand {
|
public interface ExecutableCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the command with the given arguments.
|
* Execute the command with the given arguments.
|
||||||
*
|
*
|
||||||
* @param sender The command sender.
|
* @param sender The command sender.
|
||||||
* @param arguments The arguments.
|
* @param arguments The arguments.
|
||||||
|
* @param commandService The command service.
|
||||||
*/
|
*/
|
||||||
public abstract void executeCommand(CommandSender sender, List<String> arguments);
|
void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import java.util.List;
|
|||||||
* count doesn't match. Guarantees that the command description field is not null; difference is 0.0</li>
|
* count doesn't match. Guarantees that the command description field is not null; difference is 0.0</li>
|
||||||
* <li>{@link FoundResultStatus#UNKNOWN_LABEL}: The labels could not be mapped to a command. The command description
|
* <li>{@link FoundResultStatus#UNKNOWN_LABEL}: The labels could not be mapped to a command. The command description
|
||||||
* may be set to the most similar command, or it may be null. Difference is above 0.0.</li>
|
* may be set to the most similar command, or it may be null. Difference is above 0.0.</li>
|
||||||
|
* <li>{@link FoundResultStatus#NO_PERMISSION}: The command could be matched properly but the sender does not have
|
||||||
|
* permission to execute it.</li>
|
||||||
* <li>{@link FoundResultStatus#MISSING_BASE_COMMAND} should never occur. All other fields may be null and any further
|
* <li>{@link FoundResultStatus#MISSING_BASE_COMMAND} should never occur. All other fields may be null and any further
|
||||||
* processing of the object should be aborted.</li>
|
* processing of the object should be aborted.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@ -54,17 +56,6 @@ public class FoundCommandResult {
|
|||||||
this.resultStatus = resultStatus;
|
this.resultStatus = resultStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a fully successfully matched command.
|
|
||||||
*
|
|
||||||
* @param commandDescription The matched command description.
|
|
||||||
* @param labels The labels used to access the command.
|
|
||||||
* @param arguments The command arguments.
|
|
||||||
*/
|
|
||||||
public FoundCommandResult(CommandDescription commandDescription, List<String> labels, List<String> arguments) {
|
|
||||||
this(commandDescription, labels, arguments, 0.0, FoundResultStatus.SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandDescription getCommandDescription() {
|
public CommandDescription getCommandDescription() {
|
||||||
return this.commandDescription;
|
return this.commandDescription;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ public enum FoundResultStatus {
|
|||||||
|
|
||||||
UNKNOWN_LABEL,
|
UNKNOWN_LABEL,
|
||||||
|
|
||||||
|
NO_PERMISSION,
|
||||||
|
|
||||||
MISSING_BASE_COMMAND
|
MISSING_BASE_COMMAND
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package fr.xephi.authme.command.executable;
|
package fr.xephi.authme.command.executable;
|
||||||
|
|
||||||
import fr.xephi.authme.command.CommandHandler;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.CommandUtils;
|
import fr.xephi.authme.command.CommandUtils;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.command.FoundCommandResult;
|
import fr.xephi.authme.command.FoundCommandResult;
|
||||||
import fr.xephi.authme.command.FoundResultStatus;
|
import fr.xephi.authme.command.FoundResultStatus;
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.util.Wrapper;
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
@ -16,41 +14,33 @@ import java.util.List;
|
|||||||
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
|
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
|
||||||
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
|
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
|
||||||
|
|
||||||
public class HelpCommand extends ExecutableCommand {
|
public class HelpCommand implements ExecutableCommand {
|
||||||
|
|
||||||
// Convention: arguments is not the actual invoked arguments but the command that was invoked,
|
// Convention: arguments is not the actual invoked arguments but the command that was invoked,
|
||||||
// e.g. "/authme help register" would typically be arguments = [register], but here we pass [authme, register]
|
// e.g. "/authme help register" would typically be arguments = [register], but here we pass [authme, register]
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) {
|
||||||
// TODO #306 ljacqu 20151213: Get command handler from non-static context
|
FoundCommandResult result = commandService.mapPartsToCommand(sender, arguments);
|
||||||
CommandHandler commandHandler = Wrapper.getInstance().getAuthMe().getCommandHandler();
|
|
||||||
FoundCommandResult foundCommandResult = commandHandler.mapPartsToCommand(arguments);
|
|
||||||
|
|
||||||
// TODO ljacqu 20151213: This is essentially the same logic as in CommandHandler and we'd like to have the same
|
FoundResultStatus resultStatus = result.getResultStatus();
|
||||||
// messages. Maybe we can have another method in CommandHandler where the end command isn't executed upon
|
|
||||||
// success.
|
|
||||||
FoundResultStatus resultStatus = foundCommandResult.getResultStatus();
|
|
||||||
if (MISSING_BASE_COMMAND.equals(resultStatus)) {
|
if (MISSING_BASE_COMMAND.equals(resultStatus)) {
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Could not get base command");
|
sender.sendMessage(ChatColor.DARK_RED + "Could not get base command");
|
||||||
return;
|
return;
|
||||||
} else if (UNKNOWN_LABEL.equals(resultStatus)) {
|
} else if (UNKNOWN_LABEL.equals(resultStatus)) {
|
||||||
if (foundCommandResult.getCommandDescription() == null) {
|
if (result.getCommandDescription() == null) {
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Unknown command");
|
sender.sendMessage(ChatColor.DARK_RED + "Unknown command");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(ChatColor.GOLD + "Assuming " + ChatColor.WHITE
|
sender.sendMessage(ChatColor.GOLD + "Assuming " + ChatColor.WHITE
|
||||||
+ CommandUtils.constructCommandPath(foundCommandResult.getCommandDescription()));
|
+ CommandUtils.constructCommandPath(result.getCommandDescription()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionsManager permissionsManager = Wrapper.getInstance().getAuthMe().getPermissionsManager();
|
if (arguments.size() == 1) {
|
||||||
List<String> lines = arguments.size() == 1
|
commandService.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN);
|
||||||
? HelpProvider.printHelp(foundCommandResult, HelpProvider.SHOW_CHILDREN)
|
} else {
|
||||||
: HelpProvider.printHelp(foundCommandResult, sender, permissionsManager, HelpProvider.ALL_OPTIONS);
|
commandService.outputHelp(sender, result, HelpProvider.ALL_OPTIONS);
|
||||||
for (String line : lines) {
|
|
||||||
sender.sendMessage(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,88 +1,65 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AccountsCommand extends ExecutableCommand {
|
/**
|
||||||
|
* Shows all accounts registered by the same IP address for the given player name or IP address.
|
||||||
|
*/
|
||||||
|
public class AccountsCommand implements ExecutableCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments,
|
||||||
final AuthMe plugin = AuthMe.getInstance();
|
final CommandService commandService) {
|
||||||
final Messages m = plugin.getMessages();
|
|
||||||
|
|
||||||
final String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
|
final String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
|
||||||
|
|
||||||
// Command logic
|
// Assumption: a player name cannot contain '.'
|
||||||
if (!playerName.contains(".")) {
|
if (!playerName.contains(".")) {
|
||||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
commandService.runTaskAsynchronously(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
PlayerAuth auth = plugin.database.getAuth(playerName.toLowerCase());
|
PlayerAuth auth = commandService.getDataSource().getAuth(playerName.toLowerCase());
|
||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
m.send(sender, MessageKey.UNKNOWN_USER);
|
commandService.send(sender, MessageKey.UNKNOWN_USER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StringBuilder message = new StringBuilder("[AuthMe] ");
|
|
||||||
List<String> accountList = plugin.database.getAllAuthsByName(auth);
|
List<String> accountList = commandService.getDataSource().getAllAuthsByName(auth);
|
||||||
if (accountList.isEmpty()) {
|
if (accountList.isEmpty()) {
|
||||||
m.send(sender, MessageKey.USER_NOT_REGISTERED);
|
commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
|
||||||
return;
|
} else if (accountList.size() == 1) {
|
||||||
}
|
|
||||||
if (accountList.size() == 1) {
|
|
||||||
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
|
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
|
||||||
return;
|
} else {
|
||||||
|
outputAccountsList(sender, playerName, accountList);
|
||||||
}
|
}
|
||||||
int i = 0;
|
|
||||||
for (String account : accountList) {
|
|
||||||
i++;
|
|
||||||
message.append(account);
|
|
||||||
if (i != accountList.size()) {
|
|
||||||
message.append(", ");
|
|
||||||
} else {
|
|
||||||
message.append('.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage("[AuthMe] " + playerName + " has "
|
|
||||||
+ String.valueOf(accountList.size()) + " accounts.");
|
|
||||||
sender.sendMessage(message.toString());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
commandService.runTaskAsynchronously(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
List<String> accountList = plugin.database.getAllAuthsByIp(playerName);
|
List<String> accountList = commandService.getDataSource().getAllAuthsByIp(playerName);
|
||||||
StringBuilder message = new StringBuilder("[AuthMe] ");
|
|
||||||
if (accountList.isEmpty()) {
|
if (accountList.isEmpty()) {
|
||||||
sender.sendMessage("[AuthMe] This IP does not exist in the database.");
|
sender.sendMessage("[AuthMe] This IP does not exist in the database.");
|
||||||
return;
|
} else if (accountList.size() == 1) {
|
||||||
}
|
|
||||||
if (accountList.size() == 1) {
|
|
||||||
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
|
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
|
||||||
return;
|
} else {
|
||||||
|
outputAccountsList(sender, playerName, accountList);
|
||||||
}
|
}
|
||||||
int i = 0;
|
|
||||||
for (String account : accountList) {
|
|
||||||
i++;
|
|
||||||
message.append(account);
|
|
||||||
if (i != accountList.size()) {
|
|
||||||
message.append(", ");
|
|
||||||
} else {
|
|
||||||
message.append('.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage("[AuthMe] " + playerName + " has "
|
|
||||||
+ String.valueOf(accountList.size()) + " accounts.");
|
|
||||||
sender.sendMessage(message.toString());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void outputAccountsList(CommandSender sender, String playerName, List<String> accountList) {
|
||||||
|
sender.sendMessage("[AuthMe] " + playerName + " has " + accountList.size() + " accounts.");
|
||||||
|
String message = "[AuthMe] " + StringUtils.join(", ", accountList) + ".";
|
||||||
|
sender.sendMessage(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.AntiBot;
|
import fr.xephi.authme.AntiBot;
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.CommandHandler;
|
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.command.FoundCommandResult;
|
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SwitchAntiBotCommand extends ExecutableCommand {
|
public class SwitchAntiBotCommand implements ExecutableCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments, CommandService commandService) {
|
||||||
if (arguments.isEmpty()) {
|
if (arguments.isEmpty()) {
|
||||||
sender.sendMessage("[AuthMe] AntiBot status: " + AntiBot.getAntiBotStatus().name());
|
sender.sendMessage("[AuthMe] AntiBot status: " + AntiBot.getAntiBotStatus().name());
|
||||||
return;
|
return;
|
||||||
@ -32,12 +28,13 @@ public class SwitchAntiBotCommand extends ExecutableCommand {
|
|||||||
sender.sendMessage("[AuthMe] AntiBotMod Manual Override: disabled!");
|
sender.sendMessage("[AuthMe] AntiBotMod Manual Override: disabled!");
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(ChatColor.DARK_RED + "Invalid AntiBot mode!");
|
sender.sendMessage(ChatColor.DARK_RED + "Invalid AntiBot mode!");
|
||||||
// TODO ljacqu 20151213: Fix static retrieval of command handler
|
// FIXME #306: Restore help showing logic
|
||||||
|
/*
|
||||||
CommandHandler commandHandler = AuthMe.getInstance().getCommandHandler();
|
CommandHandler commandHandler = AuthMe.getInstance().getCommandHandler();
|
||||||
FoundCommandResult foundCommandResult =
|
FoundCommandResult foundCommandResult =
|
||||||
commandHandler.mapPartsToCommand(Arrays.asList("authme", "antibot"));
|
commandHandler.mapPartsToCommand(Arrays.asList("authme", "antibot"));
|
||||||
HelpProvider.printHelp(foundCommandResult, HelpProvider.SHOW_ARGUMENTS);
|
HelpProvider.printHelp(foundCommandResult, HelpProvider.SHOW_ARGUMENTS);
|
||||||
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/authme help antibot");
|
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/authme help antibot");*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package fr.xephi.authme.command.executable.email;
|
||||||
|
|
||||||
|
import fr.xephi.authme.command.CommandService;
|
||||||
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base command for /email, showing information about the child commands.
|
||||||
|
*/
|
||||||
|
public class EmailBaseCommand implements ExecutableCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) {
|
||||||
|
// FIXME #306 use getCommandService().getHelpProvider();
|
||||||
|
// FIXME #306 HelpProvider.printHelp()
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ import static java.util.Collections.singletonList;
|
|||||||
/**
|
/**
|
||||||
* Help syntax generator for AuthMe commands.
|
* Help syntax generator for AuthMe commands.
|
||||||
*/
|
*/
|
||||||
public final class HelpProvider {
|
public class HelpProvider {
|
||||||
|
|
||||||
// --- Bit flags ---
|
// --- Bit flags ---
|
||||||
/** Set to <i>not</i> show the command. */
|
/** Set to <i>not</i> show the command. */
|
||||||
@ -43,13 +43,22 @@ public final class HelpProvider {
|
|||||||
/** Shortcut for setting all options apart from {@link HelpProvider#HIDE_COMMAND}. */
|
/** Shortcut for setting all options apart from {@link HelpProvider#HIDE_COMMAND}. */
|
||||||
public static final int ALL_OPTIONS = ~HIDE_COMMAND;
|
public static final int ALL_OPTIONS = ~HIDE_COMMAND;
|
||||||
|
|
||||||
private HelpProvider() {
|
private final PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
public HelpProvider(PermissionsManager permissionsManager) {
|
||||||
|
this.permissionsManager = permissionsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> printHelp(FoundCommandResult foundCommand, int options) {
|
public static List<String> printHelp(FoundCommandResult foundCommand, int options) {
|
||||||
return printHelp(foundCommand, null, null, options);
|
return printHelp(foundCommand, null, null, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
|
||||||
|
// FIXME don't overload and pass to the static method
|
||||||
|
// FIXME remove the static methods altogether
|
||||||
|
return printHelp(result, sender, permissionsManager, options);
|
||||||
|
}
|
||||||
|
|
||||||
// sender and permissions manager may be null if SHOW_PERMISSIONS is not set
|
// sender and permissions manager may be null if SHOW_PERMISSIONS is not set
|
||||||
public static List<String> printHelp(FoundCommandResult foundCommand, CommandSender sender,
|
public static List<String> printHelp(FoundCommandResult foundCommand, CommandSender sender,
|
||||||
PermissionsManager permissionsManager, int options) {
|
PermissionsManager permissionsManager, int options) {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package fr.xephi.authme.command;
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
import fr.xephi.authme.command.executable.HelpCommand;
|
import fr.xephi.authme.command.executable.HelpCommand;
|
||||||
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.permission.DefaultPermission;
|
import fr.xephi.authme.permission.DefaultPermission;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.permission.PlayerPermission;
|
import fr.xephi.authme.permission.PlayerPermission;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
@ -35,12 +37,12 @@ import static org.mockito.Mockito.never;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link CommandHandler}.
|
* Test for {@link CommandMapper}.
|
||||||
*/
|
*/
|
||||||
public class CommandHandlerTest {
|
public class CommandMapperTest {
|
||||||
|
|
||||||
private static Set<CommandDescription> commands;
|
private static Set<CommandDescription> commands;
|
||||||
private static CommandHandler handler;
|
private static CommandMapper mapper;
|
||||||
private static PermissionsManager permissionsManagerMock;
|
private static PermissionsManager permissionsManagerMock;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -69,7 +71,7 @@ public class CommandHandlerTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUpMocks() {
|
public void setUpMocks() {
|
||||||
permissionsManagerMock = mock(PermissionsManager.class);
|
permissionsManagerMock = mock(PermissionsManager.class);
|
||||||
handler = new CommandHandler(commands, permissionsManagerMock);
|
mapper = new CommandMapper(commands, mock(Messages.class), permissionsManagerMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------
|
// -----------
|
||||||
@ -79,9 +81,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldMapPartsToLoginChildCommand() {
|
public void shouldMapPartsToLoginChildCommand() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("authme", "login", "test1");
|
List<String> parts = Arrays.asList("authme", "login", "test1");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("login", "authme")));
|
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("login", "authme")));
|
||||||
@ -96,9 +100,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldMapPartsToCommandWithNoCaseSensitivity() {
|
public void shouldMapPartsToCommandWithNoCaseSensitivity() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("Authme", "REG", "arg1", "arg2");
|
List<String> parts = Arrays.asList("Authme", "REG", "arg1", "arg2");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
||||||
@ -112,9 +118,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldRejectCommandWithTooManyArguments() {
|
public void shouldRejectCommandWithTooManyArguments() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("authme", "register", "pass123", "pass123", "pass123");
|
List<String> parts = Arrays.asList("authme", "register", "pass123", "pass123", "pass123");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
||||||
@ -128,9 +136,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldRejectCommandWithTooFewArguments() {
|
public void shouldRejectCommandWithTooFewArguments() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("authme", "Reg");
|
List<String> parts = Arrays.asList("authme", "Reg");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
||||||
@ -144,9 +154,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldSuggestCommandWithSimilarLabel() {
|
public void shouldSuggestCommandWithSimilarLabel() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("authme", "reh", "pass123", "pass123");
|
List<String> parts = Arrays.asList("authme", "reh", "pass123", "pass123");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
assertThat(result.getCommandDescription(), equalTo(getChildWithLabel("register", "authme")));
|
||||||
@ -161,9 +173,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldSuggestMostSimilarCommand() {
|
public void shouldSuggestMostSimilarCommand() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = Arrays.asList("authme", "asdfawetawty4asdca");
|
List<String> parts = Arrays.asList("authme", "asdfawetawty4asdca");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getCommandDescription(), not(nullValue()));
|
assertThat(result.getCommandDescription(), not(nullValue()));
|
||||||
@ -177,9 +191,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldHandleBaseWithWrongArguments() {
|
public void shouldHandleBaseWithWrongArguments() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = singletonList("unregister");
|
List<String> parts = singletonList("unregister");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.INCORRECT_ARGUMENTS));
|
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.INCORRECT_ARGUMENTS));
|
||||||
@ -193,9 +209,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldHandleUnknownBase() {
|
public void shouldHandleUnknownBase() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = asList("bogus", "label1", "arg1");
|
List<String> parts = asList("bogus", "label1", "arg1");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.MISSING_BASE_COMMAND));
|
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.MISSING_BASE_COMMAND));
|
||||||
@ -205,7 +223,7 @@ public class CommandHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldHandleNullInput() {
|
public void shouldHandleNullInput() {
|
||||||
// given / when
|
// given / when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(null);
|
FoundCommandResult result = mapper.mapPartsToCommand(mock(CommandSender.class), null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.MISSING_BASE_COMMAND));
|
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.MISSING_BASE_COMMAND));
|
||||||
@ -216,9 +234,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldMapToBaseWithProperArguments() {
|
public void shouldMapToBaseWithProperArguments() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = asList("Unreg", "player1");
|
List<String> parts = asList("Unreg", "player1");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.SUCCESS));
|
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.SUCCESS));
|
||||||
@ -232,9 +252,11 @@ public class CommandHandlerTest {
|
|||||||
public void shouldReturnChildlessBaseCommandWithArgCountError() {
|
public void shouldReturnChildlessBaseCommandWithArgCountError() {
|
||||||
// given
|
// given
|
||||||
List<String> parts = asList("unregistER", "player1", "wrongArg");
|
List<String> parts = asList("unregistER", "player1", "wrongArg");
|
||||||
|
CommandSender sender = mock(CommandSender.class);
|
||||||
|
given(permissionsManagerMock.hasPermission(eq(sender), any(CommandDescription.class))).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
FoundCommandResult result = handler.mapPartsToCommand(parts);
|
FoundCommandResult result = mapper.mapPartsToCommand(sender, parts);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.INCORRECT_ARGUMENTS));
|
assertThat(result.getResultStatus(), equalTo(FoundResultStatus.INCORRECT_ARGUMENTS));
|
||||||
@ -248,6 +270,7 @@ public class CommandHandlerTest {
|
|||||||
// processCommand() tests
|
// processCommand() tests
|
||||||
// ----------
|
// ----------
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void shouldCallMappedCommandWithArgs() {
|
public void shouldCallMappedCommandWithArgs() {
|
||||||
// given
|
// given
|
||||||
String bukkitLabel = "Authme";
|
String bukkitLabel = "Authme";
|
||||||
@ -258,11 +281,13 @@ public class CommandHandlerTest {
|
|||||||
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
handler.processCommand(sender, bukkitLabel, bukkitArgs);
|
// FIXME #306 Move to CommandHandler test
|
||||||
|
// mapper.processCommand(sender, bukkitLabel, bukkitArgs);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
||||||
verify(command.getExecutableCommand()).executeCommand(eq(sender), argsCaptor.capture());
|
verify(command.getExecutableCommand())
|
||||||
|
.executeCommand(eq(sender), argsCaptor.capture(), any(CommandService.class));
|
||||||
List<String> argument = argsCaptor.getValue();
|
List<String> argument = argsCaptor.getValue();
|
||||||
assertThat(argument, contains("myPass"));
|
assertThat(argument, contains("myPass"));
|
||||||
// Ensure that no error message was issued to the command sender
|
// Ensure that no error message was issued to the command sender
|
||||||
@ -270,6 +295,7 @@ public class CommandHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void shouldNotCallExecutableCommandIfNoPermission() {
|
public void shouldNotCallExecutableCommandIfNoPermission() {
|
||||||
// given
|
// given
|
||||||
String bukkitLabel = "unreg";
|
String bukkitLabel = "unreg";
|
||||||
@ -279,13 +305,14 @@ public class CommandHandlerTest {
|
|||||||
.willReturn(false);
|
.willReturn(false);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
handler.processCommand(sender, bukkitLabel, bukkitArgs);
|
// FIXME #306 Move to CommandHandler test
|
||||||
|
// mapper.processCommand(sender, bukkitLabel, bukkitArgs);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
CommandDescription command = getCommandWithLabel("unregister", commands);
|
CommandDescription command = getCommandWithLabel("unregister", commands);
|
||||||
verify(permissionsManagerMock).hasPermission(sender, command);
|
verify(permissionsManagerMock).hasPermission(sender, command);
|
||||||
verify(command.getExecutableCommand(), never())
|
verify(command.getExecutableCommand(), never())
|
||||||
.executeCommand(any(CommandSender.class), anyListOf(String.class));
|
.executeCommand(any(CommandSender.class), anyListOf(String.class), any(CommandService.class));
|
||||||
|
|
||||||
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
verify(sender).sendMessage(messageCaptor.capture());
|
verify(sender).sendMessage(messageCaptor.capture());
|
||||||
@ -294,6 +321,7 @@ public class CommandHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void shouldStripWhitespace() {
|
public void shouldStripWhitespace() {
|
||||||
// given
|
// given
|
||||||
String bukkitLabel = "AuthMe";
|
String bukkitLabel = "AuthMe";
|
||||||
@ -304,17 +332,20 @@ public class CommandHandlerTest {
|
|||||||
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
handler.processCommand(sender, bukkitLabel, bukkitArgs);
|
// FIXME #306 Move to CommandHandler test
|
||||||
|
// mapper.processCommand(sender, bukkitLabel, bukkitArgs);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
||||||
verify(command.getExecutableCommand()).executeCommand(eq(sender), argsCaptor.capture());
|
verify(command.getExecutableCommand())
|
||||||
|
.executeCommand(eq(sender), argsCaptor.capture(), any(CommandService.class));
|
||||||
List<String> arguments = argsCaptor.getValue();
|
List<String> arguments = argsCaptor.getValue();
|
||||||
assertThat(arguments, contains("testArg"));
|
assertThat(arguments, contains("testArg"));
|
||||||
verify(sender, never()).sendMessage(anyString());
|
verify(sender, never()).sendMessage(anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void shouldPassCommandPathAsArgumentsToHelpCommand() {
|
public void shouldPassCommandPathAsArgumentsToHelpCommand() {
|
||||||
// given
|
// given
|
||||||
String bukkitLabel = "email";
|
String bukkitLabel = "email";
|
||||||
@ -325,11 +356,13 @@ public class CommandHandlerTest {
|
|||||||
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
given(permissionsManagerMock.hasPermission(sender, command)).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
handler.processCommand(sender, bukkitLabel, bukkitArgs);
|
// FIXME #306 Move to CommandHandler test
|
||||||
|
// mapper.processCommand(sender, bukkitLabel, bukkitArgs);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
|
||||||
verify(command.getExecutableCommand()).executeCommand(eq(sender), argsCaptor.capture());
|
verify(command.getExecutableCommand())
|
||||||
|
.executeCommand(eq(sender), argsCaptor.capture(), any(CommandService.class));
|
||||||
List<String> arguments = argsCaptor.getValue();
|
List<String> arguments = argsCaptor.getValue();
|
||||||
assertThat(arguments, contains("email", "arg1"));
|
assertThat(arguments, contains("email", "arg1"));
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user