mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-14 20:11:24 +00:00
Merge pull request #40 from EETagent/parent_details
Parent details, massive refactoring
This commit is contained in:
commit
72ae61637f
25 changed files with 498 additions and 348 deletions
|
|
@ -51,7 +51,7 @@ impl<'r> FromRequest<'r> for AdminAuth {
|
|||
match session {
|
||||
Ok(model) => Outcome::Success(AdminAuth(model, private_key.to_string())),
|
||||
Err(e) => Outcome::Failure(
|
||||
(Status::from_code(e.code()).unwrap_or(Status::InternalServerError), None)
|
||||
(Status::from_code(e.code()).unwrap_or(Status::Unauthorized), None)
|
||||
),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
|||
|
||||
use portfolio_core::{
|
||||
crypto::random_8_char_string,
|
||||
services::{admin_service::AdminService, candidate_service::CandidateService},
|
||||
services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService},
|
||||
};
|
||||
use requests::{AdminLoginRequest, RegisterRequest};
|
||||
use rocket::http::{Cookie, Status, CookieJar};
|
||||
|
|
@ -75,22 +75,14 @@ pub async fn create_candidate(
|
|||
|
||||
let plain_text_password = random_8_char_string();
|
||||
|
||||
let candidate = CandidateService::create(
|
||||
ApplicationService::create_candidate_with_parent(
|
||||
db,
|
||||
form.application_id,
|
||||
&plain_text_password,
|
||||
form.personal_id_number,
|
||||
)
|
||||
.await;
|
||||
|
||||
if candidate.is_err() {
|
||||
// TODO cleanup
|
||||
let e = candidate.err().unwrap();
|
||||
return Err(Custom(
|
||||
Status::from_code(e.code()).unwrap_or_default(),
|
||||
e.message(),
|
||||
));
|
||||
}
|
||||
.await
|
||||
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
||||
|
||||
Ok(plain_text_password)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use portfolio_core::services::candidate_service::{CandidateService, UserDetails};
|
||||
use portfolio_core::candidate_details::ApplicationDetails;
|
||||
use portfolio_core::services::application_service::ApplicationService;
|
||||
use portfolio_core::services::candidate_service::{CandidateService};
|
||||
use requests::LoginRequest;
|
||||
use rocket::http::{Cookie, CookieJar, Status};
|
||||
use rocket::response::status::Custom;
|
||||
|
|
@ -59,18 +61,18 @@ pub async fn whoami(session: CandidateAuth) -> Result<String, Custom<String>> {
|
|||
#[post("/details", data = "<details>")]
|
||||
pub async fn fill_details(
|
||||
conn: Connection<'_, Db>,
|
||||
details: Json<UserDetails>,
|
||||
details: Json<ApplicationDetails>,
|
||||
session: CandidateAuth,
|
||||
) -> Result<String, Custom<String>> {
|
||||
let db = conn.into_inner();
|
||||
let form = details.into_inner();
|
||||
let candidate: entity::candidate::Model = session.into();
|
||||
let candidate: entity::candidate::Model = session.into(); // TODO: don't return candidate from session
|
||||
|
||||
let candidate = CandidateService::add_user_details(db, candidate, form).await;
|
||||
let candidate_parent = ApplicationService::add_all_details(db, candidate.application, form).await;
|
||||
|
||||
if candidate.is_err() {
|
||||
if candidate_parent.is_err() {
|
||||
// TODO cleanup
|
||||
let e = candidate.err().unwrap();
|
||||
let e = candidate_parent.err().unwrap();
|
||||
return Err(Custom(
|
||||
Status::from_code(e.code()).unwrap_or_default(),
|
||||
e.message(),
|
||||
|
|
@ -85,13 +87,13 @@ pub async fn get_details(
|
|||
conn: Connection<'_, Db>,
|
||||
password_form: Json<PasswordRequest>,
|
||||
session: CandidateAuth,
|
||||
) -> Result<Json<UserDetails>, Custom<String>> {
|
||||
) -> Result<Json<ApplicationDetails>, Custom<String>> {
|
||||
let db = conn.into_inner();
|
||||
let candidate: entity::candidate::Model = session.into();
|
||||
let password = password_form.password.clone();
|
||||
|
||||
// let handle = tokio::spawn(async move {
|
||||
let details = CandidateService::decrypt_details(db, candidate.application, password)
|
||||
let details = ApplicationService::decrypt_all_details(db, candidate.application, password)
|
||||
.await
|
||||
.map_err(|e| Custom(Status::from_code(e.code()).unwrap_or_default(), e.message()));
|
||||
|
||||
|
|
|
|||
203
core/src/candidate_details.rs
Normal file
203
core/src/candidate_details.rs
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
use chrono::{NaiveDate};
|
||||
use entity::{candidate, parent};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::{error::ServiceError, crypto};
|
||||
|
||||
pub const NAIVE_DATE_FMT: &str = "%Y-%m-%d";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EncryptedString(String);
|
||||
|
||||
impl EncryptedString {
|
||||
pub async fn new(s: &str, recipients: &Vec<&str>) -> Result<Self, ServiceError> {
|
||||
match crypto::encrypt_password_with_recipients(&s, &recipients).await{
|
||||
Ok(encrypted) => Ok(Self(encrypted)),
|
||||
Err(_) => Err(ServiceError::CryptoEncryptFailed),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn decrypt(&self, private_key: &String) -> Result<String, ServiceError> {
|
||||
match crypto::decrypt_password_with_private_key(&self.0, private_key).await {
|
||||
Ok(decrypted) => Ok(decrypted),
|
||||
Err(_) => Err(ServiceError::CryptoDecryptFailed),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for EncryptedString {
|
||||
fn into(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Option<String>> for EncryptedString {
|
||||
type Error = ServiceError;
|
||||
|
||||
fn try_from(s: Option<String>) -> Result<Self, Self::Error> {
|
||||
match s {
|
||||
Some(s) => Ok(Self(s)),
|
||||
None => Err(ServiceError::CandidateDetailsNotSet),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Option<NaiveDate>> for EncryptedString { // TODO: take a look at this
|
||||
type Error = ServiceError;
|
||||
|
||||
fn try_from(d: Option<NaiveDate>) -> Result<Self, Self::Error> {
|
||||
match d {
|
||||
Some(d) => Ok(Self(d.to_string())),
|
||||
None => Err(ServiceError::CandidateDetailsNotSet),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EncryptedApplicationDetails {
|
||||
// Candidate
|
||||
pub name: EncryptedString,
|
||||
pub surname: EncryptedString,
|
||||
pub birthplace: EncryptedString,
|
||||
pub birthdate: EncryptedString,
|
||||
pub address: EncryptedString,
|
||||
pub telephone: EncryptedString,
|
||||
pub citizenship: EncryptedString,
|
||||
pub email: EncryptedString,
|
||||
pub sex: EncryptedString,
|
||||
pub study: EncryptedString,
|
||||
|
||||
// Parent
|
||||
pub parent_name: EncryptedString,
|
||||
pub parent_surname: EncryptedString,
|
||||
pub parent_telephone: EncryptedString,
|
||||
pub parent_email: EncryptedString,
|
||||
}
|
||||
|
||||
impl EncryptedApplicationDetails {
|
||||
pub async fn new(form: ApplicationDetails, recipients: Vec<&str>) -> Result<EncryptedApplicationDetails, ServiceError> {
|
||||
let birthdate_str = form.birthdate.format(NAIVE_DATE_FMT).to_string();
|
||||
let d = tokio::try_join!(
|
||||
EncryptedString::new(&form.name, &recipients),
|
||||
EncryptedString::new(&form.surname, &recipients),
|
||||
EncryptedString::new(&form.birthplace, &recipients),
|
||||
EncryptedString::new(&birthdate_str, &recipients),
|
||||
EncryptedString::new(&form.address, &recipients),
|
||||
EncryptedString::new(&form.telephone, &recipients),
|
||||
EncryptedString::new(&form.citizenship, &recipients),
|
||||
EncryptedString::new(&form.email, &recipients),
|
||||
EncryptedString::new(&form.sex, &recipients),
|
||||
EncryptedString::new(&form.study, &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,
|
||||
study: d.9,
|
||||
|
||||
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<ApplicationDetails, ServiceError> {
|
||||
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.study.decrypt(&priv_key), // 9
|
||||
|
||||
self.parent_name.decrypt(&priv_key),
|
||||
self.parent_surname.decrypt(&priv_key),
|
||||
self.parent_telephone.decrypt(&priv_key),
|
||||
self.parent_email.decrypt(&priv_key),
|
||||
)?;
|
||||
|
||||
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,
|
||||
study: d.9,
|
||||
|
||||
parent_name: d.10,
|
||||
parent_surname: d.11,
|
||||
parent_telephone: d.12,
|
||||
parent_email: d.13,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(candidate::Model, parent::Model)> for EncryptedApplicationDetails {
|
||||
type Error = ServiceError;
|
||||
|
||||
fn try_from((candidate, parent): (candidate::Model, parent::Model)) -> Result<Self, Self::Error> {
|
||||
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)?,
|
||||
study: EncryptedString::try_from(candidate.study)?,
|
||||
|
||||
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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ApplicationDetails {
|
||||
// Candidate
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
pub birthplace: String,
|
||||
pub birthdate: NaiveDate, // TODO: User NaiveDate or String?
|
||||
pub address: String,
|
||||
pub telephone: String,
|
||||
pub citizenship: String,
|
||||
pub email: String,
|
||||
pub sex: String,
|
||||
pub study: String,
|
||||
|
||||
// Parent
|
||||
pub parent_name: String,
|
||||
pub parent_surname: String,
|
||||
pub parent_telephone: String,
|
||||
pub parent_email: String,
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Mutation, services::candidate_service::EncryptedUserDetails};
|
||||
use crate::{Mutation, candidate_details::{EncryptedApplicationDetails}};
|
||||
|
||||
use ::entity::candidate::{self};
|
||||
use sea_orm::{*};
|
||||
|
|
@ -29,18 +29,19 @@ impl Mutation {
|
|||
pub async fn add_candidate_details(
|
||||
db: &DbConn,
|
||||
user: candidate::Model,
|
||||
enc_details: EncryptedUserDetails,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
) -> Result<candidate::Model, sea_orm::DbErr> {
|
||||
let mut user: candidate::ActiveModel = user.into();
|
||||
user.name = Set(Some(enc_details.name));
|
||||
user.surname = Set(Some(enc_details.surname));
|
||||
user.birthplace = Set(Some(enc_details.birthplace));
|
||||
user.address = Set(Some(enc_details.address));
|
||||
user.telephone = Set(Some(enc_details.telephone));
|
||||
user.citizenship = Set(Some(enc_details.citizenship));
|
||||
user.email = Set(Some(enc_details.email));
|
||||
user.sex = Set(Some(enc_details.sex));
|
||||
user.study = Set(Some(enc_details.study));
|
||||
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.study = Set(Some(enc_details.study.into()));
|
||||
|
||||
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::Mutation;
|
||||
use crate::{Mutation, candidate_details::EncryptedApplicationDetails};
|
||||
|
||||
use ::entity::parent::{self, Model};
|
||||
use sea_orm::*;
|
||||
|
|
@ -17,17 +17,14 @@ impl Mutation {
|
|||
|
||||
pub async fn add_parent_details(
|
||||
db: &DbConn,
|
||||
user: Model,
|
||||
name: String,
|
||||
surname: String,
|
||||
telephone: String,
|
||||
email: String,
|
||||
parent: Model,
|
||||
enc_details: EncryptedApplicationDetails, // TODO: use seperate struct??
|
||||
) -> Result<Model, sea_orm::DbErr> {
|
||||
let mut user: parent::ActiveModel = user.into();
|
||||
user.name = Set(Some(name));
|
||||
user.surname = Set(Some(surname));
|
||||
user.telephone = Set(Some(telephone));
|
||||
user.email = Set(Some(email));
|
||||
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()));
|
||||
|
||||
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ pub struct Query;
|
|||
|
||||
pub mod candidate;
|
||||
pub mod admin;
|
||||
pub mod session;
|
||||
pub mod session;
|
||||
pub mod parent;
|
||||
17
core/src/database/query/parent.rs
Normal file
17
core/src/database/query/parent.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
use entity::parent::Model;
|
||||
use entity::parent::Entity;
|
||||
use sea_orm::{DbConn, DbErr};
|
||||
use sea_orm::EntityTrait;
|
||||
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub async fn find_parent_by_id(
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
) -> Result<Option<Model>, DbErr> {
|
||||
|
||||
Entity::find_by_id(application_id).one(db).await
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,8 @@ pub enum ServiceError {
|
|||
ExpiredSession,
|
||||
JwtError,
|
||||
UserAlreadyExists,
|
||||
UserNotFound,
|
||||
CandidateNotFound,
|
||||
ParentNotFound,
|
||||
DbError,
|
||||
UserNotFoundByJwtId,
|
||||
UserNotFoundBySessionId,
|
||||
|
|
@ -24,7 +25,8 @@ impl ServiceError {
|
|||
ServiceError::ExpiredSession => (401, "Session expired, please login again".to_string()),
|
||||
ServiceError::JwtError => (500, "Error while encoding JWT".to_string()),
|
||||
ServiceError::UserAlreadyExists => (409, "User already exists".to_string()),
|
||||
ServiceError::UserNotFound => (404, "User not found".to_string()),
|
||||
ServiceError::CandidateNotFound => (404, "User not found".to_string()),
|
||||
ServiceError::ParentNotFound => (500, "Parent not found".to_string()),
|
||||
ServiceError::DbError => (500, "Database error".to_string()),
|
||||
ServiceError::UserNotFoundByJwtId => (500, "User not found, please contact technical support".to_string()),
|
||||
ServiceError::UserNotFoundBySessionId => (500, "User not found, please contact technical support".to_string()),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ pub mod crypto;
|
|||
pub mod filetype;
|
||||
pub mod services;
|
||||
pub mod error;
|
||||
pub mod candidate_details;
|
||||
|
||||
pub use database::mutation::*;
|
||||
pub use database::query::*;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl AdminService {
|
|||
};
|
||||
|
||||
let Some(admin) = admin else {
|
||||
return Err(ServiceError::UserNotFound);
|
||||
return Err(ServiceError::CandidateNotFound);
|
||||
};
|
||||
|
||||
let private_key_encrypted = admin.private_key;
|
||||
|
|
@ -55,7 +55,7 @@ impl AdminService {
|
|||
match SessionService::auth_user_session(db, session_uuid).await {
|
||||
Ok(user) => match user {
|
||||
AdminUser::Admin(admin) => Ok(admin),
|
||||
AdminUser::User(_) => Err(ServiceError::DbError),
|
||||
AdminUser::Candidate(_) => Err(ServiceError::DbError),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
|
|
|
|||
95
core/src/services/application_service.rs
Normal file
95
core/src/services/application_service.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
use entity::{candidate, parent};
|
||||
use sea_orm::DbConn;
|
||||
|
||||
use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query, crypto};
|
||||
|
||||
use super::{parent_service::ParentService, candidate_service::CandidateService};
|
||||
|
||||
pub struct ApplicationService;
|
||||
|
||||
impl ApplicationService {
|
||||
pub async fn create_candidate_with_parent( // uchazeč s maminkou 👩🍼
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
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)
|
||||
)? */
|
||||
|
||||
|
||||
(
|
||||
CandidateService::create(db, application_id, plain_text_password, personal_id_number).await?,
|
||||
ParentService::create(db, application_id).await?
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn add_all_details(
|
||||
db: &DbConn,
|
||||
application: i32,
|
||||
form: ApplicationDetails,
|
||||
) -> Result<(candidate::Model, parent::Model), ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, application)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
|
||||
let parent = Query::find_parent_by_id(db, application)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)?
|
||||
.ok_or(ServiceError::ParentNotFound)?;
|
||||
|
||||
let Ok(admin_public_keys) = Query::get_all_admin_public_keys(db).await else {
|
||||
return Err(ServiceError::DbError);
|
||||
};
|
||||
|
||||
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 enc_details = EncryptedApplicationDetails::new(form, recipients).await?;
|
||||
|
||||
Ok(
|
||||
tokio::try_join!(
|
||||
CandidateService::add_candidate_details(db, candidate, enc_details.clone()),
|
||||
ParentService::add_parent_details(db, parent, enc_details.clone())
|
||||
)?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn decrypt_all_details(
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
password: String,
|
||||
) -> Result<ApplicationDetails, ServiceError> {
|
||||
let candidate = match Query::find_candidate_by_id(db, application_id).await {
|
||||
Ok(candidate) => candidate.unwrap(),
|
||||
Err(_) => return Err(ServiceError::DbError), // TODO: logging
|
||||
};
|
||||
let parent = Query::find_parent_by_id(db, application_id).await.unwrap().unwrap();
|
||||
|
||||
match crypto::verify_password((&password).to_string(), candidate.code.clone()).await {
|
||||
Ok(valid) => {
|
||||
if !valid {
|
||||
return Err(ServiceError::InvalidCredentials);
|
||||
}
|
||||
}
|
||||
Err(_) => return Err(ServiceError::InvalidCredentials),
|
||||
}
|
||||
|
||||
let dec_priv_key = crypto::decrypt_password(candidate.private_key.clone(), password)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
let enc_details = EncryptedApplicationDetails::try_from((candidate, parent))?;
|
||||
|
||||
enc_details.decrypt(dec_priv_key).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,188 +1,16 @@
|
|||
use entity::candidate;
|
||||
use entity::{candidate};
|
||||
use sea_orm::{prelude::Uuid, DbConn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
crypto::{self, hash_password},
|
||||
error::ServiceError,
|
||||
Mutation, Query,
|
||||
Mutation, Query, candidate_details::{EncryptedApplicationDetails},
|
||||
};
|
||||
|
||||
use super::session_service::{AdminUser, SessionService};
|
||||
use super::{session_service::{AdminUser, SessionService}};
|
||||
|
||||
const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"];
|
||||
|
||||
pub(crate) struct EncryptedUserDetails {
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
pub birthplace: String,
|
||||
// pub birthdate: NaiveDate,
|
||||
pub address: String,
|
||||
pub telephone: String,
|
||||
pub citizenship: String,
|
||||
pub email: String,
|
||||
pub sex: String,
|
||||
pub study: String,
|
||||
}
|
||||
|
||||
impl EncryptedUserDetails {
|
||||
pub async fn encrypt_form(form: UserDetails, recipients: Vec<&str>) -> EncryptedUserDetails {
|
||||
let (
|
||||
Ok(name),
|
||||
Ok(surname),
|
||||
Ok(birthplace),
|
||||
// Ok(enc_birthdate),
|
||||
Ok(address),
|
||||
Ok(telephone),
|
||||
Ok(citizenship),
|
||||
Ok(email),
|
||||
Ok(sex),
|
||||
Ok(study),
|
||||
) = tokio::join!(
|
||||
crypto::encrypt_password_with_recipients(&form.name, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.surname, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.birthplace, &recipients),
|
||||
// crypto::encrypt_password_with_recipients(&self.birthdate, &recipients), // TODO
|
||||
crypto::encrypt_password_with_recipients(&form.address, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.telephone, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.citizenship, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.email, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.sex, &recipients),
|
||||
crypto::encrypt_password_with_recipients(&form.study, &recipients),
|
||||
) else {
|
||||
panic!("Failed to encrypt user details"); // TODO
|
||||
};
|
||||
|
||||
EncryptedUserDetails {
|
||||
name,
|
||||
surname,
|
||||
birthplace,
|
||||
// birthdate: NaiveDate::from_ymd(2000, 1, 1),
|
||||
address,
|
||||
telephone,
|
||||
citizenship,
|
||||
email,
|
||||
sex,
|
||||
study,
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_enc_candidate_details(
|
||||
candidate: candidate::Model,
|
||||
) -> Result<UserDetails, ServiceError> {
|
||||
let ( // TODO: simplify??
|
||||
Some(name),
|
||||
Some(surname),
|
||||
Some(birthplace),
|
||||
// Some(birthdate),
|
||||
Some(address),
|
||||
Some(telephone),
|
||||
Some(citizenship),
|
||||
Some(email),
|
||||
Some(sex),
|
||||
Some(study),
|
||||
) = (
|
||||
candidate.name,
|
||||
candidate.surname,
|
||||
candidate.birthplace,
|
||||
// candidate.birthdate,
|
||||
candidate.address,
|
||||
candidate.telephone,
|
||||
candidate.citizenship,
|
||||
candidate.email,
|
||||
candidate.sex,
|
||||
candidate.study,
|
||||
) else {
|
||||
return Err(ServiceError::CandidateDetailsNotSet);
|
||||
};
|
||||
|
||||
Ok(UserDetails {
|
||||
name,
|
||||
surname,
|
||||
birthplace,
|
||||
// birthdate,
|
||||
address,
|
||||
telephone,
|
||||
citizenship,
|
||||
email,
|
||||
sex,
|
||||
study,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_model(candidate: candidate::Model) -> Result<EncryptedUserDetails, ServiceError> {
|
||||
let Ok(details) = Self::extract_enc_candidate_details(candidate) else {
|
||||
return Err(ServiceError::CandidateDetailsNotSet);
|
||||
};
|
||||
Ok(EncryptedUserDetails {
|
||||
name: details.name,
|
||||
surname: details.surname,
|
||||
birthplace: details.birthplace,
|
||||
// birthdate,
|
||||
address: details.address,
|
||||
telephone: details.telephone,
|
||||
citizenship: details.citizenship,
|
||||
email: details.email,
|
||||
sex: details.sex,
|
||||
study: details.study,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn decrypt(self, priv_key: String) -> Result<UserDetails, ServiceError> {
|
||||
let (
|
||||
Ok(name),
|
||||
Ok(surname),
|
||||
Ok(birthplace),
|
||||
// Ok(enc_birthdate),
|
||||
Ok(address),
|
||||
Ok(telephone),
|
||||
Ok(citizenship),
|
||||
Ok(email),
|
||||
Ok(sex),
|
||||
Ok(study),
|
||||
) = tokio::join!(
|
||||
crypto::decrypt_password_with_private_key(&self.name, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.surname, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.birthplace, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.address, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.telephone, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.citizenship, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.email, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.sex, &priv_key),
|
||||
crypto::decrypt_password_with_private_key(&self.study, &priv_key),
|
||||
) else {
|
||||
panic!("Failed to encrypt user details"); // TODO
|
||||
};
|
||||
|
||||
Ok(UserDetails {
|
||||
name,
|
||||
surname,
|
||||
birthplace,
|
||||
// birthdate: NaiveDate::from_ymd(2000, 1, 1),
|
||||
address,
|
||||
telephone,
|
||||
citizenship,
|
||||
email,
|
||||
sex,
|
||||
study,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct UserDetails {
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
pub birthplace: String,
|
||||
// pub birthdate: NaiveDate,
|
||||
pub address: String,
|
||||
pub telephone: String,
|
||||
pub citizenship: String,
|
||||
pub email: String,
|
||||
pub sex: String,
|
||||
pub study: String,
|
||||
}
|
||||
|
||||
pub struct CandidateService;
|
||||
|
||||
impl CandidateService {
|
||||
|
|
@ -191,7 +19,7 @@ impl CandidateService {
|
|||
/// Hashed password
|
||||
/// Encrypted private key
|
||||
/// Public key
|
||||
pub async fn create(
|
||||
pub(in crate::services) async fn create(
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
plain_text_password: &String,
|
||||
|
|
@ -224,9 +52,6 @@ impl CandidateService {
|
|||
let Ok(hashed_personal_id_number) = hash_password(personal_id_number).await else {
|
||||
return Err(ServiceError::CryptoHashFailed);
|
||||
};
|
||||
/* let encrypted_personal_id_number = crypto::encrypt_password_with_recipients(
|
||||
&personal_id_number, &vec![&pubkey]
|
||||
).await.unwrap(); */
|
||||
|
||||
Mutation::create_candidate(
|
||||
db,
|
||||
|
|
@ -236,66 +61,25 @@ impl CandidateService {
|
|||
pubkey,
|
||||
encrypted_priv_key,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)
|
||||
}
|
||||
|
||||
pub async fn add_user_details(
|
||||
db: &DbConn,
|
||||
user: candidate::Model,
|
||||
form: UserDetails,
|
||||
) -> Result<entity::candidate::Model, ServiceError> {
|
||||
let Ok(admin_public_keys) = Query::get_all_admin_public_keys(db).await else {
|
||||
return Err(ServiceError::DbError);
|
||||
};
|
||||
|
||||
let mut admin_public_keys_refrence: Vec<&str> =
|
||||
admin_public_keys.iter().map(|s| &**s).collect();
|
||||
|
||||
let mut recipients = vec![&*user.public_key];
|
||||
|
||||
recipients.append(&mut admin_public_keys_refrence);
|
||||
|
||||
let enc_details = EncryptedUserDetails::encrypt_form(form, recipients).await;
|
||||
|
||||
Mutation::add_candidate_details(db, user, enc_details)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)
|
||||
}
|
||||
|
||||
pub async fn decrypt_details(
|
||||
pub(in crate::services) async fn add_candidate_details(
|
||||
db: &DbConn,
|
||||
candidate_id: i32,
|
||||
password: String,
|
||||
) -> Result<UserDetails, ServiceError> {
|
||||
let candidate = match Query::find_candidate_by_id(db, candidate_id).await {
|
||||
Ok(candidate) => candidate.unwrap(),
|
||||
Err(_) => return Err(ServiceError::DbError), // TODO: logging
|
||||
};
|
||||
|
||||
match crypto::verify_password((&password).to_string(), candidate.code.clone()).await {
|
||||
Ok(valid) => {
|
||||
if !valid {
|
||||
return Err(ServiceError::InvalidCredentials);
|
||||
}
|
||||
}
|
||||
Err(_) => return Err(ServiceError::InvalidCredentials),
|
||||
}
|
||||
|
||||
let dec_priv_key = crypto::decrypt_password(candidate.private_key.clone(), password)
|
||||
candidate: candidate::Model,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
) -> Result<entity::candidate::Model, ServiceError> {
|
||||
Mutation::add_candidate_details(db, candidate, enc_details.clone())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
let enc_details = EncryptedUserDetails::from_model(candidate)?;
|
||||
|
||||
enc_details.decrypt(dec_priv_key).await
|
||||
.map_err(|_| ServiceError::DbError)
|
||||
}
|
||||
|
||||
pub async fn is_set_up(candidate: &candidate::Model) -> bool {
|
||||
pub fn is_set_up(candidate: &candidate::Model) -> bool {
|
||||
candidate.name.is_some() &&
|
||||
candidate.surname.is_some() &&
|
||||
candidate.birthplace.is_some() &&
|
||||
// birthdate: NaiveDate::from_ymd(2000, 1, 1),
|
||||
candidate.birthdate.is_some() &&
|
||||
candidate.address.is_some() &&
|
||||
candidate.telephone.is_some() &&
|
||||
candidate.citizenship.is_some() &&
|
||||
|
|
@ -323,20 +107,9 @@ impl CandidateService {
|
|||
}
|
||||
|
||||
async fn decrypt_private_key(
|
||||
db: &DbConn,
|
||||
candidate_id: i32,
|
||||
candidate: candidate::Model,
|
||||
password: String,
|
||||
) -> Result<String, ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, candidate_id).await;
|
||||
|
||||
let Ok(candidate) = candidate else {
|
||||
return Err(ServiceError::DbError);
|
||||
};
|
||||
|
||||
let Some(candidate) = candidate else {
|
||||
return Err(ServiceError::UserNotFound);
|
||||
};
|
||||
|
||||
let private_key_encrypted = candidate.private_key;
|
||||
|
||||
let private_key = crypto::decrypt_password(private_key_encrypted, password).await;
|
||||
|
|
@ -350,15 +123,20 @@ impl CandidateService {
|
|||
|
||||
pub async fn login(
|
||||
db: &DbConn,
|
||||
user_id: i32,
|
||||
candidate_id: i32,
|
||||
password: String,
|
||||
ip_addr: String,
|
||||
) -> Result<(String, String), ServiceError> {
|
||||
let candidate = Query::find_candidate_by_id(db, candidate_id)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)?
|
||||
.ok_or(ServiceError::CandidateNotFound)?;
|
||||
|
||||
let session_id =
|
||||
SessionService::new_session(db, Some(user_id), None, password.clone(), ip_addr).await;
|
||||
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(db, user_id, password).await?;
|
||||
let private_key = Self::decrypt_private_key(candidate, password).await?;
|
||||
Ok((session_id, private_key))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
|
|
@ -368,7 +146,7 @@ impl CandidateService {
|
|||
pub async fn auth(db: &DbConn, session_uuid: Uuid) -> Result<candidate::Model, ServiceError> {
|
||||
match SessionService::auth_user_session(db, session_uuid).await {
|
||||
Ok(user) => match user {
|
||||
AdminUser::User(candidate) => Ok(candidate),
|
||||
AdminUser::Candidate(candidate) => Ok(candidate),
|
||||
AdminUser::Admin(_) => Err(ServiceError::DbError),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
|
|
@ -388,15 +166,19 @@ impl CandidateService {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use entity::candidate::Model;
|
||||
use sea_orm::{Database, DbConn};
|
||||
|
||||
use crate::{
|
||||
crypto,
|
||||
services::candidate_service::{CandidateService, UserDetails},
|
||||
services::candidate_service::{CandidateService}, Mutation,
|
||||
};
|
||||
|
||||
use super::EncryptedUserDetails;
|
||||
use super::EncryptedApplicationDetails;
|
||||
use chrono::NaiveDate;
|
||||
use entity::{parent, candidate};
|
||||
|
||||
use crate::services::application_service::ApplicationService;
|
||||
use crate::candidate_details::ApplicationDetails;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_application_id_validation() {
|
||||
|
|
@ -411,7 +193,7 @@ mod tests {
|
|||
|
||||
#[cfg(test)]
|
||||
async fn get_memory_sqlite_connection() -> DbConn {
|
||||
use entity::{admin, candidate};
|
||||
use entity::{admin, candidate, parent};
|
||||
use sea_orm::Schema;
|
||||
use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, DbBackend};
|
||||
|
||||
|
|
@ -420,8 +202,8 @@ mod tests {
|
|||
|
||||
let schema = Schema::new(DbBackend::Sqlite);
|
||||
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||
|
||||
let stmt2: TableCreateStatement = schema.create_table_from_entity(admin::Entity);
|
||||
let stmt3: TableCreateStatement = schema.create_table_from_entity(parent::Entity);
|
||||
|
||||
db.execute(db.get_database_backend().build(&stmt))
|
||||
.await
|
||||
|
|
@ -429,6 +211,9 @@ mod tests {
|
|||
db.execute(db.get_database_backend().build(&stmt2))
|
||||
.await
|
||||
.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt3))
|
||||
.await
|
||||
.unwrap();
|
||||
db
|
||||
}
|
||||
|
||||
|
|
@ -440,11 +225,15 @@ mod tests {
|
|||
|
||||
let secret_message = "trnka".to_string();
|
||||
|
||||
|
||||
let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
Mutation::create_parent(&db, 103151)
|
||||
.await.unwrap();
|
||||
|
||||
let encrypted_message =
|
||||
crypto::encrypt_password_with_recipients(&secret_message, &vec![&candidate.public_key])
|
||||
.await
|
||||
|
|
@ -464,53 +253,57 @@ mod tests {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn put_user_data(db: &DbConn) -> Model {
|
||||
async fn put_user_data(db: &DbConn) -> (candidate::Model, parent::Model) {
|
||||
let plain_text_password = "test".to_string();
|
||||
let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string())
|
||||
let (candidate, parent) = ApplicationService::create_candidate_with_parent(&db, 103151, &plain_text_password, "".to_string())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let form = UserDetails {
|
||||
let form = ApplicationDetails {
|
||||
name: "test".to_string(),
|
||||
surname: "a".to_string(),
|
||||
surname: "aaa".to_string(),
|
||||
birthplace: "b".to_string(),
|
||||
// birthdate: NaiveDate::from_ymd(1999, 1, 1),
|
||||
birthdate: NaiveDate::from_ymd(1999, 1, 1),
|
||||
address: "test".to_string(),
|
||||
telephone: "test".to_string(),
|
||||
citizenship: "test".to_string(),
|
||||
email: "test".to_string(),
|
||||
sex: "test".to_string(),
|
||||
study: "test".to_string(),
|
||||
parent_name: "test".to_string(),
|
||||
parent_surname: "test".to_string(),
|
||||
parent_telephone: "test".to_string(),
|
||||
parent_email: "test".to_string(),
|
||||
|
||||
};
|
||||
CandidateService::add_user_details(&db, candidate, form)
|
||||
|
||||
ApplicationService::add_all_details(&db, candidate.application, form)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_put_user_data() {
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
let candidate = put_user_data(&db).await;
|
||||
let (candidate, parent) = put_user_data(&db).await;
|
||||
assert!(candidate.name.is_some());
|
||||
assert!(parent.name.is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_encrypt_decrypt_user_data() {
|
||||
let password = "test".to_string();
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
let enc_candidate = put_user_data(&db).await;
|
||||
let (enc_candidate, enc_parent) = put_user_data(&db).await;
|
||||
|
||||
let dec_priv_key = crypto::decrypt_password(enc_candidate.private_key.clone(), password)
|
||||
.await
|
||||
.unwrap();
|
||||
let dec_candidate = EncryptedUserDetails::from_model(enc_candidate)
|
||||
.unwrap()
|
||||
.decrypt(dec_priv_key)
|
||||
.await
|
||||
.unwrap();
|
||||
let enc_details = EncryptedApplicationDetails::try_from((enc_candidate, enc_parent)).ok().unwrap();
|
||||
let dec_details = enc_details.decrypt(dec_priv_key).await.ok().unwrap();
|
||||
|
||||
assert_eq!(dec_candidate.name, "test");
|
||||
assert_eq!(dec_details.name, "test"); // TODO: test every element
|
||||
assert_eq!(dec_details.parent_surname, "test");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
pub mod session_service;
|
||||
pub mod candidate_service;
|
||||
pub mod admin_service;
|
||||
pub mod admin_service;
|
||||
pub mod parent_service;
|
||||
pub mod application_service;
|
||||
31
core/src/services/parent_service.rs
Normal file
31
core/src/services/parent_service.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use entity::{parent};
|
||||
use sea_orm::DbConn;
|
||||
|
||||
use crate::{error::ServiceError, Mutation, candidate_details::EncryptedApplicationDetails};
|
||||
|
||||
pub struct ParentService;
|
||||
|
||||
impl ParentService {
|
||||
pub async fn create(
|
||||
db: &DbConn,
|
||||
application_id: i32,
|
||||
) -> Result<parent::Model, ServiceError> {
|
||||
let parent = Mutation::create_parent(db, application_id)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)?;
|
||||
|
||||
Ok(parent)
|
||||
}
|
||||
|
||||
pub async fn add_parent_details(
|
||||
db: &DbConn,
|
||||
parent: parent::Model,
|
||||
enc_details: EncryptedApplicationDetails,
|
||||
) -> Result<parent::Model, ServiceError> {
|
||||
let parent = Mutation::add_parent_details(db, parent, enc_details)
|
||||
.await
|
||||
.map_err(|_| ServiceError::DbError)?;
|
||||
|
||||
Ok(parent)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
|
||||
pub enum AdminUser {
|
||||
Admin(entity::admin::Model),
|
||||
User(entity::candidate::Model),
|
||||
Candidate(entity::candidate::Model),
|
||||
}
|
||||
|
||||
pub(in crate::services) struct SessionService;
|
||||
|
|
@ -57,7 +57,7 @@ impl SessionService {
|
|||
let candidate = match Query::find_candidate_by_id(db, user_id.unwrap()).await {
|
||||
Ok(candidate) => match candidate {
|
||||
Some(candidate) => candidate,
|
||||
None => return Err(ServiceError::UserNotFound),
|
||||
None => return Err(ServiceError::CandidateNotFound),
|
||||
},
|
||||
Err(_) => return Err(ServiceError::DbError),
|
||||
};
|
||||
|
|
@ -78,7 +78,7 @@ impl SessionService {
|
|||
let admin = match Query::find_admin_by_id(db, admin_id.unwrap()).await {
|
||||
Ok(admin) => match admin {
|
||||
Some(admin) => admin,
|
||||
None => return Err(ServiceError::UserNotFound),
|
||||
None => return Err(ServiceError::CandidateNotFound),
|
||||
},
|
||||
Err(_) => return Err(ServiceError::DbError),
|
||||
};
|
||||
|
|
@ -147,7 +147,7 @@ impl SessionService {
|
|||
|
||||
if candidate.is_ok() {
|
||||
if let Some(candidate) = candidate.unwrap() {
|
||||
return Ok(AdminUser::User(candidate));
|
||||
return Ok(AdminUser::Candidate(candidate));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ impl SessionService {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use entity::{admin, candidate, session};
|
||||
use entity::{admin, candidate, session, parent};
|
||||
|
||||
use sea_orm::{
|
||||
prelude::Uuid, sea_query::TableCreateStatement, ConnectionTrait, Database, DbBackend,
|
||||
|
|
@ -171,7 +171,7 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
crypto,
|
||||
services::{candidate_service::CandidateService, session_service::SessionService},
|
||||
services::{session_service::SessionService, application_service::ApplicationService},
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -183,6 +183,7 @@ mod tests {
|
|||
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||
let stmt2: TableCreateStatement = schema.create_table_from_entity(admin::Entity);
|
||||
let stmt3: TableCreateStatement = schema.create_table_from_entity(session::Entity);
|
||||
let stmt4: TableCreateStatement = schema.create_table_from_entity(parent::Entity);
|
||||
db.execute(db.get_database_backend().build(&stmt))
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -192,6 +193,9 @@ mod tests {
|
|||
db.execute(db.get_database_backend().build(&stmt3))
|
||||
.await
|
||||
.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt4))
|
||||
.await
|
||||
.unwrap();
|
||||
db
|
||||
}
|
||||
|
||||
|
|
@ -201,10 +205,10 @@ mod tests {
|
|||
|
||||
let db = get_memory_sqlite_connection().await;
|
||||
|
||||
let candidate = CandidateService::create(&db, 103151, &SECRET.to_string(), "".to_string())
|
||||
let candidate = ApplicationService::create_candidate_with_parent(&db, 103151, &SECRET.to_string(), "".to_string())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
.unwrap().0;
|
||||
|
||||
assert_eq!(candidate.application, 103151);
|
||||
assert_ne!(candidate.code, SECRET.to_string());
|
||||
|
|
@ -218,10 +222,9 @@ mod tests {
|
|||
async fn test_candidate_session_correct_password() {
|
||||
let db = &get_memory_sqlite_connection().await;
|
||||
|
||||
CandidateService::create(&db, 103151, &"Tajny_kod".to_string(), "".to_string())
|
||||
ApplicationService::create_candidate_with_parent(db, 103151, &"Tajny_kod".to_string(), "".to_string())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
.unwrap().0;
|
||||
|
||||
// correct password
|
||||
let session = SessionService::new_session(
|
||||
|
|
@ -231,9 +234,8 @@ mod tests {
|
|||
"Tajny_kod".to_string(),
|
||||
"127.0.0.1".to_string(),
|
||||
)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
.await
|
||||
.unwrap();
|
||||
// println!("{}", session.err().unwrap().1);
|
||||
assert!(
|
||||
SessionService::auth_user_session(db, Uuid::parse_str(&session).unwrap())
|
||||
|
|
@ -247,10 +249,9 @@ mod tests {
|
|||
let db = &get_memory_sqlite_connection().await;
|
||||
|
||||
let candidate_form =
|
||||
CandidateService::create(&db, 103151, &"Tajny_kod".to_string(), "".to_string())
|
||||
ApplicationService::create_candidate_with_parent(&db, 103151, &"Tajny_kod".to_string(), "".to_string())
|
||||
.await
|
||||
.ok()
|
||||
.unwrap();
|
||||
.unwrap().0;
|
||||
|
||||
// incorrect password
|
||||
assert!(SessionService::new_session(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "admin")]
|
||||
pub struct Model {
|
||||
#[sea_orm(column_type = "Integer", primary_key)]
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub public_key: String,
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "candidate")]
|
||||
pub struct Model {
|
||||
#[sea_orm(column_type = "Integer", primary_key, auto_increment = false)]
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub application: i32,
|
||||
pub code: String,
|
||||
pub name: Option<String>,
|
||||
pub surname: Option<String>,
|
||||
pub birth_surname: Option<String>,
|
||||
pub birthplace: Option<String>,
|
||||
pub birthdate: Option<Date>,
|
||||
pub birthdate: Option<String>,
|
||||
pub address: Option<String>,
|
||||
pub telephone: Option<String>,
|
||||
pub citizenship: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub sex: Option<String>,
|
||||
pub study: Option<String>,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub personal_identification_number: Option<String>,
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub personal_identification_number_hash: String,
|
||||
pub public_key: String,
|
||||
pub private_key: String,
|
||||
|
|
@ -28,7 +30,7 @@ pub struct Model {
|
|||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_one = "super::parent::Entity")]
|
||||
#[sea_orm(has_many = "super::parent::Entity")]
|
||||
Parent,
|
||||
#[sea_orm(has_many = "super::session::Entity")]
|
||||
Session,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod admin;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
|
|
@ -18,7 +20,9 @@ pub enum Relation {
|
|||
#[sea_orm(
|
||||
belongs_to = "super::candidate::Entity",
|
||||
from = "Column::Application",
|
||||
to = "super::candidate::Column::Application"
|
||||
to = "super::candidate::Column::Application",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Candidate,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
pub use super::admin::Entity as Admin;
|
||||
pub use super::candidate::Entity as Candidate;
|
||||
pub use super::parent::Entity as Parent;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
|
|
@ -5,10 +7,8 @@ use sea_orm::entity::prelude::*;
|
|||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(column_type = "Integer", nullable)]
|
||||
pub admin_id: Option<i32>,
|
||||
#[sea_orm(column_type = "Integer", nullable)]
|
||||
pub user_id: Option<i32>,
|
||||
pub admin_id: Option<i32>,
|
||||
pub ip_address: String,
|
||||
pub created_at: DateTime,
|
||||
pub expires_at: DateTime,
|
||||
|
|
@ -34,16 +34,16 @@ pub enum Relation {
|
|||
Candidate,
|
||||
}
|
||||
|
||||
impl Related<super::candidate::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Candidate.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::admin::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Admin.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::candidate::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Candidate.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ mod m20221024_134454_insert_sample_admin;
|
|||
mod m20221025_154422_create_session;
|
||||
mod m20221027_194728_session_create_user_fk;
|
||||
mod m20221028_194728_session_create_admin_fk;
|
||||
mod m20221030_133428_parent_create_candidate_fk;
|
||||
mod m20221112_112212_create_parent_candidate_fk;
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
|
@ -21,7 +21,7 @@ impl MigratorTrait for Migrator {
|
|||
Box::new(m20221025_154422_create_session::Migration),
|
||||
Box::new(m20221027_194728_session_create_user_fk::Migration),
|
||||
Box::new(m20221028_194728_session_create_admin_fk::Migration),
|
||||
Box::new(m20221030_133428_parent_create_candidate_fk::Migration),
|
||||
Box::new(m20221112_112212_create_parent_candidate_fk::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl MigrationTrait for Migration {
|
|||
.col(ColumnDef::new(Candidate::Surname).string())
|
||||
.col(ColumnDef::new(Candidate::BirthSurname).string())
|
||||
.col(ColumnDef::new(Candidate::Birthplace).string())
|
||||
.col(ColumnDef::new(Candidate::Birthdate).date())
|
||||
.col(ColumnDef::new(Candidate::Birthdate).string())
|
||||
.col(ColumnDef::new(Candidate::Address).string())
|
||||
.col(ColumnDef::new(Candidate::Telephone).string())
|
||||
.col(ColumnDef::new(Candidate::Citizenship).string())
|
||||
|
|
|
|||
Loading…
Reference in a new issue