rust_cnb/
issues.rs

1//! Issues API 客户端
2
3use crate::error::{ApiError, Result};
4use reqwest::Client;
5use serde_json::Value;
6use url::Url;
7
8/// Issues API 客户端
9pub struct IssuesClient {
10    base_url: String,
11    client: Client,
12}
13
14impl IssuesClient {
15    /// 创建新的 Issues API 客户端
16    pub fn new(base_url: String, client: Client) -> Self {
17        Self { base_url, client }
18    }
19
20    /// 设置认证信息
21    pub fn with_auth(self, token: &str) -> Self {
22        // 这里可以扩展认证逻辑
23        self
24    }
25
26    /// 检查用户是否可以被添加到 Issue 的 Assignees 中。 Checks if a user can be assigned to an issue.
27    pub async fn get_repo_issues_number_assignees_assignee(
28        &self,
29        repo: String,
30        number: String,
31        assignee: String,
32    ) -> Result<Value> {
33        let path = format!("/{}/-/issues/{}/assignees/{}", repo, number, assignee);
34        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
35        
36
37                let request = self.client.request(
38            reqwest::Method::GET,
39            url
40        );
41        
42
43
44
45        let response = request.send().await?;
46        
47        if response.status().is_success() {
48            let json: Value = response.json().await?;
49            Ok(json)
50        } else {
51            Err(ApiError::HttpError(response.status().as_u16()))
52        }
53    }
54
55    /// 获取一个 Issue Comment。Get an issue comment.
56    pub async fn get_repo_issues_number_comments_comment_id(
57        &self,
58        repo: String,
59        number: String,
60        comment_id: String,
61    ) -> Result<Value> {
62        let path = format!("/{}/-/issues/{}/comments/{}", repo, number, comment_id);
63        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
64        
65
66                let request = self.client.request(
67            reqwest::Method::GET,
68            url
69        );
70        
71
72
73
74        let response = request.send().await?;
75        
76        if response.status().is_success() {
77            let json: Value = response.json().await?;
78            Ok(json)
79        } else {
80            Err(ApiError::HttpError(response.status().as_u16()))
81        }
82    }
83
84    /// 修改一个 Issue Comment。Update an issue comment.
85    pub async fn patch_repo_issues_number_comments_comment_id(
86        &self,
87        repo: String,
88        number: i64,
89        comment_id: i64,
90        patch_issue_comment_form: serde_json::Value,
91    ) -> Result<Value> {
92        let path = format!("/{}/-/issues/{}/comments/{}", repo, number, comment_id);
93        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
94        
95
96        
97        let mut request = self.client.request(
98            reqwest::Method::PATCH,
99            url
100        );
101
102
103
104        request = request.json(&patch_issue_comment_form);
105
106        let response = request.send().await?;
107        
108        if response.status().is_success() {
109            let json: Value = response.json().await?;
110            Ok(json)
111        } else {
112            Err(ApiError::HttpError(response.status().as_u16()))
113        }
114    }
115
116    /// 查询指定的 Issues。Get an issue.
117    pub async fn get_repo_issues_number(
118        &self,
119        repo: String,
120        number: i64,
121    ) -> Result<Value> {
122        let path = format!("/{}/-/issues/{}", repo, number);
123        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
124        
125
126                let request = self.client.request(
127            reqwest::Method::GET,
128            url
129        );
130        
131
132
133
134        let response = request.send().await?;
135        
136        if response.status().is_success() {
137            let json: Value = response.json().await?;
138            Ok(json)
139        } else {
140            Err(ApiError::HttpError(response.status().as_u16()))
141        }
142    }
143
144    /// 更新一个 Issue。Update an issue.
145    pub async fn patch_repo_issues_number(
146        &self,
147        repo: String,
148        number: i64,
149        patch_issue_form: serde_json::Value,
150    ) -> Result<Value> {
151        let path = format!("/{}/-/issues/{}", repo, number);
152        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
153        
154
155        
156        let mut request = self.client.request(
157            reqwest::Method::PATCH,
158            url
159        );
160
161
162
163        request = request.json(&patch_issue_form);
164
165        let response = request.send().await?;
166        
167        if response.status().is_success() {
168            let json: Value = response.json().await?;
169            Ok(json)
170        } else {
171            Err(ApiError::HttpError(response.status().as_u16()))
172        }
173    }
174
175    /// 查询仓库的 Issues。List issues.
176    pub async fn get_repo_issues(
177        &self,
178        repo: String,
179        page: Option<i64>,
180        page_size: Option<i64>,
181        state: Option<String>,
182        keyword: Option<String>,
183        priority: Option<String>,
184        labels: Option<String>,
185        authors: Option<String>,
186        assignees: Option<String>,
187        updated_time_begin: Option<String>,
188        updated_time_end: Option<String>,
189        close_time_begin: Option<String>,
190        close_time_end: Option<String>,
191        order_by: Option<String>,
192    ) -> Result<Value> {
193        let path = format!("/{}/-/issues", repo);
194        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
195        
196        if let Some(value) = page {
197            url.query_pairs_mut().append_pair("page", &value.to_string());
198        }
199        if let Some(value) = page_size {
200            url.query_pairs_mut().append_pair("page_size", &value.to_string());
201        }
202        if let Some(value) = state {
203            url.query_pairs_mut().append_pair("state", &value.to_string());
204        }
205        if let Some(value) = keyword {
206            url.query_pairs_mut().append_pair("keyword", &value.to_string());
207        }
208        if let Some(value) = priority {
209            url.query_pairs_mut().append_pair("priority", &value.to_string());
210        }
211        if let Some(value) = labels {
212            url.query_pairs_mut().append_pair("labels", &value.to_string());
213        }
214        if let Some(value) = authors {
215            url.query_pairs_mut().append_pair("authors", &value.to_string());
216        }
217        if let Some(value) = assignees {
218            url.query_pairs_mut().append_pair("assignees", &value.to_string());
219        }
220        if let Some(value) = updated_time_begin {
221            url.query_pairs_mut().append_pair("updated_time_begin", &value.to_string());
222        }
223        if let Some(value) = updated_time_end {
224            url.query_pairs_mut().append_pair("updated_time_end", &value.to_string());
225        }
226        if let Some(value) = close_time_begin {
227            url.query_pairs_mut().append_pair("close_time_begin", &value.to_string());
228        }
229        if let Some(value) = close_time_end {
230            url.query_pairs_mut().append_pair("close_time_end", &value.to_string());
231        }
232        if let Some(value) = order_by {
233            url.query_pairs_mut().append_pair("order_by", &value.to_string());
234        }
235
236                let request = self.client.request(
237            reqwest::Method::GET,
238            url
239        );
240        
241
242
243
244        let response = request.send().await?;
245        
246        if response.status().is_success() {
247            let json: Value = response.json().await?;
248            Ok(json)
249        } else {
250            Err(ApiError::HttpError(response.status().as_u16()))
251        }
252    }
253
254    /// 创建一个 Issue。Create an issue.
255    pub async fn post_repo_issues(
256        &self,
257        repo: String,
258        post_issue_form: serde_json::Value,
259    ) -> Result<Value> {
260        let path = format!("/{}/-/issues", repo);
261        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
262        
263
264        
265        let mut request = self.client.request(
266            reqwest::Method::POST,
267            url
268        );
269
270
271
272        request = request.json(&post_issue_form);
273
274        let response = request.send().await?;
275        
276        if response.status().is_success() {
277            let json: Value = response.json().await?;
278            Ok(json)
279        } else {
280            Err(ApiError::HttpError(response.status().as_u16()))
281        }
282    }
283
284    /// 删除 Issue 标签。Remove a label from an issue.
285    pub async fn delete_repo_issues_number_labels_name(
286        &self,
287        repo: String,
288        number: i64,
289        name: String,
290    ) -> Result<Value> {
291        let path = format!("/{}/-/issues/{}/labels/{}", repo, number, name);
292        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
293        
294
295                let request = self.client.request(
296            reqwest::Method::DELETE,
297            url
298        );
299        
300
301
302
303        let response = request.send().await?;
304        
305        if response.status().is_success() {
306            let json: Value = response.json().await?;
307            Ok(json)
308        } else {
309            Err(ApiError::HttpError(response.status().as_u16()))
310        }
311    }
312
313    /// 查询指定 Issue 的 Assignees。 List repository issue assignees.
314    pub async fn get_repo_issues_number_assignees(
315        &self,
316        repo: String,
317        number: String,
318    ) -> Result<Value> {
319        let path = format!("/{}/-/issues/{}/assignees", repo, number);
320        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
321        
322
323                let request = self.client.request(
324            reqwest::Method::GET,
325            url
326        );
327        
328
329
330
331        let response = request.send().await?;
332        
333        if response.status().is_success() {
334            let json: Value = response.json().await?;
335            Ok(json)
336        } else {
337            Err(ApiError::HttpError(response.status().as_u16()))
338        }
339    }
340
341    /// 添加 Assignees 到指定的 Issue。 Adds up to 10 assignees to an issue. Users already assigned to an issue are not replaced.
342    pub async fn post_repo_issues_number_assignees(
343        &self,
344        repo: String,
345        number: String,
346        post_issue_assignees_form: serde_json::Value,
347    ) -> Result<Value> {
348        let path = format!("/{}/-/issues/{}/assignees", repo, number);
349        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
350        
351
352        
353        let mut request = self.client.request(
354            reqwest::Method::POST,
355            url
356        );
357
358
359
360        request = request.json(&post_issue_assignees_form);
361
362        let response = request.send().await?;
363        
364        if response.status().is_success() {
365            let json: Value = response.json().await?;
366            Ok(json)
367        } else {
368            Err(ApiError::HttpError(response.status().as_u16()))
369        }
370    }
371
372    /// 删除 Issue 中的 Assignees。 Removes one or more assignees from an issue.
373    pub async fn delete_repo_issues_number_assignees(
374        &self,
375        repo: String,
376        number: String,
377        delete_issue_assignees_form: serde_json::Value,
378    ) -> Result<Value> {
379        let path = format!("/{}/-/issues/{}/assignees", repo, number);
380        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
381        
382
383        
384        let mut request = self.client.request(
385            reqwest::Method::DELETE,
386            url
387        );
388
389
390
391        request = request.json(&delete_issue_assignees_form);
392
393        let response = request.send().await?;
394        
395        if response.status().is_success() {
396            let json: Value = response.json().await?;
397            Ok(json)
398        } else {
399            Err(ApiError::HttpError(response.status().as_u16()))
400        }
401    }
402
403    /// 更新 Issue 中的 Assignees。 Updates the assignees of an issue.
404    pub async fn patch_repo_issues_number_assignees(
405        &self,
406        repo: String,
407        number: String,
408        patch_issue_assignees_form: serde_json::Value,
409    ) -> Result<Value> {
410        let path = format!("/{}/-/issues/{}/assignees", repo, number);
411        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
412        
413
414        
415        let mut request = self.client.request(
416            reqwest::Method::PATCH,
417            url
418        );
419
420
421
422        request = request.json(&patch_issue_assignees_form);
423
424        let response = request.send().await?;
425        
426        if response.status().is_success() {
427            let json: Value = response.json().await?;
428            Ok(json)
429        } else {
430            Err(ApiError::HttpError(response.status().as_u16()))
431        }
432    }
433
434    /// 查询仓库的 Issue 评论列表。List repository issue comments.
435    pub async fn get_repo_issues_number_comments(
436        &self,
437        repo: String,
438        number: i64,
439        page: Option<i64>,
440        page_size: Option<i64>,
441    ) -> Result<Value> {
442        let path = format!("/{}/-/issues/{}/comments", repo, number);
443        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
444        
445        if let Some(value) = page {
446            url.query_pairs_mut().append_pair("page", &value.to_string());
447        }
448        if let Some(value) = page_size {
449            url.query_pairs_mut().append_pair("page_size", &value.to_string());
450        }
451
452                let request = self.client.request(
453            reqwest::Method::GET,
454            url
455        );
456        
457
458
459
460        let response = request.send().await?;
461        
462        if response.status().is_success() {
463            let json: Value = response.json().await?;
464            Ok(json)
465        } else {
466            Err(ApiError::HttpError(response.status().as_u16()))
467        }
468    }
469
470    /// 创建一个 Issue Comment。Create an issue comment.
471    pub async fn post_repo_issues_number_comments(
472        &self,
473        repo: String,
474        number: i64,
475        post_issue_comment_form: serde_json::Value,
476    ) -> Result<Value> {
477        let path = format!("/{}/-/issues/{}/comments", repo, number);
478        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
479        
480
481        
482        let mut request = self.client.request(
483            reqwest::Method::POST,
484            url
485        );
486
487
488
489        request = request.json(&post_issue_comment_form);
490
491        let response = request.send().await?;
492        
493        if response.status().is_success() {
494            let json: Value = response.json().await?;
495            Ok(json)
496        } else {
497            Err(ApiError::HttpError(response.status().as_u16()))
498        }
499    }
500
501    /// 查询 Issue 的标签(label) 列表。List labels for an issue.
502    pub async fn get_repo_issues_number_labels(
503        &self,
504        repo: String,
505        number: i64,
506        page: Option<i64>,
507        page_size: Option<i64>,
508    ) -> Result<Value> {
509        let path = format!("/{}/-/issues/{}/labels", repo, number);
510        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
511        
512        if let Some(value) = page {
513            url.query_pairs_mut().append_pair("page", &value.to_string());
514        }
515        if let Some(value) = page_size {
516            url.query_pairs_mut().append_pair("page_size", &value.to_string());
517        }
518
519                let request = self.client.request(
520            reqwest::Method::GET,
521            url
522        );
523        
524
525
526
527        let response = request.send().await?;
528        
529        if response.status().is_success() {
530            let json: Value = response.json().await?;
531            Ok(json)
532        } else {
533            Err(ApiError::HttpError(response.status().as_u16()))
534        }
535    }
536
537    /// 新增 Issue 标签。Add labels to an issue.
538    pub async fn post_repo_issues_number_labels(
539        &self,
540        repo: String,
541        number: i64,
542        post_issue_labels_form: serde_json::Value,
543    ) -> Result<Value> {
544        let path = format!("/{}/-/issues/{}/labels", repo, number);
545        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
546        
547
548        
549        let mut request = self.client.request(
550            reqwest::Method::POST,
551            url
552        );
553
554
555
556        request = request.json(&post_issue_labels_form);
557
558        let response = request.send().await?;
559        
560        if response.status().is_success() {
561            let json: Value = response.json().await?;
562            Ok(json)
563        } else {
564            Err(ApiError::HttpError(response.status().as_u16()))
565        }
566    }
567
568    /// 设置 Issue 标签。 Set the new labels for an issue.
569    pub async fn put_repo_issues_number_labels(
570        &self,
571        repo: String,
572        number: i64,
573        put_issue_labels_form: serde_json::Value,
574    ) -> Result<Value> {
575        let path = format!("/{}/-/issues/{}/labels", repo, number);
576        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
577        
578
579        
580        let mut request = self.client.request(
581            reqwest::Method::PUT,
582            url
583        );
584
585
586
587        request = request.json(&put_issue_labels_form);
588
589        let response = request.send().await?;
590        
591        if response.status().is_success() {
592            let json: Value = response.json().await?;
593            Ok(json)
594        } else {
595            Err(ApiError::HttpError(response.status().as_u16()))
596        }
597    }
598
599    /// 清空 Issue 标签。Remove all labels from an issue.
600    pub async fn delete_repo_issues_number_labels(
601        &self,
602        repo: String,
603        number: i64,
604    ) -> Result<Value> {
605        let path = format!("/{}/-/issues/{}/labels", repo, number);
606        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
607        
608
609                let request = self.client.request(
610            reqwest::Method::DELETE,
611            url
612        );
613        
614
615
616
617        let response = request.send().await?;
618        
619        if response.status().is_success() {
620            let json: Value = response.json().await?;
621            Ok(json)
622        } else {
623            Err(ApiError::HttpError(response.status().as_u16()))
624        }
625    }
626
627}