diff --git a/src/kinds.rs b/src/kinds.rs index f96b5a3..2989af4 100644 --- a/src/kinds.rs +++ b/src/kinds.rs @@ -113,7 +113,7 @@ pub(crate) fn extract_tags(input: &str) -> (String, Vec) { (main, tags) } -fn to_hashtag(tag: &str) -> Tag { +pub fn to_hashtag(tag: &str) -> Tag { TagStandard::Hashtag(tag.to_string()).into() } diff --git a/src/task.rs b/src/task.rs index fbea130..8dfcaa3 100644 --- a/src/task.rs +++ b/src/task.rs @@ -14,6 +14,7 @@ use nostr_sdk::{Alphabet, Event, EventId, Kind, Tag, TagStandard, Timestamp}; use crate::helpers::{format_timestamp_local, some_non_empty}; use crate::kinds::{is_hashtag, Prio, PRIO, PROCEDURE_KIND, PROCEDURE_KIND_ID, TASK_KIND}; +use crate::tasks::now; pub static MARKER_PARENT: &str = "parent"; pub static MARKER_DEPENDS: &str = "depends"; @@ -137,7 +138,7 @@ impl Task { } pub(crate) fn state(&self) -> Option { - let now = Timestamp::now(); + let now = now(); // TODO do not iterate constructed state objects let state = self.states().rev().take_while_inclusive(|ts| ts.time > now); state.last().map(|ts| { @@ -177,9 +178,10 @@ impl Task { } fn tags(&self) -> impl Iterator { - self.props.iter().flat_map(|e| e.tags.iter() - .filter(|t| t.single_letter_tag().is_none_or(|s| s.character != Alphabet::E))) - .chain(self.tags.iter().flatten()) + self.tags.iter().flatten().chain( + self.props.iter().flat_map(|e| e.tags.iter() + .filter(|t| t.single_letter_tag().is_none_or(|s| s.character != Alphabet::E))) + ) } fn join_tags

(&self, predicate: P) -> String @@ -200,7 +202,7 @@ impl Task { "id" => Some(self.event.id.to_string()), "parentid" => self.parent_id().map(|i| i.to_string()), "name" => Some(self.event.content.clone()), - "pubkey" => Some(self.event.pubkey.to_string()), + "key" | "pubkey" => Some(self.event.pubkey.to_string()), "created" => Some(format_timestamp_local(&self.event.created_at)), "kind" => Some(self.event.kind.to_string()), // Dynamic @@ -209,7 +211,7 @@ impl Task { "desc" => self.descriptions().last().cloned(), "description" => Some(self.descriptions().join(" ")), "hashtags" => Some(self.join_tags(|tag| { is_hashtag(tag) })), - "tags" => Some(self.join_tags(|_| true)), + "tags" => Some(self.join_tags(|_| true)), // TODO test these! "alltags" => Some(format!("{:?}", self.tags)), "refs" => Some(format!("{:?}", self.refs.iter().map(|re| format!("{}: {}", re.0, re.1)).collect_vec())), "props" => Some(format!( diff --git a/src/tasks.rs b/src/tasks.rs index 59c7c32..8db9da7 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1646,14 +1646,21 @@ mod tasks_test { #[test] fn test_recursive_closing() { let mut tasks = stub_tasks(); + + tasks.custom_time = Some(Timestamp::zero()); let parent = tasks.make_task("parent #tag1"); tasks.move_to(Some(parent)); - let sub = tasks.make_task("sub # tag2"); - assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2"]); + let sub = tasks.make_task("sub #oi # tag2"); + assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2"]); tasks.make_note("note with #tag3 # yeah"); - assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2", "tag3", "yeah"]); - tasks.update_state("Done #yei", State::Done); - // TODO assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2", "tag3", "yeah", "yei"]); + assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2", "tag3", "yeah"]); + + tasks.custom_time = Some(Timestamp::now()); + tasks.update_state("Finished #yeah # oi", State::Done); + assert_eq!(tasks.get_by_id(&parent).unwrap().get_hashtags().cloned().collect_vec(), ["tag1", "tag3", "yeah", "oi", "yeah"].map(to_hashtag)); + assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2", "tag3", "yeah"]); + + tasks.custom_time = Some(now()); tasks.update_state("Closing Down", State::Closed); assert_eq!(tasks.get_by_id(&sub).unwrap().pure_state(), State::Closed); assert_eq!(tasks.all_hashtags().next(), None);