Add support for CommandPermission annotation as parameter for permiss… (#197)

…ions by Optional annotation

In the past we could not handle a permission in relation to the presence of an optional argument, it forced us to manage it in the body of the command, and could be repetitive and boring, note that it also works with the annotation Default
This commit is contained in:
Kévin Jimenez
2019-03-09 17:03:04 +01:00
committed by Daniel Ennis
parent d7477cb732
commit d2754b99c9
5 changed files with 58 additions and 16 deletions
@@ -27,9 +27,10 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"WeakerAccess"})
public class CommandExecutionContext <CEC extends CommandExecutionContext, I extends CommandIssuer> {
public class CommandExecutionContext<CEC extends CommandExecutionContext, I extends CommandIssuer> {
private final RegisteredCommand cmd;
private final CommandParameter param;
protected final I issuer;
@@ -69,7 +70,7 @@ public class CommandExecutionContext <CEC extends CommandExecutionContext, I ext
}
public boolean isLastArg() {
return cmd.parameters.length -1 == index;
return cmd.parameters.length - 1 == index;
}
public int getNumParams() {
@@ -108,6 +109,10 @@ public class CommandExecutionContext <CEC extends CommandExecutionContext, I ext
return null;
}
public Set<String> getPermissions() {
return param.getPermissions();
}
public boolean isOptional() {
return param.isOptional();
}
@@ -170,6 +175,7 @@ public class CommandExecutionContext <CEC extends CommandExecutionContext, I ext
/**
* This method will not support annotation processors!! use getAnnotationValue or hasAnnotation
*
* @deprecated Use {@link #getAnnotationValue(Class)}
*/
@Deprecated
@@ -226,6 +232,7 @@ public class CommandExecutionContext <CEC extends CommandExecutionContext, I ext
public String joinArgs() {
return ACFUtil.join(args, " ");
}
public String joinArgs(String sep) {
return ACFUtil.join(args, sep);
}
@@ -23,6 +23,7 @@
package co.aikar.commands;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Conditions;
import co.aikar.commands.annotation.Default;
import co.aikar.commands.annotation.Description;
@@ -37,10 +38,13 @@ import co.aikar.commands.contexts.IssuerOnlyContextResolver;
import co.aikar.commands.contexts.OptionalContextResolver;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extends CommandIssuer>> {
public class CommandParameter<CEC extends CommandExecutionContext<CEC, ? extends CommandIssuer>> {
private final Parameter parameter;
private final Class<?> type;
private final String name;
@@ -49,6 +53,8 @@ public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extend
private ContextResolver<?, CEC> resolver;
private boolean optional;
private Set<String> permissions = new HashSet<>();
private String permission;
private String description;
private String defaultValue;
private String syntax;
@@ -82,6 +88,7 @@ public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extend
}
this.optional = annotations.hasAnnotation(param, Optional.class) || this.defaultValue != null || (isLast && type == String[].class);
this.permission = annotations.getAnnotationValue(param, CommandPermission.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);
this.optionalResolver = isOptionalResolver(resolver);
this.requiresInput = !this.optional && !this.optionalResolver;
//noinspection unchecked
@@ -109,6 +116,7 @@ public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extend
parseFlags(flags);
}
inheritContextFlags(command.scope);
this.computePermissions();
}
private void inheritContextFlags(BaseCommand scope) {
@@ -134,10 +142,17 @@ public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extend
}
}
private void computePermissions() {
this.permissions.clear();
if (this.permission != null && !this.permission.isEmpty()) {
this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission)));
}
}
private boolean isOptionalResolver(ContextResolver<?, CEC> resolver) {
return resolver instanceof IssuerAwareContextResolver
|| resolver instanceof IssuerOnlyContextResolver
|| resolver instanceof OptionalContextResolver;
|| resolver instanceof IssuerOnlyContextResolver
|| resolver instanceof OptionalContextResolver;
}
@@ -256,4 +271,8 @@ public class CommandParameter <CEC extends CommandExecutionContext<CEC, ? extend
public void setConditions(String conditions) {
this.conditions = conditions;
}
public Set<String> getPermissions() {
return permissions;
}
}
@@ -226,11 +226,13 @@ public class RegisteredCommand<CEC extends CommandExecutionContext<CEC, ? extend
if (requiresInput && remainingRequired > 0) {
remainingRequired--;
}
if (args.isEmpty() && !(isLast && type == String[].class)) {
if (allowOptional && parameter.getDefaultValue() != null) {
args.add(parameter.getDefaultValue());
} else if (allowOptional && parameter.isOptional()) {
Object value = parameter.isOptionalResolver() ? resolver.getContext(context) : null;
if (value == null && parameter.getClass().isPrimitive()) {
throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional.");
}
@@ -244,6 +246,7 @@ public class RegisteredCommand<CEC extends CommandExecutionContext<CEC, ? extend
return null;
}
}
if (parameter.getValues() != null) {
String arg = !args.isEmpty() ? args.get(0) : "";
@@ -258,13 +261,27 @@ public class RegisteredCommand<CEC extends CommandExecutionContext<CEC, ? extend
possible.add(s.toLowerCase());
}
}
if (!possible.contains(arg.toLowerCase())) {
throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF,
"{valid}", ACFUtil.join(possible, ", "));
}
}
Object paramValue = resolver.getContext(context);
Set<String> parameterPermissions = parameter.getPermissions();
if (!parameter.isOptionalResolver() && parameterPermissions != null && !parameterPermissions.isEmpty()) {
if (allowOptional && parameter.isOptional()) {
for (String perm : parameterPermissions) {
if (!perm.isEmpty() && !sender.hasPermission(perm)) {
sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED);
return null;
}
}
} else {
throw new IllegalStateException("Using CommandPermission annotation on parameter that is not optional is useless and you should not do it.");
}
}
//noinspection unchecked
this.manager.conditions.validateConditions(context, paramValue);
passedArgs.put(parameterName, paramValue);
@@ -30,11 +30,11 @@ import java.lang.annotation.Target;
/**
* Sets the permission required to perform this command.
*
* <p>
* Permission format will vary based on implementation platform
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
public @interface CommandPermission {
String value();
}