feat: add dms, hieracthical arguments, permission and rank system
This commit is contained in:
parent
544bbf73cb
commit
257bc55b75
25 changed files with 503 additions and 209 deletions
163
src/main.rs
163
src/main.rs
|
|
@ -35,10 +35,63 @@ use std::sync::Arc;
|
|||
static ALLOCATOR: Cap<std::alloc::System> = Cap::new(std::alloc::System, usize::MAX);
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct User {
|
||||
pub struct User {
|
||||
_id: String,
|
||||
balance: i32,
|
||||
items: sqlx::types::Json<Vec<String>>,
|
||||
extra_permissions: sqlx::types::Json<Vec<String>>,
|
||||
rank: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Rank {
|
||||
name: String,
|
||||
permissions: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn get_ranks(registry: CommandRegistry) -> HashMap<String, Rank> {
|
||||
let mut ranks: HashMap<String, Rank> = HashMap::new();
|
||||
let mut command_permissions: Vec<String> = Vec::new();
|
||||
|
||||
for command in registry.values() {
|
||||
let locked_command = command.lock().await;
|
||||
command_permissions.push(format!("commands.{}", locked_command.name()));
|
||||
drop(locked_command);
|
||||
}
|
||||
|
||||
ranks.insert(
|
||||
"owner".to_string(),
|
||||
Rank {
|
||||
name: "owner".to_string(),
|
||||
permissions: {
|
||||
let mut perms = command_permissions.clone();
|
||||
perms.push("play.high_note_counts".to_string());
|
||||
perms
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
ranks.insert(
|
||||
"user".to_string(),
|
||||
Rank {
|
||||
name: "user".to_string(),
|
||||
permissions: {
|
||||
let mut perms = command_permissions.clone();
|
||||
perms.retain(|p| p != "commands.launch");
|
||||
perms
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
ranks
|
||||
}
|
||||
|
||||
pub fn has_permission(user: &User, ranks: HashMap<String, Rank>, permission: String) -> bool {
|
||||
let rank = ranks.get(&user.rank);
|
||||
|
||||
rank.map(|r| r.permissions.contains(&permission))
|
||||
.unwrap_or(false)
|
||||
|| user.extra_permissions.0.contains(&permission)
|
||||
}
|
||||
|
||||
macro_rules! register_all {
|
||||
|
|
@ -97,6 +150,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
let midi_state = Arc::new(Mutex::new(MidiState::new()));
|
||||
|
||||
let mut registry = CommandRegistry::new();
|
||||
let ranks: HashMap<String, Rank> = HashMap::new();
|
||||
|
||||
register_all!(
|
||||
registry,
|
||||
|
|
@ -118,10 +172,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
CoinflipCommand::new(arc_pool.clone()),
|
||||
TranslateCommand,
|
||||
AboutCommand,
|
||||
HelpCommand::new(registry.clone()),
|
||||
RankCommand::new(arc_pool.clone(), ranks.clone()),
|
||||
]
|
||||
);
|
||||
|
||||
registry
|
||||
.register(HelpCommand::new(registry.clone()), client.clone())
|
||||
.await;
|
||||
|
||||
let ranks = get_ranks(registry.clone()).await;
|
||||
|
||||
registry
|
||||
.register(
|
||||
RankCommand::new(arc_pool.clone(), ranks.clone()),
|
||||
client.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let client_events = client.clone();
|
||||
let events_pool = arc_pool.clone();
|
||||
|
||||
|
|
@ -151,46 +218,63 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
if let Some(no_prefix) = message.strip_prefix(conf.commands.prefix.as_str()) {
|
||||
let mut parts = no_prefix.split_whitespace();
|
||||
if let Some(cmd_name) = parts.next() {
|
||||
let args = Arguments::new(parts.map(|s| s.to_string()).collect());
|
||||
let user =
|
||||
sqlx::query_as::<_, User>("SELECT * FROM users WHERE _id = $1")
|
||||
.bind(&player._id)
|
||||
.fetch_optional(events_pool.as_ref())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mut cmd_opt: Option<CommandArc> = None;
|
||||
for cmd in registry.values() {
|
||||
let cmd_lock = cmd.lock().await;
|
||||
if cmd_lock.name() == cmd_name
|
||||
|| cmd_lock.aliases().contains(&cmd_name)
|
||||
{
|
||||
cmd_opt = Some(cmd.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !has_permission(
|
||||
&user,
|
||||
ranks.clone(),
|
||||
format!("commands.{}", cmd_name),
|
||||
) {
|
||||
client_events
|
||||
.message(format!("You do not have permission \"commands.{}\" to run this command.", cmd_name))
|
||||
.await;
|
||||
} else {
|
||||
let args = Arguments::new(parts.map(|s| s.to_string()).collect());
|
||||
|
||||
if let Some(cmd) = cmd_opt {
|
||||
let mut cmd_lock = cmd.lock().await;
|
||||
let specs = cmd_lock.argument_spec();
|
||||
match crate::commands::argument::parse_arguments(specs, &args.args)
|
||||
{
|
||||
Ok(parsed_args_struct) => {
|
||||
cmd_lock
|
||||
.execute(
|
||||
client_events.clone(),
|
||||
player.clone(),
|
||||
parsed_args_struct,
|
||||
)
|
||||
.await;
|
||||
let mut cmd_opt: Option<CommandArc> = None;
|
||||
for cmd in registry.values() {
|
||||
let cmd_lock = cmd.lock().await;
|
||||
if cmd_lock.name() == cmd_name
|
||||
|| cmd_lock.aliases().contains(&cmd_name)
|
||||
{
|
||||
cmd_opt = Some(cmd.clone());
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
client_events
|
||||
.message(format!("Argument error: {}", e))
|
||||
.await;
|
||||
}
|
||||
|
||||
if let Some(cmd) = cmd_opt {
|
||||
let mut cmd_lock = cmd.lock().await;
|
||||
let specs = cmd_lock.argument_spec();
|
||||
match crate::commands::argument::parse_arguments(
|
||||
specs, &args.args,
|
||||
) {
|
||||
Ok(parsed_args_struct) => {
|
||||
cmd_lock
|
||||
.execute(
|
||||
client_events.clone(),
|
||||
player.clone(),
|
||||
parsed_args_struct,
|
||||
user,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
client_events
|
||||
.message(format!("Argument error: {}", e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if message == "!ping" {
|
||||
client_events.message("pong").await;
|
||||
}
|
||||
log!(MSG, player.name, message);
|
||||
}
|
||||
ClientEvent::PlayerJoined(player) => {
|
||||
|
|
@ -204,12 +288,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
let user_exists = user.unwrap().is_some();
|
||||
|
||||
if !user_exists {
|
||||
let _ = sqlx::query!(
|
||||
"INSERT INTO users (_id, balance, items) VALUES ($1, $2, $3)",
|
||||
player.id,
|
||||
0,
|
||||
serde_json::json!([])
|
||||
// INSERT with extra_permissions and rank columns (defaults)
|
||||
let _ = sqlx::query(
|
||||
"INSERT INTO users (_id, balance, items, extra_permissions, rank) VALUES ($1, $2, $3, $4, $5)",
|
||||
)
|
||||
.bind(&player._id)
|
||||
.bind(0_i32)
|
||||
.bind(serde_json::json!([]))
|
||||
.bind(serde_json::json!([]))
|
||||
.bind("user")
|
||||
.execute(events_pool.as_ref())
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue