diff --git a/src/api/mod.rs b/src/api/mod.rs index 559eb3c..eb6e2e7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -125,6 +125,18 @@ impl VikunjaAPI { .unwrap() } + fn delete_request(&self, path: &str) -> String { + let client = reqwest::blocking::Client::new(); + + client + .delete(format!("{}/api/v1{}", self.host, path)) + .header("Authorization", format!("Bearer {}", self.token)) + .send() + .unwrap() + .text() + .unwrap() + } + // projects pub fn get_project_name_from_id(&self, id: isize) -> String { @@ -164,6 +176,47 @@ impl VikunjaAPI { serde_json::from_str(&resp).unwrap() } + pub fn remove_label(&self, title: &str) { + let labels = self.get_all_labels(); + + let label_id = labels + .into_iter() + .find(|x| x.title.trim() == title) + .unwrap() + .id; + + self.delete_request(&format!("/labels/{label_id}")); + } + + pub fn label_task_remove(&self, label: &str, task_id: isize) { + let labels = self.get_all_labels(); + + let label_id = labels + .into_iter() + .find(|x| x.title.trim() == label) + .unwrap() + .id; + + self.delete_request(&format!("/tasks/{task_id}/labels/{label_id}")); + } + + pub fn label_task(&self, label: &str, task_id: isize) { + let labels = self.get_all_labels(); + + let label_id = labels + .into_iter() + .find(|x| x.title.trim() == label) + .unwrap() + .id; + + self.put_request( + &format!("/tasks/{task_id}/labels"), + &serde_json::json!({ + "label_id": label_id + }), + ); + } + // tasks pub fn get_task_page(&self, page: usize) -> Vec { let resp = self.get_request(&format!("/tasks/all?page={page}")); diff --git a/src/args.rs b/src/args.rs index eb2ebf2..d88ae8d 100644 --- a/src/args.rs +++ b/src/args.rs @@ -35,6 +35,14 @@ pub fn get_args() -> clap::ArgMatches { .subcommand( command!() .name("label") + .about("Add a label to a task") + .arg(arg!(-u --undo "Remove label from task").required(false)) + .arg(arg!([label] "Label").required(true)) + .arg(arg!([task_id] "Task ID").required(true)), + ) + .subcommand( + command!() + .name("labels") .about("Manage labels") .subcommand(command!().name("ls").about("List all labels")) .subcommand( @@ -49,8 +57,13 @@ pub fn get_args() -> clap::ArgMatches { .required(false), ) .arg(arg!( "Label title").required(true)), - ), // todo : label rm - // todo : label <label> <task> + ) + .subcommand( + command!() + .name("rm") + .about("Remove a label") + .arg(arg!(<title> "Label title").required(true)), + ), ) .subcommand( command!() diff --git a/src/main.rs b/src/main.rs index ab232ef..7a31e08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,10 +25,15 @@ fn main() { ui::project::list_projects(&api); } }, - Some(("label", label_args)) => match label_args.subcommand() { + Some(("labels", label_args)) => match label_args.subcommand() { Some(("ls", _)) => { ui::print_all_labels(&api); } + Some(("rm", rm_label_arg)) => { + let title: &String = rm_label_arg.get_one("title").unwrap(); + + api.remove_label(title); + } Some(("new", new_label_arg)) => { let description: Option<&String> = new_label_arg.get_one("description"); let color: Option<&String> = new_label_arg.get_one("color"); @@ -40,10 +45,19 @@ fn main() { color.map(|x| x.as_str()), ); } - _ => { - // todo : label tasks - } + _ => {} }, + Some(("label", label_args)) => { + let label: &String = label_args.get_one("label").unwrap(); + let task_id: &String = label_args.get_one("task_id").unwrap(); + let undo = label_args.get_flag("undo"); + + if undo { + api.label_task_remove(label, task_id.parse().unwrap()); + } else { + api.label_task(label, task_id.parse().unwrap()); + } + } Some(("new", new_task_arg)) => { let title: &String = new_task_arg.get_one("title").unwrap(); let project: &String = new_task_arg.get_one("project").unwrap(); diff --git a/src/ui/task.rs b/src/ui/task.rs index 3532ed1..f7b484b 100644 --- a/src/ui/task.rs +++ b/src/ui/task.rs @@ -100,6 +100,11 @@ pub fn print_task_info(task_id: isize, api: &VikunjaAPI) { ); println!("Created by {}", task.created_by.username); + println!( + "Created: {} | Updated: {}", + time_since(parse_datetime(&task.created).unwrap()), + time_since(parse_datetime(&task.updated).unwrap()) + ); if let Some(due_date) = parse_datetime(&task.due_date) { // todo : color if overdue @@ -118,16 +123,14 @@ pub fn print_task_info(task_id: isize, api: &VikunjaAPI) { } if let Some(labels) = task.labels { - // todo : labels and color - println!("Labels: {}", labels.first().unwrap().title); + print!("Labels: "); + for label in labels { + print_label(&label); + print!(" "); + } + println!(); } - println!( - "Created: {} | Updated: {}", - time_since(parse_datetime(&task.created).unwrap()), - time_since(parse_datetime(&task.updated).unwrap()) - ); - if task.description != "<p></p>" && !task.description.is_empty() { println!("---\n{}", task.description); }