From e2e7ab4417c6c89968a7361fdc0eba559cb31671 Mon Sep 17 00:00:00 2001 From: Filip-L <67787091+Filip-L@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:20:40 +0100 Subject: [PATCH] Get rid of the matches (#247) Co-authored-by: Filip Lelek --- fplus-database/src/database/allocators.rs | 8 +- fplus-database/src/database/applications.rs | 77 +- .../src/middleware/verifier_auth.rs | 50 +- fplus-http-server/src/router/allocator.rs | 110 +- fplus-http-server/src/router/application.rs | 641 ++++---- fplus-http-server/src/router/autoallocator.rs | 38 +- fplus-http-server/src/router/blockchain.rs | 23 +- fplus-http-server/src/router/mod.rs | 4 +- fplus-http-server/src/router/verifier.rs | 10 +- fplus-lib/src/core/allocator/mod.rs | 499 +++--- fplus-lib/src/core/autoallocator/mod.rs | 13 +- fplus-lib/src/core/mod.rs | 1332 +++++++---------- fplus-lib/src/external_services/blockchain.rs | 27 +- fplus-lib/src/external_services/github.rs | 89 +- fplus-lib/src/helpers.rs | 40 +- 15 files changed, 1290 insertions(+), 1671 deletions(-) diff --git a/fplus-database/src/database/allocators.rs b/fplus-database/src/database/allocators.rs index 01a06bff..933d43fb 100644 --- a/fplus-database/src/database/allocators.rs +++ b/fplus-database/src/database/allocators.rs @@ -275,11 +275,9 @@ pub async fn update_allocator_threshold( */ pub async fn delete_allocator(owner: &str, repo: &str) -> Result<(), sea_orm::DbErr> { let conn = get_database_connection().await?; - let allocator = get_allocator(owner, repo).await?; - let allocator = match allocator { - Some(allocator) => allocator, - None => return Err(DbErr::Custom("Allocator not found".to_string())), - }; + let allocator = get_allocator(owner, repo) + .await? + .ok_or(DbErr::Custom("Allocator not found".to_string()))?; allocator.delete(&conn).await?; Ok(()) } diff --git a/fplus-database/src/database/applications.rs b/fplus-database/src/database/applications.rs index a9ddc9b1..c19c1f9d 100644 --- a/fplus-database/src/database/applications.rs +++ b/fplus-database/src/database/applications.rs @@ -174,15 +174,13 @@ pub async fn get_application( query = query.filter(Column::PrNumber.eq(number as i64)); } - let result = query + let application = query .order_by(Column::PrNumber, Order::Desc) .one(&conn) - .await?; + .await? + .ok_or(DbErr::Custom("Application not found".to_string()))?; - match result { - Some(application) => Ok(application), - None => Err(DbErr::Custom("Application not found".to_string())), - } + Ok(application) } /** @@ -202,17 +200,15 @@ pub async fn get_application_by_pr_number( pr_number: u64, ) -> Result { let conn = get_database_connection().await?; - let result = Application::find() + let application = Application::find() .filter(Column::Owner.contains(owner)) .filter(Column::Repo.contains(repo)) .filter(Column::PrNumber.eq(pr_number as i64)) .one(&conn) - .await?; + .await? + .ok_or(DbErr::Custom("Application not found".to_string()))?; - match result { - Some(application) => Ok(application), - None => Err(DbErr::Custom("Application not found".to_string())), - } + Ok(application) } /** @@ -312,36 +308,32 @@ pub async fn update_application( ) -> Result { let conn = get_database_connection().await?; - match get_application(id.clone(), owner.clone(), repo.clone(), Some(pr_number)).await { - Ok(existing_application) => { - let mut active_application: ActiveModel = existing_application.into_active_model(); - active_application.application = Set(Some(app_file.clone())); - let file_sha = sha.unwrap_or_else(|| { - //Calculate SHA - let mut hasher = Sha1::new(); - let application = format!("blob {}\x00{}", app_file.len(), app_file); - hasher.update(application.as_bytes()); - format!("{:x}", hasher.finalize()) - }); - active_application.sha = Set(Some(file_sha)); + let existing_application = + get_application(id.clone(), owner.clone(), repo.clone(), Some(pr_number)).await?; - if let Some(path) = path { - active_application.path = Set(Some(path)); - }; + let mut active_application: ActiveModel = existing_application.into_active_model(); + active_application.application = Set(Some(app_file.clone())); + let file_sha = sha.unwrap_or_else(|| { + //Calculate SHA + let mut hasher = Sha1::new(); + let application = format!("blob {}\x00{}", app_file.len(), app_file); + hasher.update(application.as_bytes()); + format!("{:x}", hasher.finalize()) + }); + active_application.sha = Set(Some(file_sha)); - if let Some(client_contract_address) = client_contract_address { - active_application.client_contract_address = Set(Some(client_contract_address)); - } else { - active_application.client_contract_address = Set(None); - } + if let Some(path) = path { + active_application.path = Set(Some(path)); + }; - let updated_application = active_application.update(&conn).await?; - Ok(updated_application) - } - Err(_) => Err(sea_orm::DbErr::Custom( - "Failed to find the application to update.".into(), - )), + if let Some(client_contract_address) = client_contract_address { + active_application.client_contract_address = Set(Some(client_contract_address)); + } else { + active_application.client_contract_address = Set(None); } + + let updated_application = active_application.update(&conn).await?; + Ok(updated_application) } /** @@ -387,13 +379,8 @@ pub async fn create_application( ..Default::default() }; - match new_application.insert(&conn).await { - Ok(application) => Ok(application), - Err(e) => Err(sea_orm::DbErr::Custom(format!( - "Failed to insert new application: {}", - e - ))), - } + let application = new_application.insert(&conn).await?; + Ok(application) } /** diff --git a/fplus-http-server/src/middleware/verifier_auth.rs b/fplus-http-server/src/middleware/verifier_auth.rs index 7c8b99ed..49bc5984 100644 --- a/fplus-http-server/src/middleware/verifier_auth.rs +++ b/fplus-http-server/src/middleware/verifier_auth.rs @@ -88,36 +88,28 @@ where .header("Authorization", format!("Bearer {}", token)) .header("User-Agent", "Actix-web") .send() - .await; - - match user_info_result { - Ok(response) => { - //Raise an actix test error - if response.status().is_success() { - let user_info = response - .json::() - .await - .expect("Failed to parse JSON"); - - if let Some(login) = user_info.get("login").and_then(|v| v.as_str()) { - user_handle = login.to_string(); - } else { - println!("GitHub handle information not found."); - return Err(actix_web::error::ErrorInternalServerError( - "GitHub handle information not found.", - )); - } - } else { - println!("Failed to get GitHub user info"); - return Err(actix_web::error::ErrorUnauthorized( - "Failed to get GitHub user info.", - )); - } - } - Err(e) => { - println!("Request error: {:?}", e); - return Err(actix_web::error::ErrorBadRequest(e)); + .await + .map_err(actix_web::error::ErrorBadRequest)?; + + if user_info_result.status().is_success() { + let user_info = user_info_result + .json::() + .await + .expect("Failed to parse JSON"); + + if let Some(login) = user_info.get("login").and_then(|v| v.as_str()) { + user_handle = login.to_string(); + } else { + println!("GitHub handle information not found."); + return Err(actix_web::error::ErrorInternalServerError( + "GitHub handle information not found.", + )); } + } else { + println!("Failed to get GitHub user info"); + return Err(actix_web::error::ErrorUnauthorized( + "Failed to get GitHub user info.", + )); } } diff --git a/fplus-http-server/src/router/allocator.rs b/fplus-http-server/src/router/allocator.rs index 2f26b7c3..7338b7a3 100644 --- a/fplus-http-server/src/router/allocator.rs +++ b/fplus-http-server/src/router/allocator.rs @@ -1,4 +1,8 @@ -use actix_web::{delete, get, post, web, HttpResponse, Responder}; +use actix_web::{ + delete, + error::{ErrorInternalServerError, ErrorNotFound}, + get, post, web, HttpResponse, Responder, +}; use fplus_database::database::allocators as allocators_db; use fplus_lib::core::{ allocator::{ @@ -15,15 +19,11 @@ use reqwest::Client; * @return HttpResponse - The result of the operation */ #[get("/allocators")] -pub async fn allocators() -> impl Responder { - let allocators = allocators_db::get_allocators().await; - match allocators { - Ok(allocators) => HttpResponse::Ok().json(allocators), - Err(e) => { - log::error!("Failed to fetch allocators: {}", e); - HttpResponse::InternalServerError().body(e.to_string()) - } - } +pub async fn allocators() -> actix_web::Result { + let allocators = allocators_db::get_allocators() + .await + .map_err(ErrorNotFound)?; + Ok(HttpResponse::Ok().json(allocators)) } /** * Creates new Allocator in the db from a JSON file in the repository @@ -35,15 +35,17 @@ pub async fn allocators() -> impl Responder { * @return HttpResponse - The result of the operation */ #[post("/allocator/create")] -pub async fn create_allocator_from_json(files: web::Json) -> impl Responder { +pub async fn create_allocator_from_json( + files: web::Json, +) -> actix_web::Result { let ChangedAllocators { files_changed } = files.into_inner(); - match create_allocator_from_file(files_changed).await { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("All files processed successfully") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + create_allocator_from_file(files_changed) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("All files processed successfully") + .expect("Serialization of static string should succeed"), + )) } /** @@ -56,14 +58,15 @@ pub async fn create_allocator_from_json(files: web::Json) -> * @return HttpResponse - The result of the operation */ #[get("/allocator/{owner}/{repo}")] -pub async fn allocator(path: web::Path<(String, String)>) -> impl Responder { +pub async fn allocator(path: web::Path<(String, String)>) -> actix_web::Result { let (owner, repo) = path.into_inner(); - match allocators_db::get_allocator(&owner, &repo).await { - Ok(allocator) => match allocator { - Some(allocator) => HttpResponse::Ok().json(allocator), - None => HttpResponse::NotFound().finish(), - }, - Err(e) => HttpResponse::InternalServerError().body(e.to_string()), + let allocator = allocators_db::get_allocator(&owner, &repo) + .await + .map_err(ErrorInternalServerError)?; + if let Some(allocator) = allocator { + Ok(HttpResponse::Ok().json(allocator)) + } else { + Err(ErrorNotFound("Allocator not found")) } } @@ -77,17 +80,12 @@ pub async fn allocator(path: web::Path<(String, String)>) -> impl Responder { * @return HttpResponse - The result of the operation */ #[delete("/allocator/{owner}/{repo}")] -pub async fn delete(path: web::Path<(String, String)>) -> impl Responder { +pub async fn delete(path: web::Path<(String, String)>) -> actix_web::Result { let (owner, repo) = path.into_inner(); - match allocators_db::delete_allocator(&owner, &repo).await { - Ok(_) => HttpResponse::Ok().finish(), - Err(e) => { - if e.to_string().contains("Allocator not found") { - return HttpResponse::NotFound().body(e.to_string()); - } - HttpResponse::InternalServerError().body(e.to_string()) - } - } + allocators_db::delete_allocator(&owner, &repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().finish()) } /** @@ -99,7 +97,9 @@ pub async fn delete(path: web::Path<(String, String)>) -> impl Responder { * @param AllocatorUpdateForceInfo - The list of changed JSON file names and allocators to update */ #[post("/allocator/update/force")] -pub async fn update_allocator_force(body: web::Json) -> impl Responder { +pub async fn update_allocator_force( + body: web::Json, +) -> actix_web::Result { // First we need to deconstruct the body let AllocatorUpdateForceInfo { files, @@ -107,34 +107,22 @@ pub async fn update_allocator_force(body: web::Json) - } = body.into_inner(); // Logic will be implemented in allocator::update_allocator_force - match force_update_allocators(files, affected_allocators).await { - Ok(results) => HttpResponse::Ok().json(results), - Err(e) => { - log::error!("Failed to update allocators: {}", e); - HttpResponse::InternalServerError().body(format!("{}", e)) - } - } + force_update_allocators(files, affected_allocators) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(())) } #[get("/get_installation_ids")] -pub async fn get_installation_ids() -> impl Responder { +pub async fn get_installation_ids() -> actix_web::Result { let client = Client::new(); - let jwt = match generate_github_app_jwt().await { - Ok(jwt) => jwt, - Err(e) => { - log::error!("Failed to generate GitHub App JWT: {}", e); - return HttpResponse::InternalServerError().finish(); // Ensure to call .finish() - } - }; + let jwt = generate_github_app_jwt() + .await + .map_err(ErrorInternalServerError)?; - match fetch_installation_ids(&client, &jwt).await { - Ok(ids) => { - // Assuming `ids` can be serialized directly; adjust based on your actual data structure - HttpResponse::Ok().json(ids) - } - Err(e) => { - log::error!("Failed to fetch installation IDs: {}", e); - HttpResponse::InternalServerError().finish() - } - } + let ids = fetch_installation_ids(&client, &jwt).await.map_err(|e| { + log::error!("Failed to generate GitHub App JWT: {}", e); + ErrorInternalServerError(e) + })?; + Ok(HttpResponse::Ok().json(ids)) } diff --git a/fplus-http-server/src/router/application.rs b/fplus-http-server/src/router/application.rs index 9b60dd00..a136b03f 100644 --- a/fplus-http-server/src/router/application.rs +++ b/fplus-http-server/src/router/application.rs @@ -1,4 +1,7 @@ -use actix_web::{get, post, web, HttpResponse, Responder}; +use actix_web::{ + error::{ErrorBadRequest, ErrorInternalServerError, ErrorNotFound}, + get, post, web, HttpResponse, Responder, +}; use fplus_lib::core::{ application::file::{StorageProviderChangeVerifier, VerifierInput}, ApplicationQueryParams, BranchDeleteInfo, CompleteGovernanceReviewInfo, @@ -9,61 +12,55 @@ use fplus_lib::core::{ }; #[post("/application")] -pub async fn create(info: web::Json) -> impl Responder { - match LDNApplication::new_from_issue(info.into_inner()).await { - Ok(app) => HttpResponse::Ok().body(format!( - "Created new application for issue: {}", - app.application_id.clone() - )), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } +pub async fn create(info: web::Json) -> actix_web::Result { + let app = LDNApplication::new_from_issue(info.into_inner()) + .await + .map_err(ErrorBadRequest)?; + Ok(HttpResponse::Ok().body(format!( + "Created new application for issue: {}", + app.application_id.clone() + ))) } #[get("/application")] -pub async fn single(query: web::Query) -> impl Responder { +pub async fn single( + query: web::Query, +) -> actix_web::Result { let ApplicationQueryParams { id, owner, repo } = query.into_inner(); - match LDNApplication::load_from_db(id, owner, repo).await { - Ok(app_file) => match serde_json::to_string_pretty(&app_file) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + let app_file = LDNApplication::load_from_db(id, owner, repo) + .await + .map_err(ErrorNotFound)?; + let body = serde_json::to_string_pretty(&app_file).map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body(body)) } #[get("/application/with-allocation-amount")] pub async fn application_with_allocation_amount_handler( query: web::Query, -) -> impl Responder { +) -> actix_web::Result { let ApplicationQueryParams { id, owner, repo } = query.into_inner(); - - match LDNApplication::application_with_allocation_amount(id, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + let application = LDNApplication::application_with_allocation_amount(id, owner, repo) + .await + .map_err(ErrorNotFound)?; + Ok(HttpResponse::Ok().json(application)) } #[post("/application/trigger")] pub async fn trigger( query: web::Query, info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + dbg!(&ldn_application); let CompleteGovernanceReviewInfo { allocation_amount, client_contract_address, } = info.into_inner(); - match ldn_application + let response = ldn_application .complete_governance_review( query.github_username.clone(), query.owner.clone(), @@ -72,61 +69,47 @@ pub async fn trigger( client_contract_address, ) .await - { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest() - .body(format!("Application is not in the correct state {}", e)), - } + .map_err(ErrorBadRequest)?; + + let serialized_app = serde_json::to_string_pretty(&response) + .map_err(|_| ErrorInternalServerError("Failed to serialize success message".to_string()))?; + + Ok(HttpResponse::Ok().body(serialized_app)) } #[post("/application/approve_changes")] -pub async fn approve_changes(query: web::Query) -> impl Responder { +pub async fn approve_changes( + query: web::Query, +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; - - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + + let response = ldn_application .approve_changes(query.owner.clone(), query.repo.clone()) .await - { - Ok(result) => match serde_json::to_string_pretty(&result) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorNotFound)?; + + let serialized_app = serde_json::to_string_pretty(&response) + .map_err(|_| ErrorInternalServerError("Failed to serialize success message".to_string()))?; + Ok(HttpResponse::Ok().body(serialized_app)) } #[post("/application/propose")] pub async fn propose( info: web::Json, query: web::Query, -) -> impl Responder { +) -> actix_web::Result { let CompleteNewApplicationProposalInfo { signer, request_id, new_allocation_amount, } = info.into_inner(); let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; let updated_signer = VerifierInput { github_username: query.github_username.clone(), // Use the provided `github_username` parameter signing_address: signer.signing_address, @@ -134,7 +117,7 @@ pub async fn propose( message_cid: signer.message_cids.message_cid, increase_allowance_cid: signer.message_cids.increase_allowance_cid, }; - match ldn_application + let response = ldn_application .complete_new_application_proposal( updated_signer, request_id, @@ -143,35 +126,26 @@ pub async fn propose( new_allocation_amount, ) .await - { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + let serialized_app = serde_json::to_string_pretty(&response) + .map_err(|_| ErrorInternalServerError("Failed to serialize success message".to_string()))?; + Ok(HttpResponse::Ok().body(serialized_app)) } #[post("/application/propose_storage_providers")] pub async fn propose_storage_providers( info: web::Json, query: web::Query, -) -> impl Responder { +) -> actix_web::Result { let StorageProvidersChangeProposalInfo { signer, allowed_sps, max_deviation, } = info.into_inner(); let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; let verifier = StorageProviderChangeVerifier { github_username: query.github_username.clone(), signing_address: signer.signing_address.clone(), @@ -180,7 +154,7 @@ pub async fn propose_storage_providers( remove_allowed_sps_cids: signer.removed_allowed_sps_cids.clone(), }; - match ldn_application + ldn_application .complete_sps_change_proposal( verifier, query.owner.clone(), @@ -189,29 +163,23 @@ pub async fn propose_storage_providers( max_deviation, ) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("/application/approve_storage_providers")] pub async fn approve_storage_providers( info: web::Json, query: web::Query, -) -> impl Responder { +) -> actix_web::Result { let StorageProvidersChangeApprovalInfo { signer, request_id } = info.into_inner(); let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; let verifier = StorageProviderChangeVerifier { github_username: query.github_username.clone(), signing_address: signer.signing_address.clone(), @@ -219,7 +187,7 @@ pub async fn approve_storage_providers( add_allowed_sps_cids: signer.allowed_sps_cids.clone(), remove_allowed_sps_cids: signer.removed_allowed_sps_cids.clone(), }; - match ldn_application + ldn_application .complete_sps_change_approval( verifier, query.owner.clone(), @@ -227,29 +195,23 @@ pub async fn approve_storage_providers( request_id, ) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("/application/approve")] pub async fn approve( query: web::Query, info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let CompleteNewApplicationApprovalInfo { signer, request_id } = info.into_inner(); let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; let updated_signer = VerifierInput { github_username: query.github_username.clone(), // Use the provided `github_username` parameter signing_address: signer.signing_address, @@ -257,7 +219,7 @@ pub async fn approve( message_cid: signer.message_cids.message_cid, increase_allowance_cid: signer.message_cids.increase_allowance_cid, }; - match ldn_application + let app = ldn_application .complete_new_application_approval( updated_signer, request_id, @@ -266,355 +228,312 @@ pub async fn approve( None, ) .await - { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + let serialized_app = serde_json::to_string_pretty(&app).map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body(serialized_app)) } #[post("/application/decline")] -pub async fn decline(query: web::Query) -> impl Responder { +pub async fn decline( + query: web::Query, +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + ldn_application .decline_application(query.owner.clone(), query.repo.clone()) .await - { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(_) => HttpResponse::BadRequest().body("Application is not in the correct state"), - } + .map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body(())) } #[post("/application/additional_info_required")] pub async fn additional_info_required( query: web::Query, info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let MoreInfoNeeded { verifier_message } = info.into_inner(); let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => { - return HttpResponse::BadRequest().body(e.to_string()); - } - }; - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + let app = ldn_application .additional_info_required(query.owner.clone(), query.repo.clone(), verifier_message) .await - { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(_) => HttpResponse::BadRequest().body("Application is not in the correct state"), - } + .map_err(ErrorInternalServerError)?; + let serialized_app = serde_json::to_string_pretty(&app).map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body(serialized_app)) } #[get("/applications")] -pub async fn all_applications() -> impl Responder { - match LDNApplication::all_applications().await { - Ok(apps) => match serde_json::to_string_pretty(&apps) { - Ok(json) => HttpResponse::Ok() - .content_type("application/json") - .body(json), - Err(e) => HttpResponse::InternalServerError() - .body(format!("Failed to serialize applications: {}", e)), - }, - Err(errors) => match serde_json::to_string_pretty(&errors) { - Ok(json) => HttpResponse::BadRequest() - .content_type("application/json") - .body(json), - Err(e) => HttpResponse::InternalServerError() - .body(format!("Failed to serialize errors: {}", e)), - }, - } +pub async fn all_applications() -> actix_web::Result { + let apps = LDNApplication::all_applications() + .await + .map_err(ErrorNotFound)?; + + let parsed = serde_json::to_string_pretty(&apps).map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(parsed)) } #[get("/application/active")] -pub async fn active(query: web::Query) -> impl Responder { +pub async fn active(query: web::Query) -> actix_web::Result { let GithubQueryParams { owner, repo } = query.into_inner(); - match LDNApplication::active(owner, repo, None).await { - Ok(app) => match serde_json::to_string_pretty(&app) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + let app = LDNApplication::active(owner, repo, None) + .await + .map_err(ErrorInternalServerError)?; + let serialized_app = serde_json::to_string_pretty(&app).map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body(serialized_app)) } #[get("/application/merged")] pub async fn merged(query: web::Query) -> actix_web::Result { let GithubQueryParams { owner, repo } = query.into_inner(); - match LDNApplication::merged(owner, repo).await { - Ok(apps) => match serde_json::to_string_pretty(&apps) { - Ok(response) => Ok(HttpResponse::Ok().body(response)), - Err(_) => { - Ok(HttpResponse::InternalServerError().body("Failed to serialize success message")) - } - }, - Err(e) => Ok(HttpResponse::InternalServerError().body(e.to_string())), - } + let apps = LDNApplication::merged(owner, repo) + .await + .map_err(ErrorInternalServerError)?; + let serialized_apps = serde_json::to_string_pretty(&apps).map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body(serialized_apps)) } #[post("/application/notify_refill")] -pub async fn notify_refill(info: web::Json) -> impl Responder { - match LDNApplication::notify_refill(info.into_inner()).await { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } +pub async fn notify_refill(info: web::Json) -> actix_web::Result { + LDNApplication::notify_refill(info.into_inner()) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("/application/totaldcreached")] pub async fn total_dc_reached(data: web::Json) -> actix_web::Result { let DcReachedInfo { id, owner, repo } = data.into_inner(); - match LDNApplication::total_dc_reached(id, owner, repo).await { - Ok(applications) => Ok(HttpResponse::Ok().json(applications)), - Err(e) => Ok(HttpResponse::BadRequest().body(e.to_string())), - } + let applications = LDNApplication::total_dc_reached(id, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(applications)) } #[post("application/flow/validate")] pub async fn validate_application_flow( info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - match pr_number { - Ok(pr_number) => { - match LDNApplication::validate_flow(pr_number, &user_handle, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - } - } - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::validate_flow(pr_number, &user_handle, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("application/trigger/validate")] pub async fn validate_application_trigger( info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - - match pr_number { - Ok(pr_number) => { - match LDNApplication::validate_trigger(pr_number, &user_handle, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - } - } - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::validate_trigger(pr_number, &user_handle, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("application/proposal/validate")] pub async fn validate_application_proposal( info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle: _, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - - match pr_number { - Ok(pr_number) => match LDNApplication::validate_proposal(pr_number, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - }, - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::validate_proposal(pr_number, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("application/approval/validate")] pub async fn validate_application_approval( info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle: _, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - - match pr_number { - Ok(pr_number) => match LDNApplication::validate_approval(pr_number, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - }, - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::validate_approval(pr_number, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("application/merge/validate")] pub async fn validate_application_merge( info: web::Json, -) -> impl Responder { +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle: _, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - - match pr_number { - Ok(pr_number) => { - match LDNApplication::validate_merge_application(pr_number, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - } - } - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::validate_merge_application(pr_number, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("/application/branch/delete")] pub async fn delete_branch(data: web::Json) -> actix_web::Result { let info = data.into_inner(); - match LDNApplication::delete_branch(info.owner, info.repo, info.branch_name).await { - Ok(result) => Ok(HttpResponse::Ok().json(result)), - Err(e) => Ok(HttpResponse::BadRequest().body(e.to_string())), - } + let result = LDNApplication::delete_branch(info.owner, info.repo, info.branch_name) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) } #[post("application/cache/renewal")] -pub async fn cache_renewal(info: web::Json) -> impl Responder { +pub async fn cache_renewal( + info: web::Json, +) -> actix_web::Result { let GithubQueryParams { owner, repo } = info.into_inner(); - let active_result = LDNApplication::cache_renewal_active(owner.clone(), repo.clone()).await; - - let merged_result = LDNApplication::cache_renewal_merged(owner, repo).await; + LDNApplication::cache_renewal_active(owner.clone(), repo.clone()) + .await + .map_err(ErrorInternalServerError)?; - match (active_result, merged_result) { - (Ok(_), Ok(_)) => { - HttpResponse::Ok().json("Cache renewal for active and merged applications succeeded") - } - (Err(e), _) | (_, Err(e)) => HttpResponse::InternalServerError().json(e.to_string()), - } + LDNApplication::cache_renewal_merged(owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json("Cache renewal for active and merged applications succeeded")) } #[post("application/update-from-issue")] -pub async fn update_from_issue(info: web::Json) -> impl Responder { - match LDNApplication::update_from_issue(info.into_inner()).await { - Ok(app) => HttpResponse::Ok().body(format!( - "Updated application for issue: {}", - app.application_id.clone() - )), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } +pub async fn update_from_issue( + info: web::Json, +) -> actix_web::Result { + let app = LDNApplication::update_from_issue(info.into_inner()) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body(format!( + "Updated application for issue: {}", + app.application_id.clone() + ))) } #[post("application/check_for_changes")] -pub async fn check_for_changes(info: web::Json) -> impl Responder { +pub async fn check_for_changes( + info: web::Json, +) -> actix_web::Result { let ValidationPullRequestData { pr_number, user_handle, owner, repo, } = info.into_inner(); - let pr_number = pr_number.trim_matches('"').parse::(); - - match pr_number { - Ok(pr_number) => { - match LDNApplication::check_for_changes(pr_number, &user_handle, owner, repo).await { - Ok(result) => HttpResponse::Ok().json(result), - Err(e) => HttpResponse::InternalServerError().json(e.to_string()), - } - } - Err(_) => HttpResponse::BadRequest().json("Invalid PR Number"), + + if let Ok(pr_number) = pr_number.trim_matches('"').parse::() { + let result = LDNApplication::check_for_changes(pr_number, &user_handle, owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(result)) + } else { + Err(ErrorBadRequest("Invalid PR Number")) } } #[post("application/submit_kyc")] -pub async fn submit_kyc(info: web::Json) -> impl Responder { - let ldn_application = match LDNApplication::load( +pub async fn submit_kyc(info: web::Json) -> actix_web::Result { + let ldn_application = LDNApplication::load( info.message.client_id.clone(), info.message.allocator_repo_owner.clone(), info.message.allocator_repo_name.clone(), ) .await - { - Ok(app) => app, - Err(e) => return HttpResponse::BadRequest().body(e.to_string()), - }; - match ldn_application.submit_kyc(&info.into_inner()).await { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Address verified with score") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorNotFound)?; + + ldn_application + .submit_kyc(&info.into_inner()) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Address verified with score") + .expect("Serialization of static string should succeed"), + )) } #[get("/health")] -pub async fn health() -> impl Responder { - HttpResponse::Ok().body("OK") +pub async fn health() -> actix_web::Result { + Ok(HttpResponse::Ok().body("OK")) } #[post("application/request_kyc")] -pub async fn request_kyc(query: web::Query) -> impl Responder { +pub async fn request_kyc( + query: web::Query, +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => return HttpResponse::BadRequest().body(e.to_string()), - }; - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + ldn_application .request_kyc(&query.id, &query.owner, &query.repo) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("application/trigger_ssa")] pub async fn trigger_ssa( query: web::Query, info: web::Json, -) -> impl Responder { - match LDNApplication::trigger_ssa( +) -> actix_web::Result { + LDNApplication::trigger_ssa( &query.id, &query.owner, &query.repo, @@ -622,53 +541,47 @@ pub async fn trigger_ssa( info.into_inner(), ) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("application/remove_pending_allocation")] pub async fn remove_pending_allocation( query: web::Query, -) -> impl Responder { +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => return HttpResponse::BadRequest().body(e.to_string()), - }; - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + ldn_application .remove_pending_allocation(&query.id, &query.owner, &query.repo) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } #[post("application/allocation_failed")] -pub async fn allocation_failed(query: web::Query) -> impl Responder { +pub async fn allocation_failed( + query: web::Query, +) -> actix_web::Result { let ldn_application = - match LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()).await - { - Ok(app) => app, - Err(e) => return HttpResponse::BadRequest().body(e.to_string()), - }; - match ldn_application + LDNApplication::load(query.id.clone(), query.owner.clone(), query.repo.clone()) + .await + .map_err(ErrorNotFound)?; + ldn_application .revert_to_ready_to_sign(&query.id, &query.owner, &query.repo) .await - { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } + .map_err(ErrorInternalServerError)?; + + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } diff --git a/fplus-http-server/src/router/autoallocator.rs b/fplus-http-server/src/router/autoallocator.rs index dca8fc8b..fcebde84 100644 --- a/fplus-http-server/src/router/autoallocator.rs +++ b/fplus-http-server/src/router/autoallocator.rs @@ -1,3 +1,4 @@ +use actix_web::error::ErrorInternalServerError; use actix_web::{get, post, web, HttpResponse, Responder}; use fplus_database::database::autoallocations as autoallocations_db; use fplus_lib::core::autoallocator; @@ -5,25 +6,26 @@ use fplus_lib::core::{LastAutoallocationQueryParams, TriggerAutoallocationInfo}; #[get("/autoallocator/last_client_allocation")] pub async fn last_client_allocation( query: web::Query, -) -> impl Responder { - match autoallocations_db::get_last_client_autoallocation(query.evm_wallet_address).await { - Ok(last_client_allocation) => match serde_json::to_string_pretty(&last_client_allocation) { - Ok(response) => HttpResponse::Ok().body(response), - Err(_) => { - HttpResponse::InternalServerError().body("Failed to serialize success message") - } - }, - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } +) -> actix_web::Result { + let last_client_allocation = + autoallocations_db::get_last_client_autoallocation(query.evm_wallet_address) + .await + .map_err(ErrorInternalServerError)?; + + let serialized_last_client_allocation = + serde_json::to_string_pretty(&last_client_allocation).map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body(serialized_last_client_allocation)) } #[post("autoallocator/trigger_autoallocation")] -pub async fn trigger_autoallocation(info: web::Json) -> impl Responder { - match autoallocator::trigger_autoallocation(&info.into_inner()).await { - Ok(_) => HttpResponse::Ok().body( - serde_json::to_string_pretty("Success") - .expect("Serialization of static string should succeed"), - ), - Err(e) => HttpResponse::BadRequest().body(e.to_string()), - } +pub async fn trigger_autoallocation( + info: web::Json, +) -> actix_web::Result { + autoallocator::trigger_autoallocation(&info.into_inner()) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body( + serde_json::to_string_pretty("Success") + .expect("Serialization of static string should succeed"), + )) } diff --git a/fplus-http-server/src/router/blockchain.rs b/fplus-http-server/src/router/blockchain.rs index 279581b7..c9acf199 100644 --- a/fplus-http-server/src/router/blockchain.rs +++ b/fplus-http-server/src/router/blockchain.rs @@ -1,4 +1,4 @@ -use actix_web::{get, web, HttpResponse, Responder}; +use actix_web::{error::ErrorInternalServerError, get, web, HttpResponse, Responder}; use fplus_lib::external_services::{ blockchain::BlockchainData, filecoin::get_allowance_for_address, }; @@ -22,11 +22,11 @@ use fplus_lib::external_services::{ /// ``` #[get("/blockchain/address_allowance/{address}")] -pub async fn address_allowance(address: web::Path) -> impl Responder { - match get_allowance_for_address(&address.into_inner()).await { - Ok(res) => HttpResponse::Ok().body(res), - Err(_) => HttpResponse::InternalServerError().body("SOMETHING IS WRONG WITH DEMOB SETUP!"), - } +pub async fn address_allowance(address: web::Path) -> actix_web::Result { + let res = get_allowance_for_address(&address.into_inner()) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body(res)) } /// Verified Clients. @@ -48,10 +48,11 @@ pub async fn address_allowance(address: web::Path) -> impl Responder { /// ``` #[get("/blockchain/verified_clients")] -pub async fn verified_clients() -> impl Responder { +pub async fn verified_clients() -> actix_web::Result { let blockchain = BlockchainData::new(); - match blockchain.get_verified_clients().await { - Ok(res) => HttpResponse::Ok().body(res), - Err(_) => HttpResponse::InternalServerError().body("SOMETHING IS WRONG WITH DEMOB SETUP!"), - } + let res = blockchain + .get_verified_clients() + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().body(res)) } diff --git a/fplus-http-server/src/router/mod.rs b/fplus-http-server/src/router/mod.rs index 18f706d4..a4a83543 100644 --- a/fplus-http-server/src/router/mod.rs +++ b/fplus-http-server/src/router/mod.rs @@ -8,6 +8,6 @@ pub mod verifier; /// Return server health status #[get("/health")] -pub async fn health() -> impl Responder { - HttpResponse::Ok().body("OK") +pub async fn health() -> actix_web::Result { + Ok(HttpResponse::Ok().body("OK")) } diff --git a/fplus-http-server/src/router/verifier.rs b/fplus-http-server/src/router/verifier.rs index f72162b2..7b8ee325 100644 --- a/fplus-http-server/src/router/verifier.rs +++ b/fplus-http-server/src/router/verifier.rs @@ -1,12 +1,12 @@ -use actix_web::{get, web, HttpResponse, Responder}; +use actix_web::{error::ErrorInternalServerError, get, web, HttpResponse, Responder}; use fplus_lib::core::{GithubQueryParams, LDNApplication}; #[get("/verifiers")] pub async fn verifiers(query: web::Query) -> actix_web::Result { let GithubQueryParams { owner, repo } = query.into_inner(); - match LDNApplication::fetch_verifiers(owner, repo).await { - Ok(notaries) => Ok(HttpResponse::Ok().json(notaries)), - Err(e) => Ok(HttpResponse::InternalServerError().body(e.to_string())), - } + let notaries = LDNApplication::fetch_verifiers(owner, repo) + .await + .map_err(ErrorInternalServerError)?; + Ok(HttpResponse::Ok().json(notaries)) } diff --git a/fplus-lib/src/core/allocator/mod.rs b/fplus-lib/src/core/allocator/mod.rs index 26a9dddc..3a1bfe8a 100644 --- a/fplus-lib/src/core/allocator/mod.rs +++ b/fplus-lib/src/core/allocator/mod.rs @@ -58,57 +58,49 @@ pub async fn process_allocator_file(file_name: &str) -> Result Result { - let encoded_content = match file.items.first().and_then(|f| f.content.clone()) { - Some(content) => { - log::info!("Fetched content: {:?}", content); - content - } - None => { + let encoded_content = file + .items + .first() + .and_then(|f| f.content.clone()) + .ok_or_else(|| { log::error!("Allocator file is corrupted or empty"); - return Err(LDNError::Load("Allocator file is corrupted".to_string())); - } - }; + LDNError::Load("Allocator file is corrupted".to_string()) + })?; + + log::info!("Fetched content: {:?}", encoded_content); let cleaned_content = encoded_content.replace('\n', ""); log::info!("Cleaned content: {:?}", cleaned_content); + let mut model = decode_allocator_model(&cleaned_content).ok_or(LDNError::Load( + "Failed to parse allocator model".to_string(), + ))?; + let mut owner_repo_parts: Vec<&str> = model + .application + .allocation_bookkeeping + .split('/') + .collect(); + // If last part is empty, remove it + if owner_repo_parts[owner_repo_parts.len() - 1].is_empty() { + owner_repo_parts.pop(); + } + if owner_repo_parts.len() < 2 { + log::error!("Failed to parse allocator model"); + return Err(LDNError::Load( + "Failed to parse allocator model".to_string(), + )); + } - match decode_allocator_model(&cleaned_content) { - Some(mut model) => { - let mut owner_repo_parts: Vec<&str> = model - .application - .allocation_bookkeeping - .split('/') - .collect(); - // If last part is empty, remove it - if owner_repo_parts[owner_repo_parts.len() - 1].is_empty() { - owner_repo_parts.pop(); - } - if owner_repo_parts.len() < 2 { - log::error!("Failed to parse allocator model"); - return Err(LDNError::Load( - "Failed to parse allocator model".to_string(), - )); - } - - //If repo ends with .git, remove it - let mut repo = owner_repo_parts[owner_repo_parts.len() - 1].to_string(); - if repo.ends_with(".git") { - repo = repo[..repo.len() - 4].to_string(); - } + //If repo ends with .git, remove it + let mut repo = owner_repo_parts[owner_repo_parts.len() - 1].to_string(); + if repo.ends_with(".git") { + repo = repo[..repo.len() - 4].to_string(); + } - model.owner = Some(owner_repo_parts[owner_repo_parts.len() - 2].to_string()); - model.repo = Some(repo); + model.owner = Some(owner_repo_parts[owner_repo_parts.len() - 2].to_string()); + model.repo = Some(repo); - log::info!("Parsed allocator model successfully"); - Ok(model) - } - None => { - log::error!("Failed to parse allocator model"); - Err(LDNError::Load( - "Failed to parse allocator model".to_string(), - )) - } - } + log::info!("Parsed allocator model successfully"); + Ok(model) } pub async fn is_allocator_repo_initialized(gh: &GithubWrapper) -> Result { @@ -166,56 +158,8 @@ pub async fn create_file_in_repo( .map_err(|e| LDNError::Load(format!("here1 {}", e)))?; //Get file from target repo. If file does not exist or fails to retrieve, create it - let target_file = gh.get_file(&file_path, "main").await.map_err(|e| { - LDNError::Load(format!( - "Failed to retrieve file from GitHub. Reason: {} in file {}", - e, file_path - )) - }); - - match target_file { - Ok(target_file) => { - if target_file.items.is_empty() { - log::info!("Creating file in target repo: {}", file_path); - gh.add_file(&file_path, &file, "first commit", "main") - .await - .map_err(|e| { - LDNError::Load(format!( - "Failed to create file in GitHub repo {}/{}. Reason: {} in file {}", - gh.owner.clone(), - gh.repo.clone(), - e, - file_path - )) - })?; - } else if !force { - log::info!( - "File already exists in target repo {}/{}: {}", - gh.owner.clone(), - gh.repo.clone(), - file_path - ); - } else if target_file.items[0].sha.clone() != file_sha { - log::info!( - "Force creating file in target repo {}/{}: {}", - gh.owner.clone(), - gh.repo.clone(), - file_path - ); - let file_sha = target_file.items[0].sha.clone(); - gh.update_file(&file_path, "Update", &file, "main", &file_sha) - .await - .map_err(|e| { - LDNError::Load(format!( - "Failed to update file in GitHub repo {}/{}. Reason: {} in file {}", - gh.owner.clone(), - gh.repo.clone(), - e, - file_path - )) - })?; - } - } + let target_file = match gh.get_file(&file_path, "main").await { + Ok(target_file) => target_file, Err(_) => { log::info!("Creating file in target repo: {}", file_path); gh.add_file(&file_path, &file, "first commit", "main") @@ -229,7 +173,48 @@ pub async fn create_file_in_repo( file_path )) })?; + return Ok(()); } + }; + if target_file.items.is_empty() { + log::info!("Creating file in target repo: {}", file_path); + gh.add_file(&file_path, &file, "first commit", "main") + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to create file in GitHub repo {}/{}. Reason: {} in file {}", + gh.owner.clone(), + gh.repo.clone(), + e, + file_path + )) + })?; + } else if !force { + log::info!( + "File already exists in target repo {}/{}: {}", + gh.owner.clone(), + gh.repo.clone(), + file_path + ); + } else if target_file.items[0].sha.clone() != file_sha { + log::info!( + "Force creating file in target repo {}/{}: {}", + gh.owner.clone(), + gh.repo.clone(), + file_path + ); + let file_sha = target_file.items[0].sha.clone(); + gh.update_file(&file_path, "Update", &file, "main", &file_sha) + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to update file in GitHub repo {}/{}. Reason: {} in file {}", + gh.owner.clone(), + gh.repo.clone(), + e, + file_path + )) + })?; } Ok(()) @@ -287,20 +272,16 @@ pub async fn generate_github_app_jwt() -> Result { })?; let pem = get_env_var_or_default("GH_PRIVATE_KEY"); - match EncodingKey::from_rsa_pem(pem.to_string().as_bytes()) { - Ok(key) => { - let token = create_jwt(octocrab::models::AppId(app_id), &key) - .map_err(|e| LDNError::Load(format!("Failed to create jwt: {}", e)))?; - Ok(token) - } - Err(e) => { - println!("Error: {:?}", e); - Err(LDNError::Load(format!("{}", e))) - } - } + let key = EncodingKey::from_rsa_pem(pem.to_string().as_bytes()) + .map_err(|e| LDNError::Load(format!("Failed to load RSA PEM: {}", e)))?; + + let token = create_jwt(octocrab::models::AppId(app_id), &key) + .map_err(|e| LDNError::Load(format!("Failed to create JWT: {}", e)))?; + + Ok(token) } -pub async fn fetch_installation_ids(client: &Client, jwt: &str) -> Result> { +pub async fn fetch_installation_ids(client: &Client, jwt: &str) -> Result, LDNError> { let req_url = "https://api.github.com/app/installations"; let response = client .get(req_url) @@ -309,23 +290,23 @@ pub async fn fetch_installation_ids(client: &Client, jwt: &str) -> Result = match serde_json::from_str(&text) { - Ok(data) => data, - Err(e) => { - log::error!("Failed to parse response as JSON: {}", e); - return Err(e.into()); - } - }; + let installations: Vec = serde_json::from_str(&text) + .map_err(|e| LDNError::Load(format!("Failed to parse response as JSON: {}", e)))?; + Ok(installations.into_iter().map(|i| i.id).collect()) } @@ -497,7 +478,7 @@ pub async fn force_update_allocators( let files = files.iter().filter(|f| !ignored_files.contains(f)); for file in files { - match gh + let content = gh .get_files_from_public_repo( &allocator_template_owner, &allocator_template_repo, @@ -505,19 +486,8 @@ pub async fn force_update_allocators( Some(file), ) .await - { - Ok(content) => match create_file_in_repo(&gh, &content.items[0], true).await { - Ok(_) => { - log::info!("File {} updated successfully", file); - } - Err(e) => { - log::error!("{}", e); - } - }, - Err(e) => { - log::error!("{}", e); - } - } + .map_err(|e| LDNError::Load(format!("Failed to get files: {}", e)))?; + create_file_in_repo(&gh, &content.items[0], true).await?; } } @@ -565,155 +535,146 @@ pub fn is_valid_fixed_option(option: &str) -> bool { pub async fn create_allocator_from_file(files_changed: Vec) -> Result<(), LDNError> { for file_name in files_changed { log::info!("Starting allocator creation on: {}", file_name); - match process_allocator_file(file_name.as_str()).await { - Ok(mut model) => { - let mut quantity_options: Vec; - if let Some(allocation_amount) = model.application.allocation_amount.clone() { - if allocation_amount.amount_type.clone().is_none() - || allocation_amount.quantity_options.clone().is_none() - { - return Err(LDNError::New( - "Amount type and quantity options are required".to_string(), - )); - } - - let amount_type = allocation_amount - .amount_type - .clone() - .ok_or(LDNError::Load("Failed to get amount type".to_string()))? - .to_lowercase(); // Assuming you still want to unwrap here - quantity_options = allocation_amount - .quantity_options - .ok_or(LDNError::Load("Failed to get quantity options".to_string()))?; - - for option in quantity_options.iter_mut() { - *option = process_amount(option.clone()); - } - - validate_amount_type_and_options(&amount_type, &quantity_options) - .map_err(|e| LDNError::New(e.to_string()))?; - - model - .application - .allocation_amount - .as_mut() - .ok_or(LDNError::Load( - "Failed to get allocation amount".to_string(), - ))? - .quantity_options = Some(quantity_options); - } + let mut model = process_allocator_file(file_name.as_str()).await?; - let verifiers_gh_handles = if model.application.verifiers_gh_handles.is_empty() { - None - } else { - Some(model.application.verifiers_gh_handles.join(", ")) // Join verifiers in a string if exists - }; - - let tooling = if model.application.tooling.is_empty() { - None - } else { - Some(model.application.tooling.join(", ")) - }; - let owner = model.owner.clone().unwrap_or_default().to_string(); - let repo = model.repo.clone().unwrap_or_default().to_string(); - let gh = GithubWrapper::new(owner.to_string(), repo.to_string(), None)?; - let installation_id: i64 = gh - .inner - .apps() - .get_repository_installation(owner.to_string(), repo.to_string()) - .await - .map(|installation| { - installation - .id - .0 - .try_into() - .expect("Installation Id sucessfully parsed to u64") - }) - .map_err(|e| { - LDNError::New(format!( - "Installation Id not found for a repo: {} /// {}", - repo, e - )) - })?; - - let gh = - GithubWrapper::new(owner.to_string(), repo.to_string(), Some(installation_id))?; - - match is_allocator_repo_initialized(&gh).await { - Ok(true) => (), - Ok(false) => init_allocator_repo(&gh).await.map_err(|e| { - LDNError::New(format!("Initializing the allocator repo failed: {}", e)) - })?, - Err(e) => { - return Err(LDNError::New(format!( - "Checking if the repo is initialized failed: {}", - e - ))); - } - } + let mut quantity_options: Vec; + if let Some(allocation_amount) = model.application.allocation_amount.clone() { + if allocation_amount.amount_type.clone().is_none() + || allocation_amount.quantity_options.clone().is_none() + { + return Err(LDNError::New( + "Amount type and quantity options are required".to_string(), + )); + } - let allocator_creation_result = create_or_update_allocator( - owner.clone(), - repo.clone(), - Some(installation_id), - Some(model.pathway_addresses.msig), - verifiers_gh_handles, - model.multisig_threshold, - model - .application - .allocation_amount - .clone() - .and_then(|a| a.amount_type.clone()), - model.address, - tooling, - Some(model.application.data_types), - Some(model.application.required_sps), - Some(model.application.required_replicas), - Some(file_name.to_owned()), - model.application.client_contract_address, - ) - .await - .map_err(|e| LDNError::New(format!("Create or update allocator failed: {}", e)))?; - - let allocator_id = allocator_creation_result.id; - - // Delete all old allocation amounts by allocator id - delete_allocation_amounts_by_allocator_id(allocator_id) - .await - .map_err(|e| { - LDNError::New(format!( - "Delete all old allocation amounts by allocator id failed: {}", - e - )) - })?; - - if let Some(allocation_amount) = model.application.allocation_amount.clone() { - if let Some(allocation_amounts) = allocation_amount.quantity_options { - for allocation_amount in allocation_amounts { - let parsed_allocation_amount = allocation_amount.replace('%', ""); - create_allocation_amount(allocator_id, parsed_allocation_amount) - .await - .map_err(|e| { - LDNError::New(format!( - "Create allocation amount rows in the database failed: {}", - e - )) - })?; - } - } else { - return Err(LDNError::New( - "Failed to get quantity options for allocation amount".to_string(), - )); - } - } + let amount_type = allocation_amount + .amount_type + .clone() + .ok_or(LDNError::Load("Failed to get amount type".to_string()))? + .to_lowercase(); // Assuming you still want to unwrap here + quantity_options = allocation_amount + .quantity_options + .ok_or(LDNError::Load("Failed to get quantity options".to_string()))?; + + for option in quantity_options.iter_mut() { + *option = process_amount(option.clone()); } + + validate_amount_type_and_options(&amount_type, &quantity_options) + .map_err(|e| LDNError::New(e.to_string()))?; + + model + .application + .allocation_amount + .as_mut() + .ok_or(LDNError::Load( + "Failed to get allocation amount".to_string(), + ))? + .quantity_options = Some(quantity_options); + } + + let verifiers_gh_handles = if model.application.verifiers_gh_handles.is_empty() { + None + } else { + Some(model.application.verifiers_gh_handles.join(", ")) // Join verifiers in a string if exists + }; + + let tooling = if model.application.tooling.is_empty() { + None + } else { + Some(model.application.tooling.join(", ")) + }; + let owner = model.owner.clone().unwrap_or_default().to_string(); + let repo = model.repo.clone().unwrap_or_default().to_string(); + let gh = GithubWrapper::new(owner.to_string(), repo.to_string(), None)?; + let installation_id: i64 = gh + .inner + .apps() + .get_repository_installation(owner.to_string(), repo.to_string()) + .await + .map(|installation| { + installation + .id + .0 + .try_into() + .expect("Installation Id sucessfully parsed to u64") + }) + .map_err(|e| { + LDNError::New(format!( + "Installation Id not found for a repo: {} /// {}", + repo, e + )) + })?; + + let gh = GithubWrapper::new(owner.to_string(), repo.to_string(), Some(installation_id))?; + + match is_allocator_repo_initialized(&gh).await { + Ok(true) => (), + Ok(false) => init_allocator_repo(&gh).await.map_err(|e| { + LDNError::New(format!("Initializing the allocator repo failed: {}", e)) + })?, Err(e) => { return Err(LDNError::New(format!( - "Create allocator from json file failed: {}", + "Checking if the repo is initialized failed: {}", e ))); } } + + let allocator_creation_result = create_or_update_allocator( + owner.clone(), + repo.clone(), + Some(installation_id), + Some(model.pathway_addresses.msig), + verifiers_gh_handles, + model.multisig_threshold, + model + .application + .allocation_amount + .clone() + .and_then(|a| a.amount_type.clone()), + model.address, + tooling, + Some(model.application.data_types), + Some(model.application.required_sps), + Some(model.application.required_replicas), + Some(file_name.to_owned()), + model.application.client_contract_address, + ) + .await + .map_err(|e| LDNError::New(format!("Create or update allocator failed: {}", e)))?; + + let allocator_id = allocator_creation_result.id; + + // Delete all old allocation amounts by allocator id + delete_allocation_amounts_by_allocator_id(allocator_id) + .await + .map_err(|e| { + LDNError::New(format!( + "Delete all old allocation amounts by allocator id failed: {}", + e + )) + })?; + + if let Some(allocation_amount) = model.application.allocation_amount.clone() { + if let Some(allocation_amounts) = allocation_amount.quantity_options { + for allocation_amount in allocation_amounts { + let parsed_allocation_amount = allocation_amount.replace('%', ""); + create_allocation_amount(allocator_id, parsed_allocation_amount) + .await + .map_err(|e| { + LDNError::New(format!( + "Create allocation amount rows in the database failed: {}", + e + )) + })?; + } + } else { + return Err(LDNError::New( + "Failed to get quantity options for allocation amount".to_string(), + )); + } + } } Ok(()) } diff --git a/fplus-lib/src/core/autoallocator/mod.rs b/fplus-lib/src/core/autoallocator/mod.rs index 9416e17a..4712c959 100644 --- a/fplus-lib/src/core/autoallocator/mod.rs +++ b/fplus-lib/src/core/autoallocator/mod.rs @@ -31,14 +31,11 @@ pub async fn trigger_autoallocation(info: &TriggerAutoallocationInfo) -> Result< )) })?; upsert_autoallocation_if_eligible(&evm_address_from_signature).await?; - match add_verified_client(fil_client_address, &amount).await { - Ok(_) => {} - Err(e) => { - autoallocations_db::delete_autoallocation(evm_address_from_signature) - .await - .map_err(|e| LDNError::New(format!("Delete autoallocation failed: {}", e)))?; - return Err(LDNError::New(format!("Add verified client failed: {}", e))); - } + if let Err(e) = add_verified_client(fil_client_address, &amount).await { + autoallocations_db::delete_autoallocation(evm_address_from_signature) + .await + .map_err(|err| LDNError::New(format!("Delete autoallocation failed: {}", err)))?; + return Err(LDNError::New(format!("Add verified client failed: {}", e))); } Ok(()) } diff --git a/fplus-lib/src/core/mod.rs b/fplus-lib/src/core/mod.rs index 926ad5a0..040cb563 100644 --- a/fplus-lib/src/core/mod.rs +++ b/fplus-lib/src/core/mod.rs @@ -33,7 +33,9 @@ use crate::{ github_async_new, CreateMergeRequestData, CreateRefillMergeRequestData, GithubWrapper, }, }, - helpers::{compare_allowance_and_allocation, parse_size_to_bytes, process_amount}, + helpers::{ + is_allocator_allowance_bigger_than_allocation_amount, parse_size_to_bytes, process_amount, + }, parsers::ParsedIssue, }; use fplus_database::database::allocation_amounts::get_allocation_quantity_options; @@ -376,11 +378,10 @@ impl LDNApplication { repo: String, ) -> Result { let app_model_result = - database::applications::get_application(application_id, owner, repo, None).await; - match app_model_result { - Ok(model) => Ok(model), - Err(e) => Err(LDNError::Load(format!("Database error: {}", e))), - } + database::applications::get_application(application_id, owner, repo, None) + .await + .map_err(|e| LDNError::Load(format!("Failed to get application: {}", e)))?; + Ok(app_model_result) } pub async fn load_from_db( @@ -408,18 +409,14 @@ impl LDNApplication { owner: String, repo: String, ) -> Result { - let app_model_result = database::applications::get_application( + let app_model = database::applications::get_application( application_id.clone(), owner.clone(), repo.clone(), None, ) - .await; - - let app_model = match app_model_result { - Ok(model) => model, - Err(e) => return Err(LDNError::Load(format!("Database error: {}", e))), - }; + .await + .map_err(|e| LDNError::Load(format!("Failed to get application: {}", e)))?; // Check if the application field is present and parse it let app_str = app_model.application.ok_or_else(|| { @@ -508,26 +505,24 @@ impl LDNApplication { }) } - pub async fn all_applications() -> Result, Vec> - { - let db_apps = database::applications::get_applications().await; + pub async fn all_applications() -> Result, LDNError> { + let db_apps = database::applications::get_applications() + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to get applications from the database: {}", + e + )) + })?; let mut all_apps: Vec<(ApplicationFile, String, String)> = Vec::new(); - match db_apps { - Ok(apps) => { - for app in apps { - if let Some(application_data) = app.application { - if let Ok(app_file) = ApplicationFile::from_str(&application_data) { - all_apps.push((app_file, app.owner, app.repo)); - } - } + for app in db_apps { + if let Some(application_data) = app.application { + if let Ok(app_file) = ApplicationFile::from_str(&application_data) { + all_apps.push((app_file, app.owner, app.repo)); } - Ok(all_apps) } - Err(e) => Err(vec![LDNError::Load(format!( - "Failed to retrieve applications from the database /// {}", - e - ))]), } + Ok(all_apps) } pub async fn active( @@ -536,14 +531,9 @@ impl LDNApplication { filter: Option, ) -> Result, LDNError> { // Get all active applications from the database. - let active_apps_result = - database::applications::get_active_applications(Some(owner), Some(repo)).await; - - // Handle errors in getting active applications. - let active_apps = match active_apps_result { - Ok(apps) => apps, - Err(e) => return Err(LDNError::Load(format!("Database error: {}", e))), - }; + let active_apps = database::applications::get_active_applications(Some(owner), Some(repo)) + .await + .map_err(|e| LDNError::Load(format!("Failed to get active applications: {}", e)))?; // Filter and convert active applications. let mut apps: Vec = Vec::new(); @@ -774,32 +764,25 @@ impl LDNApplication { } } } + let client_allocation = + get_client_allocation(&application_id).await.map_err(|e| { + LDNError::Load(format!("Failed to get client allocation: {}", e)) + })?; + if client_allocation.count.is_some() { + log::info!("Allocation found for client {}", application_id); + Self::issue_pathway_mismatch_comment( + issue_number, + info.owner, + info.repo, + None, + ) + .await?; - match get_client_allocation(&application_id).await { - Ok(response) => { - if response.count.is_some() { - log::info!("Allocation found for client {}", application_id); - Self::issue_pathway_mismatch_comment( - issue_number, - info.owner, - info.repo, - None, - ) - .await?; - - return Err(LDNError::New( - "Pathway mismatch: Client has already allocation".to_string(), - )); - } else { - log::info!("Client allocation not found"); - } - } - Err(e) => { - return Err(LDNError::New(format!( - "Getting client allocation failed /// {}", - e - ))); - } + return Err(LDNError::New( + "Pathway mismatch: Client has already allocation".to_string(), + )); + } else { + log::info!("Client allocation not found"); } } @@ -843,35 +826,37 @@ impl LDNApplication { info.repo.clone(), ) .await?; - match gh.get_pull_request_by_head(&branch_name).await { - Ok(prs) => { - if let Some(pr) = prs.first() { - let number = pr.number; - let issue_number = issue_number.parse::().map_err(|e| { - LDNError::New(format!( - "Parse issue number: {} to i64 failed. {}", - issue_number, e - )) - })?; - database::applications::create_application( - application_id.clone(), - info.owner.clone(), - info.repo.clone(), - number, - issue_number, - file_content, - LDNPullRequest::application_path(&app_id), - ) - .await - .map_err(|e| { - LDNError::New(format!( - "Application issue {} cannot create application in DB /// {}", - application_id, e - )) - })?; - } - } - Err(e) => log::warn!("Failed to get pull request by head: {}", e), + let prs = gh + .get_pull_request_by_head(&branch_name) + .await + .map_err(|e| { + LDNError::Load(format!("Failed to get pull request by head: {}", e)) + })?; + + if let Some(pr) = prs.first() { + let number = pr.number; + let issue_number = issue_number.parse::().map_err(|e| { + LDNError::New(format!( + "Parse issue number: {} to i64 failed. {}", + issue_number, e + )) + })?; + database::applications::create_application( + application_id.clone(), + info.owner.clone(), + info.repo.clone(), + number, + issue_number, + file_content, + LDNPullRequest::application_path(&app_id), + ) + .await + .map_err(|e| { + LDNError::New(format!( + "Application issue {} cannot create application in DB /// {}", + application_id, e + )) + })?; } Ok(LDNApplication { @@ -923,130 +908,106 @@ impl LDNApplication { allocation_amount: String, client_contract_address: Option, ) -> Result { - match self.app_state().await { - Ok(s) => match s { - AppState::KYCRequested - | AppState::Submitted - | AppState::AdditionalInfoRequired - | AppState::AdditionalInfoSubmitted => { - let app_file: ApplicationFile = self.file().await?; - let allocation_amount_parsed = process_amount(allocation_amount.clone()); - - let db_allocator = get_allocator(&owner, &repo) - .await - .map_err(|e| { - LDNError::Load(format!("Failed to get an allocator. /// {}", e)) - })? - .ok_or(LDNError::Load("Allocator not found.".to_string()))?; - let db_multisig_address = db_allocator.multisig_address.ok_or( - LDNError::Load("Failed to get multisig address.".to_string()), - )?; - Self::check_and_handle_allowance( - &db_multisig_address.clone(), - Some(allocation_amount_parsed.clone()), - ) - .await?; + let app_state = self.app_state().await?; + if app_state != AppState::KYCRequested + && app_state != AppState::Submitted + && app_state != AppState::AdditionalInfoRequired + && app_state != AppState::AdditionalInfoSubmitted + { + return Err(LDNError::Load(format!( + "Application state is {:?}. Expected one of the following KYCRequested, Submitted, AdditionalInfoRequired or AdditionalInfoSubmitted", + app_state + ))); + } + let app_file: ApplicationFile = self.file().await?; + let allocation_amount_parsed = process_amount(allocation_amount.clone()); - let uuid = uuidv4::uuid::v4(); - let request = AllocationRequest::new( - actor.clone(), - uuid, - AllocationRequestType::First, - allocation_amount_parsed, - ); - - let app_file = app_file.complete_governance_review( - actor.clone(), - request, - client_contract_address.clone(), - ); - let file_content = serde_json::to_string_pretty(&app_file).map_err(|e| { - LDNError::Load(format!("Failed to pare into string: {}", e)) - })?; - let app_path = &self.file_name.clone(); - let app_branch = self.branch_name.clone(); - Self::issue_datacap_request_trigger( - app_file.clone(), - owner.clone(), - repo.clone(), - ) - .await?; - match LDNPullRequest::add_commit_to( - app_path.to_string(), - app_branch.clone(), - LDNPullRequest::application_move_to_proposal_commit(&actor), - file_content.clone(), - self.file_sha.clone(), - owner.clone(), - repo.clone(), - ) - .await - { - Some(()) => { - match self.github.get_pull_request_by_head(&app_branch).await { - Ok(prs) => { - if let Some(pr) = prs.first() { - database::applications::update_application( - app_file.id.clone(), - owner.clone(), - repo.clone(), - pr.number, - file_content, - Some(app_path.clone()), - None, - client_contract_address, - ) - .await - .map_err(|e| { - LDNError::Load(format!( - "Failed to update application: {} /// {}", - app_file.id, e - )) - })?; - - Self::issue_datacap_allocation_requested( - app_file.clone(), - app_file.get_active_allocation(), - owner.clone(), - repo.clone(), - ) - .await?; - Self::update_issue_labels( - app_file.issue_number.clone(), - &[AppState::ReadyToSign.as_str()], - owner.clone(), - repo.clone(), - ) - .await?; - Self::add_comment_to_issue( - app_file.issue_number.clone(), - owner, - repo, - "Application is ready to sign".to_string(), - ) - .await?; - } - } - Err(e) => log::warn!("Failed to get pull request by head: {}", e), - }; - Ok(app_file) - } - None => Err(LDNError::New(format!( - "Application issue {} cannot be triggered(1)", - self.application_id - ))), - } - } - _ => Err(LDNError::New(format!( - "Application issue {} cannot be triggered(2)", - self.application_id - ))), - }, - Err(e) => Err(LDNError::New(format!( - "Application issue {} cannot be triggered {}(3)", - self.application_id, e - ))), + let db_allocator = get_allocator(&owner, &repo) + .await + .map_err(|e| LDNError::Load(format!("Failed to get an allocator. /// {}", e)))? + .ok_or(LDNError::Load("Allocator not found.".to_string()))?; + let db_multisig_address = db_allocator.multisig_address.ok_or(LDNError::Load( + "Failed to get multisig address.".to_string(), + ))?; + Self::is_allowance_sufficient(&db_multisig_address.clone(), &allocation_amount_parsed) + .await?; + + let uuid = uuidv4::uuid::v4(); + let request = AllocationRequest::new( + actor.clone(), + uuid, + AllocationRequestType::First, + allocation_amount_parsed, + ); + + let app_file = app_file.complete_governance_review( + actor.clone(), + request, + client_contract_address.clone(), + ); + let file_content = serde_json::to_string_pretty(&app_file) + .map_err(|e| LDNError::Load(format!("Failed to pare into string: {}", e)))?; + let app_path = &self.file_name.clone(); + let app_branch = self.branch_name.clone(); + Self::issue_datacap_request_trigger(app_file.clone(), owner.clone(), repo.clone()).await?; + LDNPullRequest::add_commit_to( + app_path.to_string(), + app_branch.clone(), + LDNPullRequest::application_move_to_proposal_commit(&actor), + file_content.clone(), + self.file_sha.clone(), + owner.clone(), + repo.clone(), + ) + .await?; + let prs = self + .github + .get_pull_request_by_head(&app_branch) + .await + .map_err(|e| LDNError::Load(format!("Failed to get pull request by head: {}", e)))?; + if let Some(pr) = prs.first() { + database::applications::update_application( + app_file.id.clone(), + owner.clone(), + repo.clone(), + pr.number, + file_content, + Some(app_path.clone()), + None, + client_contract_address, + ) + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to update application: {} /// {}", + app_file.id, e + )) + })?; + + Self::issue_datacap_allocation_requested( + app_file.clone(), + app_file.get_active_allocation(), + owner.clone(), + repo.clone(), + ) + .await?; + Self::update_issue_labels( + app_file.issue_number.clone(), + &[AppState::ReadyToSign.as_str()], + owner.clone(), + repo.clone(), + ) + .await?; + Self::add_comment_to_issue( + app_file.issue_number.clone(), + owner, + repo, + "Application is ready to sign".to_string(), + ) + .await?; } + + Ok(app_file) } /// Move application from Proposal to Approved @@ -1101,123 +1062,96 @@ impl LDNApplication { ) .await; } + let app_state = self.app_state().await?; + if app_state != AppState::ReadyToSign { + return Err(LDNError::Load(format!( + "Application state is {:?}. Expected ReadyToSign", + app_state + ))); + } + let mut app_file: ApplicationFile = self.file().await?; + if !app_file.allocation.is_active(request_id.clone()) { + return Err(LDNError::Load(format!( + "Request {} is not active", + request_id + ))); + } + app_file = app_file.update_lifecycle_after_sign_datacap_proposal(&signer.github_username); + app_file = app_file.add_signer_to_allocation(signer.clone().into(), &request_id); - match self.app_state().await { - Ok(s) => match s { - AppState::ReadyToSign => { - let mut app_file: ApplicationFile = self.file().await?; - if !app_file.allocation.is_active(request_id.clone()) { - return Err(LDNError::Load(format!( - "Request {} is not active", - request_id - ))); - } - app_file = app_file - .update_lifecycle_after_sign_datacap_proposal(&signer.github_username); - app_file = - app_file.add_signer_to_allocation(signer.clone().into(), &request_id); - - if let Some(new_allocation_amount) = new_allocation_amount { - if app_file.allocation.0.len() > 1 { - Self::check_and_handle_allowance( - &db_multisig_address, - Some(new_allocation_amount.clone()), - ) - .await?; + if let Some(new_allocation_amount) = new_allocation_amount { + if app_file.allocation.0.len() > 1 { + Self::is_allowance_sufficient(&db_multisig_address, &new_allocation_amount).await?; - let parsed_allocation_amount = process_amount(new_allocation_amount); + let parsed_allocation_amount = process_amount(new_allocation_amount); - app_file.adjust_active_allocation_amount(parsed_allocation_amount)?; - } - } + app_file.adjust_active_allocation_amount(parsed_allocation_amount)?; + } + } - let file_content = serde_json::to_string_pretty(&app_file).map_err(|e| { - LDNError::Load(format!("Failed to pare into string: {}", e)) - })?; - match LDNPullRequest::add_commit_to( - self.file_name.to_string(), - self.branch_name.clone(), - LDNPullRequest::application_move_to_approval_commit( - &signer.signing_address, - ), - file_content.clone(), - self.file_sha.clone(), - owner.clone(), - repo.clone(), - ) - .await - { - Some(()) => { - match self - .github - .get_pull_request_by_head(&self.branch_name) - .await - { - Ok(prs) => { - if let Some(pr) = prs.first() { - database::applications::update_application( - app_file.id.clone(), - owner.clone(), - repo.clone(), - pr.number, - file_content, - Some(self.file_name.clone()), - None, - app_file.client_contract_address.clone(), - ) - .await - .map_err(|e| { - LDNError::Load(format!( - "Failed to update application: {} /// {}", - app_file.id, e - )) - })?; - - Self::add_comment_to_issue( - app_file.issue_number.clone(), - owner.clone(), - repo.clone(), - "Application is in the process of signing datacap" - .to_string(), - ) - .await?; - - Self::issue_datacap_request_signature( - app_file.clone(), - "proposed".to_string(), - owner.clone(), - repo.clone(), - ) - .await?; - Self::update_issue_labels( - app_file.issue_number.clone(), - &[AppState::StartSignDatacap.as_str()], - owner.clone(), - repo.clone(), - ) - .await?; - } - } - Err(e) => log::warn!("Failed to get pull request by head: {}", e), - }; - Ok(app_file) - } - None => Err(LDNError::New(format!( - "Application issue {} cannot be proposed(1)", - self.application_id - ))), - } - } - _ => Err(LDNError::New(format!( - "Application issue {} cannot be proposed(2)", - self.application_id - ))), - }, - Err(e) => Err(LDNError::New(format!( - "Application issue {} cannot be proposed {}(3)", - self.application_id, e - ))), + let file_content = serde_json::to_string_pretty(&app_file) + .map_err(|e| LDNError::Load(format!("Failed to pare into string: {}", e)))?; + + LDNPullRequest::add_commit_to( + self.file_name.to_string(), + self.branch_name.clone(), + LDNPullRequest::application_move_to_approval_commit(&signer.signing_address), + file_content.clone(), + self.file_sha.clone(), + owner.clone(), + repo.clone(), + ) + .await?; + + let prs = self + .github + .get_pull_request_by_head(&self.branch_name) + .await + .map_err(|e| LDNError::Load(format!("Failed to get pull request by head: {}", e)))?; + + if let Some(pr) = prs.first() { + database::applications::update_application( + app_file.id.clone(), + owner.clone(), + repo.clone(), + pr.number, + file_content, + Some(self.file_name.clone()), + None, + app_file.client_contract_address.clone(), + ) + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to update application: {} /// {}", + app_file.id, e + )) + })?; + + Self::add_comment_to_issue( + app_file.issue_number.clone(), + owner.clone(), + repo.clone(), + "Application is in the process of signing datacap".to_string(), + ) + .await?; + + Self::issue_datacap_request_signature( + app_file.clone(), + "proposed".to_string(), + owner.clone(), + repo.clone(), + ) + .await?; + Self::update_issue_labels( + app_file.issue_number.clone(), + &[AppState::StartSignDatacap.as_str()], + owner.clone(), + repo.clone(), + ) + .await?; } + Ok(app_file) } pub async fn complete_sps_change_proposal( @@ -1682,20 +1616,18 @@ impl LDNApplication { } pub async fn file(&self) -> Result { - match self + let file = self .github .get_file(&self.file_name, &self.branch_name) .await - { - Ok(file) => LDNApplication::content_items_to_app_file(file), - Err(e) => { - dbg!(&e); - Err(LDNError::Load(format!( - "Application issue {} file does not exist ///", - self.application_id - ))) - } - } + .map_err(|e| { + LDNError::Load(format!( + "Application issue {} file does not exist /// {}", + self.application_id, e + )) + })?; + + LDNApplication::content_items_to_app_file(file) } pub async fn fetch_verifiers( @@ -1704,15 +1636,11 @@ impl LDNApplication { ) -> Result { let allocator = database::allocators::get_allocator(&owner, &repo) .await - .map_err(|e| LDNError::Load(format!("Failed to retrieve allocators /// {}", e)))?; + .map_err(|e| LDNError::Load(format!("Failed to retrieve allocators /// {}", e)))? + .ok_or(LDNError::Load("Allocator not found".to_string()))?; let mut verifiers_handles = Vec::new(); - let allocator = match allocator { - Some(a) => a, - None => return Err(LDNError::Load("No allocator found".into())), - }; - if let Some(handles) = allocator.verifiers_gh_handles { verifiers_handles.extend(handles.split(',').map(|s| s.trim().to_string())); } @@ -1784,17 +1712,12 @@ impl LDNApplication { repo: String, ) -> Result, LDNError> { // Retrieve all applications in the main branch from the database. - let merged_apps_result = database::applications::get_merged_applications( + let merged_app_models = database::applications::get_merged_applications( Some(owner.clone()), Some(repo.clone()), ) - .await; - - // Handle errors in getting applications from the main branch. - let merged_app_models = match merged_apps_result { - Ok(apps) => apps, - Err(e) => return Err(LDNError::Load(format!("Database error: {}", e))), - }; + .await + .map_err(|e| LDNError::Load(format!("Database error:: {}", e)))?; // Convert applications from the main branch. let mut merged_apps: Vec<(ApplicationGithubInfo, ApplicationFile)> = Vec::new(); @@ -1915,19 +1838,7 @@ impl LDNApplication { log::info!("- Validating merge for PR number {}", pr_number,); let application = - match LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await { - Ok(app) => { - log::info!("- Got application"); - app - } - Err(err) => { - log::error!("- Failed to get application. Reason: {}", err); - return Err(LDNError::Load(format!( - "Failed to get application. Reason: {}", - err - ))); - } - }; + LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await?; // conditions for automerge: // 1. Application is in Granted state @@ -2002,19 +1913,11 @@ impl LDNApplication { ); let gh = github_async_new(owner.to_string(), repo.to_string()).await?; - let author = match gh.get_last_commit_author(pr_number).await { - Ok(author) => { - log::info!("- Last commit author: {}", author); - author - } - Err(err) => { - log::error!("- Failed to get last commit author. Reason: {}", err); - return Err(LDNError::Load(format!( - "Failed to get last commit author. Reason: {}", - err - ))); - } - }; + let author = gh + .get_last_commit_author(pr_number) + .await + .map_err(|e| LDNError::Load(format!("Failed to get last commit author: {}", e)))?; + log::info!("- Last commit author: {}", author); if author.is_empty() { log::warn!("- Author is empty"); @@ -2040,36 +1943,18 @@ impl LDNApplication { return Ok(false); } - let branch_name = match gh.get_branch_name_from_pr(pr_number).await { - Ok(branch_name) => { - log::info!("- Branch name: {}", branch_name); - branch_name - } - Err(err) => { - log::error!( - "- Failed to get branch name from pull request. Reason: {}", - err - ); - return Err(LDNError::Load(format!( - "Failed to get branch name from pull request. Reason: {}", - err - ))); - } - }; + let branch_name = gh.get_branch_name_from_pr(pr_number).await.map_err(|e| { + LDNError::Load(format!( + "Failed to get branch name from pull request: {}", + e + )) + })?; - let application = match gh.get_file(&files[0].filename, &branch_name).await { - Ok(file) => { - log::info!("- Got File content"); - LDNApplication::content_items_to_app_file(file)? - } - Err(err) => { - log::error!("- Failed to get file content. Reason: {}", err); - return Err(LDNError::Load(format!( - "Failed to get file content. Reason: {}", - err - ))); - } - }; + let file = gh + .get_file(&files[0].filename, &branch_name) + .await + .map_err(|e| LDNError::Load(format!("Failed to get file content: {}", e)))?; + let application = LDNApplication::content_items_to_app_file(file)?; // Check if application is in Submitted state let state = application.lifecycle.get_state(); @@ -2277,7 +2162,7 @@ impl LDNApplication { LDNApplication::load(app_file.id.clone(), owner.clone(), repo.clone()).await?; let parsed_app_file = serde_json::to_string_pretty(&app_file) .map_err(|e| LDNError::Load(format!("Failed to pare into string: {}", e)))?; - if let Some(()) = LDNPullRequest::add_commit_to( + LDNPullRequest::add_commit_to( ldn_application.file_name.clone(), ldn_application.branch_name.clone(), "Move application back to review".to_string(), @@ -2286,31 +2171,31 @@ impl LDNApplication { owner.clone(), repo.clone(), ) - .await - { - let gh = github_async_new(owner.to_string(), repo.to_string()).await?; - match gh - .get_pull_request_by_head(&ldn_application.branch_name) - .await - { - Ok(prs) => { - if let Some(pr) = prs.first() { - let number = pr.number; - let _ = database::applications::update_application( - app_file.id.clone(), - owner, - repo, - number, - parsed_app_file, - Some(ldn_application.file_name.clone()), - None, - app_file.client_contract_address, - ) - .await; - } - } - Err(e) => log::warn!("Failed to get pull request by head: {}", e), - }; + .await?; + + let gh = github_async_new(owner.to_string(), repo.to_string()).await?; + + let prs = gh + .get_pull_request_by_head(&ldn_application.branch_name) + .await + .map_err(|e| { + LDNError::Load(format!("Failed to get pull request by head: {}", e)) + })?; + + if let Some(pr) = prs.first() { + let number = pr.number; + database::applications::update_application( + app_file.id.clone(), + owner, + repo, + number, + parsed_app_file, + Some(ldn_application.file_name.clone()), + None, + app_file.client_contract_address, + ) + .await + .map_err(|e| LDNError::Load(format!("Failed to update application: {}", e)))?; }; return Ok(false); @@ -2352,7 +2237,7 @@ impl LDNApplication { }; // Commit the changes to the branch - match LDNPullRequest::add_commit_to( + LDNPullRequest::add_commit_to( filename.clone(), branch_name.clone(), commit_message, @@ -2361,50 +2246,39 @@ impl LDNApplication { owner.clone(), repo.clone(), ) - .await - { - Some(()) => { - // Retrieve and update the pull request - match self.github.get_pull_request_by_head(&branch_name).await { - Ok(prs) => { - if let Some(pr) = prs.first() { - let update_result = database::applications::update_application( - db_application_file.id.clone(), - owner.clone(), - repo.clone(), - pr.number, - file_content, - Some(filename.clone()), - None, - db_application_file.client_contract_address.clone(), - ) - .await; - - match update_result { - Ok(_) => Ok(db_application_file), // Return the updated ApplicationFile - Err(e) => { - log::error!("Failed to update application: {}", e); - Err(LDNError::New( - "Failed to update the application in the database" - .to_string(), - )) - } - } - } else { - Err(LDNError::New( - "No pull request found for the given branch".to_string(), - )) - } - } - Err(e) => { - log::warn!("Failed to get pull request by head: {}", e); - Err(LDNError::New(format!("Failed to get pull request: {}", e))) - } - } - } - None => Err(LDNError::New( - "Adding commit in approve changes failed".to_string(), - )), + .await?; + + // Retrieve and update the pull request + let prs = self + .github + .get_pull_request_by_head(&branch_name) + .await + .map_err(|e| LDNError::Load(format!("Failed to get pull request: {}", e)))?; + + if let Some(pr) = prs.first() { + database::applications::update_application( + db_application_file.id.clone(), + owner.clone(), + repo.clone(), + pr.number, + file_content, + Some(filename.clone()), + None, + db_application_file.client_contract_address.clone(), + ) + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to update the application in the database: {}", + e + )) + })?; + + Ok(db_application_file) + } else { + Err(LDNError::New( + "No pull request found for the given branch".to_string(), + )) } } @@ -2582,24 +2456,24 @@ impl LDNApplication { let application_id: String = application_file.id.clone(); - let db_application_file_str_result = database::applications::get_application( + let db_application_str_result = database::applications::get_application( application_file.id.clone(), owner.clone(), repo.clone(), None, ) - .await; - let db_application_file_str = match db_application_file_str_result { - Ok(file) => file - .application - .unwrap_or_else(|| panic!("Application data is missing")), // Consider more graceful error handling here - Err(e) => { - return Err(LDNError::New(format!( - "Failed to fetch application data from the database: {}", - e - ))); - } - }; + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to fetch application data from the database: {}", + e + )) + })?; + + let db_application_file_str = + db_application_str_result.application.ok_or(LDNError::Load( + "Active change request not found. Please propose change firstly".to_string(), + ))?; let db_application_file = serde_json::from_str::(&db_application_file_str) .map_err(|e| { @@ -2642,22 +2516,13 @@ impl LDNApplication { ))); } }; - let branch_name = match gh.get_branch_name_from_pr(pr_number).await { - Ok(branch_name) => { - log::info!("- Branch name: {}", branch_name); - branch_name - } - Err(err) => { - log::error!( - "- Failed to get branch name from pull request. Reason: {}", - err - ); - return Err(LDNError::Load(format!( - "Failed to get branch name from pull request. Reason: {}", - err - ))); - } - }; + + let branch_name = gh.get_branch_name_from_pr(pr_number).await.map_err(|e| { + LDNError::Load(format!( + "Failed to get branch name from pull request: {}", + e + )) + })?; match database::applications::get_application_by_pr_number( owner.clone(), @@ -2743,85 +2608,70 @@ impl LDNApplication { ) -> Result { log::info!("Starting validate_approval:"); log::info!("Validating approval for PR number {}", pr_number); - match LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await { - Ok(application_file) => { - if !application_file.lifecycle.get_active_status() { - log::info!("No approval to validate. Application lifecycle is inactive so the Total DC was reached."); - return Ok(true); - } - let app_state: AppState = application_file.lifecycle.get_state(); - if application_file.lifecycle.edited.unwrap_or(false) { - log::warn!("Val Trigger - Application has been edited"); - return Ok(false); - } + let application_file = + LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await?; - log::info!("Val Approval - App state is {:?}", app_state.as_str()); - if app_state < AppState::Granted { - log::warn!("Val Approval < (G)- State is less than Granted"); - Ok(false) - } else if app_state == AppState::Granted { - let active_request_id = match application_file - .clone() - .lifecycle - .get_active_allocation_id() - { - Some(id) => id, - None => { - log::warn!("Val Approval (G) - No active request"); - return Ok(false); - } - }; - let active_request = - match application_file.allocation.find_one(active_request_id) { - Some(request) => request, - None => { - log::warn!("Val Approval (G) - No active request"); - return Ok(false); - } - }; + if !application_file.lifecycle.get_active_status() { + log::info!("No approval to validate. Application lifecycle is inactive so the Total DC was reached."); + return Ok(true); + } + let app_state: AppState = application_file.lifecycle.get_state(); + if application_file.lifecycle.edited.unwrap_or(false) { + log::warn!("Val Trigger - Application has been edited"); + return Ok(false); + } - let db_allocator = get_allocator(&owner, &repo) - .await - .map_err(|e| { - LDNError::Load(format!("Failed to get an allocator. /// {}", e)) - })? - .ok_or(LDNError::Load("Allocator not found.".to_string()))?; - let db_multisig_threshold = - db_allocator.multisig_threshold.unwrap_or(2) as usize; - let signers: application::file::Verifiers = active_request.signers.clone(); - - // Check if the number of signers meets or exceeds the multisig threshold - if signers.0.len() < db_multisig_threshold { - log::warn!("Not enough signers for approval"); - return Ok(false); - } - let signer_index = if db_multisig_threshold <= 1 { 0 } else { 1 }; + log::info!("Val Approval - App state is {:?}", app_state.as_str()); + if app_state < AppState::Granted { + log::warn!("Val Approval < (G)- State is less than Granted"); + Ok(false) + } else if app_state == AppState::Granted { + let active_request_id = application_file + .clone() + .lifecycle + .get_active_allocation_id() + .ok_or(LDNError::Load( + "Failed to get active allocation id".to_string(), + ))?; - let signer = signers - .0 - .get(signer_index) - .ok_or(LDNError::Load("Failed to get signer".to_string()))?; - let signer_gh_handle = signer.github_username.clone(); + let active_request = application_file + .allocation + .find_one(active_request_id) + .ok_or(LDNError::Load("Failed to get active request".to_string()))?; - let valid_verifiers: ValidVerifierList = - Self::fetch_verifiers(owner.clone(), repo.clone()).await?; + let db_allocator = get_allocator(&owner, &repo) + .await + .map_err(|e| LDNError::Load(format!("Failed to get an allocator. /// {}", e)))? + .ok_or(LDNError::Load("Allocator not found.".to_string()))?; + let db_multisig_threshold = db_allocator.multisig_threshold.unwrap_or(2) as usize; + let signers: application::file::Verifiers = active_request.signers.clone(); + + // Check if the number of signers meets or exceeds the multisig threshold + if signers.0.len() < db_multisig_threshold { + log::warn!("Not enough signers for approval"); + return Ok(false); + } + let signer_index = if db_multisig_threshold <= 1 { 0 } else { 1 }; - if valid_verifiers.is_valid(&signer_gh_handle) { - log::info!("Val Approval (G)- Validated!"); - return Ok(true); - } + let signer = signers + .0 + .get(signer_index) + .ok_or(LDNError::Load("Failed to get signer".to_string()))?; + let signer_gh_handle = signer.github_username.clone(); - log::warn!("Val Approval (G) - Not validated!"); - Ok(false) - } else { - log::info!("Val Approval > (G) - State is greater than Granted"); - Ok(true) - } + let valid_verifiers: ValidVerifierList = + Self::fetch_verifiers(owner.clone(), repo.clone()).await?; + + if valid_verifiers.is_valid(&signer_gh_handle) { + log::info!("Val Approval (G)- Validated!"); + return Ok(true); } - Err(e) => Err(LDNError::Load(format!( - "PR number {} not found: {}", - pr_number, e - ))), + + log::warn!("Val Approval (G) - Not validated!"); + Ok(false) + } else { + log::info!("Val Approval > (G) - State is greater than Granted"); + Ok(true) } } @@ -2832,56 +2682,50 @@ impl LDNApplication { ) -> Result { log::info!("Starting validate_proposal:"); log::info!("- Validating proposal for PR number {}", pr_number); - match LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await { - Ok(application_file) => { - if !application_file.lifecycle.get_active_status() { - log::info!("No proposal to validate. Application lifecycle is inactive so the Total DC was reached."); - return Ok(true); - } - let app_state: AppState = application_file.lifecycle.get_state(); - log::info!("Val Proposal - App state is {:?}", app_state.as_str()); - if application_file.lifecycle.edited.unwrap_or(false) { - log::warn!("Val Trigger - Application has been edited"); + let application_file = + LDNApplication::single_active(pr_number, owner.clone(), repo.clone()).await?; + + if !application_file.lifecycle.get_active_status() { + log::info!("No proposal to validate. Application lifecycle is inactive so the Total DC was reached."); + return Ok(true); + } + let app_state: AppState = application_file.lifecycle.get_state(); + log::info!("Val Proposal - App state is {:?}", app_state.as_str()); + if application_file.lifecycle.edited.unwrap_or(false) { + log::warn!("Val Trigger - Application has been edited"); + return Ok(false); + } + + if app_state < AppState::StartSignDatacap { + log::warn!("Val Proposal (< SSD) - State is less than StartSignDatacap"); + Ok(false) + } else if app_state == AppState::StartSignDatacap { + if let Some(active_request) = application_file.allocation.active() { + let signers = active_request.signers.clone(); + if signers.0.len() != 1 { + log::warn!("Val Proposal (SSD) - Not enough signers"); return Ok(false); } - if app_state < AppState::StartSignDatacap { - log::warn!("Val Proposal (< SSD) - State is less than StartSignDatacap"); - Ok(false) - } else if app_state == AppState::StartSignDatacap { - if let Some(active_request) = application_file.allocation.active() { - let signers = active_request.signers.clone(); - if signers.0.len() != 1 { - log::warn!("Val Proposal (SSD) - Not enough signers"); - return Ok(false); - } - - let signer = signers - .0 - .first() - .ok_or(LDNError::Load("Failed to get signer".to_string()))?; - let signer_gh_handle = signer.github_username.clone(); - let valid_verifiers = - Self::fetch_verifiers(owner.clone(), repo.clone()).await?; - if valid_verifiers.is_valid(&signer_gh_handle) { - log::info!("Val Proposal (SSD) - Validated!"); - return Ok(true); - } - log::warn!("Val Proposal (SSD) - Not validated!"); - Ok(false) - } else { - log::warn!("Val Proposal (SSD)- No active request"); - return Ok(false); - } - } else { - log::info!("Val Proposal (> SSD) - State is greater than StartSignDatacap"); - Ok(true) + let signer = signers + .0 + .first() + .ok_or(LDNError::Load("Failed to get signer".to_string()))?; + let signer_gh_handle = signer.github_username.clone(); + let valid_verifiers = Self::fetch_verifiers(owner.clone(), repo.clone()).await?; + if valid_verifiers.is_valid(&signer_gh_handle) { + log::info!("Val Proposal (SSD) - Validated!"); + return Ok(true); } + log::warn!("Val Proposal (SSD) - Not validated!"); + Ok(false) + } else { + log::warn!("Val Proposal (SSD)- No active request"); + return Ok(false); } - Err(e) => Err(LDNError::Load(format!( - "PR number {} not found: {}", - pr_number, e - ))), + } else { + log::info!("Val Proposal (> SSD) - State is greater than StartSignDatacap"); + Ok(true) } } @@ -3033,7 +2877,7 @@ impl LDNApplication { .sha .clone() .ok_or(LDNError::Load("Failed to get sha".to_string()))?; - match LDNPullRequest::add_commit_to( + LDNPullRequest::add_commit_to( path.clone(), branch_name.clone(), format!( @@ -3045,82 +2889,70 @@ impl LDNApplication { application_model.owner.clone(), application_model.repo.clone(), ) - .await - { - Some(()) => { - if app_file.allocation.0.is_empty() { - match gh.get_pull_request_by_head(&branch_name).await { - Ok(prs) => { - if let Some(pr) = prs.first() { - let number = pr.number; - - database::applications::update_application( - app_file.id.clone(), - application_model.owner.clone(), - application_model.repo.clone(), - number, - file_content, - application_model.path.clone(), - None, - app_file.client_contract_address, - ) - .await - .map_err(|e| { - LDNError::Load(format!( - "Failed to update application: {} /// {}", - app_file.id, e - )) - })?; - } - } - Err(e) => log::warn!("Failed to get pull request by head: {}", e), - }; - } - Ok(LDNApplication { - github: gh, - application_id, - file_sha: sha, - file_name: path, - branch_name, - }) + .await?; + + if app_file.allocation.0.is_empty() { + let prs = gh + .get_pull_request_by_head(&branch_name) + .await + .map_err(|e| { + LDNError::Load(format!("Failed to get pull request by head: {}", e)) + })?; + + if let Some(pr) = prs.first() { + database::applications::update_application( + app_file.id.clone(), + application_model.owner.clone(), + application_model.repo.clone(), + pr.number, + file_content, + application_model.path.clone(), + None, + app_file.client_contract_address, + ) + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to update application: {} /// {}", + app_file.id, e + )) + })?; } - None => Err(LDNError::New(format!( - "Application issue {} cannot be modified", - app_file.issue_number - ))), - } + }; + + Ok(LDNApplication { + github: gh, + application_id, + file_sha: sha, + file_name: path, + branch_name, + }) } - async fn check_and_handle_allowance( + async fn is_allowance_sufficient( db_multisig_address: &str, - new_allocation_amount: Option, + new_allocation_amount: &str, ) -> Result<(), LDNError> { - match get_allowance_for_address(db_multisig_address).await { - Ok(allowance) if allowance != "0" => { - log::info!("Allowance found and is not zero. Value is {}", allowance); - match compare_allowance_and_allocation(&allowance, new_allocation_amount) { - Some(result) => { - if result { - println!("Allowance is sufficient."); - Ok(()) - } else { - println!("Allowance is not sufficient."); - Err(LDNError::New("Multisig address has less allowance than the new allocation amount".to_string())) - } - } - None => { - println!("Error parsing sizes."); - Err(LDNError::New("Error parsing sizes".to_string())) - } - } + let allowance = get_allowance_for_address(db_multisig_address) + .await + .map_err(|e| LDNError::Load(format!("Failed to retrieve allowance: {}", e)))?; + + if allowance != "0" { + if is_allocator_allowance_bigger_than_allocation_amount( + &allowance, + new_allocation_amount, + )? { + Ok(()) + } else { + Err(LDNError::New( + "Multisig address has less allowance than the new allocation amount" + .to_string(), + )) } - Ok(_) => Err(LDNError::New( + } else { + Err(LDNError::New( "Multisig address has no remaining allowance".to_string(), - )), - Err(e) => { - log::error!("Failed to retrieve allowance: {:?}", e); - Err(LDNError::New("Failed to retrieve allowance".to_string())) - } + )) } } @@ -3920,18 +3752,17 @@ _The initial issue can be edited in order to solve the request of the verifier. repo.clone(), None, ) - .await; - let db_application_file_str = match db_application_file_str_result { - Ok(file) => file - .application - .unwrap_or_else(|| panic!("Application data is missing")), // Consider more graceful error handling here - Err(e) => { - return Err(LDNError::New(format!( - "Failed to fetch application data from the database: {}", - e - ))); - } - }; + .await + .map_err(|e| { + LDNError::Load(format!( + "Failed to fetch application data from the database: {}", + e + )) + })?; + + let db_application_file_str = db_application_file_str_result + .application + .ok_or(LDNError::Load("Failed to get appliction".to_string()))?; let mut db_application_file = serde_json::from_str::( &db_application_file_str.clone(), @@ -4579,7 +4410,7 @@ impl LDNPullRequest { owner, repo, issue_number ); - let pr = match gh + let pr = gh .create_refill_merge_request(CreateRefillMergeRequestData { issue_link, file_name: file_name.clone(), @@ -4590,38 +4421,29 @@ impl LDNPullRequest { commit: pr_title, }) .await - { - Ok(pr) => { - if should_create_in_db { - let issue_number = issue_number.parse::().map_err(|e| { - LDNError::New(format!("Parse issue number to i64 failed: {}", e)) - })?; - database::applications::create_application( - application_id.clone(), - owner, - repo, - pr.0.number, - issue_number, - file_content, - file_name, - ) - .await - .map_err(|e| { - LDNError::New(format!( - "Application issue {} cannot create application in DB /// {}", - application_id, e - )) - })?; - } - pr - } - Err(e) => { - return Err(LDNError::New(format!( + .map_err(|e| LDNError::Load(format!("Failed to get list of pull requests: {}", e)))?; + + if should_create_in_db { + let issue_number = issue_number + .parse::() + .map_err(|e| LDNError::New(format!("Parse issue number to i64 failed: {}", e)))?; + database::applications::create_application( + application_id.clone(), + owner, + repo, + pr.0.number, + issue_number, + file_content, + file_name, + ) + .await + .map_err(|e| { + LDNError::New(format!( "Application issue {} cannot create branch /// {}", application_id, e - ))); - } - }; + )) + })?; + } Ok(pr.0.number) } @@ -4633,26 +4455,18 @@ impl LDNPullRequest { file_sha: String, owner: String, repo: String, - ) -> Option<()> { - let gh = github_async_new(owner.to_string(), repo.to_string()) - .await - .ok()?; - match gh - .update_file_content( - &path, - &commit_message, - &new_content, - &branch_name, - &file_sha, - ) - .await - { - Ok(_) => Some(()), - Err(e) => { - log::error!("Failed to add commit: {}", e); - None - } - } + ) -> Result<(), LDNError> { + let gh = github_async_new(owner.to_string(), repo.to_string()).await?; + gh.update_file_content( + &path, + &commit_message, + &new_content, + &branch_name, + &file_sha, + ) + .await + .map_err(|e| LDNError::Load(format!("Failed to add commit: {}", e)))?; + Ok(()) } pub async fn close_pull_request( @@ -4727,13 +4541,7 @@ impl LDNPullRequest { } pub fn get_file_sha(content: &ContentItems) -> Option { - match content.items.first() { - Some(item) => { - let sha = item.sha.clone(); - Some(sha) - } - None => None, - } + content.items.first().map(|item| item.clone().sha) } // #[cfg(test)] diff --git a/fplus-lib/src/external_services/blockchain.rs b/fplus-lib/src/external_services/blockchain.rs index 3e69c66a..7c3445c5 100644 --- a/fplus-lib/src/external_services/blockchain.rs +++ b/fplus-lib/src/external_services/blockchain.rs @@ -54,20 +54,19 @@ impl BlockchainData { pub async fn get_verified_clients(&self) -> Result { let query = "getVerifiedClients"; let url = self.build_url(query); - let res = match self.client.get(url).send().await { - Ok(res) => res, - Err(e) => { - println!("Error: {}", e); - return Err(BlockchainDataError::Err(e.to_string())); - } - }; - let body = match res.text().await { - Ok(body) => body, - Err(e) => { - log::error!("Error: {}", e); - return Err(BlockchainDataError::Err(e.to_string())); - } - }; + + let res = self + .client + .get(url) + .send() + .await + .map_err(|e| BlockchainDataError::Err(e.to_string()))?; + + let body = res + .text() + .await + .map_err(|e| BlockchainDataError::Err(e.to_string()))?; + Ok(body) } diff --git a/fplus-lib/src/external_services/github.rs b/fplus-lib/src/external_services/github.rs index 39eecf0f..07890b77 100644 --- a/fplus-lib/src/external_services/github.rs +++ b/fplus-lib/src/external_services/github.rs @@ -89,21 +89,12 @@ struct Author { } pub async fn github_async_new(owner: String, repo: String) -> Result { - let allocator_result = get_allocator(owner.as_str(), repo.as_str()).await; + let allocator = get_allocator(owner.as_str(), repo.as_str()) + .await + .map_err(|e| LDNError::Load(format!("Failed to get allocator: {}", e)))? + .ok_or(LDNError::Load("Allocator not found".to_string()))?; - let allocator = match allocator_result { - Ok(allocator) => allocator, - Err(e) => { - log::error!("Failed to get allocator from database: {:?}", e); - std::process::exit(1); - } - }; - - if allocator.is_none() { - log::error!("No allocator found for owner: {}, repo: {}", owner, repo); - } - - let installation_id = allocator.expect("Allocator exist").installation_id; + let installation_id = allocator.installation_id; GithubWrapper::new(owner, repo, installation_id) } @@ -335,13 +326,14 @@ impl GithubWrapper { .send() .await?; - match commits.items.into_iter().next() { - Some(commit) => match commit.commit.author.and_then(|author| author.date) { - Some(date) => Ok(date), - None => Ok(chrono::Utc::now()), - }, - None => Ok(chrono::Utc::now()), - } + let date = commits + .items + .into_iter() + .next() + .and_then(|commit| commit.commit.author.and_then(|author| author.date)) + .unwrap_or_else(chrono::Utc::now); + + Ok(date) } pub async fn list_branches(&self) -> Result, OctocrabError> { @@ -357,13 +349,10 @@ impl GithubWrapper { /// creates new branch under head on github /// you should use build_create_ref_request function to construct request pub async fn create_branch(&self, request: Request) -> Result { - match self.inner.execute(request).await { - Ok(_) => {} - Err(e) => { - println!("Error creating branch: {:?}", e); - return Ok(false); - } - }; + if let Err(e) = self.inner.execute(request).await { + println!("Error creating branch: {:?}", e); + return Ok(false); + } Ok(true) } @@ -731,13 +720,10 @@ impl GithubWrapper { .build_request::(request, None) .map_err(|e| LDNError::Load(format!("Failed to build request: {}", e)))?; - let mut response = match self.inner.execute(request).await { - Ok(r) => r, - Err(e) => { - println!("Error fetching last commit author: {:?}", e); - return Ok("".to_string()); - } - }; + let mut response = + self.inner.execute(request).await.map_err(|e| { + LDNError::Load(format!("Error fetching last commit author: {:?}", e)) + })?; let response_body = response.body_mut(); let body = hyper::body::to_bytes(response_body) @@ -773,24 +759,21 @@ impl GithubWrapper { path: Option<&str>, ) -> Result { //if path is not provided, take all files from root - let contents_items = match path { - Some(p) => { - self.inner - .repos(owner, repo) - .get_content() - .r#ref(branch) - .path(p) - .send() - .await? - } - None => { - self.inner - .repos(owner, repo) - .get_content() - .r#ref(branch) - .send() - .await? - } + let contents_items = if let Some(path) = path { + self.inner + .repos(owner, repo) + .get_content() + .r#ref(branch) + .path(path) + .send() + .await? + } else { + self.inner + .repos(owner, repo) + .get_content() + .r#ref(branch) + .send() + .await? }; Ok(contents_items) diff --git a/fplus-lib/src/helpers.rs b/fplus-lib/src/helpers.rs index 3641d124..9eee2ca4 100644 --- a/fplus-lib/src/helpers.rs +++ b/fplus-lib/src/helpers.rs @@ -1,38 +1,28 @@ use size::Size; +use crate::error::LDNError; + pub fn parse_size_to_bytes(size: &str) -> Option { let size = Size::from_str(size).ok()?; let bytes = size.bytes(); bytes.try_into().ok() } -pub fn compare_allowance_and_allocation( +pub fn is_allocator_allowance_bigger_than_allocation_amount( allowance: &str, - new_allocation_amount: Option, -) -> Option { - let allowance_bytes: u64 = match allowance.parse::() { - Ok(value) => { - println!("Allowance value: {}", value); - value - } - Err(_) => { - println!("Error parsing allowance value"); - return None; - } - }; - - let allocation_bytes = match new_allocation_amount { - Some(amount) => { - println!("Allowance value: {}", amount); - parse_size_to_bytes(&amount)? - } - None => { - println!("Error parsing allocation value"); - return None; - } - }; + new_allocation_amount: &str, +) -> Result { + let allowance_bytes: u64 = allowance.parse::().map_err(|e| { + LDNError::New(format!( + "Parse allowance: {} to u64 failed. {}", + &allowance, e + )) + })?; + let allocation_bytes = parse_size_to_bytes(new_allocation_amount).ok_or(LDNError::Load( + "Failed to parse allocation amount to bytes".to_string(), + ))?; - Some(allowance_bytes >= allocation_bytes) + Ok(allowance_bytes >= allocation_bytes) } pub fn process_amount(mut amount: String) -> String {