From 0a400e0b38b72bce89c2e78d5c5b45e891065f79 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 10:51:01 +0100 Subject: [PATCH 01/13] chore: add once_cell dependency --- Cargo.lock | 1 + core/Cargo.toml | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 027ca82..03dcfad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2060,6 +2060,7 @@ dependencies = [ "dotenv", "futures", "infer", + "once_cell", "portfolio-entity", "rand 0.8.5", "sea-orm", diff --git a/core/Cargo.toml b/core/Cargo.toml index a4ec0d4..56c1c6d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,7 +13,7 @@ portfolio-entity = { path = "../entity" } serde = { version = "^1.0", features = ["derive"] } # csv -csv = "^1.1" +csv = "1.1" # error @@ -23,7 +23,7 @@ thiserror = "^1.0" dotenv = "^0.15" # async -tokio = "^1.22" +tokio = "^1.21" futures = "^0.3" async-compat = "^0.2" @@ -49,6 +49,7 @@ features = [ ] [dev-dependencies] -tokio = { version = "^1.22", features = ["macros"] } +tokio = { version = "^1.21", features = ["macros"] } async-tempfile = "^0.2" serial_test = "0.9.0" +once_cell = "1.9.0" \ No newline at end of file From 6499c8ce960a178dc8df6e2e44e0442568edcd02 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 10:53:40 +0100 Subject: [PATCH 02/13] refactor: personal_id_number in ApplicationDetails --- api/src/routes/candidate.rs | 1 + core/src/candidate_details.rs | 166 +++++++++++++++--------- core/src/database/mutation/candidate.rs | 21 +-- core/src/database/mutation/parent.rs | 20 +-- core/src/services/candidate_service.rs | 37 +----- 5 files changed, 117 insertions(+), 128 deletions(-) diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 6328b23..83b780d 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -359,6 +359,7 @@ mod tests { \"citizenship\": \"Czech Republic\", \"email\": \"magor@magor.cz\", \"sex\": \"MALE\", + \"personal_id_number\": \"0000000000\", \"study\": \"KB\", \"parent_name\": \"maminka\", \"parent_surname\": \"chad\", diff --git a/core/src/candidate_details.rs b/core/src/candidate_details.rs index 29c40e6..d0739dc 100644 --- a/core/src/candidate_details.rs +++ b/core/src/candidate_details.rs @@ -71,6 +71,7 @@ pub struct EncryptedApplicationDetails { pub citizenship: EncryptedString, pub email: EncryptedString, pub sex: EncryptedString, + pub personal_id_number: EncryptedString, pub study: String, // Parent @@ -96,6 +97,7 @@ impl EncryptedApplicationDetails { EncryptedString::new(&form.citizenship, &recipients), EncryptedString::new(&form.email, &recipients), EncryptedString::new(&form.sex, &recipients), + EncryptedString::new(&form.personal_id_number, &recipients), EncryptedString::new(&form.parent_name, &recipients), EncryptedString::new(&form.parent_surname, &recipients), @@ -113,30 +115,32 @@ impl EncryptedApplicationDetails { citizenship: d.6, email: d.7, sex: d.8, + personal_id_number: d.9, study: form.study, - parent_name: d.9, - parent_surname: d.10, - parent_telephone: d.11, - parent_email: d.12, + parent_name: d.10, + parent_surname: d.11, + parent_telephone: d.12, + parent_email: d.13, }) } pub async fn decrypt(self, priv_key: String) -> Result { let d = tokio::try_join!( - self.name.decrypt(&priv_key), // 0 - self.surname.decrypt(&priv_key), // 1 - self.birthplace.decrypt(&priv_key), // 2 - self.birthdate.decrypt(&priv_key), // 3 - self.address.decrypt(&priv_key), // 4 - self.telephone.decrypt(&priv_key), // 5 - self.citizenship.decrypt(&priv_key), // 6 - self.email.decrypt(&priv_key), // 7 - self.sex.decrypt(&priv_key), // 8 - self.parent_name.decrypt(&priv_key), - self.parent_surname.decrypt(&priv_key), - self.parent_telephone.decrypt(&priv_key), - self.parent_email.decrypt(&priv_key), + self.name.decrypt(&priv_key), // 0 + self.surname.decrypt(&priv_key), // 1 + self.birthplace.decrypt(&priv_key), // 2 + self.birthdate.decrypt(&priv_key), // 3 + self.address.decrypt(&priv_key), // 4 + self.telephone.decrypt(&priv_key), // 5 + self.citizenship.decrypt(&priv_key), // 6 + self.email.decrypt(&priv_key), // 7 + self.sex.decrypt(&priv_key), // 8 + self.personal_id_number.decrypt(&priv_key),// 9 + self.parent_name.decrypt(&priv_key), // 10 + self.parent_surname.decrypt(&priv_key), // 11 + self.parent_telephone.decrypt(&priv_key), // 12 + self.parent_email.decrypt(&priv_key), // 13 )?; Ok(ApplicationDetails { @@ -149,12 +153,13 @@ impl EncryptedApplicationDetails { citizenship: d.6, email: d.7, sex: d.8, + personal_id_number: d.9, study: self.study, - parent_name: d.9, - parent_surname: d.10, - parent_telephone: d.11, - parent_email: d.12, + parent_name: d.10, + parent_surname: d.11, + parent_telephone: d.12, + parent_email: d.13, }) } } @@ -175,6 +180,7 @@ impl TryFrom<(candidate::Model, parent::Model)> for EncryptedApplicationDetails citizenship: EncryptedString::try_from(candidate.citizenship)?, email: EncryptedString::try_from(candidate.email)?, sex: EncryptedString::try_from(candidate.sex)?, + personal_id_number: EncryptedString::try_from(candidate.personal_identification_number)?, study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?, parent_name: EncryptedString::try_from(parent.name)?, @@ -201,6 +207,7 @@ impl TryFrom for EncryptedApplicationDetails { citizenship: EncryptedString::try_from(cp.citizenship)?, email: EncryptedString::try_from(cp.email)?, sex: EncryptedString::try_from(cp.sex)?, + personal_id_number: EncryptedString::try_from(cp.personal_identification_number)?, study: cp.study.ok_or(ServiceError::CandidateDetailsNotSet)?, parent_name: EncryptedString::try_from(cp.parent_name)?, @@ -213,7 +220,7 @@ impl TryFrom for EncryptedApplicationDetails { -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct ApplicationDetails { // Candidate pub name: String, @@ -226,7 +233,7 @@ pub struct ApplicationDetails { pub email: String, pub sex: String, pub study: String, - + pub personal_id_number: String, // Parent pub parent_name: String, pub parent_surname: String, @@ -235,33 +242,61 @@ pub struct ApplicationDetails { } #[cfg(test)] -mod tests { +pub mod tests { + use std::sync::Mutex; + + use chrono::NaiveDate; + use once_cell::sync::Lazy; + use crate::crypto; use super::{ApplicationDetails, EncryptedApplicationDetails, EncryptedString}; + pub static APPLICATION_DETAILS: Lazy> = Lazy::new(|| + Mutex::new(ApplicationDetails { + name: "name".to_string(), + surname: "surname".to_string(), + birthplace: "birthplace".to_string(), + birthdate: chrono::NaiveDate::from_ymd(2000, 1, 1), + address: "address".to_string(), + telephone: "telephone".to_string(), + citizenship: "citizenship".to_string(), + email: "email".to_string(), + sex: "sex".to_string(), + personal_id_number: "personal_id_number".to_string(), + study: "study".to_string(), + parent_email: "parent_email".to_string(), + parent_name: "parent_name".to_string(), + parent_surname: "parent_surname".to_string(), + parent_telephone: "parent_telephone".to_string() + }) + ); + + pub fn assert_all_application_details(details: &ApplicationDetails) { + assert_eq!(details.name, "name"); + assert_eq!(details.surname, "surname"); + assert_eq!(details.birthplace, "birthplace"); + assert_eq!(details.birthdate, chrono::NaiveDate::from_ymd(2000, 1, 1)); + assert_eq!(details.address, "address"); + assert_eq!(details.telephone, "telephone"); + assert_eq!(details.citizenship, "citizenship"); + assert_eq!(details.email, "email"); + assert_eq!(details.sex, "sex"); + assert_eq!(details.study, "study"); + assert_eq!(details.personal_id_number, "personal_id_number"); + assert_eq!(details.parent_name, "parent_name"); + assert_eq!(details.parent_surname, "parent_surname"); + assert_eq!(details.parent_telephone, "parent_telephone"); + assert_eq!(details.parent_email, "parent_email"); + } + #[tokio::test] async fn test_encrypted_application_details_new() { const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; let encrypted_details = EncryptedApplicationDetails::new( - ApplicationDetails { - name: "test".to_string(), - surname: "test".to_string(), - birthplace: "test".to_string(), - birthdate: chrono::offset::Local::now().date_naive(), - address: "test".to_string(), - telephone: "test".to_string(), - citizenship: "test".to_string(), - email: "test".to_string(), - parent_email: "test".to_string(), - parent_name: "test".to_string(), - parent_surname: "test".to_string(), - parent_telephone: "test".to_string(), - sex: "test".to_string(), - study: "test".to_string(), - }, + APPLICATION_DETAILS.lock().unwrap().clone(), vec![PUBLIC_KEY], ) .await @@ -271,19 +306,19 @@ mod tests { crypto::decrypt_password_with_private_key(&encrypted_details.name.0, PRIVATE_KEY) .await .unwrap(), - "test" + "name" ); assert_eq!( crypto::decrypt_password_with_private_key(&encrypted_details.email.0, PRIVATE_KEY) .await .unwrap(), - "test" + "email" ); assert_eq!( crypto::decrypt_password_with_private_key(&encrypted_details.sex.0, PRIVATE_KEY) .await .unwrap(), - "test" + "sex" ); } @@ -292,23 +327,9 @@ mod tests { const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; + let encrypted_details = EncryptedApplicationDetails::new( - ApplicationDetails { - name: "test".to_string(), - surname: "test".to_string(), - birthplace: "test".to_string(), - birthdate: chrono::offset::Local::now().date_naive(), - address: "test".to_string(), - telephone: "test".to_string(), - citizenship: "test".to_string(), - email: "test".to_string(), - parent_email: "test".to_string(), - parent_name: "test".to_string(), - parent_surname: "test".to_string(), - parent_telephone: "test".to_string(), - sex: "test".to_string(), - study: "test".to_string(), - }, + APPLICATION_DETAILS.lock().unwrap().clone(), vec![PUBLIC_KEY], ) .await @@ -319,11 +340,32 @@ mod tests { .await .unwrap(); - assert_eq!(application_details.name, "test"); - assert_eq!(application_details.email, "test"); - assert_eq!(application_details.sex, "test"); + assert_all_application_details(&application_details); } + // TODO + /* #[tokio::test] + async fn test_encrypted_application_details_from_candidate_parent() { + const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; + const PRIVATE_KEY: &str = + "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; + + const birthdate: NaiveDate = chrono::offset::Local::now().date_naive(); + let encrypted_details = EncryptedApplicationDetails::try_from( + , + vec![PUBLIC_KEY], + ) + .await + .unwrap(); + + let application_details = encrypted_details + .decrypt(PRIVATE_KEY.to_string()) + .await + .unwrap(); + + assert_all_application_details(&application_details); + } */ + #[tokio::test] async fn test_encrypted_string_new() { const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index 3fbc113..2de10e1 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -56,6 +56,7 @@ impl Mutation { user.citizenship = Set(Some(enc_details.citizenship.into())); user.email = Set(Some(enc_details.email.into())); user.sex = Set(Some(enc_details.sex.into())); + user.personal_identification_number = Set(Some(enc_details.personal_id_number.into())); user.study = Set(Some(enc_details.study.into())); user.updated_at = Set(chrono::offset::Local::now().naive_local()); @@ -66,7 +67,8 @@ impl Mutation { #[cfg(test)] mod tests { - use crate::candidate_details::{ApplicationDetails, EncryptedApplicationDetails}; + use crate::candidate_details::tests::APPLICATION_DETAILS; + use crate::candidate_details::{EncryptedApplicationDetails}; use crate::util::get_memory_sqlite_connection; use crate::{Mutation, Query}; @@ -111,22 +113,7 @@ mod tests { .unwrap(); let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( - ApplicationDetails { - name: "test".to_string(), - surname: "test".to_string(), - birthplace: "test".to_string(), - birthdate: chrono::offset::Local::now().date_naive(), - address: "test".to_string(), - telephone: "test".to_string(), - citizenship: "test".to_string(), - email: "test".to_string(), - parent_email: "test".to_string(), - parent_name: "test".to_string(), - parent_surname: "test".to_string(), - parent_telephone: "test".to_string(), - sex: "test".to_string(), - study: "test".to_string(), - }, + APPLICATION_DETAILS.lock().unwrap().clone(), vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], ).await.unwrap(); diff --git a/core/src/database/mutation/parent.rs b/core/src/database/mutation/parent.rs index 1cfd01d..2b8ed6c 100644 --- a/core/src/database/mutation/parent.rs +++ b/core/src/database/mutation/parent.rs @@ -34,7 +34,8 @@ impl Mutation { #[cfg(test)] mod tests { - use crate::candidate_details::{ApplicationDetails, EncryptedApplicationDetails}; + use crate::candidate_details::tests::APPLICATION_DETAILS; + use crate::candidate_details::{EncryptedApplicationDetails}; use crate::util::get_memory_sqlite_connection; use crate::{Mutation, Query}; @@ -81,22 +82,7 @@ mod tests { let parent = Mutation::create_parent(&db, APPLICATION_ID).await.unwrap(); let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( - ApplicationDetails { - name: "test".to_string(), - surname: "test".to_string(), - birthplace: "test".to_string(), - birthdate: chrono::offset::Local::now().date_naive(), - address: "test".to_string(), - telephone: "test".to_string(), - citizenship: "test".to_string(), - email: "test".to_string(), - parent_email: "test".to_string(), - parent_name: "test".to_string(), - parent_surname: "test".to_string(), - parent_telephone: "test".to_string(), - sex: "test".to_string(), - study: "test".to_string(), - }, + APPLICATION_DETAILS.lock().unwrap().clone(), vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], ) .await diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index a62a9e6..6a86932 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -247,14 +247,13 @@ impl CandidateService { pub mod tests { use sea_orm::{DbConn}; + use crate::candidate_details::tests::assert_all_application_details; use crate::util::get_memory_sqlite_connection; use crate::{crypto, services::candidate_service::CandidateService, Mutation}; use super::EncryptedApplicationDetails; - use chrono::NaiveDate; use entity::{candidate, parent, admin}; - use crate::candidate_details::{ApplicationDetails}; use crate::services::application_service::ApplicationService; const APPLICATION_ID: i32 = 103151; @@ -368,6 +367,8 @@ pub mod tests { #[cfg(test)] pub async fn put_user_data(db: &DbConn) -> (candidate::Model, parent::Model) { + use crate::candidate_details::tests::APPLICATION_DETAILS; + let plain_text_password = "test".to_string(); let (candidate, _parent) = ApplicationService::create_candidate_with_parent( &db, @@ -379,22 +380,7 @@ pub mod tests { .ok() .unwrap(); - let form = ApplicationDetails { - name: "name".to_string(), - surname: "surname".to_string(), - birthplace: "birthplace".to_string(), - birthdate: NaiveDate::from_ymd(2000, 1, 1), - address: "address".to_string(), - telephone: "telephone".to_string(), - citizenship: "citizenship".to_string(), - email: "email".to_string(), - sex: "sex".to_string(), - study: "KB".to_string(), - parent_name: "parent_name".to_string(), - parent_surname: "parent_surname".to_string(), - parent_telephone: "parent_telephone".to_string(), - parent_email: "parent_email".to_string(), - }; + let form = APPLICATION_DETAILS.lock().unwrap().clone(); ApplicationService::add_all_details(&db, candidate.application, form) .await @@ -423,19 +409,6 @@ pub mod tests { .unwrap(); let dec_details = enc_details.decrypt(dec_priv_key).await.ok().unwrap(); - assert_eq!(dec_details.name, "name"); - assert_eq!(dec_details.surname, "surname"); - assert_eq!(dec_details.birthplace, "birthplace"); - assert_eq!(dec_details.birthdate, NaiveDate::from_ymd(2000, 1, 1)); - assert_eq!(dec_details.address, "address"); - assert_eq!(dec_details.telephone, "telephone"); - assert_eq!(dec_details.citizenship, "citizenship"); - assert_eq!(dec_details.email, "email"); - assert_eq!(dec_details.sex, "sex"); - assert_eq!(dec_details.study, "KB"); - assert_eq!(dec_details.parent_name, "parent_name"); - assert_eq!(dec_details.parent_surname, "parent_surname"); - assert_eq!(dec_details.parent_telephone, "parent_telephone"); - assert_eq!(dec_details.parent_email, "parent_email"); + assert_all_application_details(&dec_details); } } From 02303d4b31a1e2ce64d5e0e1ba697e14ce9889dc Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:03:37 +0100 Subject: [PATCH 03/13] feat: use reference as constructor parameter --- core/src/candidate_details.rs | 8 ++++---- core/src/database/mutation/candidate.rs | 2 +- core/src/database/mutation/parent.rs | 2 +- core/src/services/application_service.rs | 2 +- core/src/services/candidate_service.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/candidate_details.rs b/core/src/candidate_details.rs index d0739dc..f235b08 100644 --- a/core/src/candidate_details.rs +++ b/core/src/candidate_details.rs @@ -83,7 +83,7 @@ pub struct EncryptedApplicationDetails { impl EncryptedApplicationDetails { pub async fn new( - form: ApplicationDetails, + form: &ApplicationDetails, recipients: Vec<&str>, ) -> Result { let birthdate_str = form.birthdate.format(NAIVE_DATE_FMT).to_string(); @@ -116,7 +116,7 @@ impl EncryptedApplicationDetails { email: d.7, sex: d.8, personal_id_number: d.9, - study: form.study, + study: form.study.clone(), parent_name: d.10, parent_surname: d.11, @@ -296,7 +296,7 @@ pub mod tests { const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; let encrypted_details = EncryptedApplicationDetails::new( - APPLICATION_DETAILS.lock().unwrap().clone(), + &APPLICATION_DETAILS.lock().unwrap().clone(), vec![PUBLIC_KEY], ) .await @@ -329,7 +329,7 @@ pub mod tests { "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; let encrypted_details = EncryptedApplicationDetails::new( - APPLICATION_DETAILS.lock().unwrap().clone(), + &APPLICATION_DETAILS.lock().unwrap().clone(), vec![PUBLIC_KEY], ) .await diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index 2de10e1..7921f74 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -113,7 +113,7 @@ mod tests { .unwrap(); let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( - APPLICATION_DETAILS.lock().unwrap().clone(), + &APPLICATION_DETAILS.lock().unwrap().clone(), vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], ).await.unwrap(); diff --git a/core/src/database/mutation/parent.rs b/core/src/database/mutation/parent.rs index 2b8ed6c..4c49ded 100644 --- a/core/src/database/mutation/parent.rs +++ b/core/src/database/mutation/parent.rs @@ -82,7 +82,7 @@ mod tests { let parent = Mutation::create_parent(&db, APPLICATION_ID).await.unwrap(); let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( - APPLICATION_DETAILS.lock().unwrap().clone(), + &APPLICATION_DETAILS.lock().unwrap().clone(), vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], ) .await diff --git a/core/src/services/application_service.rs b/core/src/services/application_service.rs index eec9931..5eedd36 100644 --- a/core/src/services/application_service.rs +++ b/core/src/services/application_service.rs @@ -31,7 +31,7 @@ impl ApplicationService { pub async fn add_all_details( db: &DbConn, application: i32, - form: ApplicationDetails, + form: &ApplicationDetails, ) -> Result<(candidate::Model, parent::Model), ServiceError> { let candidate = Query::find_candidate_by_id(db, application) .await? diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 6a86932..d127705 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -125,7 +125,7 @@ impl CandidateService { let enc_details_opt = EncryptedApplicationDetails::try_from((candidate, parent)); if let Ok(enc_details) = enc_details_opt { let application_details = enc_details.decrypt(admin_private_key).await?; - ApplicationService::add_all_details(db, id, application_details).await?; + ApplicationService::add_all_details(db, id, &application_details).await?; } Ok(new_password_plain) @@ -382,7 +382,7 @@ pub mod tests { let form = APPLICATION_DETAILS.lock().unwrap().clone(); - ApplicationService::add_all_details(&db, candidate.application, form) + ApplicationService::add_all_details(&db, candidate.application, &form) .await .unwrap() } From 44f036a4c43f8502b764b0fd580f833c2ee3abc3 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:05:00 +0100 Subject: [PATCH 04/13] refactor: get_details endpoint --- api/src/routes/candidate.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 83b780d..e034f85 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -82,13 +82,13 @@ pub async fn add_details( conn: Connection<'_, Db>, details: Json, session: CandidateAuth, -) -> Result> { +) -> Result, Custom> { let db = conn.into_inner(); let form = details.into_inner(); let candidate: entity::candidate::Model = session.into(); // TODO: don't return candidate from session let candidate_parent = - ApplicationService::add_all_details(db, candidate.application, form).await; + ApplicationService::add_all_details(db, candidate.application, &form).await; if candidate_parent.is_err() { // TODO cleanup @@ -99,10 +99,12 @@ pub async fn add_details( )); } - Ok("Details added".to_string()) + Ok( + Json(form) + ) } -#[post("/get_details")] +#[get("/details")] pub async fn get_details( conn: Connection<'_, Db>, session: CandidateAuth, @@ -404,7 +406,7 @@ mod tests { assert_eq!(response.status(), Status::Ok); let response = client - .post("/candidate/get_details") + .get("/candidate/details") .cookie(cookies.0) .cookie(cookies.1) .dispatch(); @@ -433,7 +435,7 @@ mod tests { assert_eq!(response.status(), Status::Unauthorized); let response = client - .post("/candidate/get_details") + .get("/candidate/details") .cookie(id.clone()) .cookie(key.clone()) .dispatch(); @@ -461,7 +463,7 @@ mod tests { assert_eq!(response.status(), Status::Unauthorized); let response = client - .post("/candidate/get_details") + .get("/candidate/details") .cookie(cookies.0.clone()) .cookie(cookies.1.clone()) .dispatch(); From 1a7d95fb3d681022d364d18027d7e45f39c2b60b Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:10:57 +0100 Subject: [PATCH 05/13] refactor: post details endpoint --- api/src/lib.rs | 2 +- api/src/routes/candidate.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index edd5814..b695ac0 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -43,12 +43,12 @@ pub fn rocket() -> Rocket{ routes::candidate::logout, routes::candidate::whoami, routes::candidate::get_details, + routes::candidate::post_details, ], ) .mount( "/candidate/add", routes![ - routes::candidate::add_details, routes::candidate::upload_portfolio_letter, routes::candidate::upload_portfolio_zip, routes::candidate::upload_cover_letter, diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index e034f85..2bb1233 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -77,8 +77,9 @@ pub async fn whoami(session: CandidateAuth) -> Result> { Ok(candidate.application.to_string()) } +// TODO: use put instead of post??? #[post("/details", data = "
")] -pub async fn add_details( +pub async fn post_details( conn: Connection<'_, Db>, details: Json, session: CandidateAuth, @@ -397,7 +398,7 @@ mod tests { let details_orig: ApplicationDetails = serde_json::from_str(CANDIDATE_DETAILS).unwrap(); let response = client - .post("/candidate/add/details") + .post("/candidate/details") .cookie(cookies.0.clone()) .cookie(cookies.1.clone()) .body(CANDIDATE_DETAILS.to_string()) @@ -427,7 +428,7 @@ mod tests { let key = Cookie::new("key", private_key); let response = client - .post("/candidate/add/details") + .post("/candidate/details") .cookie(id.clone()) .cookie(key.clone()) .body(CANDIDATE_DETAILS.to_string()) @@ -455,7 +456,7 @@ mod tests { let cookies = admin_login(&client); let response = client - .post("/candidate/add/details") + .post("/candidate/details") .cookie(cookies.0.clone()) .cookie(cookies.1.clone()) .body(CANDIDATE_DETAILS.to_string()) From 6a3158d958490ebd576ba1f402b947a6206e03bc Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:19:15 +0100 Subject: [PATCH 06/13] refactor: base candidate response --- api/src/routes/admin.rs | 12 ++++++------ core/src/responses.rs | 4 ++-- core/src/services/candidate_service.rs | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index 3700704..d7bfc0d 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -2,7 +2,7 @@ use std::net::{SocketAddr, IpAddr, Ipv4Addr}; use portfolio_core::{ crypto::random_8_char_string, - services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::CandidateResponse, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, + services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::BaseCandidateResponse, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, }; use requests::{AdminLoginRequest, RegisterRequest}; use rocket::http::{Cookie, Status, CookieJar}; @@ -11,7 +11,7 @@ use rocket::serde::json::Json; use sea_orm_rocket::Connection; -use crate::{guards::request::auth::AdminAuth, pool::Db, requests}; +use crate::{guards::request::{auth::AdminAuth, self}, pool::Db, requests}; #[post("/login", data = "")] pub async fn login( @@ -82,14 +82,14 @@ pub async fn hello(_session: AdminAuth) -> Result> { Ok("Hello admin".to_string()) } -#[post("/create", data = "")] +#[post("/create", data = "")] pub async fn create_candidate( conn: Connection<'_, Db>, _session: AdminAuth, - post_form: Json, + request: Json, ) -> Result> { let db = conn.into_inner(); - let form = post_form.into_inner(); + let form = request.into_inner(); let plain_text_password = random_8_char_string(); @@ -111,7 +111,7 @@ pub async fn list_candidates( session: AdminAuth, field: Option, page: Option, -) -> Result>, Custom> { +) -> Result>, Custom> { let db = conn.into_inner(); let private_key = session.get_private_key(); if let Some(field) = field.clone() { diff --git a/core/src/responses.rs b/core/src/responses.rs index c0b7e5b..970c7ba 100644 --- a/core/src/responses.rs +++ b/core/src/responses.rs @@ -3,7 +3,7 @@ use serde::Serialize; use crate::{candidate_details::EncryptedString, error::ServiceError}; #[derive(Debug, Serialize)] -pub struct CandidateResponse { +pub struct BaseCandidateResponse { pub application_id: i32, pub name: String, pub surname: String, @@ -11,7 +11,7 @@ pub struct CandidateResponse { pub submitted: bool, } -impl CandidateResponse { +impl BaseCandidateResponse { pub async fn from_encrypted( private_key: &String, application_id: i32, diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index d127705..c750990 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -7,7 +7,7 @@ use crate::{ candidate_details::{EncryptedApplicationDetails}, crypto::{self, hash_password}, error::ServiceError, - Mutation, Query, responses::CandidateResponse, + Mutation, Query, responses::BaseCandidateResponse, }; use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService}; @@ -150,7 +150,7 @@ impl CandidateService { db: &DbConn, field_of_study: Option, page: Option, - ) -> Result, ServiceError> { + ) -> Result, ServiceError> { let candidates = Query::list_candidates( db, @@ -158,11 +158,11 @@ impl CandidateService { page ).await?; - let mut result: Vec = vec![]; + let mut result: Vec = vec![]; for candidate in candidates { result.push( - CandidateResponse::from_encrypted( + BaseCandidateResponse::from_encrypted( &private_key, candidate.application, candidate.name, From 314138a1113cbf22c2ace25eec2fa5803bd5eb3d Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:25:36 +0100 Subject: [PATCH 07/13] feat: new create candidate response --- api/src/routes/admin.rs | 16 ++++++++++++---- core/src/responses.rs | 7 +++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index d7bfc0d..c71e383 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -2,7 +2,7 @@ use std::net::{SocketAddr, IpAddr, Ipv4Addr}; use portfolio_core::{ crypto::random_8_char_string, - services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::BaseCandidateResponse, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, + services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::{BaseCandidateResponse, CreateCandidateResponse}, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, }; use requests::{AdminLoginRequest, RegisterRequest}; use rocket::http::{Cookie, Status, CookieJar}; @@ -87,7 +87,7 @@ pub async fn create_candidate( conn: Connection<'_, Db>, _session: AdminAuth, request: Json, -) -> Result> { +) -> Result, Custom> { let db = conn.into_inner(); let form = request.into_inner(); @@ -97,12 +97,20 @@ pub async fn create_candidate( db, form.application_id, &plain_text_password, - form.personal_id_number, + form.personal_id_number.clone(), ) .await .map_err(|e| Custom(Status::InternalServerError, e.to_string()))?; - Ok(plain_text_password) + Ok( + Json( + CreateCandidateResponse { + application_id: form.application_id, + personal_id_number: form.personal_id_number, + password: plain_text_password, + } + ) + ) } #[get("/candidates?&")] diff --git a/core/src/responses.rs b/core/src/responses.rs index 970c7ba..967ee0b 100644 --- a/core/src/responses.rs +++ b/core/src/responses.rs @@ -2,6 +2,13 @@ use serde::Serialize; use crate::{candidate_details::EncryptedString, error::ServiceError}; +#[derive(Debug, Serialize)] +pub struct CreateCandidateResponse { + pub application_id: i32, + pub personal_id_number: String, + pub password: String, +} + #[derive(Debug, Serialize)] pub struct BaseCandidateResponse { pub application_id: i32, From 8a9b7a4ae4cbea453ce4bc388b50f0d73656bb66 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 11:44:08 +0100 Subject: [PATCH 08/13] refactor: reset password response --- api/src/routes/admin.rs | 19 ++++++++++-------- core/src/responses.rs | 4 ++-- core/src/services/candidate_service.rs | 27 ++++++++++++++++++++------ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index c71e383..904527c 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -11,7 +11,7 @@ use rocket::serde::json::Json; use sea_orm_rocket::Connection; -use crate::{guards::request::{auth::AdminAuth, self}, pool::Db, requests}; +use crate::{guards::request::{auth::AdminAuth}, pool::Db, requests}; #[post("/login", data = "")] pub async fn login( @@ -161,15 +161,17 @@ pub async fn reset_candidate_password( conn: Connection<'_, Db>, session: AdminAuth, id: i32, -) -> Result> { +) -> Result, Custom> { let db = conn.into_inner(); let private_key = session.get_private_key(); - let new_password = CandidateService::reset_password(private_key, db, id) + let response = CandidateService::reset_password(private_key, db, id) .await .map_err(|e| Custom(Status::from_code(e.code()).unwrap(), e.to_string()))?; - Ok(new_password) + Ok( + Json(response) + ) } #[get("/candidate//portfolio")] @@ -188,6 +190,7 @@ pub async fn get_candidate_portfolio( #[cfg(test)] pub mod tests { + use portfolio_core::responses::CreateCandidateResponse; use rocket::{local::blocking::Client, http::{Cookie, Status}}; use crate::test::tests::{test_client, ADMIN_PASSWORD, ADMIN_ID}; @@ -216,7 +219,7 @@ pub mod tests { cookies: (Cookie, Cookie), id: i32, pid: String, - ) -> String { + ) -> CreateCandidateResponse { let response = client .post("/admin/create") .body(format!( @@ -232,15 +235,15 @@ pub mod tests { assert_eq!(response.status(), Status::Ok); - response.into_string().unwrap() + response.into_json::().unwrap() } #[test] fn test_create_candidate() { let client = test_client().lock().unwrap(); let cookies = admin_login(&client); - let password = create_candidate(&client, cookies, 1031511, "0".to_string()); + let response = create_candidate(&client, cookies, 1031511, "0".to_string()); - assert_eq!(password.len(), 8); + assert_eq!(response.password.len(), 8); } } \ No newline at end of file diff --git a/core/src/responses.rs b/core/src/responses.rs index 967ee0b..a1ccf56 100644 --- a/core/src/responses.rs +++ b/core/src/responses.rs @@ -1,8 +1,8 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crate::{candidate_details::EncryptedString, error::ServiceError}; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct CreateCandidateResponse { pub application_id: i32, pub personal_id_number: String, diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index c750990..4b1033f 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -4,10 +4,10 @@ use entity::candidate; use sea_orm::{prelude::Uuid, DbConn}; use crate::{ - candidate_details::{EncryptedApplicationDetails}, + candidate_details::{EncryptedApplicationDetails, EncryptedString}, crypto::{self, hash_password}, error::ServiceError, - Mutation, Query, responses::BaseCandidateResponse, + Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, }; use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService}; @@ -103,7 +103,7 @@ impl CandidateService { admin_private_key: String, db: &DbConn, id: i32, - ) -> Result { + ) -> Result { let candidate = Query::find_candidate_by_id(db, id).await? .ok_or(ServiceError::CandidateNotFound)?; let parent = Query::find_parent_by_id(db, id).await? @@ -122,13 +122,28 @@ impl CandidateService { SessionService::revoke_all_sessions(db, Some(id), None).await?; Mutation::update_candidate_password_with_keys(db, candidate.clone(), new_password_hash, pubkey, encrypted_priv_key).await?; - let enc_details_opt = EncryptedApplicationDetails::try_from((candidate, parent)); + // user might no have filled his details yet, but personal id number is filled from beginning + // TODO: make personal id number required + let personal_id_number = EncryptedString::try_from(candidate.personal_identification_number.clone())? + .decrypt(&admin_private_key) + .await?; + + let enc_details_opt = EncryptedApplicationDetails::try_from( + (candidate, parent) + ); + if let Ok(enc_details) = enc_details_opt { let application_details = enc_details.decrypt(admin_private_key).await?; ApplicationService::add_all_details(db, id, &application_details).await?; } - Ok(new_password_plain) + Ok( + CreateCandidateResponse { + application_id: id, + personal_id_number: personal_id_number, + password: new_password_plain, + } + ) } pub async fn logout(db: &DbConn, session_id: Uuid) -> Result<(), ServiceError> { @@ -281,7 +296,7 @@ pub mod tests { CandidateService::login(&db, candidate.application, "test".to_string(), "127.0.0.1".to_string()).await.is_ok() ); - let new_password = CandidateService::reset_password(private_key, &db, candidate.application).await.unwrap(); + let new_password = CandidateService::reset_password(private_key, &db, candidate.application).await.unwrap().password; assert!( CandidateService::login(&db, candidate.application, "test".to_string(), "127.0.0.1".to_string()).await.is_err() From d9f4090c6a89efb32441b0a7ae5180a843c1e119 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 12:08:35 +0100 Subject: [PATCH 09/13] feat: set personal id number when user is created --- core/src/candidate_details.rs | 7 +++++- core/src/database/mutation/candidate.rs | 8 +++---- core/src/database/query/candidate.rs | 4 ++-- core/src/database/query/parent.rs | 2 +- core/src/services/candidate_service.rs | 20 ++++++++++++----- entity/src/candidate.rs | 22 +++++++++---------- .../src/m20221024_121621_create_candidate.rs | 4 ++-- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/core/src/candidate_details.rs b/core/src/candidate_details.rs index f235b08..fb3b071 100644 --- a/core/src/candidate_details.rs +++ b/core/src/candidate_details.rs @@ -46,6 +46,11 @@ impl TryFrom> for EncryptedString { } } } +impl From for EncryptedString { + fn from(s: String) -> Self { + Self(s) + } +} impl TryFrom> for EncryptedString { // TODO: take a look at this @@ -180,7 +185,7 @@ impl TryFrom<(candidate::Model, parent::Model)> for EncryptedApplicationDetails citizenship: EncryptedString::try_from(candidate.citizenship)?, email: EncryptedString::try_from(candidate.email)?, sex: EncryptedString::try_from(candidate.sex)?, - personal_id_number: EncryptedString::try_from(candidate.personal_identification_number)?, + personal_id_number: EncryptedString::from(candidate.personal_identification_number), study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?, parent_name: EncryptedString::try_from(parent.name)?, diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index 7921f74..a687ebe 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -8,13 +8,13 @@ impl Mutation { db: &DbConn, application_id: i32, hashed_password: String, - hashed_personal_id_number: String, + enc_personal_id_number: String, pubkey: String, encrypted_priv_key: String, ) -> Result { candidate::ActiveModel { application: Set(application_id), - personal_identification_number_hash: Set(hashed_personal_id_number), + personal_identification_number: Set(enc_personal_id_number), code: Set(hashed_password), public_key: Set(pubkey), private_key: Set(encrypted_priv_key), @@ -26,7 +26,7 @@ impl Mutation { .await } - pub async fn update_candidate_password_with_keys( + pub async fn update_candidate_password_and_keys( db: &DbConn, candidate: candidate::Model, new_password_hash: String, @@ -56,7 +56,7 @@ impl Mutation { user.citizenship = Set(Some(enc_details.citizenship.into())); user.email = Set(Some(enc_details.email.into())); user.sex = Set(Some(enc_details.sex.into())); - user.personal_identification_number = Set(Some(enc_details.personal_id_number.into())); + user.personal_identification_number = Set(enc_details.personal_id_number.into()); // TODO: do not set this here, it is already set in the create_candidate mutation??? user.study = Set(Some(enc_details.study.into())); user.updated_at = Set(chrono::offset::Local::now().naive_local()); diff --git a/core/src/database/query/candidate.rs b/core/src/database/query/candidate.rs index 4a696dd..4bf96d6 100644 --- a/core/src/database/query/candidate.rs +++ b/core/src/database/query/candidate.rs @@ -132,7 +132,7 @@ mod tests { code: Set("test".to_string()), public_key: Set("test".to_string()), private_key: Set("test".to_string()), - personal_identification_number_hash: Set("test".to_string()), + personal_identification_number: Set("test".to_string()), created_at: Set(chrono::offset::Local::now().naive_local()), updated_at: Set(chrono::offset::Local::now().naive_local()), ..Default::default() @@ -141,7 +141,7 @@ mod tests { .await .unwrap(); - let candidate = Query::find_candidate_by_id(&db, candidate.application) + let candidate = Query::find_candidate_by_id(&db, candidate.application) .await .unwrap(); assert!(candidate.is_some()); diff --git a/core/src/database/query/parent.rs b/core/src/database/query/parent.rs index 665d9de..c53e443 100644 --- a/core/src/database/query/parent.rs +++ b/core/src/database/query/parent.rs @@ -35,7 +35,7 @@ mod tests { code: Set("test".to_string()), public_key: Set("test".to_string()), private_key: Set("test".to_string()), - personal_identification_number_hash: Set("test".to_string()), + personal_identification_number: Set("test".to_string()), created_at: Set(chrono::offset::Local::now().naive_local()), updated_at: Set(chrono::offset::Local::now().naive_local()), ..Default::default() diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 4b1033f..ee4be52 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -76,14 +76,24 @@ impl CandidateService { return Err(ServiceError::UserAlreadyExists); } + let hashed_password = hash_password(plain_text_password.to_string()).await?; - + let (pubkey, priv_key_plain_text) = crypto::create_identity(); let encrypted_priv_key = crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await?; - let hashed_personal_id_number = hash_password(personal_id_number).await?; + + let admin_public_keys = Query::get_all_admin_public_keys(db).await?; + let mut admin_public_keys_ref = admin_public_keys.iter().map(|s| &**s).collect(); + let mut recipients = vec![&*pubkey]; + recipients.append(&mut admin_public_keys_ref); + + let enc_personal_id_number = EncryptedString::new( + &personal_id_number, + &recipients, + ).await?; tokio::fs::create_dir_all(Self::get_file_store_path().join(&application_id.to_string()).join("cache")).await?; @@ -91,7 +101,7 @@ impl CandidateService { db, application_id, hashed_password, - hashed_personal_id_number, + enc_personal_id_number.to_string(), pubkey, encrypted_priv_key, ) @@ -120,11 +130,11 @@ impl CandidateService { SessionService::revoke_all_sessions(db, Some(id), None).await?; - Mutation::update_candidate_password_with_keys(db, candidate.clone(), new_password_hash, pubkey, encrypted_priv_key).await?; + Mutation::update_candidate_password_and_keys(db, candidate.clone(), new_password_hash, pubkey, encrypted_priv_key).await?; // user might no have filled his details yet, but personal id number is filled from beginning // TODO: make personal id number required - let personal_id_number = EncryptedString::try_from(candidate.personal_identification_number.clone())? + let personal_id_number = EncryptedString::from(candidate.personal_identification_number.clone()) .decrypt(&admin_private_key) .await?; diff --git a/entity/src/candidate.rs b/entity/src/candidate.rs index 6b7d5bd..fdfbc46 100644 --- a/entity/src/candidate.rs +++ b/entity/src/candidate.rs @@ -19,9 +19,9 @@ pub struct Model { pub email: Option, pub sex: Option, pub study: Option, - pub personal_identification_number: Option, - #[sea_orm(column_type = "Text")] - pub personal_identification_number_hash: String, + pub personal_identification_number: String, + #[sea_orm(column_type = "Text", nullable)] + pub personal_identification_number_hash: Option, pub public_key: String, pub private_key: String, pub created_at: DateTime, @@ -30,16 +30,10 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { - #[sea_orm(has_many = "super::parent::Entity")] - Parent, #[sea_orm(has_many = "super::session::Entity")] Session, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Parent.def() - } + #[sea_orm(has_many = "super::parent::Entity")] + Parent, } impl Related for Entity { @@ -48,4 +42,10 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::Parent.def() + } +} + impl ActiveModelBehavior for ActiveModel {} diff --git a/migration/src/m20221024_121621_create_candidate.rs b/migration/src/m20221024_121621_create_candidate.rs index 66d6466..89e0522 100644 --- a/migration/src/m20221024_121621_create_candidate.rs +++ b/migration/src/m20221024_121621_create_candidate.rs @@ -30,8 +30,8 @@ impl MigrationTrait for Migration { .col(ColumnDef::new(Candidate::Email).string()) .col(ColumnDef::new(Candidate::Sex).string()) .col(ColumnDef::new(Candidate::Study).string()) - .col(ColumnDef::new(Candidate::PersonalIdentificationNumber).string()) - .col(ColumnDef::new(Candidate::PersonalIdentificationNumberHash).text().not_null()) + .col(ColumnDef::new(Candidate::PersonalIdentificationNumber).string().not_null()) + .col(ColumnDef::new(Candidate::PersonalIdentificationNumberHash).text()) .col(ColumnDef::new(Candidate::PublicKey).string().not_null()) .col(ColumnDef::new(Candidate::PrivateKey).string().not_null()) .col(ColumnDef::new(Candidate::CreatedAt).date_time().not_null()) From 74b9ec3560a5a5a2118f60602b5e14251caee095 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 12:40:43 +0100 Subject: [PATCH 10/13] chore: upgrade dependencies --- core/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 56c1c6d..7ddcf93 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,7 +13,7 @@ portfolio-entity = { path = "../entity" } serde = { version = "^1.0", features = ["derive"] } # csv -csv = "1.1" +csv = "^1.1" # error @@ -23,7 +23,7 @@ thiserror = "^1.0" dotenv = "^0.15" # async -tokio = "^1.21" +tokio = "^1.22" futures = "^0.3" async-compat = "^0.2" @@ -49,7 +49,7 @@ features = [ ] [dev-dependencies] -tokio = { version = "^1.21", features = ["macros"] } +tokio = { version = "^1.22", features = ["macros"] } async-tempfile = "^0.2" serial_test = "0.9.0" -once_cell = "1.9.0" \ No newline at end of file +once_cell = "1.9.0" \ No newline at end of file From 9957ea232f713af73bc02f2f2917c4b6aec73c03 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 22:01:11 +0100 Subject: [PATCH 11/13] refactor: code cleanup --- api/src/routes/admin.rs | 12 +- api/src/routes/candidate.rs | 134 ++++++----------------- api/src/routes/mod.rs | 12 +- core/src/candidate_details.rs | 24 ++-- core/src/database/mutation/candidate.rs | 2 +- core/src/database/mutation/parent.rs | 2 +- core/src/services/application_service.rs | 10 +- core/src/services/candidate_service.rs | 22 ++-- core/src/util.rs | 10 ++ 9 files changed, 85 insertions(+), 143 deletions(-) diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index 904527c..15f6823 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -13,6 +13,8 @@ use sea_orm_rocket::Connection; use crate::{guards::request::{auth::AdminAuth}, pool::Db, requests}; +use super::to_custom_error; + #[post("/login", data = "")] pub async fn login( conn: Connection<'_, Db>, @@ -100,7 +102,7 @@ pub async fn create_candidate( form.personal_id_number.clone(), ) .await - .map_err(|e| Custom(Status::InternalServerError, e.to_string()))?; + .map_err(to_custom_error)?; Ok( Json( @@ -131,7 +133,7 @@ pub async fn list_candidates( let candidates = CandidateService::list_candidates(private_key, db, field, page) .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap(), e.to_string()))?; + .map_err(to_custom_error)?; Ok(Json(candidates)) } @@ -151,7 +153,7 @@ pub async fn get_candidate( id ) .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap(), e.to_string()))?; + .map_err(to_custom_error)?; Ok(Json(details)) } @@ -167,7 +169,7 @@ pub async fn reset_candidate_password( let response = CandidateService::reset_password(private_key, db, id) .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap(), e.to_string()))?; + .map_err(to_custom_error)?; Ok( Json(response) @@ -183,7 +185,7 @@ pub async fn get_candidate_portfolio( let portfolio = PortfolioService::get_portfolio(id, private_key) .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap(), e.to_string()))?; + .map_err(to_custom_error)?; Ok(portfolio) } diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 2bb1233..93b4d6f 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -16,6 +16,8 @@ use crate::guards::data::letter::Letter; use crate::guards::data::portfolio::Portfolio; use crate::{guards::request::auth::CandidateAuth, pool::Db, requests}; +use super::to_custom_error; + #[post("/login", data = "")] pub async fn login( conn: Connection<'_, Db>, @@ -25,31 +27,19 @@ pub async fn login( ) -> Result> { let ip_addr: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0); let db = conn.into_inner(); - let session_token_key = CandidateService::login( + let (session_token, private_key) = CandidateService::login( db, login_form.application_id, login_form.password.to_string(), ip_addr.ip().to_string(), ) - .await; - - let Ok(session_token_key) = session_token_key else { - let e = session_token_key.unwrap_err(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or(Status::InternalServerError), - e.to_string(), - )); - }; - - let session_token = session_token_key.0; - let private_key = session_token_key.1; + .await + .map_err(to_custom_error)?; cookies.add_private(Cookie::new("id", session_token.clone())); cookies.add_private(Cookie::new("key", private_key.clone())); - let response = format!("{} {}", session_token, private_key); - - return Ok(response); + return Ok("".to_string()); } #[post("/logout")] @@ -61,14 +51,14 @@ pub async fn logout(conn: Connection<'_, Db>, _session: CandidateAuth, cookies: let session_id = Uuid::try_parse(cookie.value()) // unwrap would be safe here because of the auth guard .map_err(|e| Custom(Status::BadRequest, e.to_string()))?; - let res = CandidateService::logout(db, session_id) + CandidateService::logout(db, session_id) .await - .map_err(|e| Custom(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), e.to_string()))?; + .map_err(to_custom_error)?; cookies.remove_private(Cookie::named("id")); cookies.remove_private(Cookie::named("key")); - Ok(res) + Ok(()) } #[get("/whoami")] @@ -86,19 +76,11 @@ pub async fn post_details( ) -> Result, Custom> { let db = conn.into_inner(); let form = details.into_inner(); - let candidate: entity::candidate::Model = session.into(); // TODO: don't return candidate from session + let candidate: entity::candidate::Model = session.into(); - let candidate_parent = - ApplicationService::add_all_details(db, candidate.application, &form).await; - - if candidate_parent.is_err() { - // TODO cleanup - let e = candidate_parent.err().unwrap(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); - } + let _candidate_parent = ApplicationService::add_all_details(db, candidate.application, &form) + .await + .map_err(to_custom_error)?; Ok( Json(form) @@ -117,14 +99,10 @@ pub async fn get_details( // let handle = tokio::spawn(async move { let details = ApplicationService::decrypt_all_details(private_key, db, candidate.application) .await - .map_err(|e| { - Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - ) - }); + .map(|x| Json(x)) + .map_err(to_custom_error); - details.map(|d| Json(d)) + details } #[post("/cover_letter", data = "")] pub async fn upload_cover_letter( @@ -133,40 +111,25 @@ pub async fn upload_cover_letter( ) -> Result> { let candidate: entity::candidate::Model = session.into(); - let candidate = - PortfolioService::add_cover_letter_to_cache(candidate.application, letter.into()).await; - - if candidate.is_err() { - // TODO cleanup - let e = candidate.err().unwrap(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); - } + PortfolioService::add_cover_letter_to_cache(candidate.application, letter.into()) + .await + .map_err(to_custom_error)?; Ok("Letter added".to_string()) } #[get("/submission_progress")] pub async fn submission_progress( - conn: Connection<'_, Db>, session: CandidateAuth ) -> Result, Custom> { let candidate: entity::candidate::Model = session.into(); let progress = PortfolioService::get_submission_progress(candidate.application) .await - .map_err(|e| { - Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - ) - })?; + .map(|x| Json(x)) + .map_err(to_custom_error); - Ok( - Json(progress) - ) + progress } // TODO: JSON #[get["/is_cover_letter"]] @@ -185,17 +148,9 @@ pub async fn upload_portfolio_letter( ) -> Result> { let candidate: entity::candidate::Model = session.into(); - let candidate = - PortfolioService::add_portfolio_letter_to_cache(candidate.application, letter.into()).await; - - if candidate.is_err() { - // TODO cleanup - let e = candidate.err().unwrap(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); - } + PortfolioService::add_portfolio_letter_to_cache(candidate.application, letter.into()) + .await + .map_err(to_custom_error)?; Ok("Letter added".to_string()) } @@ -217,17 +172,9 @@ pub async fn upload_portfolio_zip( ) -> Result> { let candidate: entity::candidate::Model = session.into(); - let candidate = - PortfolioService::add_portfolio_zip_to_cache(candidate.application, portfolio.into()).await; - - if candidate.is_err() { - // TODO cleanup - let e = candidate.err().unwrap(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); - } + PortfolioService::add_portfolio_zip_to_cache(candidate.application, portfolio.into()) + .await + .map_err(to_custom_error)?; Ok("Portfolio added".to_string()) } @@ -259,19 +206,15 @@ pub async fn submit_portfolio( // TODO: VĂ­ce kontrol? if e.code() == 500 { // Cleanup - PortfolioService::delete_portfolio(candidate.application) - .await - .unwrap(); + PortfolioService::delete_portfolio(candidate.application).await.unwrap(); } - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); + return Err(to_custom_error(e)); } Ok("Portfolio submitted".to_string()) } +#[deprecated = "Use /submission_progress instead"] #[get("/is_prepared")] pub async fn is_portfolio_prepared(session: CandidateAuth) -> Result> { let candidate: entity::candidate::Model = session.into(); @@ -289,6 +232,7 @@ pub async fn is_portfolio_prepared(session: CandidateAuth) -> Result Result> { let candidate: entity::candidate::Model = session.into(); @@ -311,17 +255,11 @@ pub async fn download_portfolio(session: CandidateAuth) -> Result, Custo let private_key = session.get_private_key(); let candidate: entity::candidate::Model = session.into(); - let file = PortfolioService::get_portfolio(candidate.application, private_key).await; + let file = PortfolioService::get_portfolio(candidate.application, private_key) + .await + .map_err(to_custom_error); - if file.is_err() { - let e = file.err().unwrap(); - return Err(Custom( - Status::from_code(e.code()).unwrap_or_default(), - e.to_string(), - )); - } - - Ok(file.unwrap()) + file } #[cfg(test)] diff --git a/api/src/routes/mod.rs b/api/src/routes/mod.rs index 90ca91f..24af610 100644 --- a/api/src/routes/mod.rs +++ b/api/src/routes/mod.rs @@ -1,2 +1,12 @@ +use portfolio_core::error::ServiceError; +use rocket::{response::status::Custom, http::Status}; + pub mod admin; -pub mod candidate; \ No newline at end of file +pub mod candidate; + +pub fn to_custom_error(e: ServiceError) -> Custom { + Custom( + Status::from_code(e.code()).unwrap_or_default(), + e.to_string() + ) +} \ No newline at end of file diff --git a/core/src/candidate_details.rs b/core/src/candidate_details.rs index fb3b071..0f7db19 100644 --- a/core/src/candidate_details.rs +++ b/core/src/candidate_details.rs @@ -11,7 +11,8 @@ pub const NAIVE_DATE_FMT: &str = "%Y-%m-%d"; pub struct EncryptedString(String); impl EncryptedString { - pub async fn new(s: &str, recipients: &Vec<&str>) -> Result { + pub async fn new(s: &str, recipients: &Vec) -> Result { + let recipients = recipients.iter().map(|s| &**s).collect(); match crypto::encrypt_password_with_recipients(&s, &recipients).await { Ok(encrypted) => Ok(Self(encrypted)), Err(_) => Err(ServiceError::CryptoEncryptFailed), @@ -89,7 +90,7 @@ pub struct EncryptedApplicationDetails { impl EncryptedApplicationDetails { pub async fn new( form: &ApplicationDetails, - recipients: Vec<&str>, + recipients: Vec, ) -> Result { let birthdate_str = form.birthdate.format(NAIVE_DATE_FMT).to_string(); let d = tokio::try_join!( @@ -250,13 +251,15 @@ pub struct ApplicationDetails { pub mod tests { use std::sync::Mutex; - use chrono::NaiveDate; use once_cell::sync::Lazy; use crate::crypto; use super::{ApplicationDetails, EncryptedApplicationDetails, EncryptedString}; + const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; + const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; + pub static APPLICATION_DETAILS: Lazy> = Lazy::new(|| Mutex::new(ApplicationDetails { name: "name".to_string(), @@ -297,12 +300,9 @@ pub mod tests { #[tokio::test] async fn test_encrypted_application_details_new() { - const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; - const PRIVATE_KEY: &str = - "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; let encrypted_details = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec![PUBLIC_KEY], + vec![PUBLIC_KEY.to_string()], ) .await .unwrap(); @@ -329,13 +329,9 @@ pub mod tests { #[tokio::test] async fn test_encrypted_application_details_decrypt() { - const PUBLIC_KEY: &str = "age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"; - const PRIVATE_KEY: &str = - "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; - let encrypted_details = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec![PUBLIC_KEY], + vec![PUBLIC_KEY.to_string()], ) .await .unwrap(); @@ -377,7 +373,7 @@ pub mod tests { const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; - let encrypted = EncryptedString::new("test", &vec![PUBLIC_KEY]) + let encrypted = EncryptedString::new("test", &vec![PUBLIC_KEY.to_string()]) .await .unwrap(); @@ -395,7 +391,7 @@ pub mod tests { const PRIVATE_KEY: &str = "AGE-SECRET-KEY-14QG24502DMUUQDT2SPMX2YXPSES0X8UD6NT0PCTDAT6RH8V5Q3GQGSRXPS"; - let encrypted = EncryptedString::new("test", &vec![PUBLIC_KEY]) + let encrypted = EncryptedString::new("test", &vec![PUBLIC_KEY.to_string()]) .await .unwrap(); diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index a687ebe..8d85bab 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -114,7 +114,7 @@ mod tests { let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], + vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], ).await.unwrap(); Mutation::add_candidate_details(&db, candidate, encrypted_details).await.unwrap(); diff --git a/core/src/database/mutation/parent.rs b/core/src/database/mutation/parent.rs index 4c49ded..51586c8 100644 --- a/core/src/database/mutation/parent.rs +++ b/core/src/database/mutation/parent.rs @@ -83,7 +83,7 @@ mod tests { let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5"], + vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], ) .await .unwrap(); diff --git a/core/src/services/application_service.rs b/core/src/services/application_service.rs index 5eedd36..85b54e4 100644 --- a/core/src/services/application_service.rs +++ b/core/src/services/application_service.rs @@ -1,7 +1,7 @@ use entity::{candidate, parent}; use sea_orm::DbConn; -use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query}; +use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query, util::get_recipients}; use super::{parent_service::ParentService, candidate_service::CandidateService}; @@ -41,13 +41,7 @@ impl ApplicationService { .await? .ok_or(ServiceError::ParentNotFound)?; - let admin_public_keys = Query::get_all_admin_public_keys(db).await?; - - let mut admin_public_keys_refrence: Vec<&str> = - admin_public_keys.iter().map(|s| &**s).collect(); - - let mut recipients = vec![&*candidate.public_key]; - recipients.append(&mut admin_public_keys_refrence); + let recipients = get_recipients(db, &candidate.public_key).await?; let enc_details = EncryptedApplicationDetails::new(form, recipients).await?; diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index ee4be52..80c37b3 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -7,7 +7,7 @@ use crate::{ candidate_details::{EncryptedApplicationDetails, EncryptedString}, crypto::{self, hash_password}, error::ServiceError, - Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, + Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, util::get_recipients, }; use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService}; @@ -69,8 +69,7 @@ impl CandidateService { // Check if user with that application id already exists if Query::find_candidate_by_id(db, application_id) - .await - .unwrap() + .await? .is_some() { return Err(ServiceError::UserAlreadyExists); @@ -85,10 +84,7 @@ impl CandidateService { crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await?; - let admin_public_keys = Query::get_all_admin_public_keys(db).await?; - let mut admin_public_keys_ref = admin_public_keys.iter().map(|s| &**s).collect(); - let mut recipients = vec![&*pubkey]; - recipients.append(&mut admin_public_keys_ref); + let recipients = get_recipients(db, &pubkey).await?; let enc_personal_id_number = EncryptedString::new( &personal_id_number, @@ -237,14 +233,10 @@ impl CandidateService { let session_id = SessionService::new_session(db, Some(candidate_id), None, password.clone(), ip_addr) - .await; - match session_id { - Ok(session_id) => { - let private_key = Self::decrypt_private_key(candidate, password).await?; - Ok((session_id, private_key)) - } - Err(e) => Err(e), - } + .await?; + + let private_key = Self::decrypt_private_key(candidate, password).await?; + Ok((session_id, private_key)) } pub async fn auth(db: &DbConn, session_uuid: Uuid) -> Result { diff --git a/core/src/util.rs b/core/src/util.rs index a988644..cc71e0e 100644 --- a/core/src/util.rs +++ b/core/src/util.rs @@ -2,6 +2,16 @@ use entity::{admin, candidate, parent, session}; use sea_orm::{Schema, Database, DbConn}; use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, DbBackend}; +use crate::Query; +use crate::error::ServiceError; + +pub async fn get_recipients(db: &DbConn, candidate_pubkey: &str) -> Result, ServiceError> { + let mut admin_public_keys = Query::get_all_admin_public_keys(db).await?; + let mut recipients = vec![candidate_pubkey.to_string()]; + recipients.append(&mut admin_public_keys); + Ok(recipients) +} + pub async fn get_memory_sqlite_connection() -> sea_orm::DbConn { let base_url = "sqlite::memory:"; From 7d5fa1246537d3b9f4849eff5a701c4c7106b296 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 23:07:01 +0100 Subject: [PATCH 12/13] refactor: code cleanup --- core/src/services/candidate_service.rs | 26 ++++++++------------------ core/src/services/portfolio_service.rs | 8 ++++++++ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 80c37b3..f067ea8 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -1,5 +1,3 @@ -use std::path::{Path, PathBuf}; - use entity::candidate; use sea_orm::{prelude::Uuid, DbConn}; @@ -10,7 +8,7 @@ use crate::{ Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, util::get_recipients, }; -use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService}; +use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService, portfolio_service::PortfolioService}; // TODO @@ -45,12 +43,6 @@ const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"]; pub struct CandidateService; impl CandidateService { - // Get root path or local directory - fn get_file_store_path() -> PathBuf { - dotenv::dotenv().ok(); - Path::new(&std::env::var("STORE_PATH").unwrap_or_else(|_| "".to_string())).to_path_buf() - } - /// Creates a new candidate with: /// Encrypted personal identification number /// Hashed password @@ -74,25 +66,22 @@ impl CandidateService { { return Err(ServiceError::UserAlreadyExists); } + PortfolioService::create_user_dir(application_id).await?; let hashed_password = hash_password(plain_text_password.to_string()).await?; - let (pubkey, priv_key_plain_text) = crypto::create_identity(); - - let encrypted_priv_key = - crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await?; - + let encrypted_priv_key = crypto::encrypt_password( + priv_key_plain_text, + plain_text_password.to_string() + ).await?; let recipients = get_recipients(db, &pubkey).await?; - let enc_personal_id_number = EncryptedString::new( &personal_id_number, &recipients, ).await?; - tokio::fs::create_dir_all(Self::get_file_store_path().join(&application_id.to_string()).join("cache")).await?; - let candidate = Mutation::create_candidate( db, application_id, @@ -101,7 +90,8 @@ impl CandidateService { pubkey, encrypted_priv_key, ) - .await?; + .await?; + Ok(candidate) } diff --git a/core/src/services/portfolio_service.rs b/core/src/services/portfolio_service.rs index 6917dca..4251519 100644 --- a/core/src/services/portfolio_service.rs +++ b/core/src/services/portfolio_service.rs @@ -145,6 +145,14 @@ impl PortfolioService { Ok(()) } + pub async fn create_user_dir(application_id: i32) -> tokio::io::Result<()> { + tokio::fs::create_dir_all( + Self::get_file_store_path() + .join(&application_id.to_string()) + .join("cache")) + .await + } + pub async fn add_cover_letter_to_cache( candidate_id: i32, From 4620ed2aeb8ff19d3cc6525ad3420ce9c059ee8b Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 27 Nov 2022 23:13:01 +0100 Subject: [PATCH 13/13] refactor: move filetype.rs, util.rs to utils directory --- api/src/guards/data/letter.rs | 2 +- api/src/guards/data/portfolio.rs | 2 +- api/src/pool.rs | 2 +- core/src/database/mutation/candidate.rs | 2 +- core/src/database/mutation/parent.rs | 2 +- core/src/database/query/admin.rs | 2 +- core/src/database/query/candidate.rs | 2 +- core/src/database/query/parent.rs | 2 +- core/src/database/query/session.rs | 2 +- core/src/lib.rs | 2 -- core/src/services/admin_service.rs | 2 +- core/src/services/application_service.rs | 2 +- core/src/services/candidate_service.rs | 4 ++-- core/src/services/portfolio_service.rs | 2 +- core/src/services/session_service.rs | 2 +- core/src/{util.rs => utils/db.rs} | 0 core/src/{ => utils}/filetype.rs | 0 core/src/utils/mod.rs | 4 +++- 18 files changed, 18 insertions(+), 18 deletions(-) rename core/src/{util.rs => utils/db.rs} (100%) rename core/src/{ => utils}/filetype.rs (100%) diff --git a/api/src/guards/data/letter.rs b/api/src/guards/data/letter.rs index ed4f6e3..58ee4e2 100644 --- a/api/src/guards/data/letter.rs +++ b/api/src/guards/data/letter.rs @@ -31,7 +31,7 @@ impl<'r> FromData<'r> for Letter { let data_bytes = data_bytes.into_inner(); - let is_pdf = portfolio_core::filetype::filetype_is_pdf(&data_bytes); + let is_pdf = portfolio_core::utils::filetype::filetype_is_pdf(&data_bytes); if !is_pdf { // TODO: Not PDF diff --git a/api/src/guards/data/portfolio.rs b/api/src/guards/data/portfolio.rs index 623c589..9029220 100644 --- a/api/src/guards/data/portfolio.rs +++ b/api/src/guards/data/portfolio.rs @@ -31,7 +31,7 @@ impl<'r> FromData<'r> for Portfolio { let data_bytes = data_bytes.into_inner(); - let is_zip = portfolio_core::filetype::filetype_is_zip(&data_bytes); + let is_zip = portfolio_core::utils::filetype::filetype_is_zip(&data_bytes); if !is_zip { // TODO: Not ZIP diff --git a/api/src/pool.rs b/api/src/pool.rs index d3a45a6..539259c 100644 --- a/api/src/pool.rs +++ b/api/src/pool.rs @@ -23,7 +23,7 @@ impl sea_orm_rocket::Pool for SeaOrmPool { #[cfg(test)] async fn init(_figment: &Figment) -> Result { - let conn = portfolio_core::util::get_memory_sqlite_connection().await; + let conn = portfolio_core::utils::db::get_memory_sqlite_connection().await; crate::test::tests::run_test_migrations(&conn).await; return Ok(Self { conn }); } diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index 8d85bab..dbc2f55 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -69,7 +69,7 @@ impl Mutation { mod tests { use crate::candidate_details::tests::APPLICATION_DETAILS; use crate::candidate_details::{EncryptedApplicationDetails}; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; use crate::{Mutation, Query}; #[tokio::test] diff --git a/core/src/database/mutation/parent.rs b/core/src/database/mutation/parent.rs index 51586c8..c31298c 100644 --- a/core/src/database/mutation/parent.rs +++ b/core/src/database/mutation/parent.rs @@ -36,7 +36,7 @@ impl Mutation { mod tests { use crate::candidate_details::tests::APPLICATION_DETAILS; use crate::candidate_details::{EncryptedApplicationDetails}; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; use crate::{Mutation, Query}; #[tokio::test] diff --git a/core/src/database/query/admin.rs b/core/src/database/query/admin.rs index de61db1..307d13f 100644 --- a/core/src/database/query/admin.rs +++ b/core/src/database/query/admin.rs @@ -25,7 +25,7 @@ mod tests { use entity::admin; use sea_orm::{ActiveModelTrait, Set}; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; use crate::Query; #[tokio::test] diff --git a/core/src/database/query/candidate.rs b/core/src/database/query/candidate.rs index 4bf96d6..ae24441 100644 --- a/core/src/database/query/candidate.rs +++ b/core/src/database/query/candidate.rs @@ -122,7 +122,7 @@ mod tests { use entity::candidate; use crate::Query; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; #[tokio::test] async fn test_find_candidate_by_id() { diff --git a/core/src/database/query/parent.rs b/core/src/database/query/parent.rs index c53e443..787b85c 100644 --- a/core/src/database/query/parent.rs +++ b/core/src/database/query/parent.rs @@ -22,7 +22,7 @@ mod tests { use sea_orm::{ActiveModelTrait, Set}; use crate::Query; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; #[tokio::test] async fn test_find_parent_by_id() { diff --git a/core/src/database/query/session.rs b/core/src/database/query/session.rs index 6a1eb14..10aed95 100644 --- a/core/src/database/query/session.rs +++ b/core/src/database/query/session.rs @@ -35,7 +35,7 @@ mod tests { use entity::{session}; use sea_orm::{prelude::Uuid, ActiveModelTrait, Set}; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; use crate::Query; #[tokio::test] diff --git a/core/src/lib.rs b/core/src/lib.rs index dd3e5c8..e58447a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,11 +5,9 @@ pub use database::query::*; pub mod database; pub mod crypto; -pub mod filetype; pub mod services; pub mod error; pub mod candidate_details; -pub mod util; pub mod responses; pub mod utils; diff --git a/core/src/services/admin_service.rs b/core/src/services/admin_service.rs index fd7a62a..f393102 100644 --- a/core/src/services/admin_service.rs +++ b/core/src/services/admin_service.rs @@ -57,7 +57,7 @@ mod admin_tests { use entity::admin; use sea_orm::{Set, ActiveModelTrait}; - use crate::{util::get_memory_sqlite_connection, error::ServiceError}; + use crate::{utils::db::get_memory_sqlite_connection, error::ServiceError}; use super::*; diff --git a/core/src/services/application_service.rs b/core/src/services/application_service.rs index 85b54e4..e245a4b 100644 --- a/core/src/services/application_service.rs +++ b/core/src/services/application_service.rs @@ -1,7 +1,7 @@ use entity::{candidate, parent}; use sea_orm::DbConn; -use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query, util::get_recipients}; +use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query, utils::db::get_recipients}; use super::{parent_service::ParentService, candidate_service::CandidateService}; diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index f067ea8..34cd9b5 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -5,7 +5,7 @@ use crate::{ candidate_details::{EncryptedApplicationDetails, EncryptedString}, crypto::{self, hash_password}, error::ServiceError, - Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, util::get_recipients, + Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, utils::db::get_recipients, }; use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService, portfolio_service::PortfolioService}; @@ -255,7 +255,7 @@ pub mod tests { use sea_orm::{DbConn}; use crate::candidate_details::tests::assert_all_application_details; - use crate::util::get_memory_sqlite_connection; + use crate::utils::db::get_memory_sqlite_connection; use crate::{crypto, services::candidate_service::CandidateService, Mutation}; use super::EncryptedApplicationDetails; diff --git a/core/src/services/portfolio_service.rs b/core/src/services/portfolio_service.rs index 4251519..89deb3b 100644 --- a/core/src/services/portfolio_service.rs +++ b/core/src/services/portfolio_service.rs @@ -332,7 +332,7 @@ impl PortfolioService { mod tests { use serial_test::serial; - use crate::{services::{portfolio_service::{PortfolioService, FileType}, candidate_service::{CandidateService, tests::put_user_data}}, util::get_memory_sqlite_connection, crypto}; + use crate::{services::{portfolio_service::{PortfolioService, FileType}, candidate_service::{CandidateService, tests::put_user_data}}, utils::db::get_memory_sqlite_connection, crypto}; use std::path::PathBuf; const APPLICATION_ID: i32 = 103151; diff --git a/core/src/services/session_service.rs b/core/src/services/session_service.rs index 08c9bac..389c712 100644 --- a/core/src/services/session_service.rs +++ b/core/src/services/session_service.rs @@ -172,7 +172,7 @@ mod tests { use crate::{ crypto, services::{application_service::ApplicationService, session_service::SessionService}, - util::get_memory_sqlite_connection, + utils::db::get_memory_sqlite_connection, }; #[tokio::test] diff --git a/core/src/util.rs b/core/src/utils/db.rs similarity index 100% rename from core/src/util.rs rename to core/src/utils/db.rs diff --git a/core/src/filetype.rs b/core/src/utils/filetype.rs similarity index 100% rename from core/src/filetype.rs rename to core/src/utils/filetype.rs diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index a89587e..d498f2d 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -1 +1,3 @@ -pub mod csv; \ No newline at end of file +pub mod csv; +pub mod filetype; +pub mod db; \ No newline at end of file