1use crate::{error::GiteeError, GiteeClient};
2use reqwest::Method;
3
4mod models;
5pub use models::*;
6
7impl GiteeClient {
8 pub async fn list_issues(&self, options: Option<IssueListOptions>) -> Result<Vec<Issue>, GiteeError> {
10 let url = format!("{}/issues", self.base_url());
11 let mut request = self.client().request(Method::GET, &url)
12 .header("Authorization", self.auth_header());
13
14 if let Some(opts) = options {
15 request = request.query(&opts);
16 }
17
18 let response = request.send().await?;
19
20 if !response.status().is_success() {
21 return Err(GiteeError::ApiError(format!(
22 "Failed to list issues: {}",
23 response.status()
24 )));
25 }
26
27 let issues: Vec<Issue> = response.json().await?;
28 Ok(issues)
29 }
30
31 pub async fn list_repo_issues(&self, owner: &str, repo: &str, options: Option<IssueListOptions>) -> Result<Vec<Issue>, GiteeError> {
33 let url = format!("{}/repos/{}/{}/issues", self.base_url(), owner, repo);
34 let mut request = self.client().request(Method::GET, &url)
35 .header("Authorization", self.auth_header());
36
37 if let Some(opts) = options {
38 request = request.query(&opts);
39 }
40
41 let response = request.send().await?;
42
43 if !response.status().is_success() {
44 return Err(GiteeError::ApiError(format!(
45 "Failed to list repo issues: {}",
46 response.status()
47 )));
48 }
49
50 let issues: Vec<Issue> = response.json().await?;
51 Ok(issues)
52 }
53
54 pub async fn create_issue(
56 &self,
57 repo_owner: &str,
58 repo_name: &str,
59 title: &str,
60 body: Option<&str>,
61 ) -> Result<Issue, GiteeError> {
62 let url = format!("{}/repos/{}/issues", self.base_url(), repo_owner);
63
64 let mut payload = std::collections::HashMap::new();
65 payload.insert("repo", repo_name.to_string());
66 payload.insert("title", title.to_string());
67 if let Some(body) = body {
68 payload.insert("body", body.to_string());
69 }
70
71 let response = self
72 .client()
73 .request(Method::POST, &url)
74 .header("Authorization", self.auth_header())
75 .json(&payload)
76 .send()
77 .await?;
78
79 if !response.status().is_success() {
80 return Err(GiteeError::ApiError(format!(
81 "Failed to create issue: {}",
82 response.status()
83 )));
84 }
85
86 let issue: Issue = response.json().await?;
87 Ok(issue)
88 }
89
90 pub async fn close_issue(
92 &self,
93 repo_owner: &str,
94 repo_name: &str,
95 issue_number: &str,
96 ) -> Result<Issue, GiteeError> {
97 let url = format!(
98 "{}/repos/{}/{}/issues/{}",
99 self.base_url(),
100 repo_owner,
101 repo_name,
102 issue_number
103 );
104
105 let payload = serde_json::json!({
106 "state": "closed"
107 });
108
109 let response = self
110 .client()
111 .request(Method::PATCH, &url)
112 .header("Authorization", self.auth_header())
113 .json(&payload)
114 .send()
115 .await?;
116
117 if !response.status().is_success() {
118 return Err(GiteeError::ApiError(format!(
119 "Failed to close issue: {}",
120 response.status()
121 )));
122 }
123
124 let issue: Issue = response.json().await?;
125 Ok(issue)
126 }
127
128 pub async fn update_issue(&self, owner: &str, repo: &str, number: &str, title: Option<&str>, body: Option<&str>, state: Option<&str>) -> Result<Issue, GiteeError> {
130 let url = format!("{}/repos/{}/{}/issues/{}", self.base_url(), owner, repo, number);
131
132 let mut payload = std::collections::HashMap::new();
133 if let Some(t) = title {
134 payload.insert("title", t);
135 }
136 if let Some(b) = body {
137 payload.insert("body", b);
138 }
139 if let Some(s) = state {
140 payload.insert("state", s); }
142
143 let response = self
144 .client()
145 .request(Method::PATCH, &url)
146 .header("Authorization", self.auth_header())
147 .json(&payload)
148 .send()
149 .await?;
150
151 if !response.status().is_success() {
152 return Err(GiteeError::ApiError(format!(
153 "Failed to update issue: {}",
154 response.status()
155 )));
156 }
157
158 let issue: Issue = response.json().await?;
159 Ok(issue)
160 }
161
162 pub async fn get_issue_detail(&self, owner: &str, repo: &str, number: &str) -> Result<Issue, GiteeError> {
164 let url = format!("{}/repos/{}/{}/issues/{}", self.base_url(), owner, repo, number);
165
166 let response = self
167 .client()
168 .request(Method::GET, &url)
169 .header("Authorization", self.auth_header())
170 .send()
171 .await?;
172
173 if !response.status().is_success() {
174 return Err(GiteeError::ApiError(format!(
175 "Failed to get issue detail: {}",
176 response.status()
177 )));
178 }
179
180 let issue: Issue = response.json().await?;
181 Ok(issue)
182 }
183
184 pub async fn comment_issue(&self, owner: &str, repo: &str, number: &str, body: &str) -> Result<Comment, GiteeError> {
186 let url = format!("{}/repos/{}/{}/issues/{}/comments", self.base_url(), owner, repo, number);
187
188 let payload = [("body", body)];
189
190 let response = self
191 .client()
192 .request(Method::POST, &url)
193 .header("Authorization", self.auth_header())
194 .form(&payload)
195 .send()
196 .await?;
197
198 if !response.status().is_success() {
199 return Err(GiteeError::ApiError(format!(
200 "Failed to comment on issue: {}",
201 response.status()
202 )));
203 }
204
205 let comment: Comment = response.json().await?;
206 Ok(comment)
207 }
208
209 pub async fn list_issue_comments(&self, owner: &str, repo: &str, number: &str) -> Result<Vec<Comment>, GiteeError> {
211 let url = format!("{}/repos/{}/{}/issues/{}/comments", self.base_url(), owner, repo, number);
212
213 let response = self
214 .client()
215 .request(Method::GET, &url)
216 .header("Authorization", self.auth_header())
217 .send()
218 .await?;
219
220 if !response.status().is_success() {
221 return Err(GiteeError::ApiError(format!(
222 "Failed to list issue comments: {}",
223 response.status()
224 )));
225 }
226
227 let comments: Vec<Comment> = response.json().await?;
228 Ok(comments)
229 }
230
231 pub async fn list_repo_milestones(&self, owner: &str, repo: &str, state: Option<&str>) -> Result<Vec<Milestone>, GiteeError> {
233 let url = format!("{}/repos/{}/{}/milestones", self.base_url(), owner, repo);
234 let mut request = self.client().request(Method::GET, &url)
235 .header("Authorization", self.auth_header());
236
237 if let Some(s) = state {
238 request = request.query(&[("state", s)]);
239 }
240
241 let response = request.send().await?;
242
243 if !response.status().is_success() {
244 return Err(GiteeError::ApiError(format!(
245 "Failed to list milestones: {}",
246 response.status()
247 )));
248 }
249
250 let milestones: Vec<Milestone> = response.json().await?;
251 Ok(milestones)
252 }
253
254 pub async fn create_milestone(&self, owner: &str, repo: &str, title: &str, description: Option<&str>, due_on: Option<&str>) -> Result<Milestone, GiteeError> {
256 let url = format!("{}/repos/{}/{}/milestones", self.base_url(), owner, repo);
257
258 let mut payload = serde_json::json!({
259 "title": title,
260 });
261
262 if let Some(d) = description {
263 payload["description"] = serde_json::Value::String(d.to_string());
264 }
265 if let Some(due) = due_on {
266 payload["due_on"] = serde_json::Value::String(due.to_string());
267 }
268
269 let response = self
270 .client()
271 .request(Method::POST, &url)
272 .header("Authorization", self.auth_header())
273 .json(&payload)
274 .send()
275 .await?;
276
277 if !response.status().is_success() {
278 return Err(GiteeError::ApiError(format!(
279 "Failed to create milestone: {}",
280 response.status()
281 )));
282 }
283
284 let milestone: Milestone = response.json().await?;
285 Ok(milestone)
286 }
287
288 pub async fn get_milestone(&self, owner: &str, repo: &str, number: i32) -> Result<Milestone, GiteeError> {
290 let url = format!("{}/repos/{}/{}/milestones/{}", self.base_url(), owner, repo, number);
291 let response = self
292 .client()
293 .request(Method::GET, &url)
294 .header("Authorization", self.auth_header())
295 .send()
296 .await?;
297
298 if !response.status().is_success() {
299 return Err(GiteeError::ApiError(format!(
300 "Failed to get milestone: {}",
301 response.status()
302 )));
303 }
304
305 let milestone: Milestone = response.json().await?;
306 Ok(milestone)
307 }
308
309 pub async fn update_milestone(&self, owner: &str, repo: &str, number: i32, title: Option<&str>, description: Option<&str>, state: Option<&str>) -> Result<Milestone, GiteeError> {
311 let url = format!("{}/repos/{}/{}/milestones/{}", self.base_url(), owner, repo, number);
312
313 let mut payload = std::collections::HashMap::new();
314 if let Some(t) = title { payload.insert("title", t); }
315 if let Some(d) = description { payload.insert("description", d); }
316 if let Some(s) = state { payload.insert("state", s); }
317
318 let response = self
319 .client()
320 .request(Method::PATCH, &url)
321 .header("Authorization", self.auth_header())
322 .json(&payload)
323 .send()
324 .await?;
325
326 if !response.status().is_success() {
327 return Err(GiteeError::ApiError(format!(
328 "Failed to update milestone: {}",
329 response.status()
330 )));
331 }
332
333 let milestone: Milestone = response.json().await?;
334 Ok(milestone)
335 }
336
337 pub async fn delete_milestone(&self, owner: &str, repo: &str, number: i32) -> Result<(), GiteeError> {
339 let url = format!("{}/repos/{}/{}/milestones/{}", self.base_url(), owner, repo, number);
340 let response = self
341 .client()
342 .request(Method::DELETE, &url)
343 .header("Authorization", self.auth_header())
344 .send()
345 .await?;
346
347 if !response.status().is_success() {
348 return Err(GiteeError::ApiError(format!(
349 "Failed to delete milestone: {}",
350 response.status()
351 )));
352 }
353
354 Ok(())
355 }
356}