Skip to content

Permissions

pumbas600 edited this page Jan 4, 2022 · 18 revisions

Halpbot provides support for three different ways of determining if a member has permission to use a command. These three different ways can all be used in conjunction with each other in the @Permissions decorator. These are summarised below:

  1. Using JDA's built-in Permission enum to check the member's permissions.
  2. Defining permission suppliers which verifies if a member has the permission by calling a custom method.
  3. Binding roles to permissions and checking if the member has the necessary roles.

For basic usage of the @Permissions decorator and some examples, refer to the documentation here.

Permission Suppliers

Permission suppliers are methods annotated with @PermissionSupplier that only take in a Guild and Member (In that order) and return a boolean, defining if the member has the specified permission within that guild. The class these methods are defined in must be annotated with @Service for them to be automatically registered. Halpbot comes with two permission suppliers built-in:

Permission Description
HalpbotPermissions.BOT_OWNER Returns true if the member is the owner of the bot defined in the bot-config.
HalpbotPermissions.GUILD_OWNER Returns true if the member is the owner of the guild that the action was invoked in.

NOTE: Permission suppliers will be automatically registered on startup. If they don't match the requirements defined previously, then a warning will be logged into the console and the permission supplier ignored.

Example:

Consider the permission suppliers for the built-in BOT_OWNER and GUILD_OWNER permissions. Notice that you can inject dependencies into the class if needed.

Show Imports

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;

import org.dockbox.hartshorn.core.annotations.stereotype.Service;

import javax.inject.Inject;

import nz.pumbas.halpbot.HalpbotCore;
@Service
public class HalpbotPermissions
{
    @Inject private HalpbotCore halpbotCore;

    public static final String BOT_OWNER = "halpbot.bot.owner";
    public static final String GUILD_OWNER = "halpbot.guild.owner";

    @PermissionSupplier(GUILD_OWNER)
    public boolean isGuildOwner(Guild guild, Member member) {
        return guild.getOwnerIdLong() == member.getIdLong();
    }

    @PermissionSupplier(BOT_OWNER)
    public boolean isBotOwner(Guild guild, Member member) {
        return this.halpbotCore.ownerId() == member.getIdLong();
    }
}

They can then be used in the permissions field of the annotation like so:

Show Imports

import nz.pumbas.halpbot.commands.annotations.Command;
import nz.pumbas.halpbot.permissions.HalpbotPermissions;
import nz.pumbas.halpbot.permissions.Permissions;
@Permissions(permissions = HalpbotPermissions.GUILD_OWNER)
@Command(description = "Tests the @Permissions decorator")
public String permission() {
    return "This command is restricted to people who own the guild this command was invoked in";
}

Role Binding

Role binding allows you to create custom string-based permissions that must be bound to a discord role. When checking if someone has a bound permission, it then just needs to check if they have the appropriate role. This means you can easily assign permissions to groups of individuals within a discord without having to manually assign the permission to each person, or store the individual users with the permission. By default, role binding is disabled as it requires creating an embedded Derby database to keep track of the role bindings for each guild. To enable it, add the following to your bot-config.properties file:

useRoleBinding=true

This will automatically generate the database and handle all the role binding without you needing to install any additional software. If you want to use a different database (Or other persistent solution) you can override the PermissionService with a custom implementation. You can read more about creating custom implementations here.

NOTE: If you have role binding disabled in your bot-config but have custom permissions specified in your @Permissions decorators an error will be raised during startup.

Defining custom permissions

Any permissions that you specify in @Permissions#permissions which aren't permission suppliers are automatically treated as bindable roles, for example, in the following commands, the bindable permissions are halpbot.example.testA and halpbot.example.testB.

Show Imports

import nz.pumbas.halpbot.commands.annotations.Command;
import nz.pumbas.halpbot.permissions.Permissions;
@Permissions(permissions = "halpbot.example.testA")
@Command(description = "Tests custom permissions")
public String customPermissions() {
    return "This command is restricted to people with the *halpbot.example.testA* permission";
}

// Note: This combination of permissions doesn't really make sense and is only for demonstration purposes.
@Permissions(permissions = {"halpbot.example.testB", HalpbotPermissions.GUILD_OWNER})
@Command(description = "Tests multiple custom permissions")
public String multipleCustomPermissions() {
    return "This command is restricted to people with the *halpbot.example.testB* permission and are the guild owner";
}

Binding roles within a guild

The next step is to actually bind the permissions to roles. This can be achieved by using the built-in guildPermissions and bind permissions. Both of these permissions require the MANAGE_PERMISSIONS permission.

The guildPermissions command allows you to see the current role buildings for a guild. By default, all the permissions will be Unbound:

guildPermissions

bind <permission> <role> allows you to bind a permission to a role:

roleBinding

Now when you check the guildPermissions again, you'll see the permissions have been successfully bound:

guildPermissions

Deleting old permissions

If you remove a custom permission from the permissions field of @Permissions, then it will automatically be deleted from the database during the next startup to prevent unnecessary storage of deprecated permissions. The deleted permissions will be logged to the console for your information:

23:41:09.558 [ main           ] @ 19848 -> n.p.h.p.HalpbotPermissionService       INFO  - Deleting the following deprecated permissions from the database: halpbot.example.testA 

Permission Service

The PermissionService is an interface that abstracts away the specific implementation and can be safely injected as a dependency where necessary. The service is responsible for managing/storing the permissions suppliers and bindable permissions previously mentioned. The permission service is not responsible for locating the permission suppliers as this is automatically done by the PermissionSupplierServicePreProcessor. If you wish to tell if a member has one of JDA's built-in Permissions then you should use the appropriate Member#hasPermission method.

The PermissionService also allows you to check if a string is a permission, whether a User or Member has that permission(s) along with the methods to save, update or delete GuildPermissions (The entity containing a bound permission for a guild).

If you want to create your own PermissionService implementation, that can easily be done as described by the documentation here.