Add initial permission logic
This commit is contained in:
parent
a5748444ce
commit
6c813a209b
3 changed files with 124 additions and 19 deletions
|
|
@ -41,15 +41,18 @@ import java.util.Optional;
|
|||
*
|
||||
* @param <C> Command sender type
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class Command<C extends CommandSender> {
|
||||
|
||||
@Nonnull private final List<CommandComponent<C, ?>> components;
|
||||
@Nonnull private final CommandExecutionHandler<C> commandExecutionHandler;
|
||||
@Nullable private final Class<? extends C> senderType;
|
||||
@Nonnull private final String commandPermission;
|
||||
|
||||
protected Command(@Nonnull final List<CommandComponent<C, ?>> commandComponents,
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nullable final Class<? extends C> senderType) {
|
||||
@Nullable final Class<? extends C> senderType,
|
||||
@Nonnull final String commandPermission) {
|
||||
this.components = Objects.requireNonNull(commandComponents, "Command components may not be null");
|
||||
if (this.components.size() == 0) {
|
||||
throw new IllegalArgumentException("At least one command component is required");
|
||||
|
|
@ -67,6 +70,7 @@ public class Command<C extends CommandSender> {
|
|||
}
|
||||
this.commandExecutionHandler = commandExecutionHandler;
|
||||
this.senderType = senderType;
|
||||
this.commandPermission = commandPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -78,7 +82,7 @@ public class Command<C extends CommandSender> {
|
|||
@Nonnull
|
||||
public static <C extends CommandSender> Builder<C> newBuilder(@Nonnull final String commandName) {
|
||||
return new Builder<>(null, Collections.singletonList(StaticComponent.required(commandName)),
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>());
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -111,6 +115,16 @@ public class Command<C extends CommandSender> {
|
|||
return Optional.ofNullable(this.senderType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command permission
|
||||
*
|
||||
* @return Command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public String getCommandPermission() {
|
||||
return this.commandPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the longest chain of similar components for
|
||||
* two commands
|
||||
|
|
@ -135,13 +149,16 @@ public class Command<C extends CommandSender> {
|
|||
@Nonnull private final List<CommandComponent<C, ?>> commandComponents;
|
||||
@Nonnull private final CommandExecutionHandler<C> commandExecutionHandler;
|
||||
@Nullable private final Class<? extends C> senderType;
|
||||
@Nonnull private final String commandPermission;
|
||||
|
||||
private Builder(@Nullable final Class<? extends C> senderType,
|
||||
@Nonnull final List<CommandComponent<C, ?>> commandComponents,
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler) {
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nonnull final String commandPermission) {
|
||||
this.commandComponents = commandComponents;
|
||||
this.commandExecutionHandler = commandExecutionHandler;
|
||||
this.senderType = senderType;
|
||||
this.commandPermission = commandPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -155,7 +172,7 @@ public class Command<C extends CommandSender> {
|
|||
public <T> Builder<C> withComponent(@Nonnull final CommandComponent<C, T> component) {
|
||||
final List<CommandComponent<C, ?>> commandComponents = new LinkedList<>(this.commandComponents);
|
||||
commandComponents.add(component);
|
||||
return new Builder<>(this.senderType, commandComponents, this.commandExecutionHandler);
|
||||
return new Builder<>(this.senderType, commandComponents, this.commandExecutionHandler, this.commandPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -166,7 +183,7 @@ public class Command<C extends CommandSender> {
|
|||
*/
|
||||
@Nonnull
|
||||
public Builder<C> withHandler(@Nonnull final CommandExecutionHandler<C> commandExecutionHandler) {
|
||||
return new Builder<>(this.senderType, this.commandComponents, commandExecutionHandler);
|
||||
return new Builder<>(this.senderType, this.commandComponents, commandExecutionHandler, this.commandPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -177,7 +194,18 @@ public class Command<C extends CommandSender> {
|
|||
*/
|
||||
@Nonnull
|
||||
public Builder<C> withSenderType(@Nonnull final Class<? extends C> senderType) {
|
||||
return new Builder<>(senderType, this.commandComponents, this.commandExecutionHandler);
|
||||
return new Builder<>(senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a command permission
|
||||
*
|
||||
* @param permission Command permission
|
||||
* @return New builder instance using the command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public Builder<C> withPermission(@Nonnull final String permission) {
|
||||
return new Builder<>(this.senderType, this.commandComponents, this.commandExecutionHandler, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -187,9 +215,8 @@ public class Command<C extends CommandSender> {
|
|||
*/
|
||||
@Nonnull
|
||||
public Command<C> build() {
|
||||
return new Command<>(Collections.unmodifiableList(this.commandComponents),
|
||||
this.commandExecutionHandler,
|
||||
this.senderType);
|
||||
return new Command<>(Collections.unmodifiableList(this.commandComponents), this.commandExecutionHandler,
|
||||
this.senderType, this.commandPermission);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,11 @@ import javax.annotation.Nonnull;
|
|||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
|
|
@ -84,10 +86,18 @@ public class CommandTree<C extends CommandSender> {
|
|||
private Optional<Command<C>> parseCommand(@Nonnull final CommandContext<C> commandContext,
|
||||
@Nonnull final Queue<String> commandQueue,
|
||||
@Nonnull final Node<CommandComponent<C, ?>> root) throws NoSuchCommandException {
|
||||
if (!this.isPermitted(commandContext.getCommandSender(), root)) {
|
||||
/* TODO: Send not allowed */
|
||||
throw new RuntimeException("Nope!");
|
||||
}
|
||||
final List<Node<CommandComponent<C, ?>>> children = root.getChildren();
|
||||
if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticComponent)) {
|
||||
// The value has to be a variable
|
||||
final Node<CommandComponent<C, ?>> child = children.get(0);
|
||||
if (!this.isPermitted(commandContext.getCommandSender(), child)) {
|
||||
/* TODO: Send not allowed */
|
||||
throw new RuntimeException("Nope!");
|
||||
}
|
||||
if (child.getValue() != null) {
|
||||
if (commandQueue.isEmpty()) {
|
||||
if (child.isLeaf()) {
|
||||
|
|
@ -120,7 +130,7 @@ public class CommandTree<C extends CommandSender> {
|
|||
throw new InvalidSyntaxException(this.commandManager.getCommandSyntaxFormatter()
|
||||
.apply(Objects.requireNonNull(child.getValue()
|
||||
.getOwningCommand())
|
||||
.getComponents()),
|
||||
.getComponents()),
|
||||
commandContext.getCommandSender(), this.getChain(root)
|
||||
.stream()
|
||||
.map(Node::getValue)
|
||||
|
|
@ -153,11 +163,17 @@ public class CommandTree<C extends CommandSender> {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
} else {
|
||||
/* TODO: Indicate that we could not resolve the command here */
|
||||
final List<CommandComponent<C, ?>> components = this.getChain(root)
|
||||
.stream()
|
||||
.map(Node::getValue)
|
||||
.collect(Collectors.toList());
|
||||
/* Too many arguments. We have a unique path, so we can send the entire context */
|
||||
throw new InvalidSyntaxException(this.commandManager.getCommandSyntaxFormatter()
|
||||
.apply(Objects.requireNonNull(
|
||||
Objects.requireNonNull(root.getValue())
|
||||
.getOwningCommand())
|
||||
.getComponents()),
|
||||
commandContext.getCommandSender(), this.getChain(root)
|
||||
.stream()
|
||||
.map(Node::getValue)
|
||||
.collect(
|
||||
Collectors.toList()));
|
||||
}
|
||||
} else {
|
||||
final Iterator<Node<CommandComponent<C, ?>>> childIterator = root.getChildren().iterator();
|
||||
|
|
@ -178,7 +194,6 @@ public class CommandTree<C extends CommandSender> {
|
|||
getChain(root).stream().map(Node::getValue).collect(Collectors.toList()),
|
||||
stringOrEmpty(commandQueue.peek()));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public List<String> getSuggestions(@Nonnull final CommandContext<C> context, @Nonnull final Queue<String> commandQueue) {
|
||||
|
|
@ -188,6 +203,11 @@ public class CommandTree<C extends CommandSender> {
|
|||
public List<String> getSuggestions(@Nonnull final CommandContext<C> commandContext,
|
||||
@Nonnull final Queue<String> commandQueue,
|
||||
@Nonnull final Node<CommandComponent<C, ?>> root) {
|
||||
|
||||
/* If the sender isn't allowed to access the root node, no suggestions are needed */
|
||||
if (!this.isPermitted(commandContext.getCommandSender(), root)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<Node<CommandComponent<C, ?>>> children = root.getChildren();
|
||||
if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticComponent)) {
|
||||
// The value has to be a variable
|
||||
|
|
@ -235,11 +255,10 @@ public class CommandTree<C extends CommandSender> {
|
|||
}
|
||||
final List<String> suggestions = new LinkedList<>();
|
||||
for (final Node<CommandComponent<C, ?>> component : root.getChildren()) {
|
||||
if (component.getValue() == null) {
|
||||
if (component.getValue() == null || !this.isPermitted(commandContext.getCommandSender(), component)) {
|
||||
continue;
|
||||
}
|
||||
suggestions.addAll(
|
||||
component.getValue().getParser().suggestions(commandContext, stringOrEmpty(commandQueue.peek())));
|
||||
suggestions.addAll(component.getValue().getParser().suggestions(commandContext, stringOrEmpty(commandQueue.peek())));
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
|
@ -278,6 +297,27 @@ public class CommandTree<C extends CommandSender> {
|
|||
this.verifyAndRegister();
|
||||
}
|
||||
|
||||
private boolean isPermitted(@Nonnull final C sender, @Nonnull final Node<CommandComponent<C, ?>> node) {
|
||||
final String permission = node.nodeMeta.get("permission");
|
||||
if (permission != null) {
|
||||
return sender.hasPermission(permission);
|
||||
}
|
||||
if (node.isLeaf()) {
|
||||
// noinspection all
|
||||
return sender.hasPermission(node.value.getOwningCommand().getCommandPermission());
|
||||
}
|
||||
/*
|
||||
if any of the children would permit the execution, then the sender has a valid
|
||||
chain to execute, and so we allow them to execute the root
|
||||
*/
|
||||
for (final Node<CommandComponent<C, ?>> child : node.getChildren()) {
|
||||
if (this.isPermitted(sender, child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all commands and register them, and verify the
|
||||
* command tree contracts
|
||||
|
|
@ -299,6 +339,24 @@ public class CommandTree<C extends CommandSender> {
|
|||
this.commandRegistrationHandler.registerCommand(leaf.getOwningCommand());
|
||||
}
|
||||
});
|
||||
// Register command permissions
|
||||
this.getLeavesRaw(this.internalTree).forEach(node -> {
|
||||
/* All leaves must necessarily have an owning command */
|
||||
// noinspection all
|
||||
node.nodeMeta.put("permission", node.getValue().getOwningCommand().getCommandPermission());
|
||||
// Get chain and order it tail->head then skip the tail (leaf node)
|
||||
List<Node<CommandComponent<C, ?>>> chain = this.getChain(node);
|
||||
Collections.reverse(chain);
|
||||
chain = chain.subList(1, chain.size());
|
||||
// Go through all nodes from the tail upwards until a collision occurs
|
||||
for (final Node<CommandComponent<C, ?>> commandComponentNode : chain) {
|
||||
if (commandComponentNode.nodeMeta.containsKey("permission")) {
|
||||
commandComponentNode.nodeMeta.remove("permission");
|
||||
break;
|
||||
}
|
||||
commandComponentNode.nodeMeta.put("permission", node.nodeMeta.get("permission"));
|
||||
}
|
||||
});
|
||||
/* TODO: Figure out a way to register all combinations along a command component path */
|
||||
}
|
||||
|
||||
|
|
@ -316,6 +374,18 @@ public class CommandTree<C extends CommandSender> {
|
|||
node.children.forEach(this::checkAmbiguity);
|
||||
}
|
||||
|
||||
private List<Node<CommandComponent<C, ?>>> getLeavesRaw(@Nonnull final Node<CommandComponent<C, ?>> node) {
|
||||
final List<Node<CommandComponent<C, ?>>> leaves = new LinkedList<>();
|
||||
if (node.isLeaf()) {
|
||||
if (node.getValue() != null) {
|
||||
leaves.add(node);
|
||||
}
|
||||
} else {
|
||||
node.children.forEach(child -> leaves.addAll(getLeavesRaw(child)));
|
||||
}
|
||||
return leaves;
|
||||
}
|
||||
|
||||
private List<CommandComponent<C, ?>> getLeaves(@Nonnull final Node<CommandComponent<C, ?>> node) {
|
||||
final List<CommandComponent<C, ?>> leaves = new LinkedList<>();
|
||||
if (node.isLeaf()) {
|
||||
|
|
@ -342,6 +412,7 @@ public class CommandTree<C extends CommandSender> {
|
|||
|
||||
private static final class Node<T> {
|
||||
|
||||
private final Map<String, String> nodeMeta = new HashMap<>();
|
||||
private final List<Node<T>> children = new LinkedList<>();
|
||||
private final T value;
|
||||
private Node<T> parent;
|
||||
|
|
|
|||
|
|
@ -23,5 +23,12 @@
|
|||
//
|
||||
package com.intellectualsites.commands.sender;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public interface CommandSender {
|
||||
|
||||
default boolean hasPermission(@Nonnull final String permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue