Skip to main content

jira_core/model/
issue.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use super::attachment::Attachment;
7use super::field::FieldValue;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Issue {
11    pub id: String,
12    pub key: String,
13    pub summary: String,
14    /// ADF (Atlassian Document Format) JSON
15    pub description: Option<Value>,
16    pub status: String,
17    pub assignee: Option<String>,
18    pub reporter: Option<String>,
19    pub priority: Option<String>,
20    pub issue_type: String,
21    pub project_key: String,
22    pub created: String,
23    pub updated: String,
24    /// Attachments on this issue
25    pub attachments: Vec<Attachment>,
26    /// Raw fields map for custom fields
27    pub fields: Value,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, Default)]
31pub struct CreateIssueRequest {
32    pub project_key: String,
33    pub summary: String,
34    pub description: Option<String>,
35    pub issue_type: String,
36    pub assignee: Option<String>,
37    pub priority: Option<String>,
38}
39
40/// Extended create request with dynamic custom fields.
41#[derive(Debug, Clone, Default)]
42pub struct CreateIssueRequestV2 {
43    pub project_key: String,
44    pub summary: String,
45    pub description: Option<String>,
46    pub issue_type: String,
47    pub assignee: Option<String>,
48    pub priority: Option<String>,
49    /// Custom field ID → typed value
50    pub custom_fields: HashMap<String, FieldValue>,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, Default)]
54pub struct UpdateIssueRequest {
55    pub summary: Option<String>,
56    pub description: Option<String>,
57    pub assignee: Option<String>,
58    pub priority: Option<String>,
59    pub status: Option<String>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct SearchResult {
64    pub issues: Vec<Issue>,
65    pub next_page_token: Option<String>,
66    pub total: Option<u64>,
67}
68
69/// Raw Jira API issue response — used internally for deserialization
70#[derive(Debug, Deserialize)]
71pub(crate) struct RawIssue {
72    pub id: String,
73    pub key: String,
74    pub fields: Value,
75}
76
77impl RawIssue {
78    pub fn into_issue(self) -> Issue {
79        let fields = &self.fields;
80
81        let summary = fields
82            .get("summary")
83            .and_then(|v| v.as_str())
84            .unwrap_or("")
85            .to_string();
86
87        let description = fields.get("description").cloned();
88
89        let status = fields
90            .get("status")
91            .and_then(|v| v.get("name"))
92            .and_then(|v| v.as_str())
93            .unwrap_or("Unknown")
94            .to_string();
95
96        let assignee = fields
97            .get("assignee")
98            .and_then(|v| v.get("emailAddress").or_else(|| v.get("displayName")))
99            .and_then(|v| v.as_str())
100            .map(|s| s.to_string());
101
102        let reporter = fields
103            .get("reporter")
104            .and_then(|v| v.get("emailAddress").or_else(|| v.get("displayName")))
105            .and_then(|v| v.as_str())
106            .map(|s| s.to_string());
107
108        let priority = fields
109            .get("priority")
110            .and_then(|v| v.get("name"))
111            .and_then(|v| v.as_str())
112            .map(|s| s.to_string());
113
114        let issue_type = fields
115            .get("issuetype")
116            .and_then(|v| v.get("name"))
117            .and_then(|v| v.as_str())
118            .unwrap_or("Unknown")
119            .to_string();
120
121        let project_key = fields
122            .get("project")
123            .and_then(|v| v.get("key"))
124            .and_then(|v| v.as_str())
125            .unwrap_or("")
126            .to_string();
127
128        let created = fields
129            .get("created")
130            .and_then(|v| v.as_str())
131            .unwrap_or("")
132            .to_string();
133
134        let updated = fields
135            .get("updated")
136            .and_then(|v| v.as_str())
137            .unwrap_or("")
138            .to_string();
139
140        let attachments = fields
141            .get("attachment")
142            .and_then(|v| v.as_array())
143            .map(|arr| arr.iter().filter_map(Attachment::from_value).collect())
144            .unwrap_or_default();
145
146        Issue {
147            id: self.id,
148            key: self.key,
149            summary,
150            description,
151            status,
152            assignee,
153            reporter,
154            priority,
155            issue_type,
156            project_key,
157            created,
158            updated,
159            attachments,
160            fields: self.fields,
161        }
162    }
163}
164
165/// Raw search response from Jira API
166#[derive(Debug, Deserialize)]
167pub(crate) struct RawSearchResponse {
168    pub issues: Vec<RawIssue>,
169    #[serde(rename = "nextPageToken")]
170    pub next_page_token: Option<String>,
171    pub total: Option<u64>,
172}