mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-18 14:01:04 +00:00
Merge pull request #76 from EETagent/multiple_parents
(backend) Multiple parents
This commit is contained in:
commit
2fd479a0e1
14 changed files with 516 additions and 248 deletions
|
|
@ -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}, models::candidate::{BaseCandidateResponse, CreateCandidateResponse, ApplicationDetails}, sea_orm::prelude::Uuid,
|
||||
services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, models::candidate::{BaseCandidateResponse, CreateCandidateResponse, ApplicationDetails}, sea_orm::prelude::Uuid, Query, error::ServiceError,
|
||||
};
|
||||
use requests::{AdminLoginRequest, RegisterRequest};
|
||||
use rocket::http::{Cookie, Status, CookieJar};
|
||||
|
|
@ -146,10 +146,15 @@ pub async fn get_candidate(
|
|||
let db = conn.into_inner();
|
||||
let private_key = session.get_private_key();
|
||||
|
||||
let candidate = Query::find_candidate_by_id(db, id)
|
||||
.await
|
||||
.map_err(|e| to_custom_error(ServiceError::Forbidden))? // TODO better error handling
|
||||
.ok_or(to_custom_error(ServiceError::CandidateNotFound))?;
|
||||
|
||||
let details = ApplicationService::decrypt_all_details(
|
||||
private_key,
|
||||
db,
|
||||
id
|
||||
candidate
|
||||
)
|
||||
.await
|
||||
.map_err(to_custom_error)?;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ pub async fn post_details(
|
|||
let form = details.into_inner();
|
||||
let candidate: entity::candidate::Model = session.into();
|
||||
|
||||
let _candidate_parent = ApplicationService::add_all_details(db, candidate.application, &form)
|
||||
let _candidate_parent = ApplicationService::add_all_details(db, candidate, &form)
|
||||
.await
|
||||
.map_err(to_custom_error)?;
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ pub async fn get_details(
|
|||
let candidate: entity::candidate::Model = session.into();
|
||||
|
||||
// let handle = tokio::spawn(async move {
|
||||
let details = ApplicationService::decrypt_all_details(private_key, db, candidate.application)
|
||||
let details = ApplicationService::decrypt_all_details(private_key, db, candidate)
|
||||
.await
|
||||
.map(|x| Json(x))
|
||||
.map_err(to_custom_error);
|
||||
|
|
@ -284,21 +284,27 @@ mod tests {
|
|||
}
|
||||
|
||||
const CANDIDATE_DETAILS: &'static str = "{
|
||||
\"name\": \"idk\",
|
||||
\"surname\": \"idk\",
|
||||
\"birthplace\": \"Praha 1\",
|
||||
\"birthdate\": \"2015-09-18\",
|
||||
\"address\": \"Stefanikova jidelna\",
|
||||
\"telephone\": \"000111222333\",
|
||||
\"citizenship\": \"Czech Republic\",
|
||||
\"email\": \"magor@magor.cz\",
|
||||
\"sex\": \"MALE\",
|
||||
\"personalIdNumber\": \"0000000000\",
|
||||
\"study\": \"KB\",
|
||||
\"parentName\": \"maminka\",
|
||||
\"parentSurname\": \"chad\",
|
||||
\"parentTelephone\": \"420111222333\",
|
||||
\"parentEmail\": \"maminka@centrum.cz\"
|
||||
\"candidate\": {
|
||||
\"name\": \"idk\",
|
||||
\"surname\": \"idk\",
|
||||
\"birthplace\": \"Praha 1\",
|
||||
\"birthdate\": \"2015-09-18\",
|
||||
\"address\": \"Stefanikova jidelna\",
|
||||
\"telephone\": \"000111222333\",
|
||||
\"citizenship\": \"Czech Republic\",
|
||||
\"email\": \"magor@magor.cz\",
|
||||
\"sex\": \"MALE\",
|
||||
\"personalIdNumber\": \"0000000000\",
|
||||
\"study\": \"KB\"
|
||||
},
|
||||
\"parents\": [
|
||||
{
|
||||
\"name\": \"maminka\",
|
||||
\"surname\": \"chad\",
|
||||
\"telephone\": \"420111222333\",
|
||||
\"email\": \"maminka@centrum.cz\"
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Mutation, models::candidate_details::EncryptedApplicationDetails};
|
||||
use crate::{Mutation, models::candidate_details::{EncryptedCandidateDetails}};
|
||||
|
||||
use ::entity::candidate::{self};
|
||||
use sea_orm::*;
|
||||
|
|
@ -44,20 +44,20 @@ impl Mutation {
|
|||
pub async fn add_candidate_details(
|
||||
db: &DbConn,
|
||||
user: candidate::Model,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
enc_candidate: EncryptedCandidateDetails,
|
||||
) -> Result<candidate::Model, sea_orm::DbErr> {
|
||||
let mut user: candidate::ActiveModel = user.into();
|
||||
user.name = Set(Some(enc_details.name.into()));
|
||||
user.surname = Set(Some(enc_details.surname.into()));
|
||||
user.birthplace = Set(Some(enc_details.birthplace.into()));
|
||||
user.birthdate = Set(Some(enc_details.birthdate.into()));
|
||||
user.address = Set(Some(enc_details.address.into()));
|
||||
user.telephone = Set(Some(enc_details.telephone.into()));
|
||||
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(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.name = Set(Some(enc_candidate.name.into()));
|
||||
user.surname = Set(Some(enc_candidate.surname.into()));
|
||||
user.birthplace = Set(Some(enc_candidate.birthplace.into()));
|
||||
user.birthdate = Set(Some(enc_candidate.birthdate.into()));
|
||||
user.address = Set(Some(enc_candidate.address.into()));
|
||||
user.telephone = Set(Some(enc_candidate.telephone.into()));
|
||||
user.citizenship = Set(Some(enc_candidate.citizenship.into()));
|
||||
user.email = Set(Some(enc_candidate.email.into()));
|
||||
user.sex = Set(Some(enc_candidate.sex.into()));
|
||||
user.personal_identification_number = Set(enc_candidate.personal_id_number.into()); // TODO: do not set this here, it is already set in the create_candidate mutation???
|
||||
user.study = Set(Some(enc_candidate.study.into()));
|
||||
|
||||
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ mod tests {
|
|||
vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
|
||||
).await.unwrap();
|
||||
|
||||
Mutation::add_candidate_details(&db, candidate, encrypted_details).await.unwrap();
|
||||
Mutation::add_candidate_details(&db, candidate, encrypted_details.candidate).await.unwrap();
|
||||
|
||||
let candidate = Query::find_candidate_by_id(&db, APPLICATION_ID)
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Mutation, models::candidate_details::EncryptedApplicationDetails};
|
||||
use crate::{Mutation, models::candidate_details::{EncryptedParentDetails}};
|
||||
|
||||
use ::entity::parent::{self, Model};
|
||||
use sea_orm::*;
|
||||
|
|
@ -18,17 +18,17 @@ impl Mutation {
|
|||
pub async fn add_parent_details(
|
||||
db: &DbConn,
|
||||
parent: Model,
|
||||
enc_details: EncryptedApplicationDetails, // TODO: use seperate struct??
|
||||
enc_parent: EncryptedParentDetails,
|
||||
) -> Result<Model, sea_orm::DbErr> {
|
||||
let mut user: parent::ActiveModel = parent.into();
|
||||
user.name = Set(Some(enc_details.parent_name.into()));
|
||||
user.surname = Set(Some(enc_details.parent_surname.into()));
|
||||
user.telephone = Set(Some(enc_details.parent_telephone.into()));
|
||||
user.email = Set(Some(enc_details.parent_email.into()));
|
||||
let mut parent: parent::ActiveModel = parent.into();
|
||||
parent.name = Set(Some(enc_parent.name.into()));
|
||||
parent.surname = Set(Some(enc_parent.surname.into()));
|
||||
parent.telephone = Set(Some(enc_parent.telephone.into()));
|
||||
parent.email = Set(Some(enc_parent.email.into()));
|
||||
|
||||
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||
parent.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||
|
||||
user.update(db).await
|
||||
parent.update(db).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,9 +56,9 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
Mutation::create_parent(&db, APPLICATION_ID).await.unwrap();
|
||||
let new_parent = Mutation::create_parent(&db, APPLICATION_ID).await.unwrap();
|
||||
|
||||
let parent = Query::find_parent_by_id(&db, APPLICATION_ID).await.unwrap();
|
||||
let parent = Query::find_parent_by_id(&db, new_parent.id).await.unwrap();
|
||||
assert!(parent.is_some());
|
||||
}
|
||||
|
||||
|
|
@ -88,11 +88,11 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
Mutation::add_parent_details(&db, parent, encrypted_details)
|
||||
Mutation::add_parent_details(&db, parent.clone(), encrypted_details.parents[0].clone())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let parent = Query::find_parent_by_id(&db, APPLICATION_ID)
|
||||
let parent = Query::find_parent_by_id(&db, parent.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,18 +1,33 @@
|
|||
|
||||
use entity::candidate;
|
||||
use entity::parent;
|
||||
use entity::parent::Model;
|
||||
use entity::parent::Entity;
|
||||
use sea_orm::ModelTrait;
|
||||
use sea_orm::{DbConn, DbErr};
|
||||
use sea_orm::EntityTrait;
|
||||
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
#[deprecated(note = "Use find_candidate_parents instead")]
|
||||
pub async fn find_parent_by_id(
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
id: i32,
|
||||
) -> Result<Option<Model>, DbErr> {
|
||||
|
||||
Entity::find_by_id(application_id).one(db).await
|
||||
Entity::find_by_id(id).one(db).await
|
||||
}
|
||||
|
||||
// TODO limit to two parents??
|
||||
pub async fn find_candidate_parents(
|
||||
db: &DbConn,
|
||||
candidate: candidate::Model,
|
||||
) -> Result<Vec<Model>, DbErr> {
|
||||
|
||||
candidate.find_related(parent::Entity)
|
||||
.all(db)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ pub enum ServiceError {
|
|||
#[error("Parrent not found")]
|
||||
ParentNotFound,
|
||||
#[error("Database error")]
|
||||
ParentOverflow,
|
||||
#[error("Too many parents")]
|
||||
DbError(#[from] sea_orm::DbErr),
|
||||
#[error("User not found, please contact technical support")]
|
||||
UserNotFoundByJwtId,
|
||||
|
|
@ -78,6 +80,7 @@ impl ServiceError {
|
|||
ServiceError::UserAlreadyExists => 409,
|
||||
ServiceError::CandidateNotFound => 404,
|
||||
ServiceError::ParentNotFound => 500,
|
||||
ServiceError::ParentOverflow => 400, // TODO: correct error code
|
||||
ServiceError::DbError(_) => 500,
|
||||
ServiceError::UserNotFoundByJwtId => 500,
|
||||
ServiceError::UserNotFoundBySessionId => 500,
|
||||
|
|
|
|||
|
|
@ -27,11 +27,10 @@ pub struct BaseCandidateResponse {
|
|||
pub submitted: bool,
|
||||
}
|
||||
|
||||
/// Candidate details (admin and candidate endpoints)
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApplicationDetails {
|
||||
// Candidate
|
||||
pub struct CandidateDetails {
|
||||
// pub application_id: i32,
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
pub birthplace: String,
|
||||
|
|
@ -43,11 +42,24 @@ pub struct ApplicationDetails {
|
|||
pub sex: String,
|
||||
pub study: String,
|
||||
pub personal_id_number: String,
|
||||
// Parent
|
||||
pub parent_name: String,
|
||||
pub parent_surname: String,
|
||||
pub parent_telephone: String,
|
||||
pub parent_email: String,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParentDetails {
|
||||
// pub application_id: i32,
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
pub telephone: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
/// Candidate details (admin and candidate endpoints)
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApplicationDetails {
|
||||
// Candidate
|
||||
pub candidate: CandidateDetails,
|
||||
pub parents: Vec<ParentDetails>,
|
||||
}
|
||||
|
||||
/// CSV export (admin endpoint)
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@ use entity::{candidate, parent};
|
|||
|
||||
use crate::{crypto, models::candidate::{CandidateWithParent, ApplicationDetails}, error::ServiceError};
|
||||
|
||||
use super::candidate::{CandidateDetails, ParentDetails};
|
||||
|
||||
pub const NAIVE_DATE_FMT: &str = "%Y-%m-%d";
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EncryptedString(String);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EncryptedApplicationDetails {
|
||||
// Candidate
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EncryptedCandidateDetails {
|
||||
pub name: EncryptedString,
|
||||
pub surname: EncryptedString,
|
||||
pub birthplace: EncryptedString,
|
||||
|
|
@ -23,12 +24,19 @@ pub struct EncryptedApplicationDetails {
|
|||
pub sex: EncryptedString,
|
||||
pub personal_id_number: EncryptedString,
|
||||
pub study: String,
|
||||
}
|
||||
|
||||
// Parent
|
||||
pub parent_name: EncryptedString,
|
||||
pub parent_surname: EncryptedString,
|
||||
pub parent_telephone: EncryptedString,
|
||||
pub parent_email: EncryptedString,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EncryptedParentDetails {
|
||||
pub name: EncryptedString,
|
||||
pub surname: EncryptedString,
|
||||
pub telephone: EncryptedString,
|
||||
pub email: EncryptedString,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EncryptedApplicationDetails {
|
||||
pub candidate: EncryptedCandidateDetails,
|
||||
pub parents: Vec<EncryptedParentDetails>,
|
||||
}
|
||||
|
||||
impl EncryptedString {
|
||||
|
|
@ -86,11 +94,11 @@ impl TryFrom<Option<NaiveDate>> for EncryptedString {
|
|||
}
|
||||
}
|
||||
|
||||
impl EncryptedApplicationDetails {
|
||||
impl EncryptedCandidateDetails {
|
||||
pub async fn new(
|
||||
form: &ApplicationDetails,
|
||||
form: &CandidateDetails,
|
||||
recipients: Vec<String>,
|
||||
) -> Result<EncryptedApplicationDetails, ServiceError> {
|
||||
) -> Result<EncryptedCandidateDetails, ServiceError> {
|
||||
let birthdate_str = form.birthdate.format(NAIVE_DATE_FMT).to_string();
|
||||
let d = tokio::try_join!(
|
||||
EncryptedString::new(&form.name, &recipients),
|
||||
|
|
@ -103,34 +111,26 @@ impl EncryptedApplicationDetails {
|
|||
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),
|
||||
EncryptedString::new(&form.parent_telephone, &recipients),
|
||||
EncryptedString::new(&form.parent_email, &recipients),
|
||||
)?;
|
||||
|
||||
Ok(EncryptedApplicationDetails {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
birthplace: d.2,
|
||||
birthdate: d.3,
|
||||
address: d.4,
|
||||
telephone: d.5,
|
||||
citizenship: d.6,
|
||||
email: d.7,
|
||||
sex: d.8,
|
||||
personal_id_number: d.9,
|
||||
study: form.study.clone(),
|
||||
|
||||
parent_name: d.10,
|
||||
parent_surname: d.11,
|
||||
parent_telephone: d.12,
|
||||
parent_email: d.13,
|
||||
})
|
||||
Ok(
|
||||
EncryptedCandidateDetails {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
birthplace: d.2,
|
||||
birthdate: d.3,
|
||||
address: d.4,
|
||||
telephone: d.5,
|
||||
citizenship: d.6,
|
||||
email: d.7,
|
||||
sex: d.8,
|
||||
personal_id_number: d.9,
|
||||
study: form.study.clone(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn decrypt(self, priv_key: String) -> Result<ApplicationDetails, ServiceError> {
|
||||
pub async fn decrypt(self, priv_key: String) -> Result<CandidateDetails, ServiceError> {
|
||||
let d = tokio::try_join!(
|
||||
self.name.decrypt(&priv_key), // 0
|
||||
self.surname.decrypt(&priv_key), // 1
|
||||
|
|
@ -142,56 +142,153 @@ impl EncryptedApplicationDetails {
|
|||
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 {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
birthplace: d.2,
|
||||
birthdate: NaiveDate::parse_from_str(&d.3, NAIVE_DATE_FMT).unwrap(), // TODO
|
||||
address: d.4,
|
||||
telephone: d.5,
|
||||
citizenship: d.6,
|
||||
email: d.7,
|
||||
sex: d.8,
|
||||
personal_id_number: d.9,
|
||||
study: self.study,
|
||||
Ok(CandidateDetails {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
birthplace: d.2,
|
||||
birthdate: NaiveDate::parse_from_str(&d.3, NAIVE_DATE_FMT).unwrap(), // TODO
|
||||
address: d.4,
|
||||
telephone: d.5,
|
||||
citizenship: d.6,
|
||||
email: d.7,
|
||||
sex: d.8,
|
||||
personal_id_number: d.9,
|
||||
study: self.study,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
impl TryFrom<candidate::Model> for EncryptedCandidateDetails {
|
||||
type Error = ServiceError;
|
||||
|
||||
parent_name: d.10,
|
||||
parent_surname: d.11,
|
||||
parent_telephone: d.12,
|
||||
parent_email: d.13,
|
||||
fn try_from(
|
||||
candidate: candidate::Model,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(
|
||||
EncryptedCandidateDetails {
|
||||
name: EncryptedString::try_from(candidate.name)?,
|
||||
surname: EncryptedString::try_from(candidate.surname)?,
|
||||
birthplace: EncryptedString::try_from(candidate.birthplace)?,
|
||||
birthdate: EncryptedString::try_from(candidate.birthdate)?,
|
||||
address: EncryptedString::try_from(candidate.address)?,
|
||||
telephone: EncryptedString::try_from(candidate.telephone)?,
|
||||
citizenship: EncryptedString::try_from(candidate.citizenship)?,
|
||||
email: EncryptedString::try_from(candidate.email)?,
|
||||
sex: EncryptedString::try_from(candidate.sex)?,
|
||||
personal_id_number: EncryptedString::from(candidate.personal_identification_number),
|
||||
study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl EncryptedParentDetails {
|
||||
pub async fn new(
|
||||
form: &ParentDetails,
|
||||
recipients: Vec<String>,
|
||||
) -> Result<EncryptedParentDetails, ServiceError> {
|
||||
let d = tokio::try_join!(
|
||||
EncryptedString::new(&form.name, &recipients),
|
||||
EncryptedString::new(&form.surname, &recipients),
|
||||
EncryptedString::new(&form.telephone, &recipients),
|
||||
EncryptedString::new(&form.email, &recipients),
|
||||
)?;
|
||||
|
||||
Ok(
|
||||
EncryptedParentDetails {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
telephone: d.2,
|
||||
email: d.3,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn decrypt(&self, priv_key: String) -> Result<ParentDetails, ServiceError> {
|
||||
let d = tokio::try_join!(
|
||||
self.name.decrypt(&priv_key),
|
||||
self.surname.decrypt(&priv_key),
|
||||
self.telephone.decrypt(&priv_key),
|
||||
self.email.decrypt(&priv_key),
|
||||
)?;
|
||||
|
||||
Ok(ParentDetails {
|
||||
name: d.0,
|
||||
surname: d.1,
|
||||
telephone: d.2,
|
||||
email: d.3,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
impl TryFrom<parent::Model> for EncryptedParentDetails {
|
||||
type Error = ServiceError;
|
||||
|
||||
fn try_from(
|
||||
parent: parent::Model,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(EncryptedParentDetails {
|
||||
name: EncryptedString::try_from(parent.name)?,
|
||||
surname: EncryptedString::try_from(parent.surname)?,
|
||||
telephone: EncryptedString::try_from(parent.telephone)?,
|
||||
email: EncryptedString::try_from(parent.email)?,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl EncryptedApplicationDetails {
|
||||
pub async fn new(
|
||||
form: &ApplicationDetails,
|
||||
recipients: Vec<String>,
|
||||
) -> Result<EncryptedApplicationDetails, ServiceError> {
|
||||
let candidate = EncryptedCandidateDetails::new(&form.candidate, recipients.clone()).await?;
|
||||
let mut enc_parents= vec![];
|
||||
for parent in form.parents.iter() {
|
||||
enc_parents.push(
|
||||
EncryptedParentDetails::new(parent, recipients.clone()).await?
|
||||
);
|
||||
}
|
||||
Ok(
|
||||
EncryptedApplicationDetails {
|
||||
candidate,
|
||||
parents: enc_parents,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn decrypt(self, priv_key: String) -> Result<ApplicationDetails, ServiceError> {
|
||||
let candidate = self.candidate.decrypt(priv_key.clone()).await?;
|
||||
let mut parents = vec![];
|
||||
for parent in self.parents.iter() {
|
||||
let dec = parent.decrypt(priv_key.clone()).await?;
|
||||
parents.push(dec);
|
||||
}
|
||||
Ok(ApplicationDetails {
|
||||
candidate,
|
||||
parents: parents,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(candidate::Model, parent::Model)> for EncryptedApplicationDetails {
|
||||
// TODO: use different metehod for this
|
||||
impl TryFrom<(candidate::Model, Vec<parent::Model>)> for EncryptedApplicationDetails {
|
||||
type Error = ServiceError;
|
||||
|
||||
fn try_from(
|
||||
(candidate, parent): (candidate::Model, parent::Model),
|
||||
(candidate, parents): (candidate::Model, Vec<parent::Model>),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let mut enc_parents = vec![];
|
||||
for parent in parents.iter() {
|
||||
enc_parents.push(
|
||||
EncryptedParentDetails::try_from(parent.clone())?
|
||||
);
|
||||
}
|
||||
Ok(EncryptedApplicationDetails {
|
||||
name: EncryptedString::try_from(candidate.name)?,
|
||||
surname: EncryptedString::try_from(candidate.surname)?,
|
||||
birthplace: EncryptedString::try_from(candidate.birthplace)?,
|
||||
birthdate: EncryptedString::try_from(candidate.birthdate)?,
|
||||
address: EncryptedString::try_from(candidate.address)?,
|
||||
telephone: EncryptedString::try_from(candidate.telephone)?,
|
||||
citizenship: EncryptedString::try_from(candidate.citizenship)?,
|
||||
email: EncryptedString::try_from(candidate.email)?,
|
||||
sex: EncryptedString::try_from(candidate.sex)?,
|
||||
personal_id_number: EncryptedString::from(candidate.personal_identification_number),
|
||||
study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?,
|
||||
|
||||
parent_name: EncryptedString::try_from(parent.name)?,
|
||||
parent_surname: EncryptedString::try_from(parent.surname)?,
|
||||
parent_telephone: EncryptedString::try_from(parent.telephone)?,
|
||||
parent_email: EncryptedString::try_from(parent.email)?,
|
||||
candidate: EncryptedCandidateDetails::try_from(candidate)?,
|
||||
parents: enc_parents,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -203,22 +300,26 @@ impl TryFrom<CandidateWithParent> for EncryptedApplicationDetails {
|
|||
cp: CandidateWithParent,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(EncryptedApplicationDetails {
|
||||
name: EncryptedString::try_from(cp.name)?,
|
||||
surname: EncryptedString::try_from(cp.surname)?,
|
||||
birthplace: EncryptedString::try_from(cp.birthplace)?,
|
||||
birthdate: EncryptedString::try_from(cp.birthdate)?,
|
||||
address: EncryptedString::try_from(cp.address)?,
|
||||
telephone: EncryptedString::try_from(cp.telephone)?,
|
||||
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)?,
|
||||
candidate: EncryptedCandidateDetails {
|
||||
name: EncryptedString::try_from(cp.name)?,
|
||||
surname: EncryptedString::try_from(cp.surname)?,
|
||||
birthplace: EncryptedString::try_from(cp.birthplace)?,
|
||||
birthdate: EncryptedString::try_from(cp.birthdate)?,
|
||||
address: EncryptedString::try_from(cp.address)?,
|
||||
telephone: EncryptedString::try_from(cp.telephone)?,
|
||||
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)?,
|
||||
},
|
||||
parents: vec![EncryptedParentDetails {
|
||||
name: EncryptedString::try_from(cp.parent_name)?,
|
||||
surname: EncryptedString::try_from(cp.parent_surname)?,
|
||||
telephone: EncryptedString::try_from(cp.parent_telephone)?,
|
||||
email: EncryptedString::try_from(cp.parent_email)?,
|
||||
}]
|
||||
|
||||
parent_name: EncryptedString::try_from(cp.parent_name)?,
|
||||
parent_surname: EncryptedString::try_from(cp.parent_surname)?,
|
||||
parent_telephone: EncryptedString::try_from(cp.parent_telephone)?,
|
||||
parent_email: EncryptedString::try_from(cp.parent_email)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -240,7 +341,7 @@ pub mod tests {
|
|||
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::crypto;
|
||||
use crate::{crypto, models::candidate::{CandidateDetails, ParentDetails}};
|
||||
|
||||
use super::{ApplicationDetails, EncryptedApplicationDetails, EncryptedString};
|
||||
|
||||
|
|
@ -249,40 +350,44 @@ pub mod tests {
|
|||
|
||||
pub static APPLICATION_DETAILS: Lazy<Mutex<ApplicationDetails>> = 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()
|
||||
candidate: CandidateDetails {
|
||||
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(),
|
||||
},
|
||||
parents: vec![ParentDetails {
|
||||
name: "parent_name".to_string(),
|
||||
surname: "parent_surname".to_string(),
|
||||
telephone: "parent_telephone".to_string(),
|
||||
email: "parent_email".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");
|
||||
assert_eq!(details.candidate.name, "name");
|
||||
assert_eq!(details.candidate.surname, "surname");
|
||||
assert_eq!(details.candidate.birthplace, "birthplace");
|
||||
assert_eq!(details.candidate.birthdate, chrono::NaiveDate::from_ymd(2000, 1, 1));
|
||||
assert_eq!(details.candidate.address, "address");
|
||||
assert_eq!(details.candidate.telephone, "telephone");
|
||||
assert_eq!(details.candidate.citizenship, "citizenship");
|
||||
assert_eq!(details.candidate.email, "email");
|
||||
assert_eq!(details.candidate.sex, "sex");
|
||||
assert_eq!(details.candidate.study, "study");
|
||||
assert_eq!(details.candidate.personal_id_number, "personal_id_number");
|
||||
assert_eq!(details.parents[0].name, "parent_name");
|
||||
assert_eq!(details.parents[0].surname, "parent_surname");
|
||||
assert_eq!(details.parents[0].telephone, "parent_telephone");
|
||||
assert_eq!(details.parents[0].email, "parent_email");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -295,19 +400,19 @@ pub mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.name.0, PRIVATE_KEY)
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.name.0, PRIVATE_KEY)
|
||||
.await
|
||||
.unwrap(),
|
||||
"name"
|
||||
);
|
||||
assert_eq!(
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.email.0, PRIVATE_KEY)
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.email.0, PRIVATE_KEY)
|
||||
.await
|
||||
.unwrap(),
|
||||
"email"
|
||||
);
|
||||
assert_eq!(
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.sex.0, PRIVATE_KEY)
|
||||
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.sex.0, PRIVATE_KEY)
|
||||
.await
|
||||
.unwrap(),
|
||||
"sex"
|
||||
|
|
|
|||
|
|
@ -14,13 +14,7 @@ impl ApplicationService {
|
|||
plain_text_password: &String,
|
||||
personal_id_number: String,
|
||||
) -> Result<(candidate::Model, parent::Model), ServiceError> {
|
||||
Ok(
|
||||
/* tokio::try_join!( // TODO: try_join! is not working
|
||||
CandidateService::create(db, application_id, plain_text_password, personal_id_number),
|
||||
ParentService::create(db, application_id)
|
||||
)? */
|
||||
|
||||
|
||||
Ok(
|
||||
(
|
||||
CandidateService::create(db, application_id, plain_text_password, personal_id_number).await?,
|
||||
ParentService::create(db, application_id).await?
|
||||
|
|
@ -30,39 +24,26 @@ impl ApplicationService {
|
|||
|
||||
pub async fn add_all_details(
|
||||
db: &DbConn,
|
||||
application: i32,
|
||||
candidate: candidate::Model,
|
||||
form: &ApplicationDetails,
|
||||
) -> Result<(candidate::Model, parent::Model), ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, application)
|
||||
.await?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
|
||||
let parent = Query::find_parent_by_id(db, application)
|
||||
.await?
|
||||
.ok_or(ServiceError::ParentNotFound)?;
|
||||
|
||||
let recipients = get_recipients(db, &candidate.public_key).await?;
|
||||
|
||||
let enc_details = EncryptedApplicationDetails::new(form, recipients).await?;
|
||||
) -> Result<(candidate::Model, Vec<parent::Model>), ServiceError> { // TODO: is this service needed?
|
||||
|
||||
Ok(
|
||||
tokio::try_join!(
|
||||
CandidateService::add_candidate_details(db, candidate, enc_details.clone()),
|
||||
ParentService::add_parent_details(db, parent, enc_details.clone())
|
||||
)?
|
||||
(
|
||||
CandidateService::add_candidate_details(db, candidate.clone(), &form.candidate).await?,
|
||||
ParentService::add_parents_details(db, candidate, &form.parents).await?
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn decrypt_all_details(
|
||||
private_key: String,
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
candidate: candidate::Model,
|
||||
// parents: Vec<parent::Model>,
|
||||
) -> Result<ApplicationDetails, ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, application_id).await?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
let parent = Query::find_parent_by_id(db, application_id).await?
|
||||
.ok_or(ServiceError::ParentNotFound)?;
|
||||
let enc_details = EncryptedApplicationDetails::try_from((candidate, parent))?;
|
||||
let parents = Query::find_candidate_parents(db, candidate.clone()).await?;
|
||||
let enc_details = EncryptedApplicationDetails::try_from((candidate, parents))?;
|
||||
|
||||
enc_details.decrypt(private_key).await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use entity::candidate;
|
|||
use sea_orm::{prelude::Uuid, DbConn};
|
||||
|
||||
use crate::{
|
||||
models::candidate_details::{EncryptedApplicationDetails, EncryptedString},
|
||||
models::{candidate_details::{EncryptedApplicationDetails, EncryptedString, EncryptedCandidateDetails}, candidate::CandidateDetails},
|
||||
crypto::{self, hash_password},
|
||||
error::ServiceError,
|
||||
Mutation, Query, models::candidate::{BaseCandidateResponse, CreateCandidateResponse}, utils::db::get_recipients,
|
||||
|
|
@ -102,8 +102,7 @@ impl CandidateService {
|
|||
) -> Result<CreateCandidateResponse, ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, id).await?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
let parent = Query::find_parent_by_id(db, id).await?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
let parents = Query::find_candidate_parents(db, candidate.clone()).await?; // TODO
|
||||
|
||||
|
||||
let new_password_plain = crypto::random_8_char_string();
|
||||
|
|
@ -125,12 +124,12 @@ impl CandidateService {
|
|||
.await?;
|
||||
|
||||
let enc_details_opt = EncryptedApplicationDetails::try_from(
|
||||
(candidate, parent)
|
||||
(candidate.clone(), parents)
|
||||
);
|
||||
|
||||
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, candidate, &application_details).await?;
|
||||
}
|
||||
|
||||
Ok(
|
||||
|
|
@ -150,9 +149,11 @@ impl CandidateService {
|
|||
pub(in crate::services) async fn add_candidate_details(
|
||||
db: &DbConn,
|
||||
candidate: candidate::Model,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
details: &CandidateDetails,
|
||||
) -> Result<entity::candidate::Model, ServiceError> {
|
||||
let model = Mutation::add_candidate_details(db, candidate, enc_details.clone()).await?;
|
||||
let recipients = get_recipients(db, &candidate.public_key).await?;
|
||||
let enc_details = EncryptedCandidateDetails::new(&details, recipients).await?;
|
||||
let model = Mutation::add_candidate_details(db, candidate, enc_details).await?;
|
||||
Ok(model)
|
||||
}
|
||||
|
||||
|
|
@ -373,8 +374,8 @@ pub mod tests {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub async fn put_user_data(db: &DbConn) -> (candidate::Model, parent::Model) {
|
||||
use crate::models::candidate_details::tests::APPLICATION_DETAILS;
|
||||
pub async fn put_user_data(db: &DbConn) -> (candidate::Model, Vec<parent::Model>) {
|
||||
use crate::{models::candidate_details::tests::APPLICATION_DETAILS, Query};
|
||||
|
||||
let plain_text_password = "test".to_string();
|
||||
let (candidate, _parent) = ApplicationService::create_candidate_with_parent(
|
||||
|
|
@ -383,23 +384,28 @@ pub mod tests {
|
|||
&plain_text_password,
|
||||
"".to_string(),
|
||||
)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let form = APPLICATION_DETAILS.lock().unwrap().clone();
|
||||
|
||||
ApplicationService::add_all_details(&db, candidate.application, &form)
|
||||
let (candidate, parents) = ApplicationService::add_all_details(&db, candidate.clone(), &form)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
(
|
||||
candidate,
|
||||
parents,
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_put_user_data() {
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
let (candidate, parent) = put_user_data(&db).await;
|
||||
let (candidate, parents) = put_user_data(&db).await;
|
||||
assert!(candidate.name.is_some());
|
||||
assert!(parent.name.is_some());
|
||||
assert!(parents[0].name.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use entity::{parent};
|
||||
use entity::{parent, candidate};
|
||||
use sea_orm::DbConn;
|
||||
|
||||
use crate::{error::ServiceError, Mutation, models::candidate_details::EncryptedApplicationDetails};
|
||||
use crate::{error::ServiceError, Mutation, models::{candidate_details::{EncryptedParentDetails}, candidate::ParentDetails}, Query, utils::db::get_recipients};
|
||||
|
||||
pub struct ParentService;
|
||||
|
||||
|
|
@ -16,14 +16,140 @@ impl ParentService {
|
|||
Ok(parent)
|
||||
}
|
||||
|
||||
pub async fn add_parent_details(
|
||||
/* pub async fn add_parent_details(
|
||||
db: &DbConn,
|
||||
parent: parent::Model,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
enc_details: EncryptedParentDetails,
|
||||
) -> Result<parent::Model, ServiceError> {
|
||||
let parent = Mutation::add_parent_details(db, parent, enc_details)
|
||||
.await?;
|
||||
|
||||
Ok(parent)
|
||||
} */
|
||||
pub async fn add_parents_details(
|
||||
db: &DbConn,
|
||||
ref_candidate: candidate::Model,
|
||||
parents_details: &Vec<ParentDetails>,
|
||||
) -> Result<Vec<parent::Model>, ServiceError> {
|
||||
let found_parents = Query::find_candidate_parents(db, ref_candidate.clone()).await?;
|
||||
if found_parents.len() > 2 {
|
||||
return Err(ServiceError::ParentOverflow);
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
for i in 0..parents_details.len() {
|
||||
let found_parent = match found_parents.get(i) {
|
||||
Some(parent) => parent.clone(),
|
||||
None => ParentService::create(db, ref_candidate.application).await?,
|
||||
};
|
||||
let recipients = get_recipients(db, &ref_candidate.public_key).await?;
|
||||
let enc_details = EncryptedParentDetails::new(&parents_details[i], recipients).await?;
|
||||
let parent = Mutation::add_parent_details(db, found_parent.clone(), enc_details.clone()).await?;
|
||||
result.push(parent);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Mutex;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{utils::db::get_memory_sqlite_connection, models::{candidate::{ParentDetails, ApplicationDetails, CandidateDetails}, candidate_details::{tests::APPLICATION_DETAILS, EncryptedParentDetails, EncryptedApplicationDetails}}, services::{candidate_service::CandidateService, application_service::ApplicationService}, crypto};
|
||||
|
||||
use super::ParentService;
|
||||
|
||||
pub static APPLICATION_DETAILS_TWO_PARENTS: Lazy<Mutex<ApplicationDetails>> = Lazy::new(||
|
||||
Mutex::new(ApplicationDetails {
|
||||
candidate: CandidateDetails {
|
||||
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(),
|
||||
},
|
||||
parents: vec![ParentDetails {
|
||||
name: "parent_name".to_string(),
|
||||
surname: "parent_surname".to_string(),
|
||||
telephone: "parent_telephone".to_string(),
|
||||
email: "parent_email".to_string(),
|
||||
},
|
||||
ParentDetails {
|
||||
name: "parent_name2".to_string(),
|
||||
surname: "parent_surname2".to_string(),
|
||||
telephone: "parent_telephone2".to_string(),
|
||||
email: "parent_email2".to_string(),
|
||||
}],
|
||||
})
|
||||
);
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_parent_test() {
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
CandidateService::create(&db, 103100, &"test".to_string(), "".to_string()).await.unwrap();
|
||||
super::ParentService::create(&db, 103100).await.unwrap();
|
||||
super::ParentService::create(&db, 103100).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn add_parent_details_test() {
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
let plain_text_password = "test".to_string();
|
||||
let (candidate, _parent) = ApplicationService::create_candidate_with_parent(
|
||||
&db,
|
||||
103101,
|
||||
&plain_text_password,
|
||||
"".to_string(),
|
||||
)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
ParentService::create(&db, 103101).await.unwrap();
|
||||
|
||||
let form = APPLICATION_DETAILS_TWO_PARENTS.lock().unwrap().clone();
|
||||
|
||||
let (candidate, parents) = ApplicationService::add_all_details(&db, candidate.clone(), &form)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let priv_key = crypto::decrypt_password(candidate.private_key.clone(), plain_text_password).await.unwrap();
|
||||
let dec_details = EncryptedApplicationDetails::try_from((candidate, parents))
|
||||
.unwrap()
|
||||
.decrypt(priv_key)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(dec_details.candidate.name, form.candidate.name);
|
||||
assert_eq!(dec_details.candidate.surname, form.candidate.surname);
|
||||
assert_eq!(dec_details.candidate.birthplace, form.candidate.birthplace);
|
||||
assert_eq!(dec_details.candidate.birthdate, form.candidate.birthdate);
|
||||
assert_eq!(dec_details.candidate.address, form.candidate.address);
|
||||
assert_eq!(dec_details.candidate.telephone, form.candidate.telephone);
|
||||
assert_eq!(dec_details.candidate.citizenship, form.candidate.citizenship);
|
||||
assert_eq!(dec_details.candidate.email, form.candidate.email);
|
||||
assert_eq!(dec_details.candidate.sex, form.candidate.sex);
|
||||
assert_eq!(dec_details.candidate.personal_id_number, form.candidate.personal_id_number);
|
||||
assert_eq!(dec_details.candidate.study, form.candidate.study);
|
||||
|
||||
assert_eq!(dec_details.parents.len(), form.parents.len());
|
||||
for i in 0..dec_details.parents.len() {
|
||||
assert_eq!(dec_details.parents[i].name, form.parents[i].name);
|
||||
assert_eq!(dec_details.parents[i].surname, form.parents[i].surname);
|
||||
assert_eq!(dec_details.parents[i].telephone, form.parents[i].telephone);
|
||||
assert_eq!(dec_details.parents[i].email, form.parents[i].email);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -6,24 +6,26 @@ type Row = CandidateWithParent;
|
|||
|
||||
impl From<(i32, ApplicationDetails)> for Row {
|
||||
fn from((application, d): (i32, ApplicationDetails)) -> Self {
|
||||
let c = d.candidate;
|
||||
let p = d.parents[0].clone();
|
||||
Self {
|
||||
application,
|
||||
name: Some(d.name),
|
||||
surname: Some(d.surname),
|
||||
birthplace: Some(d.birthplace),
|
||||
birthdate: Some(d.birthdate.to_string()),
|
||||
address: Some(d.address),
|
||||
telephone: Some(d.telephone),
|
||||
citizenship: Some(d.citizenship),
|
||||
email: Some(d.email),
|
||||
sex: Some(d.sex),
|
||||
study: Some(d.study),
|
||||
personal_identification_number: Some(d.personal_id_number),
|
||||
name: Some(c.name),
|
||||
surname: Some(c.surname),
|
||||
birthplace: Some(c.birthplace),
|
||||
birthdate: Some(c.birthdate.to_string()),
|
||||
address: Some(c.address),
|
||||
telephone: Some(c.telephone),
|
||||
citizenship: Some(c.citizenship),
|
||||
email: Some(c.email),
|
||||
sex: Some(c.sex),
|
||||
study: Some(c.study),
|
||||
personal_identification_number: Some(c.personal_id_number),
|
||||
|
||||
parent_name: Some(d.parent_name),
|
||||
parent_surname: Some(d.parent_surname),
|
||||
parent_telephone: Some(d.parent_telephone),
|
||||
parent_email: Some(d.parent_email),
|
||||
parent_name: Some(p.name),
|
||||
parent_surname: Some(p.surname),
|
||||
parent_telephone: Some(p.telephone),
|
||||
parent_email: Some(p.email),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ use sea_orm::entity::prelude::*;
|
|||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "parent")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub application: i32,
|
||||
pub name: Option<String>,
|
||||
pub surname: Option<String>,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@ impl MigrationTrait for Migration {
|
|||
Table::create()
|
||||
.table(Parent::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Parent::Id)
|
||||
.integer()
|
||||
.not_null()
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Parent::Application)
|
||||
.integer()
|
||||
.not_null()
|
||||
.primary_key()
|
||||
.unique_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Parent::Name).string())
|
||||
.col(ColumnDef::new(Parent::Surname).string())
|
||||
|
|
@ -26,7 +31,7 @@ impl MigrationTrait for Migration {
|
|||
.col(ColumnDef::new(Parent::UpdatedAt).date_time().not_null())
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
|
|
@ -38,6 +43,7 @@ impl MigrationTrait for Migration {
|
|||
|
||||
#[derive(Iden)]
|
||||
pub enum Parent {
|
||||
Id,
|
||||
Table,
|
||||
Application,
|
||||
Name,
|
||||
|
|
|
|||
Loading…
Reference in a new issue