replaced allow_slash with a method to disallow text commands for soundboard. made string argument selector stricter
This commit is contained in:
parent
14ef6385a0
commit
a38e4c808e
@ -5,7 +5,7 @@ use syn::parse::{Error, Result};
|
|||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{Attribute, Ident, Lit, LitStr, Meta, NestedMeta, Path};
|
use syn::{Attribute, Ident, Lit, LitStr, Meta, NestedMeta, Path};
|
||||||
|
|
||||||
use crate::structures::{ApplicationCommandOptionType, Arg, PermissionLevel};
|
use crate::structures::{ApplicationCommandOptionType, Arg, CommandKind, PermissionLevel};
|
||||||
use crate::util::{AsOption, LitExt};
|
use crate::util::{AsOption, LitExt};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
@ -321,6 +321,18 @@ impl AttributeOption for PermissionLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AttributeOption for CommandKind {
|
||||||
|
fn parse(values: Values) -> Result<Self> {
|
||||||
|
validate(&values, &[ValueKind::SingleList])?;
|
||||||
|
|
||||||
|
Ok(values
|
||||||
|
.literals
|
||||||
|
.get(0)
|
||||||
|
.map(|(_, l)| CommandKind::from_str(&*l.to_str()).unwrap())
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AttributeOption for Arg {
|
impl AttributeOption for Arg {
|
||||||
fn parse(values: Values) -> Result<Self> {
|
fn parse(values: Values) -> Result<Self> {
|
||||||
validate(&values, &[ValueKind::EqualsList])?;
|
validate(&values, &[ValueKind::EqualsList])?;
|
||||||
|
@ -70,7 +70,7 @@ pub fn command(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
aliases;
|
aliases;
|
||||||
group;
|
group;
|
||||||
required_permissions;
|
required_permissions;
|
||||||
allow_slash
|
kind
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ pub fn command(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
group,
|
group,
|
||||||
examples,
|
examples,
|
||||||
required_permissions,
|
required_permissions,
|
||||||
allow_slash,
|
kind,
|
||||||
mut cmd_args,
|
mut cmd_args,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ pub fn command(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
group: #group,
|
group: #group,
|
||||||
examples: &[#(#examples),*],
|
examples: &[#(#examples),*],
|
||||||
required_permissions: #required_permissions,
|
required_permissions: #required_permissions,
|
||||||
allow_slash: #allow_slash,
|
kind: #kind,
|
||||||
args: &[#(&#arg_idents),*],
|
args: &[#(&#arg_idents),*],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,6 +214,55 @@ impl ToTokens for PermissionLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CommandKind {
|
||||||
|
Slash,
|
||||||
|
Both,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CommandKind {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Both
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandKind {
|
||||||
|
pub fn from_str(s: &str) -> Option<Self> {
|
||||||
|
Some(match s.to_uppercase().as_str() {
|
||||||
|
"SLASH" => Self::Slash,
|
||||||
|
"BOTH" => Self::Both,
|
||||||
|
"TEXT" => Self::Text,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for CommandKind {
|
||||||
|
fn to_tokens(&self, stream: &mut TokenStream2) {
|
||||||
|
let path = quote!(crate::framework::CommandKind);
|
||||||
|
let variant;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Self::Slash => {
|
||||||
|
variant = quote!(Slash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::Both => {
|
||||||
|
variant = quote!(Both);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::Text => {
|
||||||
|
variant = quote!(Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.extend(quote! {
|
||||||
|
#path::#variant
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ApplicationCommandOptionType {
|
pub(crate) enum ApplicationCommandOptionType {
|
||||||
SubCommand,
|
SubCommand,
|
||||||
@ -293,7 +342,7 @@ pub(crate) struct Options {
|
|||||||
pub group: String,
|
pub group: String,
|
||||||
pub examples: Vec<String>,
|
pub examples: Vec<String>,
|
||||||
pub required_permissions: PermissionLevel,
|
pub required_permissions: PermissionLevel,
|
||||||
pub allow_slash: bool,
|
pub kind: CommandKind,
|
||||||
pub cmd_args: Vec<Arg>,
|
pub cmd_args: Vec<Arg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +350,6 @@ impl Options {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
allow_slash: true,
|
|
||||||
group: "Other".to_string(),
|
group: "Other".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
THEME_COLOR,
|
THEME_COLOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::framework::CommandKind;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@ -62,29 +63,14 @@ pub async fn help(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
invoke
|
let args = if command.args.is_empty() {
|
||||||
.respond(
|
"**Arguments**
|
||||||
ctx.http.clone(),
|
• *This command has no arguments*"
|
||||||
CreateGenericResponse::new().embed(|e| {
|
.to_string()
|
||||||
e.title(format!("{} Help", command_name))
|
} else {
|
||||||
.color(THEME_COLOR)
|
format!(
|
||||||
.description(format!(
|
"**Arguments**
|
||||||
"**Aliases**
|
|
||||||
{}
|
|
||||||
|
|
||||||
**Overview**
|
|
||||||
• {}
|
|
||||||
**Arguments**
|
|
||||||
{}
|
|
||||||
|
|
||||||
{}",
|
{}",
|
||||||
command
|
|
||||||
.names
|
|
||||||
.iter()
|
|
||||||
.map(|n| format!("`{}`", n))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" "),
|
|
||||||
command.desc,
|
|
||||||
command
|
command
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
@ -95,7 +81,47 @@ pub async fn help(
|
|||||||
a.description
|
a.description
|
||||||
))
|
))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n"),
|
.join("\n")
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
invoke
|
||||||
|
.respond(
|
||||||
|
ctx.http.clone(),
|
||||||
|
CreateGenericResponse::new().embed(|e| {
|
||||||
|
e.title(format!("{} Help", command_name))
|
||||||
|
.color(THEME_COLOR)
|
||||||
|
.description(format!(
|
||||||
|
"**Available In**
|
||||||
|
`Slash Commands` {}
|
||||||
|
` Text Commands` {}
|
||||||
|
|
||||||
|
**Aliases**
|
||||||
|
{}
|
||||||
|
|
||||||
|
**Overview**
|
||||||
|
• {}
|
||||||
|
{}
|
||||||
|
|
||||||
|
{}",
|
||||||
|
if command.kind != CommandKind::Text {
|
||||||
|
"✅"
|
||||||
|
} else {
|
||||||
|
"❎"
|
||||||
|
},
|
||||||
|
if command.kind != CommandKind::Slash {
|
||||||
|
"✅"
|
||||||
|
} else {
|
||||||
|
"❎"
|
||||||
|
},
|
||||||
|
command
|
||||||
|
.names
|
||||||
|
.iter()
|
||||||
|
.map(|n| format!("`{}`", n))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" "),
|
||||||
|
command.desc,
|
||||||
|
args,
|
||||||
examples
|
examples
|
||||||
))
|
))
|
||||||
}),
|
}),
|
||||||
|
@ -186,6 +186,7 @@ pub async fn upload_new_sound(
|
|||||||
kind = "String",
|
kind = "String",
|
||||||
required = true
|
required = true
|
||||||
)]
|
)]
|
||||||
|
#[example("`/delete beep` - delete the sound with the name \"beep\"")]
|
||||||
pub async fn delete_sound(
|
pub async fn delete_sound(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
@ -278,6 +279,8 @@ pub async fn delete_sound(
|
|||||||
description = "Sound name or ID to change the privacy setting of",
|
description = "Sound name or ID to change the privacy setting of",
|
||||||
required = true
|
required = true
|
||||||
)]
|
)]
|
||||||
|
#[example("`/public 12` - change sound with ID 12 to private")]
|
||||||
|
#[example("`/public 12` - change sound with ID 12 back to public")]
|
||||||
pub async fn change_public(
|
pub async fn change_public(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
|
@ -184,14 +184,14 @@ __Available ambience sounds:__
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[command("soundboard")]
|
#[command("soundboard")]
|
||||||
#[aliases("board")]
|
|
||||||
#[group("Play")]
|
#[group("Play")]
|
||||||
|
#[kind(Slash)]
|
||||||
#[description("Get a menu of sounds with buttons to play them")]
|
#[description("Get a menu of sounds with buttons to play them")]
|
||||||
#[arg(
|
#[arg(
|
||||||
name = "1",
|
name = "1",
|
||||||
description = "Query for sound button 1",
|
description = "Query for sound button 1",
|
||||||
kind = "String",
|
kind = "String",
|
||||||
required = false
|
required = true
|
||||||
)]
|
)]
|
||||||
#[arg(
|
#[arg(
|
||||||
name = "2",
|
name = "2",
|
||||||
|
@ -40,6 +40,8 @@ fn format_search_results(search_results: Vec<Sound>) -> CreateGenericResponse {
|
|||||||
kind = "Boolean",
|
kind = "Boolean",
|
||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
|
#[example("`/list` - list sounds uploaded to the server you're in")]
|
||||||
|
#[example("`/list [me: True]` - list sounds you have uploaded across all servers")]
|
||||||
pub async fn list_sounds(
|
pub async fn list_sounds(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
|
@ -20,6 +20,9 @@ use crate::{
|
|||||||
kind = "Integer",
|
kind = "Integer",
|
||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
|
#[example("`/volume` - check the volume on the current server")]
|
||||||
|
#[example("`/volume 100` - reset the volume on the current server")]
|
||||||
|
#[example("`/volume 10` - set the volume on the current server to 10%")]
|
||||||
pub async fn change_volume(
|
pub async fn change_volume(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
@ -66,7 +69,7 @@ pub async fn change_volume(
|
|||||||
|
|
||||||
#[command("prefix")]
|
#[command("prefix")]
|
||||||
#[required_permissions(Restricted)]
|
#[required_permissions(Restricted)]
|
||||||
#[allow_slash(false)]
|
#[kind(Text)]
|
||||||
#[group("Settings")]
|
#[group("Settings")]
|
||||||
#[description("Change the prefix of the bot for using non-slash commands")]
|
#[description("Change the prefix of the bot for using non-slash commands")]
|
||||||
#[arg(
|
#[arg(
|
||||||
@ -97,7 +100,7 @@ pub async fn change_prefix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(prefix) = args.named("prefix") {
|
if let Some(prefix) = args.named("prefix") {
|
||||||
if prefix.len() <= 5 {
|
if prefix.len() <= 5 && !prefix.is_empty() {
|
||||||
let reply = format!("Prefix changed to `{}`", prefix);
|
let reply = format!("Prefix changed to `{}`", prefix);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -142,7 +145,7 @@ pub async fn change_prefix(
|
|||||||
|
|
||||||
#[command("roles")]
|
#[command("roles")]
|
||||||
#[required_permissions(Restricted)]
|
#[required_permissions(Restricted)]
|
||||||
#[allow_slash(false)]
|
#[kind(Text)]
|
||||||
#[group("Settings")]
|
#[group("Settings")]
|
||||||
#[description("Change the roles allowed to use the bot")]
|
#[description("Change the roles allowed to use the bot")]
|
||||||
pub async fn set_allowed_roles(
|
pub async fn set_allowed_roles(
|
||||||
@ -240,6 +243,8 @@ INSERT INTO roles (guild_id, role)
|
|||||||
description = "Name or ID of sound to set as your greet sound",
|
description = "Name or ID of sound to set as your greet sound",
|
||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
|
#[example("`/greet` - remove your join sound")]
|
||||||
|
#[example("`/greet 1523` - set your join sound to sound with ID 1523")]
|
||||||
pub async fn set_greet_sound(
|
pub async fn set_greet_sound(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
@ -312,6 +317,8 @@ pub async fn set_greet_sound(
|
|||||||
#[group("Settings")]
|
#[group("Settings")]
|
||||||
#[description("Configure whether users should be able to use join sounds")]
|
#[description("Configure whether users should be able to use join sounds")]
|
||||||
#[required_permissions(Restricted)]
|
#[required_permissions(Restricted)]
|
||||||
|
#[example("`/allow_greet` - disable greet sounds in the server")]
|
||||||
|
#[example("`/allow_greet` - re-enable greet sounds in the server")]
|
||||||
pub async fn allow_greet_sounds(
|
pub async fn allow_greet_sounds(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
|
@ -309,6 +309,13 @@ pub enum PermissionLevel {
|
|||||||
Restricted,
|
Restricted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum CommandKind {
|
||||||
|
Slash,
|
||||||
|
Both,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Arg {
|
pub struct Arg {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
@ -320,7 +327,7 @@ pub struct Arg {
|
|||||||
impl Arg {
|
impl Arg {
|
||||||
pub fn to_regex(&self) -> String {
|
pub fn to_regex(&self) -> String {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ApplicationCommandOptionType::String => format!(r#"(?P<{}>.*?)"#, self.name),
|
ApplicationCommandOptionType::String => format!(r#"(?P<{}>.+?)"#, self.name),
|
||||||
ApplicationCommandOptionType::Integer => format!(r#"(?P<{}>\d+)"#, self.name),
|
ApplicationCommandOptionType::Integer => format!(r#"(?P<{}>\d+)"#, self.name),
|
||||||
ApplicationCommandOptionType::Boolean => format!(r#"(?P<{0}>{0})?"#, self.name),
|
ApplicationCommandOptionType::Boolean => format!(r#"(?P<{0}>{0})?"#, self.name),
|
||||||
ApplicationCommandOptionType::User => format!(r#"<(@|@!)(?P<{}>\d+)>"#, self.name),
|
ApplicationCommandOptionType::User => format!(r#"<(@|@!)(?P<{}>\d+)>"#, self.name),
|
||||||
@ -343,7 +350,7 @@ pub struct Command {
|
|||||||
pub examples: &'static [&'static str],
|
pub examples: &'static [&'static str],
|
||||||
pub group: &'static str,
|
pub group: &'static str,
|
||||||
|
|
||||||
pub allow_slash: bool,
|
pub kind: CommandKind,
|
||||||
pub required_permissions: PermissionLevel,
|
pub required_permissions: PermissionLevel,
|
||||||
pub args: &'static [&'static Arg],
|
pub args: &'static [&'static Arg],
|
||||||
}
|
}
|
||||||
@ -528,7 +535,11 @@ impl RegexFramework {
|
|||||||
.flatten()
|
.flatten()
|
||||||
.map(|v| GuildId(v))
|
.map(|v| GuildId(v))
|
||||||
{
|
{
|
||||||
for command in self.commands_.iter().filter(|c| c.allow_slash) {
|
for command in self
|
||||||
|
.commands_
|
||||||
|
.iter()
|
||||||
|
.filter(|c| c.kind != CommandKind::Text)
|
||||||
|
{
|
||||||
guild_id
|
guild_id
|
||||||
.create_application_command(&http, |a| {
|
.create_application_command(&http, |a| {
|
||||||
a.name(command.names[0]).description(command.desc);
|
a.name(command.names[0]).description(command.desc);
|
||||||
@ -577,7 +588,11 @@ impl RegexFramework {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for command in self.commands_.iter().filter(|c| c.allow_slash) {
|
for command in self
|
||||||
|
.commands_
|
||||||
|
.iter()
|
||||||
|
.filter(|c| c.kind != CommandKind::Text)
|
||||||
|
{
|
||||||
let already_created = if let Some(current_command) = current_commands
|
let already_created = if let Some(current_command) = current_commands
|
||||||
.iter()
|
.iter()
|
||||||
.find(|curr| curr.name == command.names[0])
|
.find(|curr| curr.name == command.names[0])
|
||||||
@ -752,6 +767,7 @@ impl Framework for RegexFramework {
|
|||||||
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
|
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if command.kind != CommandKind::Slash {
|
||||||
let args = full_match
|
let args = full_match
|
||||||
.name("args")
|
.name("args")
|
||||||
.map(|m| m.as_str())
|
.map(|m| m.as_str())
|
||||||
@ -764,7 +780,9 @@ impl Framework for RegexFramework {
|
|||||||
(command.fun)(&ctx, &msg, Args::from(&args, command.args))
|
(command.fun)(&ctx, &msg, Args::from(&args, command.args))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else if command.required_permissions == PermissionLevel::Managed {
|
} else if command.required_permissions
|
||||||
|
== PermissionLevel::Managed
|
||||||
|
{
|
||||||
let _ = msg.channel_id.say(&ctx, "You must either be an Admin or have a role specified in `?roles` to do this command").await;
|
let _ = msg.channel_id.say(&ctx, "You must either be an Admin or have a role specified in `?roles` to do this command").await;
|
||||||
} else if command.required_permissions
|
} else if command.required_permissions
|
||||||
== PermissionLevel::Restricted
|
== PermissionLevel::Restricted
|
||||||
@ -775,6 +793,7 @@ impl Framework for RegexFramework {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PermissionCheck::None => {
|
PermissionCheck::None => {
|
||||||
warn!("Missing enough permissions for guild {}", guild.id);
|
warn!("Missing enough permissions for guild {}", guild.id);
|
||||||
|
Loading…
Reference in New Issue
Block a user