Skip to content

Commit 44f9886

Browse files
committed
IT BUILDS!
1 parent 6b875ff commit 44f9886

28 files changed

+594
-671
lines changed

src/auth/github.rs

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::auth::AuthenticationError;
22
use crate::database::repository::github_login_attempts;
3-
use crate::types::api::ApiError;
43
use crate::types::models::github_login_attempt::StoredLoginAttempt;
54
use reqwest::{header::HeaderValue, Client};
65
use serde::{Deserialize, Serialize};
@@ -150,7 +149,7 @@ impl GithubClient {
150149
code: &str,
151150
is_device: bool,
152151
redirect_uri: Option<&str>,
153-
) -> Result<String, ApiError> {
152+
) -> Result<String, AuthenticationError> {
154153
let json = {
155154
if is_device {
156155
json!({
@@ -183,99 +182,115 @@ impl GithubClient {
183182
.json(&json)
184183
.send()
185184
.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}")
189187
})?;
190188

191189
Ok(resp
192190
.json::<serde_json::Value>()
193191
.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}"))?
198193
.get("access_token")
199-
.ok_or(ApiError::BadRequest("Request not accepted by user".into()))?
194+
.ok_or(AuthenticationError::UserAuthPending)?
200195
.as_str()
201196
.ok_or_else(|| {
202197
log::error!("Invalid access_token received from GitHub");
203-
ApiError::InternalError
198+
AuthenticationError::InternalError(
199+
"Failed to retrieve access token from GitHub".into(),
200+
)
204201
})?
205202
.to_string())
206203
}
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> {
209205
let resp = Client::new()
210206
.get("https://api.github.com/user")
211207
.header("Accept", HeaderValue::from_str("application/json").unwrap())
212208
.header("User-Agent", "geode_index")
213209
.bearer_auth(token)
214210
.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?;
220212

221213
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+
));
223222
}
224223

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+
)))
229230
}
230231

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> {
232236
let client = Client::new();
233-
let resp = match client
237+
let resp = client
234238
.get("https://api.github.com/installation/repositories")
235239
.header("Accept", HeaderValue::from_str("application/json").unwrap())
236240
.header("User-Agent", "geode_index")
237241
.bearer_auth(token)
238242
.send()
239243
.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+
})?;
247247

248248
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+
));
250257
}
251258

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+
)))?;
259266

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+
)?;
266272

267273
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+
));
269277
}
270278

271279
let owner = repos[0]
272280
.get("owner")
273-
.ok_or(ApiError::InternalError)?
281+
.ok_or(AuthenticationError::InternalError(
282+
"Didn't find owner key on repository".into(),
283+
))?
274284
.clone();
275285

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+
)))
280295
}
281296
}

src/auth/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ pub enum AuthenticationError {
66
NoToken,
77
#[error("Provided token is invalid")]
88
InvalidToken,
9+
#[error("User didn't accept authentication")]
10+
UserRejectedAuth,
11+
#[error("User auth pending")]
12+
UserAuthPending,
913
#[error("Failed to communicate with GitHub")]
1014
RequestError(#[from] reqwest::Error),
1115
#[error("{0}")]

src/database/repository/dependencies.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
use sqlx::PgConnection;
22

3-
use crate::types::{
4-
api::ApiError,
5-
mod_json::ModJson,
6-
models::dependency::{DependencyImportance, FetchedDependency, ModVersionCompare},
3+
use crate::{
4+
database::DatabaseError,
5+
types::{
6+
mod_json::ModJson,
7+
models::dependency::{DependencyImportance, FetchedDependency, ModVersionCompare},
8+
},
79
};
810

911
pub async fn create(
1012
mod_version_id: i32,
1113
json: &ModJson,
1214
conn: &mut PgConnection,
13-
) -> Result<Vec<FetchedDependency>, ApiError> {
14-
let dependencies = json.prepare_dependencies_for_create()?;
15+
) -> Result<Vec<FetchedDependency>, DatabaseError> {
16+
let dependencies = json.prepare_dependencies_for_create().map_err(|e| {
17+
DatabaseError::InvalidInput(format!("Failed to parse dependencies from mod.json: {e}"))
18+
})?;
1519
if dependencies.is_empty() {
1620
return Ok(vec![]);
1721
}
@@ -55,20 +59,19 @@ pub async fn create(
5559
)
5660
.fetch_all(conn)
5761
.await
58-
.inspect_err(|e| log::error!("Failed to insert dependencies: {}", e))
59-
.or(Err(ApiError::DbError))
62+
.inspect_err(|e| log::error!("dependenceis::create query failed: {e}"))
63+
.map_err(|e| e.into())
6064
}
6165

62-
pub async fn clear(id: i32, conn: &mut PgConnection) -> Result<(), ApiError> {
66+
pub async fn clear(id: i32, conn: &mut PgConnection) -> Result<(), DatabaseError> {
6367
sqlx::query!(
6468
"DELETE FROM dependencies
6569
WHERE dependent_id = $1",
6670
id
6771
)
6872
.execute(conn)
6973
.await
70-
.inspect_err(|e| log::error!("Failed to clear deps: {}", e))
71-
.or(Err(ApiError::DbError))?;
72-
73-
Ok(())
74+
.inspect_err(|e| log::error!("dependencies::clear query failed: {e}"))
75+
.map_err(|e| e.into())
76+
.map(|_| ())
7477
}

src/database/repository/incompatibilities.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
use sqlx::PgConnection;
22

3-
use crate::types::{
4-
api::ApiError,
5-
mod_json::ModJson,
6-
models::{
7-
dependency::ModVersionCompare,
8-
incompatibility::{FetchedIncompatibility, IncompatibilityImportance},
3+
use crate::{
4+
database::DatabaseError,
5+
types::{
6+
mod_json::ModJson,
7+
models::{
8+
dependency::ModVersionCompare,
9+
incompatibility::{FetchedIncompatibility, IncompatibilityImportance},
10+
},
911
},
1012
};
1113

1214
pub async fn create(
1315
mod_version_id: i32,
1416
json: &ModJson,
1517
conn: &mut PgConnection,
16-
) -> Result<Vec<FetchedIncompatibility>, ApiError> {
17-
let incompats = json.prepare_incompatibilities_for_create()?;
18+
) -> Result<Vec<FetchedIncompatibility>, DatabaseError> {
19+
let incompats = json.prepare_incompatibilities_for_create().map_err(|e| {
20+
DatabaseError::InvalidInput(format!(
21+
"Failed to parse incompatibilities from mod.json: {e}"
22+
))
23+
})?;
1824
if incompats.is_empty() {
1925
return Ok(vec![]);
2026
}
@@ -58,20 +64,19 @@ pub async fn create(
5864
)
5965
.fetch_all(conn)
6066
.await
61-
.inspect_err(|e| log::error!("Failed to insert dependencies: {}", e))
62-
.or(Err(ApiError::DbError))
67+
.inspect_err(|e| log::error!("incompatibilities::create query failed: {e}"))
68+
.map_err(|e| e.into())
6369
}
6470

65-
pub async fn clear(id: i32, conn: &mut PgConnection) -> Result<(), ApiError> {
71+
pub async fn clear(id: i32, conn: &mut PgConnection) -> Result<(), DatabaseError> {
6672
sqlx::query!(
6773
"DELETE FROM incompatibilities
6874
WHERE mod_id = $1",
6975
id
7076
)
7177
.execute(conn)
7278
.await
73-
.inspect_err(|e| log::error!("Failed to clear incompats: {}", e))
74-
.or(Err(ApiError::DbError))?;
75-
76-
Ok(())
79+
.inspect_err(|e| log::error!("incompatibilities::clear query failed: {e}"))
80+
.map_err(|e| e.into())
81+
.map(|_| ())
7782
}

src/database/repository/mod_gd_versions.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
use sqlx::PgConnection;
22

3-
use crate::types::{
4-
api::ApiError,
5-
mod_json::ModJson,
6-
models::mod_gd_version::{DetailedGDVersion, GDVersionEnum, VerPlatform},
3+
use crate::{
4+
database::DatabaseError,
5+
types::{
6+
mod_json::ModJson,
7+
models::mod_gd_version::{DetailedGDVersion, GDVersionEnum, VerPlatform},
8+
},
79
};
810

911
pub async fn create(
1012
mod_version_id: i32,
1113
json: &ModJson,
1214
conn: &mut PgConnection,
13-
) -> Result<DetailedGDVersion, ApiError> {
15+
) -> Result<DetailedGDVersion, DatabaseError> {
1416
let create = json.gd.to_create_payload(json);
1517

1618
let gd: Vec<GDVersionEnum> = create.iter().map(|x| x.gd).collect();
@@ -31,22 +33,20 @@ pub async fn create(
3133
)
3234
.execute(conn)
3335
.await
34-
.inspect_err(|e| log::error!("Failed to insert mod_gd_versions: {}", e))
35-
.or(Err(ApiError::DbError))?;
36+
.inspect_err(|e| log::error!("mod_gd_versions::create query failed: {e}"))?;
3637

3738
Ok(json.gd.clone())
3839
}
3940

40-
pub async fn clear(mod_version_id: i32, conn: &mut PgConnection) -> Result<(), ApiError> {
41+
pub async fn clear(mod_version_id: i32, conn: &mut PgConnection) -> Result<(), DatabaseError> {
4142
sqlx::query!(
4243
"DELETE FROM mod_gd_versions mgv
4344
WHERE mgv.mod_id = $1",
4445
mod_version_id
4546
)
4647
.execute(&mut *conn)
4748
.await
48-
.inspect_err(|e| log::error!("Failed to remove GD versions: {}", e))
49-
.or(Err(ApiError::DbError))?;
50-
51-
Ok(())
49+
.inspect_err(|e| log::error!("incompatibilities::clear query failed: {e}"))
50+
.map_err(|e| e.into())
51+
.map(|_| ())
5252
}

src/database/repository/mod_links.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use sqlx::PgConnection;
22

3-
use crate::types::{api::ApiError, models::mod_link::ModLinks};
3+
use crate::{database::DatabaseError, types::models::mod_link::ModLinks};
44

55
pub async fn upsert(
66
mod_id: &str,
77
community: Option<String>,
88
homepage: Option<String>,
99
source: Option<String>,
1010
conn: &mut PgConnection,
11-
) -> Result<ModLinks, ApiError> {
11+
) -> Result<ModLinks, DatabaseError> {
1212
sqlx::query!(
1313
"INSERT INTO mod_links
1414
(mod_id, community, homepage, source)
@@ -26,8 +26,7 @@ pub async fn upsert(
2626
)
2727
.execute(&mut *conn)
2828
.await
29-
.inspect_err(|x| log::error!("Failed to upsert mod_links for id {}: {}", mod_id, x))
30-
.or(Err(ApiError::DbError))?;
29+
.inspect_err(|x| log::error!("Failed to upsert mod_links for id {mod_id}: {x}"))?;
3130

3231
Ok(ModLinks {
3332
mod_id: mod_id.into(),

src/database/repository/mod_versions.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,7 @@ pub async fn create_from_json(
141141
sqlx::query!("SET CONSTRAINTS mod_versions_status_id_fkey DEFERRED")
142142
.execute(&mut *conn)
143143
.await
144-
.inspect_err(|e| log::error!("Failed to update constraint: {e}"))
145-
.map_err(|e| e.into())?;
144+
.inspect_err(|e| log::error!("Failed to update constraint: {e}"))?;
146145

147146
let geode = Version::parse(&json.geode).or(Err(DatabaseError::InvalidInput(
148147
"mod.json geode version is invalid semver".into(),

0 commit comments

Comments
 (0)