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 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 pub attachments: Vec<Attachment>,
26 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#[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 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#[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#[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}