Implement flag permissions

This commit is contained in:
Frank van der Heijden 2021-07-23 16:48:55 +02:00 committed by Jason
parent 197b892100
commit 1b7fb2f34c
7 changed files with 91 additions and 10 deletions

View file

@ -88,4 +88,11 @@ public @interface Flag {
*/ */
@NonNull String description() default ""; @NonNull String description() default "";
/**
* The flag permission
*
* @return Flag permission
*/
@NonNull String permission() default "";
} }

View file

@ -30,6 +30,7 @@ import cloud.commandframework.arguments.flags.CommandFlag;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.arguments.parser.ParserParameters; import cloud.commandframework.arguments.parser.ParserParameters;
import cloud.commandframework.arguments.parser.ParserRegistry; import cloud.commandframework.arguments.parser.ParserRegistry;
import cloud.commandframework.permission.Permission;
import io.leangen.geantyref.TypeToken; import io.leangen.geantyref.TypeToken;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -61,7 +62,8 @@ final class FlagExtractor implements Function<@NonNull Method, Collection<@NonNu
final CommandFlag.Builder<Void> builder = this.commandManager final CommandFlag.Builder<Void> builder = this.commandManager
.flagBuilder(flag.value()) .flagBuilder(flag.value())
.withDescription(ArgumentDescription.of(flag.description())) .withDescription(ArgumentDescription.of(flag.description()))
.withAliases(flag.aliases()); .withAliases(flag.aliases())
.withPermission(Permission.of(flag.permission()));
if (parameter.getType().equals(boolean.class)) { if (parameter.getType().equals(boolean.class)) {
flags.add(builder.build()); flags.add(builder.build());
} else { } else {

View file

@ -218,7 +218,7 @@ public final class FlagArgument<C> extends CommandArgument<C, Object> {
final List<String> strings = new LinkedList<>(); final List<String> strings = new LinkedList<>();
/* Recommend "primary" flags */ /* Recommend "primary" flags */
for (final CommandFlag<?> flag : this.flags) { for (final CommandFlag<?> flag : this.flags) {
if (usedFlags.contains(flag)) { if (usedFlags.contains(flag) || !commandContext.hasPermission(flag.getCommandPermission())) {
continue; continue;
} }
strings.add( strings.add(
@ -231,7 +231,7 @@ public final class FlagArgument<C> extends CommandArgument<C, Object> {
/* Recommend aliases */ /* Recommend aliases */
final boolean suggestCombined = input.length() > 1 && input.charAt(0) == '-' && input.charAt(1) != '-'; final boolean suggestCombined = input.length() > 1 && input.charAt(0) == '-' && input.charAt(1) != '-';
for (final CommandFlag<?> flag : this.flags) { for (final CommandFlag<?> flag : this.flags) {
if (usedFlags.contains(flag)) { if (usedFlags.contains(flag) || !commandContext.hasPermission(flag.getCommandPermission())) {
continue; continue;
} }
for (final String alias : flag.getAliases()) { for (final String alias : flag.getAliases()) {
@ -279,7 +279,9 @@ public final class FlagArgument<C> extends CommandArgument<C, Object> {
} }
} }
} }
if (currentFlag != null && currentFlag.getCommandArgument() != null) { if (currentFlag != null
&& commandContext.hasPermission(currentFlag.getCommandPermission())
&& currentFlag.getCommandArgument() != null) {
return (List<String>) ((BiFunction) currentFlag.getCommandArgument().getSuggestionsProvider()) return (List<String>) ((BiFunction) currentFlag.getCommandArgument().getSuggestionsProvider())
.apply(commandContext, input); .apply(commandContext, input);
} }
@ -394,6 +396,12 @@ public final class FlagArgument<C> extends CommandArgument<C, Object> {
FailureReason.DUPLICATE_FLAG, FailureReason.DUPLICATE_FLAG,
commandContext commandContext
)); ));
} else if (!commandContext.hasPermission(currentFlag.getCommandPermission())) {
return ArgumentParseResult.failure(new FlagParseException(
string,
FailureReason.NO_PERMISSION,
commandContext
));
} }
parsedFlags.add(currentFlag); parsedFlags.add(currentFlag);
if (currentFlag.getCommandArgument() == null) { if (currentFlag.getCommandArgument() == null) {
@ -499,7 +507,8 @@ public final class FlagArgument<C> extends CommandArgument<C, Object> {
UNKNOWN_FLAG(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_UNKNOWN_FLAG), UNKNOWN_FLAG(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_UNKNOWN_FLAG),
DUPLICATE_FLAG(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_DUPLICATE_FLAG), DUPLICATE_FLAG(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_DUPLICATE_FLAG),
NO_FLAG_STARTED(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_NO_FLAG_STARTED), NO_FLAG_STARTED(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_NO_FLAG_STARTED),
MISSING_ARGUMENT(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT); MISSING_ARGUMENT(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT),
NO_PERMISSION(StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION);
private final Caption caption; private final Caption caption;

View file

@ -25,6 +25,8 @@ package cloud.commandframework.arguments.flags;
import cloud.commandframework.ArgumentDescription; import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.permission.CommandPermission;
import cloud.commandframework.permission.Permission;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -47,6 +49,7 @@ public final class CommandFlag<T> {
private final @NonNull String name; private final @NonNull String name;
private final @NonNull String @NonNull [] aliases; private final @NonNull String @NonNull [] aliases;
private final @NonNull ArgumentDescription description; private final @NonNull ArgumentDescription description;
private final @NonNull CommandPermission permission;
private final @Nullable CommandArgument<?, T> commandArgument; private final @Nullable CommandArgument<?, T> commandArgument;
@ -54,11 +57,13 @@ public final class CommandFlag<T> {
final @NonNull String name, final @NonNull String name,
final @NonNull String @NonNull [] aliases, final @NonNull String @NonNull [] aliases,
final @NonNull ArgumentDescription description, final @NonNull ArgumentDescription description,
final @NonNull CommandPermission permission,
final @Nullable CommandArgument<?, T> commandArgument final @Nullable CommandArgument<?, T> commandArgument
) { ) {
this.name = Objects.requireNonNull(name, "name cannot be null"); this.name = Objects.requireNonNull(name, "name cannot be null");
this.aliases = Objects.requireNonNull(aliases, "aliases cannot be null"); this.aliases = Objects.requireNonNull(aliases, "aliases cannot be null");
this.description = Objects.requireNonNull(description, "description cannot be null"); this.description = Objects.requireNonNull(description, "description cannot be null");
this.permission = Objects.requireNonNull(permission, "permission cannot be null");
this.commandArgument = commandArgument; this.commandArgument = commandArgument;
} }
@ -125,6 +130,15 @@ public final class CommandFlag<T> {
return this.commandArgument; return this.commandArgument;
} }
/**
* Get the command permission, if it exists
*
* @return Command permission, or {@code null}
*/
public CommandPermission getCommandPermission() {
return this.permission;
}
@Override @Override
public String toString() { public String toString() {
return String.format("--%s", this.name); return String.format("--%s", this.name);
@ -153,22 +167,25 @@ public final class CommandFlag<T> {
private final String name; private final String name;
private final String[] aliases; private final String[] aliases;
private final ArgumentDescription description; private final ArgumentDescription description;
private final CommandPermission permission;
private final CommandArgument<?, T> commandArgument; private final CommandArgument<?, T> commandArgument;
private Builder( private Builder(
final @NonNull String name, final @NonNull String name,
final @NonNull String[] aliases, final @NonNull String[] aliases,
final @NonNull ArgumentDescription description, final @NonNull ArgumentDescription description,
final @NonNull CommandPermission permission,
final @Nullable CommandArgument<?, T> commandArgument final @Nullable CommandArgument<?, T> commandArgument
) { ) {
this.name = name; this.name = name;
this.aliases = aliases; this.aliases = aliases;
this.description = description; this.description = description;
this.permission = permission;
this.commandArgument = commandArgument; this.commandArgument = commandArgument;
} }
private Builder(final @NonNull String name) { private Builder(final @NonNull String name) {
this(name, new String[0], ArgumentDescription.empty(), null); this(name, new String[0], ArgumentDescription.empty(), Permission.empty(), null);
} }
/** /**
@ -198,6 +215,7 @@ public final class CommandFlag<T> {
this.name, this.name,
filteredAliases.toArray(new String[0]), filteredAliases.toArray(new String[0]),
this.description, this.description,
this.permission,
this.commandArgument this.commandArgument
); );
} }
@ -214,7 +232,7 @@ public final class CommandFlag<T> {
return this.withDescription((ArgumentDescription) description); return this.withDescription((ArgumentDescription) description);
} }
/**d /**
* Create a new builder instance using the given flag description * Create a new builder instance using the given flag description
* *
* @param description Flag description * @param description Flag description
@ -222,7 +240,7 @@ public final class CommandFlag<T> {
* @since 1.4.0 * @since 1.4.0
*/ */
public Builder<T> withDescription(final @NonNull ArgumentDescription description) { public Builder<T> withDescription(final @NonNull ArgumentDescription description) {
return new Builder<>(this.name, this.aliases, description, this.commandArgument); return new Builder<>(this.name, this.aliases, description, this.permission, this.commandArgument);
} }
/** /**
@ -233,7 +251,7 @@ public final class CommandFlag<T> {
* @return New builder instance * @return New builder instance
*/ */
public <N> Builder<N> withArgument(final @NonNull CommandArgument<?, N> argument) { public <N> Builder<N> withArgument(final @NonNull CommandArgument<?, N> argument) {
return new Builder<>(this.name, this.aliases, this.description, argument); return new Builder<>(this.name, this.aliases, this.description, this.permission, argument);
} }
/** /**
@ -247,13 +265,24 @@ public final class CommandFlag<T> {
return this.withArgument(builder.build()); return this.withArgument(builder.build());
} }
/**
* Create a new builder instance using the given flag permission
*
* @param permission Flag permission
* @return New builder instance
* @since 1.6.0
*/
public Builder<T> withPermission(final @NonNull CommandPermission permission) {
return new Builder<>(this.name, this.aliases, this.description, permission, this.commandArgument);
}
/** /**
* Build a new command flag instance * Build a new command flag instance
* *
* @return Constructed instance * @return Constructed instance
*/ */
public @NonNull CommandFlag<T> build() { public @NonNull CommandFlag<T> build() {
return new CommandFlag<>(this.name, this.aliases, this.description, this.commandArgument); return new CommandFlag<>(this.name, this.aliases, this.description, this.permission, this.commandArgument);
} }
} }

View file

@ -80,6 +80,10 @@ public class SimpleCaptionRegistry<C> implements FactoryDelegatingCaptionRegistr
* Default caption for {@link StandardCaptionKeys#ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT} * Default caption for {@link StandardCaptionKeys#ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT}
*/ */
public static final String ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT = "Missing argument for '{flag}'"; public static final String ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT = "Missing argument for '{flag}'";
/**
* Default caption for {@link StandardCaptionKeys#ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION}
*/
public static final String ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION = "You don't have permission to use '{flag}'";
/** /**
* Default caption for {@link StandardCaptionKeys#ARGUMENT_PARSE_FAILURE_COLOR} * Default caption for {@link StandardCaptionKeys#ARGUMENT_PARSE_FAILURE_COLOR}
*/ */
@ -132,6 +136,10 @@ public class SimpleCaptionRegistry<C> implements FactoryDelegatingCaptionRegistr
StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT, StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT,
(caption, sender) -> ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT (caption, sender) -> ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT
); );
this.registerMessageFactory(
StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION,
(caption, sender) -> ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION
);
this.registerMessageFactory( this.registerMessageFactory(
StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_COLOR, StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_COLOR,
(caption, sender) -> ARGUMENT_PARSE_FAILURE_COLOR (caption, sender) -> ARGUMENT_PARSE_FAILURE_COLOR

View file

@ -84,6 +84,10 @@ public final class StandardCaptionKeys {
* Variables: {flag} * Variables: {flag}
*/ */
public static final Caption ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT = of("argument.parse.failure.flag.missing_argument"); public static final Caption ARGUMENT_PARSE_FAILURE_FLAG_MISSING_ARGUMENT = of("argument.parse.failure.flag.missing_argument");
/**
* Variables: {flag}
*/
public static final Caption ARGUMENT_PARSE_FAILURE_FLAG_NO_PERMISSION = of("argument.parse.failure.flag.no_permission");
/** /**
* Variables: {input} * Variables: {input}
*/ */

View file

@ -35,6 +35,7 @@ import cloud.commandframework.captions.SimpleCaptionVariableReplacementHandler;
import cloud.commandframework.keys.CloudKey; import cloud.commandframework.keys.CloudKey;
import cloud.commandframework.keys.CloudKeyHolder; import cloud.commandframework.keys.CloudKeyHolder;
import cloud.commandframework.keys.SimpleCloudKey; import cloud.commandframework.keys.SimpleCloudKey;
import cloud.commandframework.permission.CommandPermission;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -152,6 +153,27 @@ public final class CommandContext<C> {
return this.commandSender; return this.commandSender;
} }
/**
* Check whether the sender that executed the command has a permission.
*
* @param permission The permission
* @return Command sender
*/
public boolean hasPermission(final @NonNull CommandPermission permission) {
return this.commandManager.hasPermission(this.commandSender, permission);
}
/**
* Check whether the sender that executed the command has a permission.
*
* @param permission The permission
* @return Command sender
*/
public boolean hasPermission(final @NonNull String permission) {
return this.commandManager.hasPermission(this.commandSender, permission);
}
/** /**
* Check if this context was created for tab completion purposes * Check if this context was created for tab completion purposes
* *