diff --git a/src/commands/todo_cmds.rs b/src/commands/todo_cmds.rs index 4930896..3df97c9 100644 --- a/src/commands/todo_cmds.rs +++ b/src/commands/todo_cmds.rs @@ -15,7 +15,14 @@ use serenity::{ use std::fmt; -use crate::SQLPool; +use crate::{ + models::{ + UserData, + GuildData, + }, + consts::MAX_MESSAGE_LENGTH, + SQLPool, +}; use sqlx::MySqlPool; #[derive(Debug)] @@ -44,6 +51,25 @@ struct TodoTarget { } impl TodoTarget { + pub fn command(&self, subcommand_opt: Option) -> String { + let context = if self.channel.is_some() { + "channel" + } + else if self.guild.is_some() { + "guild" + } + else { + "user" + }; + + if let Some(subcommand) = subcommand_opt { + format!("todo {} {}", context, subcommand.to_string()) + } + else { + format!("todo {}", context) + } + } + pub fn name(&self) -> String { if self.channel.is_some() { "Channel" @@ -124,30 +150,38 @@ INSERT INTO todos (user_id, value) VALUES ( Ok(()) } - pub async fn remove(&self, num: usize, pool: MySqlPool) -> Result<(), Box> { + pub async fn remove(&self, num: usize, pool: &MySqlPool) -> Result> { let todos = self.view(pool.clone()).await?; if let Some(removal_todo) = todos.get(num) { + let deleting = sqlx::query_as!(Todo, + " +SELECT * FROM todos WHERE id = ? + ", removal_todo.id) + .fetch_one(&pool.clone()) + .await?; + sqlx::query!( " DELETE FROM todos WHERE id = ? ", removal_todo.id) - .execute(&pool) + .execute(pool) .await?; - Ok(()) + + Ok(deleting) } else { Err(Box::new(TodoNotFound)) } } - pub async fn clear(&self, pool: MySqlPool) -> Result<(), Box> { + pub async fn clear(&self, pool: &MySqlPool) -> Result<(), Box> { if let Some(cid) = self.channel { sqlx::query!( " DELETE FROM todos WHERE channel_id = (SELECT id FROM channels WHERE channel = ?) ", cid.as_u64()) - .execute(&pool) + .execute(pool) .await?; } else if let Some(gid) = self.guild { @@ -155,7 +189,7 @@ DELETE FROM todos WHERE channel_id = (SELECT id FROM channels WHERE channel = ?) " DELETE FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND channel_id IS NULL ", gid.as_u64()) - .execute(&pool) + .execute(pool) .await?; } else { @@ -163,7 +197,7 @@ DELETE FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND c " DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guild_id IS NULL ", self.user.as_u64()) - .execute(&pool) + .execute(pool) .await?; } @@ -178,6 +212,17 @@ enum SubCommand { Clear, } +impl ToString for SubCommand { + fn to_string(&self) -> String { + match self { + SubCommand::View => "", + SubCommand::Add => "add", + SubCommand::Remove => "remove", + SubCommand::Clear => "clear", + }.to_string() + } +} + #[command] #[permission_level(Managed)] async fn todo_parse(ctx: &Context, msg: &Message, args: String) -> CommandResult { @@ -230,42 +275,59 @@ async fn todo_parse(ctx: &Context, msg: &Message, args: String) -> CommandResult todo(ctx, msg, target, subcommand, split.collect::>().join(" ")).await; } else { - let _ = msg.channel_id.say(&ctx, "Todo help").await; + show_help(&ctx, msg, Some(target)).await; } } else { - let _ = msg.channel_id.say(&ctx, "Todo help").await; + show_help(&ctx, msg, None).await; } } else { - let _ = msg.channel_id.say(&ctx, "Todo help").await; + show_help(&ctx, msg, None).await; } Ok(()) } +async fn show_help(ctx: &Context, msg: &Message, target: Option) { + let pool = ctx.data.read().await + .get::().cloned().expect("Could not get SQLPool from data"); + + let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap(); + let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await; + + let content = user_data.response(&pool, "todo/help").await + .replace("{prefix}", &prefix) + .replace("{command}", target.map_or_else(|| "todo user".to_string(), |t| t.command(None)).as_str()); + + let _ = msg.channel_id.say(&ctx, content).await; +} + async fn todo(ctx: &Context, msg: &Message, target: TodoTarget, subcommand: SubCommand, extra: String) { let pool = ctx.data.read().await .get::().cloned().expect("Could not get SQLPool from data"); + let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap(); + let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await; + match subcommand { SubCommand::View => { let todo_items = target.view(pool).await.unwrap(); let mut todo_groups = vec!["".to_string()]; - let mut char_count: u16 = 0; + let mut char_count = 0; todo_items.iter().enumerate().for_each(|(count, todo)| { let display = format!("{}: {}\n", count + 1, todo.value); - if char_count + display.len() as u16 > 2000 { - char_count = display.len() as u16; + if char_count + display.len() > MAX_MESSAGE_LENGTH { + char_count = display.len(); todo_groups.push(display); } else { - char_count += display.len() as u16; + char_count += display.len(); let last_group = todo_groups.pop().unwrap(); @@ -284,27 +346,41 @@ async fn todo(ctx: &Context, msg: &Message, target: TodoTarget, subcommand: SubC }, SubCommand::Add => { + let content = user_data.response(&pool, "todo/added").await + .replacen("{name}", &extra, 1); + target.add(extra, pool).await.unwrap(); - let _ = msg.channel_id.say(&ctx, "Todo added").await; + let _ = msg.channel_id.say(&ctx, content).await; }, SubCommand::Remove => { let _ = if let Ok(num) = extra.parse::() { - if target.remove(num - 1, pool).await.is_ok() { - msg.channel_id.say(&ctx, "Todo removed") + if let Ok(todo) = target.remove(num - 1, &pool).await { + let content = user_data.response(&pool, "todo/removed").await + .replacen("{}", &todo.value, 1); + + msg.channel_id.say(&ctx, content) } else { - msg.channel_id.say(&ctx, "Todo not removed") + msg.channel_id.say(&ctx, user_data.response(&pool, "todo/error_index").await) } } else { - msg.channel_id.say(&ctx, "Todo not removed") + let content = user_data.response(&pool, "todo/error_value").await + .replacen("{prefix}", &prefix, 1) + .replacen("{command}", &target.command(Some(subcommand)), 1); + + msg.channel_id.say(&ctx, content) }.await; }, SubCommand::Clear => { - target.clear(pool).await.unwrap(); + target.clear(&pool).await.unwrap(); + + let content = user_data.response(&pool, "todo/cleared").await; + + let _ = msg.channel_id.say(&ctx, content).await; }, } } diff --git a/src/framework.rs b/src/framework.rs index 0cc76b0..e2992b5 100644 --- a/src/framework.rs +++ b/src/framework.rs @@ -186,13 +186,13 @@ impl SendIterator for ChannelId { } impl RegexFramework { - pub fn new(client_id: u64) -> Self { + pub fn new>(client_id: T) -> Self { Self { commands: HashMap::new(), command_matcher: Regex::new(r#"^$"#).unwrap(), dm_regex_matcher: Regex::new(r#"^$"#).unwrap(), default_prefix: env::var("DEFAULT_PREFIX").unwrap_or_else(|_| PREFIX.to_string()), - client_id, + client_id: client_id.into(), ignore_bots: true, } } @@ -209,7 +209,7 @@ impl RegexFramework { self } - pub fn add_command(mut self, name: &str, command: &'static Command) -> Self { + pub fn add_command(mut self, name: S, command: &'static Command) -> Self { self.commands.insert(name.to_string(), command); self diff --git a/src/main.rs b/src/main.rs index 57e1981..942336a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,7 +85,9 @@ async fn main() -> Result<(), Box> { let http = Http::new_with_token(&token); - let framework = RegexFramework::new(http.get_current_user().map_ok(|user| user.id.as_u64().to_owned()).await?) + let logged_in_id = http.get_current_user().map_ok(|user| user.id.as_u64().to_owned()).await?; + + let framework = RegexFramework::new(logged_in_id) .ignore_bots(true) .default_prefix(&env::var("DEFAULT_PREFIX").unwrap_or_else(|_| PREFIX.to_string()))