|
1 | 1 | use crate::auth::AuthenticationError; |
2 | 2 | use crate::database::repository::github_login_attempts; |
3 | | -use crate::types::api::ApiError; |
4 | 3 | use crate::types::models::github_login_attempt::StoredLoginAttempt; |
5 | 4 | use reqwest::{header::HeaderValue, Client}; |
6 | 5 | use serde::{Deserialize, Serialize}; |
@@ -150,7 +149,7 @@ impl GithubClient { |
150 | 149 | code: &str, |
151 | 150 | is_device: bool, |
152 | 151 | redirect_uri: Option<&str>, |
153 | | - ) -> Result<String, ApiError> { |
| 152 | + ) -> Result<String, AuthenticationError> { |
154 | 153 | let json = { |
155 | 154 | if is_device { |
156 | 155 | json!({ |
@@ -183,99 +182,115 @@ impl GithubClient { |
183 | 182 | .json(&json) |
184 | 183 | .send() |
185 | 184 | .await |
186 | | - .map_err(|e| { |
187 | | - log::error!("Failed to poll GitHub for developer access token: {}", e); |
188 | | - ApiError::InternalError |
| 185 | + .inspect_err(|e| { |
| 186 | + log::error!("Failed to poll GitHub for developer access token: {e}") |
189 | 187 | })?; |
190 | 188 |
|
191 | 189 | Ok(resp |
192 | 190 | .json::<serde_json::Value>() |
193 | 191 | .await |
194 | | - .map_err(|e| { |
195 | | - log::error!("Failed to decode GitHub response: {}", e); |
196 | | - ApiError::InternalError |
197 | | - })? |
| 192 | + .inspect_err(|e| log::error!("Failed to decode GitHub response: {e}"))? |
198 | 193 | .get("access_token") |
199 | | - .ok_or(ApiError::BadRequest("Request not accepted by user".into()))? |
| 194 | + .ok_or(AuthenticationError::UserAuthPending)? |
200 | 195 | .as_str() |
201 | 196 | .ok_or_else(|| { |
202 | 197 | log::error!("Invalid access_token received from GitHub"); |
203 | | - ApiError::InternalError |
| 198 | + AuthenticationError::InternalError( |
| 199 | + "Failed to retrieve access token from GitHub".into(), |
| 200 | + ) |
204 | 201 | })? |
205 | 202 | .to_string()) |
206 | 203 | } |
207 | | - |
208 | | - pub async fn get_user(&self, token: &str) -> Result<GitHubFetchedUser, ApiError> { |
| 204 | + pub async fn get_user(&self, token: &str) -> Result<GitHubFetchedUser, AuthenticationError> { |
209 | 205 | let resp = Client::new() |
210 | 206 | .get("https://api.github.com/user") |
211 | 207 | .header("Accept", HeaderValue::from_str("application/json").unwrap()) |
212 | 208 | .header("User-Agent", "geode_index") |
213 | 209 | .bearer_auth(token) |
214 | 210 | .send() |
215 | | - .await |
216 | | - .map_err(|e| { |
217 | | - log::error!("Request to https://api.github.com/user failed: {}", e); |
218 | | - ApiError::InternalError |
219 | | - })?; |
| 211 | + .await?; |
220 | 212 |
|
221 | 213 | if !resp.status().is_success() { |
222 | | - return Err(ApiError::InternalError); |
| 214 | + log::error!( |
| 215 | + "github::get_user: received non-2xx response: {}. Body: {}", |
| 216 | + resp.status(), |
| 217 | + resp.text().await.unwrap_or("No response body".into()) |
| 218 | + ); |
| 219 | + return Err(AuthenticationError::InternalError( |
| 220 | + "Failed to fetch user from GitHub API, received non 2xx response".into(), |
| 221 | + )); |
223 | 222 | } |
224 | 223 |
|
225 | | - resp.json::<GitHubFetchedUser>().await.map_err(|e| { |
226 | | - log::error!("Failed to create GitHubFetchedUser: {}", e); |
227 | | - ApiError::InternalError |
228 | | - }) |
| 224 | + resp.json::<GitHubFetchedUser>() |
| 225 | + .await |
| 226 | + .inspect_err(|e| log::error!("github::get_user: failed to parse response: {e}")) |
| 227 | + .or(Err(AuthenticationError::InternalError( |
| 228 | + "Failed to parse user JSON received from GitHub".into(), |
| 229 | + ))) |
229 | 230 | } |
230 | 231 |
|
231 | | - pub async fn get_installation(&self, token: &str) -> Result<GitHubFetchedUser, ApiError> { |
| 232 | + pub async fn get_installation( |
| 233 | + &self, |
| 234 | + token: &str, |
| 235 | + ) -> Result<GitHubFetchedUser, AuthenticationError> { |
232 | 236 | let client = Client::new(); |
233 | | - let resp = match client |
| 237 | + let resp = client |
234 | 238 | .get("https://api.github.com/installation/repositories") |
235 | 239 | .header("Accept", HeaderValue::from_str("application/json").unwrap()) |
236 | 240 | .header("User-Agent", "geode_index") |
237 | 241 | .bearer_auth(token) |
238 | 242 | .send() |
239 | 243 | .await |
240 | | - { |
241 | | - Err(e) => { |
242 | | - log::info!("{}", e); |
243 | | - return Err(ApiError::InternalError); |
244 | | - } |
245 | | - Ok(r) => r, |
246 | | - }; |
| 244 | + .inspect_err(|e| { |
| 245 | + log::error!("github::get_installation: failed to fetch repositories: {e}") |
| 246 | + })?; |
247 | 247 |
|
248 | 248 | if !resp.status().is_success() { |
249 | | - return Err(ApiError::InternalError); |
| 249 | + log::error!( |
| 250 | + "github::get_installation: received non-2xx response: {}. Body: {}", |
| 251 | + resp.status(), |
| 252 | + resp.text().await.unwrap_or("No response body".into()) |
| 253 | + ); |
| 254 | + return Err(AuthenticationError::InternalError( |
| 255 | + "Received non-2xx response from GitHub".into(), |
| 256 | + )); |
250 | 257 | } |
251 | 258 |
|
252 | | - let body = match resp.json::<serde_json::Value>().await { |
253 | | - Err(e) => { |
254 | | - log::error!("{}", e); |
255 | | - return Err(ApiError::InternalError); |
256 | | - } |
257 | | - Ok(b) => b, |
258 | | - }; |
| 259 | + let body = resp |
| 260 | + .json::<serde_json::Value>() |
| 261 | + .await |
| 262 | + .inspect_err(|e| log::error!("github::get_installation: failed to parse response: {e}")) |
| 263 | + .or(Err(AuthenticationError::InternalError( |
| 264 | + "Failed to parse response from GitHub".into(), |
| 265 | + )))?; |
259 | 266 |
|
260 | | - let repos = match body.get("repositories").and_then(|r| r.as_array()) { |
261 | | - None => { |
262 | | - return Err(ApiError::InternalError); |
263 | | - } |
264 | | - Some(r) => r, |
265 | | - }; |
| 267 | + let repos = body.get("repositories").and_then(|r| r.as_array()).ok_or( |
| 268 | + AuthenticationError::InternalError( |
| 269 | + "Failed to get repository array from GitHub response".into(), |
| 270 | + ), |
| 271 | + )?; |
266 | 272 |
|
267 | 273 | if repos.len() != 1 { |
268 | | - return Err(ApiError::InternalError); |
| 274 | + return Err(AuthenticationError::InternalError( |
| 275 | + "Failed to get repository from GitHub: array size isn't 1".into(), |
| 276 | + )); |
269 | 277 | } |
270 | 278 |
|
271 | 279 | let owner = repos[0] |
272 | 280 | .get("owner") |
273 | | - .ok_or(ApiError::InternalError)? |
| 281 | + .ok_or(AuthenticationError::InternalError( |
| 282 | + "Didn't find owner key on repository".into(), |
| 283 | + ))? |
274 | 284 | .clone(); |
275 | 285 |
|
276 | | - serde_json::from_value(owner).map_err(|e| { |
277 | | - log::error!("Failed to create GitHubFetchedUser: {}", e); |
278 | | - ApiError::InternalError |
279 | | - }) |
| 286 | + serde_json::from_value(owner) |
| 287 | + .inspect_err(|e| { |
| 288 | + log::error!( |
| 289 | + "github::get_installation: failed to extract owner from serde_json value: {e}" |
| 290 | + ) |
| 291 | + }) |
| 292 | + .or(Err(AuthenticationError::InternalError( |
| 293 | + "Failed to get GitHub user from installation".into(), |
| 294 | + ))) |
280 | 295 | } |
281 | 296 | } |
0 commit comments