Return new task after adding a new one

This commit is contained in:
2022-01-27 14:07:15 +01:00
parent 0cb22f7dcd
commit d9cee2be40
4 changed files with 79 additions and 31 deletions

View File

@@ -12,6 +12,7 @@ pub fn list_tasks(filters: Vec<&str>) -> Result<Vec<Task>, Error> {
}
#[tracing::instrument(level = "debug")]
pub async fn add_task(add_args: Vec<&str>) -> Result<u64, Error> {
taskwarrior::add_task(add_args).await
pub async fn add_task(add_args: Vec<&str>) -> Result<Task, Error> {
let taskwarrior_task = taskwarrior::add_task(add_args).await?;
(&taskwarrior_task).try_into()
}

View File

@@ -1,11 +1,11 @@
use chrono::{DateTime, Utc};
use configparser::ini::Ini;
use contextswitch_types::ContextSwitchMetadata;
use contextswitch_types::Task;
use contextswitch_types::{ContextSwitchMetadata, Task, TaskId};
use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_json;
use std::env;
use std::fmt;
use std::io::{Error, ErrorKind};
use std::path::Path;
use std::process::Command;
@@ -14,10 +14,34 @@ use tokio::sync::Mutex;
use tracing::debug;
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Eq)]
pub struct TaskwarriorTaskLocalId(pub u64);
impl fmt::Display for TaskwarriorTaskLocalId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Eq)]
pub struct TaskwarriorTaskId(pub Uuid);
impl fmt::Display for TaskwarriorTaskId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&TaskwarriorTaskId> for TaskId {
fn from(task: &TaskwarriorTaskId) -> Self {
TaskId(task.0)
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct TaskwarriorTask {
pub uuid: Uuid,
pub id: u64,
pub uuid: TaskwarriorTaskId,
pub id: TaskwarriorTaskLocalId,
#[serde(with = "contextswitch_types::tw_date_format")]
pub entry: DateTime<Utc>,
#[serde(with = "contextswitch_types::tw_date_format")]
@@ -65,8 +89,7 @@ impl TryFrom<&TaskwarriorTask> for Task {
)?;
Ok(Task {
uuid: task.uuid,
id: task.id,
id: (&task.uuid).into(),
entry: task.entry,
modified: task.modified,
status: task.status,
@@ -146,7 +169,23 @@ pub fn list_tasks(filters: Vec<&str>) -> Result<Vec<TaskwarriorTask>, Error> {
}
#[tracing::instrument(level = "debug")]
pub async fn add_task(add_args: Vec<&str>) -> Result<u64, Error> {
pub fn get_task_by_local_id(id: &TaskwarriorTaskLocalId) -> Result<Option<TaskwarriorTask>, Error> {
let mut tasks: Vec<TaskwarriorTask> = list_tasks(vec![&id.to_string()])?;
if tasks.len() > 1 {
return Err(Error::new(
ErrorKind::Other,
format!(
"Found more than 1 task when searching for task with local ID {}",
id
),
));
}
Ok(tasks.pop())
}
#[tracing::instrument(level = "debug")]
pub async fn add_task(add_args: Vec<&str>) -> Result<TaskwarriorTask, Error> {
lazy_static! {
static ref RE: Regex = Regex::new(r"Created task (?P<id>\d+).").unwrap();
static ref LOCK: Mutex<u32> = Mutex::new(0);
@@ -173,7 +212,17 @@ pub async fn add_task(add_args: Vec<&str>) -> Result<u64, Error> {
})?
.as_str();
task_id_str
.parse::<u64>()
.map_err(|_| Error::new(ErrorKind::Other, "Cannot parse task ID value"))
let task_id = TaskwarriorTaskLocalId(
task_id_str
.parse::<u64>()
.map_err(|_| Error::new(ErrorKind::Other, "Cannot parse task ID value"))?,
);
let task = get_task_by_local_id(&task_id)?;
task.ok_or_else(|| {
Error::new(
ErrorKind::Other,
format!("Newly created task with ID {} was not found", task_id),
)
})
}

View File

@@ -1,8 +1,7 @@
use crate::contextswitch;
use actix_web::{web, HttpResponse};
use contextswitch_types::TaskDefinition;
use contextswitch_types::{NewTask, Task};
use serde::Deserialize;
use serde_json::json;
use std::io::Error;
#[derive(Deserialize)]
@@ -16,20 +15,20 @@ pub async fn list_tasks(task_query: web::Query<TaskQuery>) -> Result<HttpRespons
.filter
.as_ref()
.map_or(vec![], |filter| filter.split(' ').collect());
let tasks = contextswitch::list_tasks(filter)?;
let tasks: Vec<Task> = contextswitch::list_tasks(filter)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&tasks)?))
}
#[tracing::instrument(level = "debug", skip_all, fields(definition = %task_definition.definition))]
pub async fn add_task(task_definition: web::Json<TaskDefinition>) -> Result<HttpResponse, Error> {
let task_id = contextswitch::add_task(task_definition.definition.split(' ').collect()).await?;
#[tracing::instrument(level = "debug", skip_all, fields(definition = %task.definition))]
pub async fn add_task(task: web::Json<NewTask>) -> Result<HttpResponse, Error> {
let task: Task = contextswitch::add_task(task.definition.split(' ').collect()).await?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(json!({ "id": task_id }).to_string()))
.body(serde_json::to_string(&task)?))
}
#[tracing::instrument(level = "debug")]

View File

@@ -1,21 +1,20 @@
pub mod test_helper;
use contextswitch_api::contextswitch::taskwarrior;
use contextswitch_types::Task;
use contextswitch_types::TaskDefinition;
use contextswitch_api::contextswitch;
use contextswitch_types::{ContextSwitchMetadata, NewTask, Task, TaskId};
use rstest::*;
use test_helper::app_address;
use uuid::Uuid;
#[rstest]
#[tokio::test]
async fn list_tasks(app_address: &str) {
let task_id =
taskwarrior::add_task(vec!["test", "list_tasks", "contextswitch:'{\"test\": 1}'"])
.await
.unwrap();
let task = contextswitch::add_task(vec!["test", "list_tasks", "contextswitch:'{\"test\": 1}'"])
.await
.unwrap();
let tasks: Vec<Task> = reqwest::Client::new()
.get(&format!("{}/tasks?filter={}", &app_address, task_id))
.get(&format!("{}/tasks?filter={}", &app_address, task.id))
.send()
.await
.expect("Failed to execute request")
@@ -34,7 +33,7 @@ async fn list_tasks(app_address: &str) {
async fn add_task(app_address: &str) {
let response: serde_json::Value = reqwest::Client::new()
.post(&format!("{}/tasks", &app_address))
.json(&TaskDefinition {
.json(&NewTask {
definition: "test add_task contextswitch:{\"test\":1}".to_string(),
})
.send()
@@ -43,14 +42,14 @@ async fn add_task(app_address: &str) {
.json()
.await
.expect("Cannot parse JSON result");
let new_task_id = response["id"].as_u64().unwrap();
let tasks = taskwarrior::list_tasks(vec![&new_task_id.to_string()]).unwrap();
let new_task_id = TaskId(Uuid::parse_str(response["id"].as_str().unwrap()).unwrap());
let tasks = contextswitch::list_tasks(vec![&new_task_id.to_string()]).unwrap();
assert_eq!(tasks.len(), 1);
assert_eq!(tasks[0].id, new_task_id);
assert_eq!(tasks[0].description, "test add_task");
assert_eq!(
tasks[0].contextswitch.as_ref().unwrap(),
&"{\"test\":1}".to_string()
&ContextSwitchMetadata { test: 1 }
);
}