Roles are a powerful feature in Discord, and admittedly have been one of the hardest parts to master in discord.js. This walkthrough aims at explaining how roles and permissions work. We'll also explore how to use roles to protect your commands.
Let's start with a basic overview of the hierarchy of roles in Discord.
... or actually not, they already explain it better than I care to: Role Management 101. Read up on that, then come back here. I'll wait. (Yeah I know that's cheesy, so sue me).
Let's get down to brass tacks. You want to know how to use roles and permissions in your bot.
This is the "easy" part once you actually get used to it. It's just like getting any other Collection element, but here's a reminder anyway!
// get role by ID
let myRole = message.guild.roles.get("264410914592129025");
// get role by name
let myRole = message.guild.roles.find(role => role.name === "Moderators");
{% hint style="info" %}
To get a role ID, mention the role with a \
before it in a Discord channel (e.g. \@rolename
). You can then grab the ID from the output message. Right-clicking a role does nothing in the UI, there's currently no way to get it from there.
{% endhint %}
In a message
handler, you have access to checking the GuildMember class of the message author:
// assuming role.id is an actual ID of a valid role:
if(message.member.roles.has(role.id)) {
console.log(`Yay, the author of the message has the role!`);
} else {
console.log(`Nope, noppers, nadda.`);
}
// Check if they have one of many roles
if(message.member.roles.some(r=>["Dev", "Mod", "Server Staff", "Proficient"].includes(r.name)) ) {
// has one of the roles
} else {
// has none of the roles
}
{% hint style="info" %} To grab members and users in different ways see the FAQ Page. {% endhint %}
let roleID = "264410914592129025";
let membersWithRole = message.guild.roles.get(roleID).members;
console.log(`Got ${membersWithRole.size} members with that role.`);
Alright, now that you have roles, you probably want to add a member to a role. Simple enough! Discord.js provides 2 handy methods to add, and remove, a role. Let's look at them!
let role = message.guild.roles.find(r => r.name === "Team Mystic");
// Let's pretend you mentioned the user you want to add a role to (!addrole @user Role Name):
let member = message.mentions.members.first();
// or the person who made the command: let member = message.member;
// Add the role!
member.addRole(role).catch(console.error);
// Remove a role!
member.removeRole(role).catch(console.error);
Alright I feel like I have to add a little precision here on implementation:
- You can not add or remove a role that is higher than the bot's. This should be obvious.
- The bot requires
MANAGE_ROLES
permissions for this. You can check for it using the code further down this page. - Because of global rate limits, you cannot do 2 role "actions" immediately one after the other. The first action will work, the second will not. You can go around that by using
<GuildMember>.setRoles([array, of, roles])
. This will overwrite all existing roles and only apply the ones in the array so be careful with it.
To check for a single permission override on a channel:
// Getting all permissions for a member on a channel.
let perms = message.channel.permissionsFor(message.member);
// Checks for Manage Messages permissions.
let can_manage_chans = message.channel.permissionsFor(message.member).has("MANAGE_MESSAGES", false);
// View permissions as an object (useful for debugging or eval)
message.channel.permissionsFor(message.member).serialize(false)
Note: We pass
false
for the checkAdmin parameter because Administrator channel overwrites don't implicently grant any permissions, unlike in Roles or when you are the Guild Owner. (The API will allow you to create an overwrite with Administrator, and even tell D.JS that a channel overwrite has had Administrator permissions set. Discord devs have stated this is intended behavior.)
Just as easy, wooh!
let perms = message.member.permissions;
// Check if a member has a specific permission on the guild!
let has_kick = perms.has("KICK_MEMBERS");
ezpz, right?
Now get to coding!
This is the list of internal permission names, used for .has(name)
in the above examples:
{
CREATE_INSTANT_INVITE: true,
KICK_MEMBERS: true,
BAN_MEMBERS: true,
ADMINISTRATOR: true,
MANAGE_CHANNELS: true,
MANAGE_GUILD: true,
ADD_REACTIONS: true,
READ_MESSAGES: true,
SEND_MESSAGES: true,
SEND_TTS_MESSAGES: true,
MANAGE_MESSAGES: true,
EMBED_LINKS: true,
ATTACH_FILES: true,
READ_MESSAGE_HISTORY: true,
MENTION_EVERYONE: true,
EXTERNAL_EMOJIS: true,
CONNECT: true,
SPEAK: true,
MUTE_MEMBERS: true,
DEAFEN_MEMBERS: true,
MOVE_MEMBERS: true,
USE_VAD: true,
CHANGE_NICKNAME: true,
MANAGE_NICKNAMES: true,
MANAGE_ROLES_OR_PERMISSIONS: true,
MANAGE_WEBHOOKS: true,
MANAGE_EMOJIS: true
}