From 3a4588b45d1a6eb65a9f2c6ed774d9fef926da49 Mon Sep 17 00:00:00 2001
From: xeruf <27jf@pm.me>
Date: Mon, 25 Nov 2024 02:29:23 +0100
Subject: [PATCH] feat: display task owner

---
 src/task.rs  | 21 ++++++++++++++++-----
 src/tasks.rs |  7 ++++---
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/src/task.rs b/src/task.rs
index ba86338..ae9949a 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -4,13 +4,14 @@ use std::collections::BTreeSet;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::once;
+use std::str::FromStr;
 use std::string::ToString;
 
 use colored::{ColoredString, Colorize};
 use itertools::Either::{Left, Right};
 use itertools::Itertools;
 use log::{debug, error, info, trace, warn};
-use nostr_sdk::{Alphabet, Event, EventId, Kind, Tag, Timestamp};
+use nostr_sdk::{Alphabet, Event, EventId, Kind, PublicKey, SingleLetterTag, Tag, TagKind, Timestamp};
 use crate::hashtag::{is_hashtag, Hashtag};
 use crate::helpers::{format_timestamp_local, some_non_empty};
 use crate::kinds::{match_event_tag, Prio, PRIO, PROCEDURE_KIND, PROCEDURE_KIND_ID, TASK_KIND};
@@ -70,6 +71,15 @@ impl Task {
         &self.event.id
     }
 
+    pub(crate) fn get_owner(&self) -> PublicKey {
+        self.tags()
+            .find(|t| t.kind() == TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::P)))
+            .and_then(|t| t.content()
+                .and_then(|c| PublicKey::from_str(c).inspect_err(|e| warn!("Unparseable pubkey in {:?}", t)).ok()))
+            .unwrap_or_else(|| self.event.pubkey)
+    }
+
+
     pub(crate) fn find_refs<'a>(&'a self, marker: &'a str) -> impl Iterator<Item=&'a EventId> {
         self.refs.iter().filter_map(move |(str, id)| Some(id).filter(|_| str == marker))
     }
@@ -184,11 +194,12 @@ impl Task {
         self.tags().filter_map(|t| Hashtag::try_from(t).ok())
     }
 
+    /// Tags of this task that are not event references, newest to oldest
     fn tags(&self) -> impl Iterator<Item=&Tag> {
-        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)))
-        )
+        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())
     }
 
     fn join_tags<P>(&self, predicate: P) -> String
diff --git a/src/tasks.rs b/src/tasks.rs
index de51531..c0d3f8d 100644
--- a/src/tasks.rs
+++ b/src/tasks.rs
@@ -159,7 +159,7 @@ impl TasksRelay {
             bookmarks: Default::default(),
 
             properties: [
-                "author",
+                "owner",
                 "prio",
                 "state",
                 "rtime",
@@ -170,7 +170,7 @@ impl TasksRelay {
             sorting: [
                 "priority",
                 "status",
-                "author",
+                "owner",
                 "hashtags",
                 "rtime",
                 "name",
@@ -661,6 +661,7 @@ impl TasksRelay {
             }
             "progress" => prog_string.clone(),
 
+            "owner" => format!("{:.6}", self.users.get_username(&task.get_owner())),
             "author" | "creator" => format!("{:.6}", self.users.get_username(&task.event.pubkey)), // FIXME temporary until proper column alignment
             "prio" => self
                 .traverse_up_from(Some(task.event.id))
@@ -1823,7 +1824,7 @@ mod tasks_test {
 
         tasks.custom_time = Some(Timestamp::now());
         tasks.update_state("Finished #YeaH # oi", State::Done);
-        assert_eq!(tasks.get_by_id(&parent).unwrap().list_hashtags().collect_vec(), ["tag1", "YeaH", "oi", "tag3", "yeah"].map(Hashtag::from));
+        assert_eq!(tasks.get_by_id(&parent).unwrap().list_hashtags().collect_vec(), ["YeaH", "oi", "tag3", "yeah", "tag1"].map(Hashtag::from));
         assert_eq!(tasks.all_hashtags(), all_tags);
 
         tasks.custom_time = Some(now());