diff --git a/crates/buzz-cli/src/commands/users.rs b/crates/buzz-cli/src/commands/users.rs index ae118cc4f8..3f8325b4b9 100644 --- a/crates/buzz-cli/src/commands/users.rs +++ b/crates/buzz-cli/src/commands/users.rs @@ -265,7 +265,7 @@ pub async fn cmd_get_presence(client: &BuzzClient, pubkeys_csv: &str) -> Result< .iter() .map(|e| { serde_json::json!({ - "pubkey": e.get("pubkey").and_then(|v| v.as_str()).unwrap_or(""), + "pubkey": presence_subject(e), "status": e.get("content").and_then(|v| v.as_str()).unwrap_or(""), "updated_at": e.get("created_at").and_then(|v| v.as_u64()).unwrap_or(0), }) @@ -276,6 +276,20 @@ pub async fn cmd_get_presence(client: &BuzzClient, pubkeys_csv: &str) -> Result< Ok(()) } +fn presence_subject(event: &serde_json::Value) -> &str { + event + .get("tags") + .and_then(|tags| tags.as_array()) + .and_then(|tags| { + tags.iter() + .find_map(|tag| match tag.as_array()?.as_slice() { + [name, subject, ..] if name == "p" => subject.as_str(), + _ => None, + }) + }) + .unwrap_or_else(|| event.get("pubkey").and_then(|v| v.as_str()).unwrap_or("")) +} + /// Set presence status — sign and submit a kind:20001 presence update event via WebSocket. /// /// Kind 20001 is ephemeral and only accepted via WebSocket connections. This @@ -319,3 +333,27 @@ pub async fn dispatch( UsersCmd::SetPresence { status } => cmd_set_presence(client, &status.to_string()).await, } } + +#[cfg(test)] +mod tests { + use super::presence_subject; + use serde_json::json; + + #[test] + fn presence_subject_uses_p_tag() { + let event = json!({"pubkey": "relay", "tags": [["p", "user"]]}); + assert_eq!(presence_subject(&event), "user"); + } + + #[test] + fn presence_subject_falls_back_to_author_without_p_tag() { + let event = json!({"pubkey": "user", "tags": [["status", "online"]]}); + assert_eq!(presence_subject(&event), "user"); + } + + #[test] + fn presence_subject_falls_back_to_author_for_malformed_p_tag() { + let event = json!({"pubkey": "user", "tags": [["p"]]}); + assert_eq!(presence_subject(&event), "user"); + } +}