Skip to main content

jira_core/model/
watcher.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Watcher {
6    pub self_url: String,
7    pub account_id: String,
8    pub display_name: String,
9    pub active: bool,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Watchers {
14    pub issue_key: String,
15    pub is_watching: bool,
16    pub watch_count: u64,
17    pub watchers: Vec<Watcher>,
18}
19
20impl Watcher {
21    pub fn from_value(v: &Value) -> Option<Self> {
22        Some(Watcher {
23            self_url: v
24                .get("self")
25                .and_then(|s| s.as_str())
26                .unwrap_or("")
27                .to_string(),
28            account_id: v.get("accountId")?.as_str()?.to_string(),
29            display_name: v
30                .get("displayName")
31                .and_then(|n| n.as_str())
32                .unwrap_or("")
33                .to_string(),
34            active: v.get("active").and_then(|a| a.as_bool()).unwrap_or(true),
35        })
36    }
37}
38
39impl Watchers {
40    pub fn from_value(v: &Value, issue_key: &str) -> Option<Self> {
41        Some(Watchers {
42            issue_key: issue_key.to_string(),
43            is_watching: v
44                .get("isWatching")
45                .and_then(|b| b.as_bool())
46                .unwrap_or(false),
47            watch_count: v.get("watchCount").and_then(|c| c.as_u64()).unwrap_or(0),
48            watchers: v
49                .get("watchers")
50                .and_then(|w| w.as_array())
51                .map(|arr| arr.iter().filter_map(Watcher::from_value).collect())
52                .unwrap_or_default(),
53        })
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use serde_json::json;
61
62    #[test]
63    fn parses_watcher() {
64        let v = json!({
65            "self": "https://x.atlassian.net/rest/api/3/user?accountId=abc",
66            "accountId": "abc",
67            "displayName": "Alice",
68            "active": true
69        });
70        let w = Watcher::from_value(&v).unwrap();
71        assert_eq!(w.account_id, "abc");
72        assert_eq!(w.display_name, "Alice");
73        assert!(w.active);
74    }
75
76    #[test]
77    fn parses_watchers_envelope() {
78        let v = json!({
79            "isWatching": true,
80            "watchCount": 2,
81            "watchers": [
82                {"self": "", "accountId": "a", "displayName": "Alice", "active": true},
83                {"self": "", "accountId": "b", "displayName": "Bob", "active": false}
84            ]
85        });
86        let ws = Watchers::from_value(&v, "ABC-1").unwrap();
87        assert_eq!(ws.issue_key, "ABC-1");
88        assert!(ws.is_watching);
89        assert_eq!(ws.watch_count, 2);
90        assert_eq!(ws.watchers.len(), 2);
91        assert_eq!(ws.watchers[1].account_id, "b");
92        assert!(!ws.watchers[1].active);
93    }
94
95    #[test]
96    fn parses_empty_watchers() {
97        let v = json!({"isWatching": false, "watchCount": 0, "watchers": []});
98        let ws = Watchers::from_value(&v, "ABC-2").unwrap();
99        assert_eq!(ws.watch_count, 0);
100        assert!(ws.watchers.is_empty());
101    }
102}