cod_client/specialized_requests/
mod.rs

1use chrono::DateTime;
2use chrono::Utc;
3use cod_endpoints::endpoint_generator::EndpointGenerator;
4use cod_types::api::branch::Branch;
5use cod_types::api::comment::Comment;
6use cod_types::api::create_options::create_comment_option::CreateCommentOption;
7use cod_types::api::create_options::create_fork_option::CreateForkOption;
8use cod_types::api::issue::Issue;
9use cod_types::api::issue_labels_option::IssueLabelsOption;
10use cod_types::api::label::Label;
11use cod_types::api::milestone::Milestone;
12use cod_types::api::notification::notification_state_type::NotificationStateType;
13use cod_types::api::notification::notification_thread::NotificationThread;
14use cod_types::api::notification::notification_type::NotificationSubjectType;
15use cod_types::api::pull_request::PullRequest;
16use cod_types::api::repository::Repository;
17use cod_types::api::search_results::SearchResults;
18use cod_types::api::state_type::StateType;
19use cod_types::api::user::User;
20use reqwest::Url;
21use serde::de::DeserializeOwned;
22use std::fmt::Debug;
23
24use crate::CodebergClient;
25
26impl CodebergClient {
27    pub async fn get_user_info(&self) -> anyhow::Result<User> {
28        let api = EndpointGenerator::user_info()?;
29        self.get(api).await
30    }
31
32    pub async fn get_all_repos_info(&self) -> anyhow::Result<Vec<Repository>> {
33        let api = EndpointGenerator::user_repos()?;
34        self.get(api).await
35    }
36
37    pub async fn get_repo_info(&self) -> anyhow::Result<Repository> {
38        let api = EndpointGenerator::repo_infos()?;
39        self.get(api).await
40    }
41
42    pub async fn get_repo_labels(&self, maybe_limit: Option<usize>) -> anyhow::Result<Vec<Label>> {
43        let api = EndpointGenerator::repo_labels()?;
44        if let Some(limit) = maybe_limit {
45            self.get_query(api, [("limit", limit)]).await
46        } else {
47            self.get(api).await
48        }
49    }
50
51    pub async fn get_state_limit_list<T>(
52        &self,
53        maybe_state: Option<StateType>,
54        maybe_limit: Option<usize>,
55        api: Url,
56    ) -> anyhow::Result<T>
57    where
58        T: DeserializeOwned + Debug,
59    {
60        use std::iter::once;
61
62        let query_args = once((
63            "limit",
64            maybe_limit.map_or_else(|| usize::MAX.to_string(), |limit| limit.to_string()),
65        ))
66        .chain(once((
67            "state",
68            maybe_state.unwrap_or(StateType::All).to_string(),
69        )))
70        .collect::<Vec<_>>();
71        if query_args.is_empty() {
72            self.get(api).await
73        } else {
74            self.get_query(api, query_args).await
75        }
76    }
77
78    pub async fn get_repo_milestones(
79        &self,
80        maybe_state: Option<StateType>,
81        maybe_limit: Option<usize>,
82    ) -> anyhow::Result<Vec<Milestone>> {
83        let api = EndpointGenerator::repo_milestones()?;
84        self.get_state_limit_list(maybe_state, maybe_limit, api)
85            .await
86    }
87
88    pub async fn get_repo_issues(
89        &self,
90        maybe_state: Option<StateType>,
91        maybe_limit: Option<usize>,
92    ) -> anyhow::Result<Vec<Issue>> {
93        let api = EndpointGenerator::repo_issues()?;
94        self.get_state_limit_list(maybe_state, maybe_limit, api)
95            .await
96    }
97
98    pub async fn get_repo_prs(
99        &self,
100        maybe_state: Option<StateType>,
101        maybe_limit: Option<usize>,
102    ) -> anyhow::Result<Vec<PullRequest>> {
103        let api = EndpointGenerator::repo_pull_requests()?;
104        self.get_state_limit_list(maybe_state, maybe_limit, api)
105            .await
106    }
107
108    pub async fn get_repo_assignees(&self) -> anyhow::Result<Vec<User>> {
109        let api = EndpointGenerator::repo_assignees()?;
110        self.get(api).await
111    }
112
113    pub async fn search_for_user(
114        &self,
115        username: &str,
116    ) -> anyhow::Result<SearchResults<Vec<User>>> {
117        let api = EndpointGenerator::user_search()?;
118        self.get_query(api, [("q", username)]).await
119    }
120
121    pub async fn search_for_repo(
122        &self,
123        reponame: &str,
124        user_id: usize,
125    ) -> anyhow::Result<SearchResults<Vec<Repository>>> {
126        let api = EndpointGenerator::repo_search()?;
127        self.get_query(
128            api,
129            [("q", reponame.to_string()), ("uid", user_id.to_string())],
130        )
131        .await
132    }
133
134    pub async fn fork_repo(&self, ownername: &str, reponame: &str) -> anyhow::Result<Repository> {
135        let api = EndpointGenerator::repo_forks(ownername, reponame)?;
136        let body = CreateForkOption::same_repo_name();
137        self.post_query_body(api, body, [("owner", ownername), ("repo", reponame)])
138            .await
139    }
140
141    pub async fn get_comments_for_id(&self, issue_or_pr_id: usize) -> anyhow::Result<Vec<Comment>> {
142        let api = EndpointGenerator::repo_comments_for_id(issue_or_pr_id)?;
143        self.get(api).await
144    }
145
146    pub async fn post_comment_for_id(
147        &self,
148        issue_id: usize,
149        comment: CreateCommentOption,
150    ) -> anyhow::Result<Comment> {
151        let api = EndpointGenerator::repo_comments_for_id(issue_id)?;
152        self.post_body(api, comment).await
153    }
154
155    pub async fn delete_label(&self, label_id: usize) -> anyhow::Result<()> {
156        let api = EndpointGenerator::repo_labels_with_id(label_id)?;
157        self.delete(api).await
158    }
159
160    pub async fn get_repo_branches(&self) -> anyhow::Result<Vec<Branch>> {
161        let api = EndpointGenerator::repo_branches()?;
162        self.get(api).await
163    }
164
165    pub async fn get_user_repos(&self, username: String) -> anyhow::Result<Vec<Repository>> {
166        let api = EndpointGenerator::get_user_repos(username)?;
167        self.get(api).await
168    }
169
170    pub async fn get_org_repos(&self, orgname: String) -> anyhow::Result<Vec<Repository>> {
171        let api = EndpointGenerator::get_org_repos(orgname)?;
172        self.get(api).await
173    }
174
175    pub async fn get_user_or_org_repos(&self, name: String) -> anyhow::Result<Vec<Repository>> {
176        self.get_org_repos(name.clone())
177            .await
178            .or(self.get_user_repos(name).await)
179    }
180
181    pub async fn replace_labels(
182        &self,
183        issue_id: usize,
184        issue_labels_option: IssueLabelsOption,
185    ) -> anyhow::Result<Vec<Label>> {
186        let api = EndpointGenerator::repo_put_issue_labels(issue_id)?;
187        self.put_body(api, issue_labels_option).await
188    }
189
190    pub async fn get_all_notifications_unfiltered(
191        &self,
192        all: bool,
193    ) -> anyhow::Result<Vec<NotificationThread>> {
194        self.get_all_notifications_filtered(
195            all,
196            None,
197            None,
198            vec![NotificationStateType::Pinned, NotificationStateType::Unread],
199            None,
200            1,
201            100000,
202        )
203        .await
204    }
205
206    pub async fn get_all_notifications_filtered(
207        &self,
208        all: bool,
209        since: Option<DateTime<Utc>>,
210        before: Option<DateTime<Utc>>,
211        status_types: Vec<NotificationStateType>,
212        subject_type: Option<NotificationSubjectType>,
213        page: usize,
214        limit: usize,
215    ) -> anyhow::Result<Vec<NotificationThread>> {
216        use std::iter::once;
217        let api = EndpointGenerator::all_notifications()?;
218        let query = since
219            .iter()
220            .map(|since| ("since", since.to_rfc3339()))
221            .chain(before.iter().map(|before| ("before", before.to_rfc3339())))
222            .chain(
223                status_types
224                    .iter()
225                    .map(|status_type| ("status-types", status_type.to_string())),
226            )
227            .chain(
228                subject_type
229                    .iter()
230                    .map(|subject_type| ("subject-type", subject_type.to_string())),
231            )
232            .chain(once(("page", page.to_string())))
233            .chain(once(("limit", limit.to_string())))
234            .chain(once(("all", all.to_string())))
235            .collect::<Vec<_>>();
236        self.get_query(api, query).await
237    }
238
239    pub async fn get_notification_thread(
240        &self,
241        thread_id: usize,
242    ) -> anyhow::Result<NotificationThread> {
243        let api = EndpointGenerator::get_notification_thread(thread_id)?;
244        self.get(api).await
245    }
246}