Return new task after adding a new one
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -349,7 +349,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "contextswitch-types"
|
name = "contextswitch-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/dax/contextswitch-types.git#e26c93cdf8c3ef4c4c82b3d37c4646dcee616b53"
|
source = "git+https://github.com/dax/contextswitch-types.git#cc6db5cc18ab9d67998065004e912756d0a81e28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub fn list_tasks(filters: Vec<&str>) -> Result<Vec<Task>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
pub async fn add_task(add_args: Vec<&str>) -> Result<u64, Error> {
|
pub async fn add_task(add_args: Vec<&str>) -> Result<Task, Error> {
|
||||||
taskwarrior::add_task(add_args).await
|
let taskwarrior_task = taskwarrior::add_task(add_args).await?;
|
||||||
|
(&taskwarrior_task).try_into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use configparser::ini::Ini;
|
use configparser::ini::Ini;
|
||||||
use contextswitch_types::ContextSwitchMetadata;
|
use contextswitch_types::{ContextSwitchMetadata, Task, TaskId};
|
||||||
use contextswitch_types::Task;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fmt;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@@ -14,10 +14,34 @@ use tokio::sync::Mutex;
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use uuid::Uuid;
|
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)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TaskwarriorTask {
|
pub struct TaskwarriorTask {
|
||||||
pub uuid: Uuid,
|
pub uuid: TaskwarriorTaskId,
|
||||||
pub id: u64,
|
pub id: TaskwarriorTaskLocalId,
|
||||||
#[serde(with = "contextswitch_types::tw_date_format")]
|
#[serde(with = "contextswitch_types::tw_date_format")]
|
||||||
pub entry: DateTime<Utc>,
|
pub entry: DateTime<Utc>,
|
||||||
#[serde(with = "contextswitch_types::tw_date_format")]
|
#[serde(with = "contextswitch_types::tw_date_format")]
|
||||||
@@ -65,8 +89,7 @@ impl TryFrom<&TaskwarriorTask> for Task {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Task {
|
Ok(Task {
|
||||||
uuid: task.uuid,
|
id: (&task.uuid).into(),
|
||||||
id: task.id,
|
|
||||||
entry: task.entry,
|
entry: task.entry,
|
||||||
modified: task.modified,
|
modified: task.modified,
|
||||||
status: task.status,
|
status: task.status,
|
||||||
@@ -146,7 +169,23 @@ pub fn list_tasks(filters: Vec<&str>) -> Result<Vec<TaskwarriorTask>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug")]
|
#[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! {
|
lazy_static! {
|
||||||
static ref RE: Regex = Regex::new(r"Created task (?P<id>\d+).").unwrap();
|
static ref RE: Regex = Regex::new(r"Created task (?P<id>\d+).").unwrap();
|
||||||
static ref LOCK: Mutex<u32> = Mutex::new(0);
|
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();
|
.as_str();
|
||||||
|
|
||||||
|
let task_id = TaskwarriorTaskLocalId(
|
||||||
task_id_str
|
task_id_str
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
.map_err(|_| Error::new(ErrorKind::Other, "Cannot parse task ID value"))
|
.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),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use crate::contextswitch;
|
use crate::contextswitch;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
use contextswitch_types::TaskDefinition;
|
use contextswitch_types::{NewTask, Task};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -16,20 +15,20 @@ pub async fn list_tasks(task_query: web::Query<TaskQuery>) -> Result<HttpRespons
|
|||||||
.filter
|
.filter
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(vec![], |filter| filter.split(' ').collect());
|
.map_or(vec![], |filter| filter.split(' ').collect());
|
||||||
let tasks = contextswitch::list_tasks(filter)?;
|
let tasks: Vec<Task> = contextswitch::list_tasks(filter)?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.content_type("application/json")
|
.content_type("application/json")
|
||||||
.body(serde_json::to_string(&tasks)?))
|
.body(serde_json::to_string(&tasks)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, fields(definition = %task_definition.definition))]
|
#[tracing::instrument(level = "debug", skip_all, fields(definition = %task.definition))]
|
||||||
pub async fn add_task(task_definition: web::Json<TaskDefinition>) -> Result<HttpResponse, Error> {
|
pub async fn add_task(task: web::Json<NewTask>) -> Result<HttpResponse, Error> {
|
||||||
let task_id = contextswitch::add_task(task_definition.definition.split(' ').collect()).await?;
|
let task: Task = contextswitch::add_task(task.definition.split(' ').collect()).await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.content_type("application/json")
|
.content_type("application/json")
|
||||||
.body(json!({ "id": task_id }).to_string()))
|
.body(serde_json::to_string(&task)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
pub mod test_helper;
|
pub mod test_helper;
|
||||||
|
|
||||||
use contextswitch_api::contextswitch::taskwarrior;
|
use contextswitch_api::contextswitch;
|
||||||
use contextswitch_types::Task;
|
use contextswitch_types::{ContextSwitchMetadata, NewTask, Task, TaskId};
|
||||||
use contextswitch_types::TaskDefinition;
|
|
||||||
use rstest::*;
|
use rstest::*;
|
||||||
use test_helper::app_address;
|
use test_helper::app_address;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn list_tasks(app_address: &str) {
|
async fn list_tasks(app_address: &str) {
|
||||||
let task_id =
|
let task = contextswitch::add_task(vec!["test", "list_tasks", "contextswitch:'{\"test\": 1}'"])
|
||||||
taskwarrior::add_task(vec!["test", "list_tasks", "contextswitch:'{\"test\": 1}'"])
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let tasks: Vec<Task> = reqwest::Client::new()
|
let tasks: Vec<Task> = reqwest::Client::new()
|
||||||
.get(&format!("{}/tasks?filter={}", &app_address, task_id))
|
.get(&format!("{}/tasks?filter={}", &app_address, task.id))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.expect("Failed to execute request")
|
.expect("Failed to execute request")
|
||||||
@@ -34,7 +33,7 @@ async fn list_tasks(app_address: &str) {
|
|||||||
async fn add_task(app_address: &str) {
|
async fn add_task(app_address: &str) {
|
||||||
let response: serde_json::Value = reqwest::Client::new()
|
let response: serde_json::Value = reqwest::Client::new()
|
||||||
.post(&format!("{}/tasks", &app_address))
|
.post(&format!("{}/tasks", &app_address))
|
||||||
.json(&TaskDefinition {
|
.json(&NewTask {
|
||||||
definition: "test add_task contextswitch:{\"test\":1}".to_string(),
|
definition: "test add_task contextswitch:{\"test\":1}".to_string(),
|
||||||
})
|
})
|
||||||
.send()
|
.send()
|
||||||
@@ -43,14 +42,14 @@ async fn add_task(app_address: &str) {
|
|||||||
.json()
|
.json()
|
||||||
.await
|
.await
|
||||||
.expect("Cannot parse JSON result");
|
.expect("Cannot parse JSON result");
|
||||||
let new_task_id = response["id"].as_u64().unwrap();
|
let new_task_id = TaskId(Uuid::parse_str(response["id"].as_str().unwrap()).unwrap());
|
||||||
let tasks = taskwarrior::list_tasks(vec![&new_task_id.to_string()]).unwrap();
|
let tasks = contextswitch::list_tasks(vec![&new_task_id.to_string()]).unwrap();
|
||||||
|
|
||||||
assert_eq!(tasks.len(), 1);
|
assert_eq!(tasks.len(), 1);
|
||||||
assert_eq!(tasks[0].id, new_task_id);
|
assert_eq!(tasks[0].id, new_task_id);
|
||||||
assert_eq!(tasks[0].description, "test add_task");
|
assert_eq!(tasks[0].description, "test add_task");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tasks[0].contextswitch.as_ref().unwrap(),
|
tasks[0].contextswitch.as_ref().unwrap(),
|
||||||
&"{\"test\":1}".to_string()
|
&ContextSwitchMetadata { test: 1 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user