bin/tau-cli: add show subcommnd and minor fixes

This commit is contained in:
Dastan-glitch
2022-03-28 22:04:30 -04:00
parent 07b27791b0
commit 70b43ca29b
5 changed files with 105 additions and 7 deletions

1
Cargo.lock generated
View File

@@ -6064,6 +6064,7 @@ dependencies = [
"log",
"num_cpus",
"prettytable-rs",
"serde",
"serde_json",
"simplelog",
"smol",

View File

@@ -28,3 +28,4 @@ prettytable-rs = "0.8.0"
# Encoding and parsing
serde_json = "1.0.79"
serde = {version = "1.0.136", features = ["derive"]}

View File

@@ -11,6 +11,7 @@ use chrono::{Datelike, Local, NaiveDate, NaiveDateTime};
use clap::{CommandFactory, Parser, Subcommand};
use log::{debug, error};
use prettytable::{cell, format, row, Cell, Row, Table};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use simplelog::{ColorChoice, TermLogger, TerminalMode};
use url::Url;
@@ -81,6 +82,26 @@ pub enum CliTauSubCommands {
},
/// List open tasks
List {},
/// Show task by ID
Show {
/// Task ID
id: u64,
},
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct TaskInfo {
ref_id: String,
id: u32,
title: String,
desc: String,
assign: Vec<String>,
project: Vec<String>,
due: String,
rank: u32,
created_at: String,
events: Vec<Value>,
comments: Vec<Value>,
}
/// Tau cli
@@ -145,8 +166,20 @@ async fn request(r: jsonrpc::JsonRequest, url: String) -> Result<Value> {
}
}
// RPCAPI:
// Add new task and returns `true` upon success.
// --> {"jsonrpc": "2.0", "method": "add", "params": ["title", "desc", ["assign"], ["project"], "due", "rank"], "id": 1}
// --> {"jsonrpc": "2.0", "method": "add",
// "params":
// [{
// "title": "..",
// "desc": "..",
// assign: [..],
// project: [..],
// "due": ..,
// "rank": ..
// }],
// "id": 1
// }
// <-- {"jsonrpc": "2.0", "result": true, "id": 1}
async fn add(url: &str, params: Value) -> Result<Value> {
let req = jsonrpc::request(json!("add"), params);
@@ -193,6 +226,14 @@ async fn set_comment(url: &str, id: u64, author: &str, content: &str) -> Result<
request(req, url.to_string()).await
}
// Show task by id.
// --> {"jsonrpc": "2.0", "method": "show", "params": [task_id], "id": 1}
// <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
async fn show(url: &str, id: u64) -> Result<Value> {
let req = jsonrpc::request(json!("show"), json!([id]));
request(req, url.to_string()).await
}
async fn start(options: CliTau) -> Result<()> {
let rpc_addr = "tcp://127.0.0.1:8875";
match options.command {
@@ -260,7 +301,11 @@ async fn start(options: CliTau) -> Result<()> {
let rank = rank.unwrap_or(0);
add(rpc_addr, json!([title, desc, assign, project, due, rank])).await?;
add(
rpc_addr,
json!([{"title": title, "desc": desc, "assign": assign, "project": project, "due": due, "rank": rank}]),
)
.await?;
}
Some(CliTauSubCommands::List {}) => {
@@ -368,11 +413,45 @@ async fn start(options: CliTau) -> Result<()> {
cmnt.push_str(comment["content"].as_str().unwrap());
cmnt.push('\n');
}
cmnt.pop();
println!("Comments on Task with id {}:\n{}", id, cmnt);
}
}
Some(CliTauSubCommands::Show { id }) => {
let rep = show(rpc_addr, id).await?;
let due = if rep["due"].is_u64() {
let timestamp = rep["due"].as_i64().unwrap();
NaiveDateTime::from_timestamp(timestamp, 0).date().format("%A %-d %B").to_string()
} else {
"".to_string()
};
let created_at = if rep["created_at"].is_u64() {
let created = rep["created_at"].as_i64().unwrap();
NaiveDateTime::from_timestamp(created, 0).date().format("%A %-d %B").to_string()
} else {
"".to_string()
};
let t = TaskInfo {
ref_id: serde_json::from_value(rep["ref_id"].clone())?,
id: serde_json::from_value(rep["id"].clone())?,
title: serde_json::from_value(rep["title"].clone())?,
desc: serde_json::from_value(rep["desc"].clone())?,
assign: serde_json::from_value(rep["assign"].clone())?,
project: serde_json::from_value(rep["project"].clone())?,
due,
rank: serde_json::from_value(rep["rank"].clone())?,
created_at,
events: serde_json::from_value(rep["events"].clone())?,
comments: serde_json::from_value(rep["comments"].clone())?,
};
// let t: TaskInfo = serde_json::from_value(rep)?;
println!("TaskInfo: {}", serde_json::to_string_pretty(&t)?);
}
_ => {
error!("Please run 'tau help' to see usage.");
return Err(Error::MissingParams)

View File

@@ -54,6 +54,7 @@ impl RequestHandler for JsonRpcInterface {
Some("set_comment") => {
return from_taud_result(self.set_comment(req.params).await, req.id)
}
Some("show") => return from_taud_result(self.show(req.params).await, req.id),
Some(_) | None => {
return JsonResult::Err(jsonerr(ErrorCode::MethodNotFound, None, req.id))
}
@@ -72,7 +73,7 @@ impl JsonRpcInterface {
// "params":
// [{
// "title": "..",
// "desc": ".."
// "desc": "..",
// assign: [..],
// project: [..],
// "due": ..,
@@ -182,6 +183,22 @@ impl JsonRpcInterface {
Ok(json!(true))
}
// RPCAPI:
// Show a task by id.
// --> {"jsonrpc": "2.0", "method": "show", "params": [task_id], "id": 1}
// <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
async fn show(&self, params: Value) -> TaudResult<Value> {
let args = params.as_array().unwrap();
if args.len() != 1 {
return Err(TaudError::InvalidData("len of params should be 1".into()))
}
let task: TaskInfo = self.load_task_by_id(&args[0])?;
Ok(json!(task))
}
fn load_task_by_id(&self, task_id: &Value) -> TaudResult<TaskInfo> {
let task_id: u64 = serde_json::from_value(task_id.clone())?;

View File

@@ -38,13 +38,13 @@ impl Comment {
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct TaskEvents(Vec<TaskEvent>);
pub struct TaskEvents(Vec<TaskEvent>);
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct TaskComments(Vec<Comment>);
pub struct TaskComments(Vec<Comment>);
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct TaskProjects(Vec<String>);
pub struct TaskProjects(Vec<String>);
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct TaskAssigns(Vec<String>);
pub struct TaskAssigns(Vec<String>);
#[derive(Clone, Debug, Serialize, Deserialize, SerialEncodable, SerialDecodable, PartialEq)]
pub struct TaskInfo {