Skip to main content

jira_core/model/
link.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct IssueLinkType {
6    pub id: String,
7    pub name: String,
8    pub inward: String,
9    pub outward: String,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct LinkedIssue {
14    pub id: String,
15    pub key: String,
16    pub summary: String,
17    pub status: String,
18    pub priority: Option<String>,
19    pub issue_type: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct IssueLink {
24    pub id: String,
25    #[serde(rename = "type")]
26    pub link_type: IssueLinkType,
27    #[serde(rename = "inwardIssue")]
28    pub inward_issue: Option<LinkedIssue>,
29    #[serde(rename = "outwardIssue")]
30    pub outward_issue: Option<LinkedIssue>,
31}
32
33impl LinkedIssue {
34    pub fn from_value(value: &Value) -> Option<Self> {
35        let id = value.get("id")?.as_str()?.to_string();
36        let key = value.get("key")?.as_str()?.to_string();
37        let fields = value.get("fields")?;
38
39        // Use the same defaulting pattern as `RawIssue::into_issue`: missing
40        // textual fields fall back to a placeholder instead of dropping the
41        // whole linked issue. Caller relies on `id`/`key` being present.
42        let summary = fields
43            .get("summary")
44            .and_then(|v| v.as_str())
45            .unwrap_or("")
46            .to_string();
47        let status = fields
48            .get("status")
49            .and_then(|s| s.get("name"))
50            .and_then(|v| v.as_str())
51            .unwrap_or("Unknown")
52            .to_string();
53        let priority = fields
54            .get("priority")
55            .and_then(|p| p.get("name"))
56            .and_then(|v| v.as_str())
57            .map(|s| s.to_string());
58        let issue_type = fields
59            .get("issuetype")
60            .and_then(|i| i.get("name"))
61            .and_then(|v| v.as_str())
62            .unwrap_or("Unknown")
63            .to_string();
64
65        Some(Self {
66            id,
67            key,
68            summary,
69            status,
70            priority,
71            issue_type,
72        })
73    }
74}
75
76impl IssueLink {
77    pub fn from_value(value: &Value) -> Option<Self> {
78        let id = value.get("id")?.as_str()?.to_string();
79        let type_val = value.get("type")?;
80        let link_type = IssueLinkType {
81            id: type_val.get("id")?.as_str()?.to_string(),
82            name: type_val.get("name")?.as_str()?.to_string(),
83            inward: type_val.get("inward")?.as_str()?.to_string(),
84            outward: type_val.get("outward")?.as_str()?.to_string(),
85        };
86
87        let inward_issue = value.get("inwardIssue").and_then(LinkedIssue::from_value);
88        let outward_issue = value.get("outwardIssue").and_then(LinkedIssue::from_value);
89
90        Some(Self {
91            id,
92            link_type,
93            inward_issue,
94            outward_issue,
95        })
96    }
97}