Vampire / command-framework

A generic CDI-based command framework
Apache License 2.0
13 stars 5 forks source link

Allow restricting commands to arbitrary permission #6

Open Saladoc opened 1 year ago

Saladoc commented 1 year ago

What?

Allow restriction of a command to an arbitrary permission understood by discord (or rather javacord/jda) without having to create a custom Restriction implementation.

Why?

Use cases will most commonly be cases where a bot command reproduces a discord (moderation) functionality and should only be made available to users that have that capability, like:

Providing a functionality like this directly in command-framework will standardize handling. It will allow other code to better inspect the RestrictionChain and from that derive the actual permissions required - this will aid, for example, if slash commands are to be registered with the appropriate default permissions.

What it...

should be

might be

should not be

Problems / Thoughts

Such a system is not supported with the current annotation / restriction concept as far as I can see, so it will require some thought on how to properly integrate it. Maybe it could be implemented by adding a phase to hook into during creation of the commands where a user-provided bean could transform the command and for example check for custom annotations, parse them and add elements to the restriction chains - but those wouldn't play nicely with the @{All,Any,None}Of annotations.

Vampire commented 1 year ago

I'm not sure I understood why you cannot use the existing restriction system. For example something like.

@Override
public boolean allowCommand(CommandContext<? extends Message> commandContext) {
    Message message = commandContext.getMessage();
    return message
            .getServer()
            .flatMap(server ->
                    message
                            .getAuthor()
                            .asUser()
                            .map(user -> server.hasAnyPermission(user, KICK_MEMBERS, BAN_MEMBERS, ADMINISTRATOR))
            )
            .orElse(FALSE);
}
Saladoc commented 1 year ago

I'd prefer a way to have an annotation on the command or a mechanism where I can parse custom annotations into restrictions. That way the permissions can be transparently viewed in the code.

Maybe this can also be used for populating the default permissions for slash commands.

Vampire commented 1 year ago

How about

@Retention(RUNTIME)
@Target(TYPE)
@Documented
public @interface RestrictedToPermission {
    PermissionType[] value();
    boolean acceptAdmin();
}

and

@Override
public boolean allowCommand(CommandContext<? extends Message> commandContext) {
    Message message = commandContext.getMessage();
    RestrictedToPermission permissionsAnnotation = commandContext
            .getCommand()
            .orElseThrow(AssertionError::new)
            .getClass()
            .getAnnotation(RestrictedToPermission.class);
    if (permissionsAnnotation == null) {
        return true;
    }
    return message
            .getServer()
            .flatMap(server ->
                    message
                            .getAuthor()
                            .asUser()
                            .map(user -> ((permissionsAnnotation.acceptAdmin() && server.hasPermission(user, ADMINISTRATOR))
                                          || server.hasAnyPermission(user, permissionsAnnotation.value())))
            )
            .orElse(FALSE);
}

?