diff --git a/src/commands/todo_cmds.rs b/src/commands/todo_cmds.rs index 9238adc..af04353 100644 --- a/src/commands/todo_cmds.rs +++ b/src/commands/todo_cmds.rs @@ -13,9 +13,21 @@ use serenity::{ framework::standard::CommandResult, }; +use std::fmt; + use crate::SQLPool; use sqlx::MySqlPool; +use std::convert::TryFrom; +#[derive(Debug)] +struct TodoNotFound; + +impl std::error::Error for TodoNotFound {} +impl fmt::Display for TodoNotFound { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Todo not found") + } +} #[derive(Debug)] struct Todo { @@ -33,6 +45,18 @@ struct TodoTarget { } impl TodoTarget { + pub fn name(&self) -> String { + if self.channel.is_some() { + "Channel" + } + else if self.guild.is_some() { + "Guild" + } + else { + "User" + }.to_string() + } + pub async fn view(&self, pool: MySqlPool) -> Result, Box> { Ok(if let Some(cid) = self.channel { sqlx::query_as!(Todo, @@ -53,7 +77,7 @@ SELECT * FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND else { sqlx::query_as!(Todo, " -SELECT * FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) +SELECT * FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guild_id IS NULL ", self.user.as_u64()) .fetch_all(&pool) .await? @@ -101,15 +125,21 @@ INSERT INTO todos (user_id, value) VALUES ( Ok(()) } - pub async fn remove(&self, num: u32, pool: MySqlPool) -> Result<(), Box> { - sqlx::query!( - " -DELETE FROM todos WHERE id = (SELECT id FROM (SELECT id FROM todos LIMIT ?,1) AS t) - ", num) - .execute(&pool) - .await?; + pub async fn remove(&self, num: usize, pool: MySqlPool) -> Result<(), Box> { + let todos = self.view(pool.clone()).await?; - Ok(()) + if let Some(removal_todo) = todos.get(num) { + sqlx::query!( + " +DELETE FROM todos WHERE id = ? + ", removal_todo.id) + .execute(&pool) + .await?; + Ok(()) + } + else { + Err(Box::try_from(TodoNotFound).unwrap()) + } } pub async fn clear(&self, pool: MySqlPool) -> Result<(), Box> { @@ -132,7 +162,7 @@ DELETE FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND c else { sqlx::query!( " -DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) +DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guild_id IS NULL ", self.user.as_u64()) .execute(&pool) .await?; @@ -197,7 +227,7 @@ async fn todo_parse(ctx: &Context, msg: &Message, args: String) -> CommandResult }; if let Some(subcommand) = subcommand_opt { - todo(ctx, target, subcommand, "".to_string()).await; + todo(ctx, msg, target, subcommand, split.collect::>().join(" ")).await; } else { let _ = msg.channel_id.say(&ctx, "Todo help").await; @@ -216,25 +246,65 @@ async fn todo_parse(ctx: &Context, msg: &Message, args: String) -> CommandResult Ok(()) } -async fn todo(ctx: &Context, target: TodoTarget, subcommand: SubCommand, extra: String) { +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"); match subcommand { SubCommand::View => { - println!("{:?}", target.view(pool).await.unwrap()); + let todo_items = target.view(pool).await.unwrap(); + let mut todo_groups = vec!["".to_string()]; + let mut char_count: u16 = 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; + + todo_groups.push(display); + } + else { + char_count += display.len() as u16; + + let last_group = todo_groups.pop().unwrap(); + + todo_groups.push(format!("{}{}", last_group, display)); + } + }); + + for group in todo_groups { + let _ = msg.channel_id.send_message(&ctx, |m| m + .embed(|e| e + .title(format!("{} Todo", target.name())) + .description(group) + ) + ).await; + } }, SubCommand::Add => { + target.add(extra, pool).await.unwrap(); + let _ = msg.channel_id.say(&ctx, "Todo added").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") + } + else { + msg.channel_id.say(&ctx, "Todo not removed") + } + } + else { + msg.channel_id.say(&ctx, "Todo not removed") + }.await; }, SubCommand::Clear => { - + target.clear(pool).await.unwrap(); }, } } diff --git a/src/main.rs b/src/main.rs index 42438e0..86820ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,6 +55,7 @@ async fn main() -> Result<(), Box> { .add_command("help", &info_cmds::HELP_COMMAND) .add_command("info", &info_cmds::INFO_COMMAND) .add_command("donate", &info_cmds::DONATE_COMMAND) + .add_command("todo", &todo_cmds::TODO_PARSE_COMMAND) .build(); let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment"))