1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(tag = "type")]
12pub enum JiraAuth {
13 OAuth2 {
15 client_id: String,
17 client_secret: String,
19 access_token: String,
21 refresh_token: Option<String>,
23 },
24 Basic {
26 email: String,
28 api_token: String,
30 },
31 PersonalAccessToken {
33 token: String,
35 },
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct JiraConfig {
41 pub base_url: String,
43 pub auth: JiraAuth,
45 #[serde(default = "default_timeout")]
47 pub timeout_secs: u64,
48 #[serde(default = "default_max_retries")]
50 pub max_retries: u32,
51 #[serde(default = "default_rate_limit")]
53 pub rate_limit_per_minute: u32,
54}
55
56fn default_timeout() -> u64 {
57 30
58}
59
60fn default_max_retries() -> u32 {
61 3
62}
63
64fn default_rate_limit() -> u32 {
65 100
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Issue {
71 pub id: String,
73 pub key: String,
75 pub fields: IssueFields,
77 #[serde(rename = "self")]
79 pub self_url: String,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct IssueFields {
85 pub summary: String,
87 pub description: Option<String>,
89 #[serde(rename = "issuetype")]
91 pub issue_type: IssueType,
92 pub status: Status,
94 pub priority: Option<Priority>,
96 pub assignee: Option<User>,
98 pub reporter: Option<User>,
100 pub project: Project,
102 #[serde(default)]
104 pub labels: Vec<String>,
105 #[serde(default)]
107 pub components: Vec<Component>,
108 pub created: String,
110 pub updated: String,
112 #[serde(flatten)]
114 pub custom_fields: HashMap<String, serde_json::Value>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct IssueType {
120 pub id: String,
121 pub name: String,
122 pub description: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct Status {
128 pub id: String,
129 pub name: String,
130 pub description: Option<String>,
131 #[serde(rename = "statusCategory")]
132 pub status_category: StatusCategory,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct StatusCategory {
138 pub id: i32,
139 pub key: String,
140 pub name: String,
141 #[serde(rename = "colorName")]
142 pub color_name: String,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct Priority {
148 pub id: String,
149 pub name: String,
150 #[serde(rename = "iconUrl")]
151 pub icon_url: Option<String>,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct User {
157 #[serde(rename = "accountId")]
158 pub account_id: String,
159 #[serde(rename = "displayName")]
160 pub display_name: String,
161 #[serde(rename = "emailAddress")]
162 pub email_address: Option<String>,
163 pub active: bool,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct Project {
169 pub id: String,
170 pub key: String,
171 pub name: String,
172 pub description: Option<String>,
173 #[serde(rename = "projectTypeKey")]
174 pub project_type_key: String,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct Component {
180 pub id: String,
181 pub name: String,
182 pub description: Option<String>,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct CreateIssueRequest {
188 pub fields: CreateIssueFields,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct CreateIssueFields {
194 pub project: ProjectRef,
195 pub summary: String,
196 pub description: Option<String>,
197 #[serde(rename = "issuetype")]
198 pub issue_type: IssueTypeRef,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub assignee: Option<UserRef>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub priority: Option<PriorityRef>,
203 #[serde(default, skip_serializing_if = "Vec::is_empty")]
204 pub labels: Vec<String>,
205 #[serde(default, skip_serializing_if = "Vec::is_empty")]
206 pub components: Vec<ComponentRef>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ProjectRef {
212 pub key: String,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct IssueTypeRef {
218 pub name: String,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct UserRef {
224 #[serde(rename = "accountId")]
225 pub account_id: String,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct PriorityRef {
231 pub name: String,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct ComponentRef {
237 pub name: String,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct UpdateIssueRequest {
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub fields: Option<HashMap<String, serde_json::Value>>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub update: Option<HashMap<String, Vec<UpdateOperation>>>,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(tag = "operation", content = "value")]
252pub enum UpdateOperation {
253 #[serde(rename = "add")]
254 Add(serde_json::Value),
255 #[serde(rename = "set")]
256 Set(serde_json::Value),
257 #[serde(rename = "remove")]
258 Remove(serde_json::Value),
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct JqlSearchRequest {
264 pub jql: String,
266 #[serde(skip_serializing_if = "Option::is_none")]
268 #[serde(rename = "startAt")]
269 pub start_at: Option<u32>,
270 #[serde(skip_serializing_if = "Option::is_none")]
272 #[serde(rename = "maxResults")]
273 pub max_results: Option<u32>,
274 #[serde(skip_serializing_if = "Option::is_none")]
276 pub fields: Option<Vec<String>>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct JqlSearchResponse {
282 pub total: u32,
284 #[serde(rename = "startAt")]
286 pub start_at: u32,
287 #[serde(rename = "maxResults")]
289 pub max_results: u32,
290 pub issues: Vec<Issue>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct Board {
297 pub id: u64,
298 pub name: String,
299 #[serde(rename = "type")]
300 pub board_type: String,
301 #[serde(rename = "self")]
302 pub self_url: String,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct Sprint {
308 pub id: u64,
309 pub name: String,
310 pub state: String,
311 #[serde(rename = "startDate")]
312 pub start_date: Option<String>,
313 #[serde(rename = "endDate")]
314 pub end_date: Option<String>,
315 #[serde(rename = "originBoardId")]
316 pub origin_board_id: u64,
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct WebhookEvent {
322 pub timestamp: i64,
324 #[serde(rename = "webhookEvent")]
326 pub webhook_event: String,
327 #[serde(rename = "issue_event_type_name")]
329 pub issue_event_type_name: Option<String>,
330 pub user: Option<User>,
332 pub issue: Option<Issue>,
334 pub changelog: Option<Changelog>,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct Changelog {
341 pub id: String,
342 pub items: Vec<ChangelogItem>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ChangelogItem {
348 pub field: String,
349 #[serde(rename = "fieldtype")]
350 pub field_type: String,
351 #[serde(rename = "fieldId")]
352 pub field_id: Option<String>,
353 pub from: Option<String>,
354 #[serde(rename = "fromString")]
355 pub from_string: Option<String>,
356 pub to: Option<String>,
357 #[serde(rename = "toString")]
358 pub to_string: Option<String>,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct ErrorResponse {
364 #[serde(rename = "errorMessages")]
365 pub error_messages: Vec<String>,
366 pub errors: HashMap<String, String>,
367}
368
369#[derive(Debug, Clone)]
371pub struct RateLimitInfo {
372 pub remaining: u32,
374 pub limit: u32,
376 pub reset_at: i64,
378}