Add bookmarks to Contextswitch data
This commit is contained in:
@@ -4,4 +4,5 @@ repos:
|
||||
hooks:
|
||||
- id: fmt
|
||||
- id: cargo-check
|
||||
args: ['--tests']
|
||||
- id: clippy
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -336,6 +336,7 @@ dependencies = [
|
||||
"configparser",
|
||||
"contextswitch-types",
|
||||
"dotenv",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"listenfd",
|
||||
"mktemp",
|
||||
@@ -357,9 +358,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "contextswitch-types"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/dax/contextswitch-types.git#5f72fdda034db4eb7b22fd1c5d6936f39360880c"
|
||||
source = "git+https://github.com/dax/contextswitch-types.git#d99bd6e6aebece04a41bdf62f00eaafcb73640ea"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"http",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
|
||||
@@ -30,9 +30,10 @@ tracing-log = "0.1.0"
|
||||
tracing-actix-web = "=0.5.0-beta.9"
|
||||
regex = "1.5.0"
|
||||
lazy_static = "1.4.0"
|
||||
tracing-bunyan-formatter = "0.3.2"
|
||||
thiserror = "1.0.30"
|
||||
anyhow = "1.0.53"
|
||||
tracing-bunyan-formatter = "0.3.0"
|
||||
thiserror = "1.0"
|
||||
anyhow = "1.0"
|
||||
http = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["json"] }
|
||||
|
||||
@@ -23,11 +23,11 @@ impl std::fmt::Debug for ContextswitchError {
|
||||
|
||||
#[derive(thiserror::Error)]
|
||||
pub enum ContextswitchError {
|
||||
#[error("Invalid Contextswitch metadata: {metadata}")]
|
||||
InvalidMetadataError {
|
||||
#[error("Invalid Contextswitch data: {data}")]
|
||||
InvalidDataError {
|
||||
#[source]
|
||||
source: serde_json::Error,
|
||||
metadata: String,
|
||||
data: String,
|
||||
},
|
||||
#[error(transparent)]
|
||||
UnexpectedError(#[from] anyhow::Error),
|
||||
@@ -35,12 +35,12 @@ pub enum ContextswitchError {
|
||||
|
||||
#[tracing::instrument(level = "debug")]
|
||||
pub fn list_tasks(filters: Vec<&str>) -> Result<Vec<Task>, ContextswitchError> {
|
||||
let tasks: Result<Vec<Task>, ContextswitchError> = taskwarrior::list_tasks(filters)
|
||||
let tasks: Vec<Task> = taskwarrior::list_tasks(filters)
|
||||
.map_err(|e| ContextswitchError::UnexpectedError(e.into()))?
|
||||
.iter()
|
||||
.map(Task::try_from)
|
||||
.map(Task::from)
|
||||
.collect();
|
||||
tasks
|
||||
Ok(tasks)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug")]
|
||||
@@ -48,5 +48,5 @@ pub async fn add_task(add_args: Vec<&str>) -> Result<Task, ContextswitchError> {
|
||||
let taskwarrior_task = taskwarrior::add_task(add_args)
|
||||
.await
|
||||
.map_err(|e| ContextswitchError::UnexpectedError(e.into()))?;
|
||||
(&taskwarrior_task).try_into()
|
||||
Ok((&taskwarrior_task).into())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::contextswitch::ContextswitchError;
|
||||
use anyhow::{anyhow, Context};
|
||||
use chrono::{DateTime, Utc};
|
||||
use configparser::ini::Ini;
|
||||
use contextswitch_types::{ContextSwitchMetadata, Task, TaskId};
|
||||
use contextswitch_types::{ContextswitchData, Task, TaskId};
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
@@ -12,7 +11,7 @@ use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Eq)]
|
||||
@@ -88,27 +87,23 @@ pub struct TaskwarriorTask {
|
||||
pub contextswitch: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&TaskwarriorTask> for Task {
|
||||
type Error = ContextswitchError;
|
||||
impl From<&TaskwarriorTask> for Task {
|
||||
fn from(task: &TaskwarriorTask) -> Self {
|
||||
let cs_data =
|
||||
task.contextswitch
|
||||
.as_ref()
|
||||
.and_then(|cs_string| -> Option<ContextswitchData> {
|
||||
let contextswitch_data_result = serde_json::from_str(cs_string);
|
||||
if contextswitch_data_result.is_err() {
|
||||
warn!(
|
||||
"Invalid Contextswitch data found in {}: {}",
|
||||
&task.uuid, cs_string
|
||||
);
|
||||
}
|
||||
contextswitch_data_result.ok()
|
||||
});
|
||||
|
||||
fn try_from(task: &TaskwarriorTask) -> Result<Self, Self::Error> {
|
||||
let cs_metadata = task.contextswitch.as_ref().map_or(
|
||||
Ok(None),
|
||||
|cs_string| -> Result<Option<ContextSwitchMetadata>, ContextswitchError> {
|
||||
if cs_string.is_empty() || cs_string == "{}" {
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(serde_json::from_str(cs_string))
|
||||
.transpose()
|
||||
.map_err(|e| ContextswitchError::InvalidMetadataError {
|
||||
source: e,
|
||||
metadata: cs_string.to_string(),
|
||||
})
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Task {
|
||||
Task {
|
||||
id: (&task.uuid).into(),
|
||||
entry: task.entry,
|
||||
modified: task.modified,
|
||||
@@ -124,8 +119,8 @@ impl TryFrom<&TaskwarriorTask> for Task {
|
||||
priority: task.priority,
|
||||
recur: task.recur,
|
||||
tags: task.tags.clone(),
|
||||
contextswitch: cs_metadata,
|
||||
})
|
||||
contextswitch: cs_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +145,7 @@ fn write_default_config(data_location: &str) -> String {
|
||||
taskrc.setstr(
|
||||
"default",
|
||||
"uda.contextswitch.label",
|
||||
Some("Context Switch metadata"),
|
||||
Some("Contextswitch data"),
|
||||
);
|
||||
taskrc.setstr("default", "uda.contextswitch.default", Some("{}"));
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ pub struct TaskQuery {
|
||||
impl ResponseError for contextswitch::ContextswitchError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
contextswitch::ContextswitchError::InvalidMetadataError { .. } => {
|
||||
contextswitch::ContextswitchError::InvalidDataError { .. } => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
contextswitch::ContextswitchError::UnexpectedError(_) => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
pub mod test_helper;
|
||||
|
||||
use contextswitch_api::contextswitch;
|
||||
use contextswitch_types::{ContextSwitchMetadata, NewTask, Task, TaskId};
|
||||
use contextswitch_types::{Bookmark, ContextswitchData, NewTask, Task, TaskId};
|
||||
use http::uri::Uri;
|
||||
use rstest::*;
|
||||
use test_helper::app_address;
|
||||
use uuid::Uuid;
|
||||
@@ -9,9 +10,13 @@ use uuid::Uuid;
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn list_tasks(app_address: &str) {
|
||||
let task = contextswitch::add_task(vec!["test", "list_tasks", "contextswitch:'{\"test\": 1}'"])
|
||||
.await
|
||||
.unwrap();
|
||||
let task = contextswitch::add_task(vec![
|
||||
"test",
|
||||
"list_tasks",
|
||||
"contextswitch:'{\"bookmarks\":[{\"uri\":\"https://example.com/path?filter=1\"}]}'",
|
||||
])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let tasks: Vec<Task> = reqwest::Client::new()
|
||||
.get(&format!("{}/tasks?filter={}", &app_address, task.id))
|
||||
@@ -24,8 +29,69 @@ async fn list_tasks(app_address: &str) {
|
||||
|
||||
assert_eq!(tasks.len(), 1);
|
||||
assert_eq!(tasks[0].description, "test list_tasks");
|
||||
let cs_metadata = tasks[0].contextswitch.as_ref().unwrap();
|
||||
assert_eq!(cs_metadata.test, 1);
|
||||
let cs_data = tasks[0].contextswitch.as_ref().unwrap();
|
||||
assert_eq!(cs_data.bookmarks.len(), 1);
|
||||
assert_eq!(cs_data.bookmarks[0].content, None);
|
||||
assert_eq!(
|
||||
cs_data.bookmarks[0].uri,
|
||||
"https://example.com/path?filter=1".parse::<Uri>().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn list_tasks_with_unknown_contextswitch_data(app_address: &str) {
|
||||
let task = contextswitch::add_task(vec![
|
||||
"test",
|
||||
"list_tasks_with_unknown_contextswitch_data",
|
||||
"contextswitch:'{\"unknown\": 1}'",
|
||||
])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let tasks: Vec<Task> = reqwest::Client::new()
|
||||
.get(&format!("{}/tasks?filter={}", &app_address, task.id))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
.json()
|
||||
.await
|
||||
.expect("Cannot parse JSON result");
|
||||
|
||||
assert_eq!(tasks.len(), 1);
|
||||
assert_eq!(
|
||||
tasks[0].description,
|
||||
"test list_tasks_with_unknown_contextswitch_data"
|
||||
);
|
||||
assert!(tasks[0].contextswitch.is_none());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn list_tasks_with_invalid_contextswitch_data(app_address: &str) {
|
||||
let task = contextswitch::add_task(vec![
|
||||
"test",
|
||||
"list_tasks_with_invalid_contextswitch_data",
|
||||
"contextswitch:'}'",
|
||||
])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let tasks: Vec<Task> = reqwest::Client::new()
|
||||
.get(&format!("{}/tasks?filter={}", &app_address, task.id))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
.json()
|
||||
.await
|
||||
.expect("Cannot parse JSON result");
|
||||
|
||||
assert_eq!(tasks.len(), 1);
|
||||
assert_eq!(
|
||||
tasks[0].description,
|
||||
"test list_tasks_with_invalid_contextswitch_data"
|
||||
);
|
||||
assert!(tasks[0].contextswitch.is_none());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -34,7 +100,9 @@ async fn add_task(app_address: &str) {
|
||||
let response: serde_json::Value = reqwest::Client::new()
|
||||
.post(&format!("{}/tasks", &app_address))
|
||||
.json(&NewTask {
|
||||
definition: "test add_task contextswitch:{\"test\":1}".to_string(),
|
||||
definition:
|
||||
"test add_task contextswitch:{\"bookmarks\":[{\"uri\":\"https://example.com/path?filter=1\"}]}"
|
||||
.to_string(),
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
@@ -50,6 +118,11 @@ async fn add_task(app_address: &str) {
|
||||
assert_eq!(tasks[0].description, "test add_task");
|
||||
assert_eq!(
|
||||
tasks[0].contextswitch.as_ref().unwrap(),
|
||||
&ContextSwitchMetadata { test: 1 }
|
||||
&ContextswitchData {
|
||||
bookmarks: vec![Bookmark {
|
||||
uri: "https://example.com/path?filter=1".parse::<Uri>().unwrap(),
|
||||
content: None
|
||||
}]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user