more todo commands

This commit is contained in:
jude 2020-08-18 00:18:33 +01:00
parent 9574283638
commit 09b09c06b2
2 changed files with 86 additions and 15 deletions

View File

@ -13,9 +13,21 @@ use serenity::{
framework::standard::CommandResult, framework::standard::CommandResult,
}; };
use std::fmt;
use crate::SQLPool; use crate::SQLPool;
use sqlx::MySqlPool; 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)] #[derive(Debug)]
struct Todo { struct Todo {
@ -33,6 +45,18 @@ struct TodoTarget {
} }
impl 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<Vec<Todo>, Box<dyn std::error::Error + Send + Sync>> { pub async fn view(&self, pool: MySqlPool) -> Result<Vec<Todo>, Box<dyn std::error::Error + Send + Sync>> {
Ok(if let Some(cid) = self.channel { Ok(if let Some(cid) = self.channel {
sqlx::query_as!(Todo, sqlx::query_as!(Todo,
@ -53,7 +77,7 @@ SELECT * FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND
else { else {
sqlx::query_as!(Todo, 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()) ", self.user.as_u64())
.fetch_all(&pool) .fetch_all(&pool)
.await? .await?
@ -101,16 +125,22 @@ INSERT INTO todos (user_id, value) VALUES (
Ok(()) Ok(())
} }
pub async fn remove(&self, num: u32, pool: MySqlPool) -> Result<(), Box<dyn std::error::Error + Sync + Send>> { pub async fn remove(&self, num: usize, pool: MySqlPool) -> Result<(), Box<dyn std::error::Error + Sync + Send>> {
let todos = self.view(pool.clone()).await?;
if let Some(removal_todo) = todos.get(num) {
sqlx::query!( sqlx::query!(
" "
DELETE FROM todos WHERE id = (SELECT id FROM (SELECT id FROM todos LIMIT ?,1) AS t) DELETE FROM todos WHERE id = ?
", num) ", removal_todo.id)
.execute(&pool) .execute(&pool)
.await?; .await?;
Ok(()) Ok(())
} }
else {
Err(Box::try_from(TodoNotFound).unwrap())
}
}
pub async fn clear(&self, pool: MySqlPool) -> Result<(), Box<dyn std::error::Error + Sync + Send>> { pub async fn clear(&self, pool: MySqlPool) -> Result<(), Box<dyn std::error::Error + Sync + Send>> {
if let Some(cid) = self.channel { if let Some(cid) = self.channel {
@ -132,7 +162,7 @@ DELETE FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND c
else { else {
sqlx::query!( 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()) ", self.user.as_u64())
.execute(&pool) .execute(&pool)
.await?; .await?;
@ -197,7 +227,7 @@ async fn todo_parse(ctx: &Context, msg: &Message, args: String) -> CommandResult
}; };
if let Some(subcommand) = subcommand_opt { if let Some(subcommand) = subcommand_opt {
todo(ctx, target, subcommand, "".to_string()).await; todo(ctx, msg, target, subcommand, split.collect::<Vec<&str>>().join(" ")).await;
} }
else { else {
let _ = msg.channel_id.say(&ctx, "Todo help").await; 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(()) 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 let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data"); .get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
match subcommand { match subcommand {
SubCommand::View => { 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 => { SubCommand::Add => {
target.add(extra, pool).await.unwrap();
let _ = msg.channel_id.say(&ctx, "Todo added").await;
}, },
SubCommand::Remove => { SubCommand::Remove => {
let _ = if let Ok(num) = extra.parse::<usize>() {
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 => { SubCommand::Clear => {
target.clear(pool).await.unwrap();
}, },
} }
} }

View File

@ -55,6 +55,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.add_command("help", &info_cmds::HELP_COMMAND) .add_command("help", &info_cmds::HELP_COMMAND)
.add_command("info", &info_cmds::INFO_COMMAND) .add_command("info", &info_cmds::INFO_COMMAND)
.add_command("donate", &info_cmds::DONATE_COMMAND) .add_command("donate", &info_cmds::DONATE_COMMAND)
.add_command("todo", &todo_cmds::TODO_PARSE_COMMAND)
.build(); .build();
let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment")) let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment"))