Skip to content

Commit

Permalink
Allow commands to be limited to certain roles (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lakelezz authored and arqunis committed Sep 5, 2017
1 parent 673852f commit d925f92
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/framework/standard/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub struct Command {
pub max_args: Option<i32>,
/// Permissions required to use this command.
pub required_permissions: Permissions,
/// Roles allowed to use this command.
pub allowed_roles: Vec<String>,
/// Whether command should be displayed in help list or not, used by other commands.
pub help_available: bool,
/// Whether command can be used only privately or not.
Expand Down Expand Up @@ -86,6 +88,7 @@ impl Command {
max_args: None,
owners_only: false,
required_permissions: Permissions::empty(),
allowed_roles: Vec::new(),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/framework/standard/create_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ impl CreateCommand {

self
}

/// Sets roles that are allowed to use the command.
pub fn allowed_roles(mut self, allowed_roles: Vec<&str>) -> Self {
self.0.allowed_roles = allowed_roles.iter().map(|x| x.to_string()).collect();

self
}
}

impl Default for Command {
Expand All @@ -226,6 +233,7 @@ impl Default for Command {
guild_only: false,
help_available: true,
owners_only: false,
allowed_roles: Vec::new(),
}
}
}
70 changes: 61 additions & 9 deletions src/framework/standard/help_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use std::fmt::Write;
use super::command::InternalCommand;
use super::{Args, Command, CommandGroup, CommandOrAlias};
use client::Context;
use model::{ChannelId, Message};
use model::{ChannelId, Guild, Member, Message};
use utils::Colour;

fn error_embed(channel_id: &ChannelId, input: &str) {
Expand All @@ -50,6 +50,17 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
result
}

fn right_roles(cmd: &Command, guild: &Guild, member: &Member) -> bool {
if cmd.allowed_roles.len() > 0 {
cmd.allowed_roles
.iter()
.flat_map(|r| guild.role_by_name(&r))
.any(|g| member.roles.contains(&g.id))
} else {
true
}
}

/// Posts an embed showing each individual command group and its commands.
///
/// # Examples
Expand Down Expand Up @@ -89,6 +100,19 @@ pub fn with_embeds(_: &mut Context,
if name == with_prefix || name == *command_name {
match *command {
CommandOrAlias::Command(ref cmd) => {
if cmd.allowed_roles.len() > 0 {
if let Some(guild) = msg.guild() {
let guild = guild.read().unwrap();
if let Some(member) = guild.members.get(&msg.author.id) {
if let Ok(permissions) = member.permissions() {
if !permissions.administrator() &&
!right_roles(&cmd, &guild, &member) {
break;
}
}
}
}
}
found = Some((command_name, cmd));
},
CommandOrAlias::Alias(ref name) => {
Expand Down Expand Up @@ -188,17 +212,25 @@ pub fn with_embeds(_: &mut Context,
let cmd = &commands[name];

if cmd.help_available {
let _ = write!(desc, "`{}`\n", name);

has_commands = true;
if let Some(guild) = msg.guild() {
let guild = guild.read().unwrap();
if let Some(member) = guild.members.get(&msg.author.id) {
if let Ok(permissions) = member.permissions() {
if cmd.help_available &&
(right_roles(&cmd, &guild, &member) ||
permissions.administrator()) {
let _ = write!(desc, "`{}`\n", name);
has_commands = true;
}
}
}
}
}
}

if has_commands {
e = e.field(|f| f.name(group_name).value(&desc));
}
}

e
})
});
Expand Down Expand Up @@ -245,6 +277,19 @@ pub fn plain(_: &mut Context,
if name == with_prefix || name == *command_name {
match *command {
CommandOrAlias::Command(ref cmd) => {
if cmd.allowed_roles.len() > 0 {
if let Some(guild) = msg.guild() {
let guild = guild.read().unwrap();
if let Some(member) = guild.members.get(&msg.author.id) {
if let Ok(permissions) = member.permissions() {
if !permissions.administrator() &&
!right_roles(&cmd, &guild, &member) {
break;
}
}
}
}
}
found = Some((command_name, cmd));
},
CommandOrAlias::Alias(ref name) => {
Expand Down Expand Up @@ -322,9 +367,16 @@ pub fn plain(_: &mut Context,

for name in command_names {
let cmd = &commands[name];

if cmd.help_available {
let _ = write!(group_help, "`{}` ", name);
if let Some(guild) = msg.guild() {
let guild = guild.read().unwrap();
if let Some(member) = guild.members.get(&msg.author.id) {
if let Ok(permissions) = member.permissions() {
if cmd.help_available &&
(permissions.administrator() || right_roles(&cmd, &guild, &member)) {
let _ = write!(group_help, "`{}` ", name);
}
}
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/framework/standard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ pub enum DispatchError {
OnlyForGuilds,
/// When the requested command can only be used by bot owners.
OnlyForOwners,
/// When the requested command requires one role.
LackingRole,
/// When there are too few arguments.
NotEnoughArguments { min: i32, given: usize },
/// When there are too many arguments.
Expand Down Expand Up @@ -521,6 +523,22 @@ impl StandardFramework {
} else if self.configuration.disabled_commands.contains(built) {
Some(DispatchError::CommandDisabled(built.to_owned()))
} else {
if command.allowed_roles.len() > 0 {
if let Some(guild) = message.guild() {
let guild = guild.read().unwrap();
if let Some(member) = guild.members.get(&message.author.id) {
let right_role = command
.allowed_roles
.iter()
.flat_map(|r| guild.role_by_name(&r))
.any(|g| member.roles.contains(&g.id));
if !right_role {
return Some(DispatchError::LackingRole);
}
}
}
}

let all_passed = command.checks.iter().all(|check| {
check(&mut context, message, args, command)
});
Expand Down

0 comments on commit d925f92

Please sign in to comment.