mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-06 11:30:44 +00:00
fix: list candidates
This commit is contained in:
parent
cf25920a5c
commit
61facc503c
21 changed files with 178 additions and 85 deletions
|
|
@ -2,7 +2,7 @@ use std::net::{SocketAddr, IpAddr, Ipv4Addr};
|
||||||
|
|
||||||
use portfolio_core::{
|
use portfolio_core::{
|
||||||
crypto::random_12_char_string,
|
crypto::random_12_char_string,
|
||||||
services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, models::{candidate::{BaseCandidateResponse, CreateCandidateResponse, ApplicationDetails}, auth::AuthenticableTrait}, sea_orm::prelude::Uuid, Query, error::ServiceError, utils::csv,
|
services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, models::{candidate::{BaseCandidateResponse, CreateCandidateResponse, ApplicationDetails}, auth::AuthenticableTrait, application::ApplicationResponse}, sea_orm::prelude::Uuid, Query, error::ServiceError, utils::csv,
|
||||||
};
|
};
|
||||||
use requests::{AdminLoginRequest, RegisterRequest};
|
use requests::{AdminLoginRequest, RegisterRequest};
|
||||||
use rocket::http::{Cookie, Status, CookieJar};
|
use rocket::http::{Cookie, Status, CookieJar};
|
||||||
|
|
@ -114,7 +114,7 @@ pub async fn list_candidates(
|
||||||
session: AdminAuth,
|
session: AdminAuth,
|
||||||
field: Option<String>,
|
field: Option<String>,
|
||||||
page: Option<u64>,
|
page: Option<u64>,
|
||||||
) -> Result<Json<Vec<BaseCandidateResponse>>, Custom<String>> {
|
) -> Result<Json<Vec<ApplicationResponse>>, Custom<String>> {
|
||||||
let db = conn.into_inner();
|
let db = conn.into_inner();
|
||||||
let private_key = session.get_private_key();
|
let private_key = session.get_private_key();
|
||||||
if let Some(field) = field.clone() {
|
if let Some(field) = field.clone() {
|
||||||
|
|
@ -124,9 +124,11 @@ pub async fn list_candidates(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let candidates = CandidateService::list_candidates(&private_key, db, field, page)
|
/* let candidates = CandidateService::list_candidates(&private_key, db, field, page)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?; */
|
||||||
|
let candidates = ApplicationService::list_applications(&private_key, db)
|
||||||
|
.await.map_err(to_custom_error)?;
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
Json(candidates)
|
Json(candidates)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use portfolio_core::models::auth::AuthenticableTrait;
|
||||||
use portfolio_core::models::candidate::{ApplicationDetails, NewCandidateResponse};
|
use portfolio_core::models::candidate::{ApplicationDetails, NewCandidateResponse};
|
||||||
use portfolio_core::sea_orm::prelude::Uuid;
|
use portfolio_core::sea_orm::prelude::Uuid;
|
||||||
use portfolio_core::services::application_service::ApplicationService;
|
use portfolio_core::services::application_service::ApplicationService;
|
||||||
use portfolio_core::services::candidate_service::CandidateService;
|
|
||||||
use portfolio_core::services::portfolio_service::{PortfolioService, SubmissionProgress};
|
use portfolio_core::services::portfolio_service::{PortfolioService, SubmissionProgress};
|
||||||
use requests::LoginRequest;
|
use requests::LoginRequest;
|
||||||
use rocket::http::{Cookie, CookieJar, Status};
|
use rocket::http::{Cookie, CookieJar, Status};
|
||||||
|
|
@ -127,9 +126,9 @@ pub async fn upload_cover_letter(
|
||||||
session: ApplicationAuth,
|
session: ApplicationAuth,
|
||||||
letter: Letter,
|
letter: Letter,
|
||||||
) -> Result<(), Custom<String>> {
|
) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.id, letter.into())
|
PortfolioService::add_cover_letter_to_cache(application.candidate_id, letter.into())
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -138,9 +137,9 @@ pub async fn upload_cover_letter(
|
||||||
|
|
||||||
#[delete("/cover_letter")]
|
#[delete("/cover_letter")]
|
||||||
pub async fn delete_cover_letter(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
pub async fn delete_cover_letter(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::delete_cover_letter_from_cache(candidate.id)
|
PortfolioService::delete_cover_letter_from_cache(application.candidate_id)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -152,9 +151,9 @@ pub async fn upload_portfolio_letter(
|
||||||
session: ApplicationAuth,
|
session: ApplicationAuth,
|
||||||
letter: Letter,
|
letter: Letter,
|
||||||
) -> Result<(), Custom<String>> {
|
) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.id, letter.into())
|
PortfolioService::add_portfolio_letter_to_cache(application.candidate_id, letter.into())
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -165,7 +164,7 @@ pub async fn upload_portfolio_letter(
|
||||||
pub async fn delete_portfolio_letter(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
pub async fn delete_portfolio_letter(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let candidate: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::delete_portfolio_letter_from_cache(candidate.id)
|
PortfolioService::delete_portfolio_letter_from_cache(candidate.candidate_id)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -177,9 +176,9 @@ pub async fn upload_portfolio_zip(
|
||||||
session: ApplicationAuth,
|
session: ApplicationAuth,
|
||||||
portfolio: Portfolio,
|
portfolio: Portfolio,
|
||||||
) -> Result<(), Custom<String>> {
|
) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.id, portfolio.into())
|
PortfolioService::add_portfolio_zip_to_cache(application.candidate_id, portfolio.into())
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -188,9 +187,9 @@ pub async fn upload_portfolio_zip(
|
||||||
|
|
||||||
#[delete("/portfolio_zip")]
|
#[delete("/portfolio_zip")]
|
||||||
pub async fn delete_portfolio_zip(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
pub async fn delete_portfolio_zip(session: ApplicationAuth) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::delete_portfolio_zip_from_cache(candidate.id)
|
PortfolioService::delete_portfolio_zip_from_cache(application.candidate_id)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -201,9 +200,9 @@ pub async fn delete_portfolio_zip(session: ApplicationAuth) -> Result<(), Custom
|
||||||
pub async fn submission_progress(
|
pub async fn submission_progress(
|
||||||
session: ApplicationAuth,
|
session: ApplicationAuth,
|
||||||
) -> Result<Json<SubmissionProgress>, Custom<String>> {
|
) -> Result<Json<SubmissionProgress>, Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
let progress = PortfolioService::get_submission_progress(candidate.id)
|
let progress = PortfolioService::get_submission_progress(application.candidate_id)
|
||||||
.await
|
.await
|
||||||
.map(|x| Json(x))
|
.map(|x| Json(x))
|
||||||
.map_err(to_custom_error);
|
.map_err(to_custom_error);
|
||||||
|
|
@ -242,9 +241,9 @@ pub async fn submit_portfolio(
|
||||||
pub async fn delete_portfolio(
|
pub async fn delete_portfolio(
|
||||||
session: ApplicationAuth,
|
session: ApplicationAuth,
|
||||||
) -> Result<(), Custom<String>> {
|
) -> Result<(), Custom<String>> {
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
PortfolioService::delete_portfolio(candidate.id)
|
PortfolioService::delete_portfolio(application.candidate_id)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error)?;
|
.map_err(to_custom_error)?;
|
||||||
|
|
||||||
|
|
@ -254,9 +253,9 @@ pub async fn delete_portfolio(
|
||||||
#[get("/download")]
|
#[get("/download")]
|
||||||
pub async fn download_portfolio(session: ApplicationAuth) -> Result<Vec<u8>, Custom<String>> {
|
pub async fn download_portfolio(session: ApplicationAuth) -> Result<Vec<u8>, Custom<String>> {
|
||||||
let private_key = session.get_private_key();
|
let private_key = session.get_private_key();
|
||||||
let candidate: entity::application::Model = session.into();
|
let application: entity::application::Model = session.into();
|
||||||
|
|
||||||
let file = PortfolioService::get_portfolio(candidate.id, private_key)
|
let file = PortfolioService::get_portfolio(application.candidate_id, private_key)
|
||||||
.await
|
.await
|
||||||
.map_err(to_custom_error);
|
.map_err(to_custom_error);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ impl Mutation {
|
||||||
.insert(db)
|
.insert(db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
info!("CANDIDATE {} CREATED", candidate.application);
|
info!("CANDIDATE {} CREATED", candidate.id);
|
||||||
Ok(candidate)
|
Ok(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ impl Mutation {
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
candidate: candidate::Model,
|
candidate: candidate::Model,
|
||||||
) -> Result<DeleteResult, DbErr> {
|
) -> Result<DeleteResult, DbErr> {
|
||||||
let application = candidate.application;
|
let application = candidate.id;
|
||||||
let delete = candidate.delete(db).await?;
|
let delete = candidate.delete(db).await?;
|
||||||
|
|
||||||
warn!("CANDIDATE {} DELETED", application);
|
warn!("CANDIDATE {} DELETED", application);
|
||||||
|
|
@ -47,7 +47,7 @@ impl Mutation {
|
||||||
user: candidate::Model,
|
user: candidate::Model,
|
||||||
enc_candidate: EncryptedCandidateDetails,
|
enc_candidate: EncryptedCandidateDetails,
|
||||||
) -> Result<candidate::Model, sea_orm::DbErr> {
|
) -> Result<candidate::Model, sea_orm::DbErr> {
|
||||||
let application = user.application;
|
let application = user.id;
|
||||||
let mut candidate: candidate::ActiveModel = user.into();
|
let mut candidate: candidate::ActiveModel = user.into();
|
||||||
|
|
||||||
candidate.name = Set(enc_candidate.name.map(|e| e.into()));
|
candidate.name = Set(enc_candidate.name.map(|e| e.into()));
|
||||||
|
|
@ -92,7 +92,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
let candidate = Query::find_candidate_by_id(&db, candidate.id)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(candidate.is_some());
|
assert!(candidate.is_some());
|
||||||
|
|
@ -116,7 +116,7 @@ mod tests {
|
||||||
|
|
||||||
let candidate = Mutation::update_candidate_details(&db, candidate, encrypted_details.candidate).await.unwrap();
|
let candidate = Mutation::update_candidate_details(&db, candidate, encrypted_details.candidate).await.unwrap();
|
||||||
|
|
||||||
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
let candidate = Query::find_candidate_by_id(&db, candidate.id)
|
||||||
.await
|
.await
|
||||||
.unwrap().unwrap();
|
.unwrap().unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_parent = Mutation::create_parent(&db, candidate.application).await.unwrap();
|
let new_parent = Mutation::create_parent(&db, candidate.id).await.unwrap();
|
||||||
|
|
||||||
let parent = Query::find_parent_by_id(&db, new_parent.id).await.unwrap();
|
let parent = Query::find_parent_by_id(&db, new_parent.id).await.unwrap();
|
||||||
assert!(parent.is_some());
|
assert!(parent.is_some());
|
||||||
|
|
@ -73,7 +73,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let parent = Mutation::create_parent(&db, candidate.application).await.unwrap();
|
let parent = Mutation::create_parent(&db, candidate.id).await.unwrap();
|
||||||
|
|
||||||
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
||||||
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,17 @@
|
||||||
use entity::{application, candidate};
|
use entity::{application, candidate};
|
||||||
use sea_orm::{EntityTrait, DbErr, DbConn, ModelTrait};
|
use sea_orm::{EntityTrait, DbErr, DbConn, ModelTrait, FromQueryResult, QuerySelect, JoinType, RelationTrait};
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Clone)]
|
||||||
|
pub struct ApplicationCandidateJoin {
|
||||||
|
pub application_id: i32,
|
||||||
|
// pub personal_id_number: String,
|
||||||
|
pub candidate_id: i32,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub surname: Option<String>,
|
||||||
|
pub email: Option<String>,
|
||||||
|
pub telephone: Option<String>,
|
||||||
|
pub study: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
use crate::Query;
|
use crate::Query;
|
||||||
|
|
||||||
|
|
@ -22,4 +34,22 @@ impl Query {
|
||||||
.one(db)
|
.one(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_applications(
|
||||||
|
db: &DbConn,
|
||||||
|
) -> Result<Vec<ApplicationCandidateJoin>, DbErr> {
|
||||||
|
application::Entity::find()
|
||||||
|
// .column_as(application::Column::Id, "application_id")
|
||||||
|
.join(JoinType::InnerJoin, application::Relation::Candidate.def())
|
||||||
|
.column_as(application::Column::Id, "application_id")
|
||||||
|
.column_as(candidate::Column::Id, "candidate_id")
|
||||||
|
.column_as(candidate::Column::Name, "name")
|
||||||
|
.column_as(candidate::Column::Surname, "surname")
|
||||||
|
.column_as(candidate::Column::Email, "email")
|
||||||
|
.column_as(candidate::Column::Telephone, "telephone")
|
||||||
|
.column_as(candidate::Column::Study, "study")
|
||||||
|
.into_model::<ApplicationCandidateJoin>()
|
||||||
|
.all(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ impl Query {
|
||||||
} else {
|
} else {
|
||||||
select
|
select
|
||||||
}
|
}
|
||||||
.order_by(candidate::Column::Application, Order::Asc)
|
.order_by(candidate::Column::Id, Order::Asc)
|
||||||
.into_model::<CandidateResult>();
|
.into_model::<CandidateResult>();
|
||||||
|
|
||||||
if let Some(page) = page {
|
if let Some(page) = page {
|
||||||
|
|
@ -66,7 +66,7 @@ impl Query {
|
||||||
db: &DbConn
|
db: &DbConn
|
||||||
) -> Result<Vec<candidate::Model>, DbErr> {
|
) -> Result<Vec<candidate::Model>, DbErr> {
|
||||||
Candidate::find()
|
Candidate::find()
|
||||||
.order_by(candidate::Column::Application, Order::Asc)
|
.order_by(candidate::Column::Id, Order::Asc)
|
||||||
.all(db)
|
.all(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
@ -75,8 +75,8 @@ impl Query {
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
) -> Result<Vec<ApplicationId>, DbErr> {
|
) -> Result<Vec<ApplicationId>, DbErr> {
|
||||||
Candidate::find()
|
Candidate::find()
|
||||||
.order_by(candidate::Column::Application, Order::Asc)
|
.order_by(candidate::Column::Id, Order::Asc)
|
||||||
.column(candidate::Column::Application)
|
.column(candidate::Column::Id)
|
||||||
.into_model::<ApplicationId>()
|
.into_model::<ApplicationId>()
|
||||||
.all(db)
|
.all(db)
|
||||||
.await
|
.await
|
||||||
|
|
@ -97,7 +97,7 @@ mod tests {
|
||||||
async fn test_find_candidate_by_id() {
|
async fn test_find_candidate_by_id() {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
let candidate = candidate::ActiveModel {
|
let candidate = candidate::ActiveModel {
|
||||||
application: Set(103158),
|
id: Set(103158),
|
||||||
personal_identification_number: Set("test".to_string()),
|
personal_identification_number: Set("test".to_string()),
|
||||||
created_at: Set(chrono::offset::Local::now().naive_local()),
|
created_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
|
|
@ -107,7 +107,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
let candidate = Query::find_candidate_by_id(&db, candidate.id)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(candidate.is_some());
|
assert!(candidate.is_some());
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ mod tests {
|
||||||
const APPLICATION_ID: i32 = 103158;
|
const APPLICATION_ID: i32 = 103158;
|
||||||
|
|
||||||
candidate::ActiveModel {
|
candidate::ActiveModel {
|
||||||
application: Set(APPLICATION_ID),
|
id: Set(APPLICATION_ID),
|
||||||
personal_identification_number: Set("test".to_string()),
|
personal_identification_number: Set("test".to_string()),
|
||||||
created_at: Set(chrono::offset::Local::now().naive_local()),
|
created_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
|
|
|
||||||
42
core/src/models/application.rs
Normal file
42
core/src/models/application.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
use crate::{database::query::application::ApplicationCandidateJoin, services::portfolio_service::SubmissionProgress, error::ServiceError};
|
||||||
|
|
||||||
|
use super::candidate_details::EncryptedString;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ApplicationResponse {
|
||||||
|
pub application_id: i32,
|
||||||
|
// pub personal_id_number: String,
|
||||||
|
pub candidate_id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub surname: String,
|
||||||
|
pub email: String,
|
||||||
|
pub telephone: String,
|
||||||
|
pub study: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationResponse {
|
||||||
|
pub async fn from_encrypted(
|
||||||
|
private_key: &String,
|
||||||
|
c: ApplicationCandidateJoin
|
||||||
|
) -> Result<Self, ServiceError> {
|
||||||
|
let name = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.name).ok(), private_key).await?;
|
||||||
|
let surname = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.surname).ok(), private_key).await?;
|
||||||
|
let email = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.email).ok(), private_key).await?;
|
||||||
|
let telephone = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.telephone).ok(), private_key).await?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
Self {
|
||||||
|
application_id: c.application_id,
|
||||||
|
name: name.unwrap_or_default(),
|
||||||
|
surname: surname.unwrap_or_default(),
|
||||||
|
email: email.unwrap_or_default(),
|
||||||
|
telephone: telephone.unwrap_or_default(),
|
||||||
|
study: c.study.unwrap_or_default(),
|
||||||
|
candidate_id: c.candidate_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -108,7 +108,7 @@ impl NewCandidateResponse {
|
||||||
let id_number = EncryptedString::from(c.personal_identification_number).decrypt(private_key).await?;
|
let id_number = EncryptedString::from(c.personal_identification_number).decrypt(private_key).await?;
|
||||||
Ok(
|
Ok(
|
||||||
Self {
|
Self {
|
||||||
application_id: c.application,
|
application_id: c.id,
|
||||||
personal_id_number: id_number,
|
personal_id_number: id_number,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod candidate_details;
|
pub mod candidate_details;
|
||||||
pub mod candidate;
|
pub mod candidate;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod application;
|
||||||
|
|
@ -3,9 +3,9 @@ use chrono::Duration;
|
||||||
use entity::{candidate, parent, application, session};
|
use entity::{candidate, parent, application, session};
|
||||||
use sea_orm::{DbConn, prelude::Uuid, IntoActiveModel};
|
use sea_orm::{DbConn, prelude::Uuid, IntoActiveModel};
|
||||||
|
|
||||||
use crate::{error::ServiceError, Query, utils::db::get_recipients, models::candidate_details::{EncryptedApplicationDetails}, models::{candidate::ApplicationDetails, candidate_details::EncryptedString, auth::AuthenticableTrait}, Mutation, crypto::{hash_password, self}};
|
use crate::{error::ServiceError, Query, utils::db::get_recipients, models::candidate_details::{EncryptedApplicationDetails}, models::{candidate::ApplicationDetails, candidate_details::EncryptedString, auth::AuthenticableTrait, application::ApplicationResponse}, Mutation, crypto::{hash_password, self}};
|
||||||
|
|
||||||
use super::{parent_service::ParentService, candidate_service::CandidateService, session_service::SessionService};
|
use super::{parent_service::ParentService, candidate_service::CandidateService, session_service::SessionService, portfolio_service::PortfolioService};
|
||||||
|
|
||||||
const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"];
|
const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"];
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ impl ApplicationService {
|
||||||
let application = Mutation::create_application(
|
let application = Mutation::create_application(
|
||||||
db,
|
db,
|
||||||
application_id,
|
application_id,
|
||||||
candidate.application,
|
candidate.id,
|
||||||
hashed_password,
|
hashed_password,
|
||||||
enc_personal_id_number.to_string(),
|
enc_personal_id_number.to_string(),
|
||||||
pubkey,
|
pubkey,
|
||||||
|
|
@ -87,8 +87,8 @@ impl ApplicationService {
|
||||||
personal_id_number: String,
|
personal_id_number: String,
|
||||||
) -> Result<(application::Model, candidate::Model, parent::Model), ServiceError> {
|
) -> Result<(application::Model, candidate::Model, parent::Model), ServiceError> {
|
||||||
let candidate = CandidateService::create(db, personal_id_number).await?;
|
let candidate = CandidateService::create(db, personal_id_number).await?;
|
||||||
let parent = ParentService::create(db, candidate.application).await?;
|
let parent = ParentService::create(db, candidate.id).await?;
|
||||||
let application = Mutation::update_candidate_fk(db, application, candidate.application).await?;
|
let application = Mutation::update_candidate_fk(db, application, candidate.id).await?;
|
||||||
Ok(
|
Ok(
|
||||||
(
|
(
|
||||||
application,
|
application,
|
||||||
|
|
@ -141,7 +141,26 @@ impl ApplicationService {
|
||||||
} else {
|
} else {
|
||||||
Err(ServiceError::Forbidden)
|
Err(ServiceError::Forbidden)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_applications(
|
||||||
|
private_key: &String,
|
||||||
|
db: &DbConn,
|
||||||
|
) -> Result<Vec<ApplicationResponse>, ServiceError> {
|
||||||
|
let applications = Query::list_applications(db).await?;
|
||||||
|
|
||||||
|
futures::future::try_join_all(
|
||||||
|
applications
|
||||||
|
.iter()
|
||||||
|
.map(|c| async move {
|
||||||
|
ApplicationResponse::from_encrypted(
|
||||||
|
private_key,
|
||||||
|
c.to_owned()
|
||||||
|
).await
|
||||||
|
})
|
||||||
|
).await
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn decrypt_private_key(
|
async fn decrypt_private_key(
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,14 @@ impl CandidateService {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
PortfolioService::create_user_dir(candidate.application).await?;
|
PortfolioService::create_user_dir(candidate.id).await?;
|
||||||
|
|
||||||
|
|
||||||
Ok(candidate)
|
Ok(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_candidate(db: &DbConn, candidate: candidate::Model) -> Result<(), ServiceError> {
|
pub async fn delete_candidate(db: &DbConn, candidate: candidate::Model) -> Result<(), ServiceError> {
|
||||||
PortfolioService::delete_candidate_root(candidate.application).await?;
|
PortfolioService::delete_candidate_root(candidate.id).await?;
|
||||||
|
|
||||||
Mutation::delete_candidate(db, candidate).await?;
|
Mutation::delete_candidate(db, candidate).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ impl ParentService {
|
||||||
for i in 0..parents_details.len() {
|
for i in 0..parents_details.len() {
|
||||||
let found_parent = match found_parents.get(i) {
|
let found_parent = match found_parents.get(i) {
|
||||||
Some(parent) => parent.to_owned(),
|
Some(parent) => parent.to_owned(),
|
||||||
None => ParentService::create(db, ref_candidate.application).await?,
|
None => ParentService::create(db, ref_candidate.id).await?,
|
||||||
};
|
};
|
||||||
let enc_details = EncryptedParentDetails::new(&parents_details[i], recipients).await?;
|
let enc_details = EncryptedParentDetails::new(&parents_details[i], recipients).await?;
|
||||||
let parent = Mutation::add_parent_details(db, found_parent, enc_details.clone()).await?;
|
let parent = Mutation::add_parent_details(db, found_parent, enc_details.clone()).await?;
|
||||||
|
|
@ -94,8 +94,8 @@ mod tests {
|
||||||
async fn create_parent_test() {
|
async fn create_parent_test() {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
let candidate = CandidateService::create(&db, "".to_string()).await.unwrap();
|
let candidate = CandidateService::create(&db, "".to_string()).await.unwrap();
|
||||||
super::ParentService::create(&db, candidate.application).await.unwrap();
|
super::ParentService::create(&db, candidate.id).await.unwrap();
|
||||||
super::ParentService::create(&db, candidate.application).await.unwrap();
|
super::ParentService::create(&db, candidate.id).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #[tokio::test]
|
/* #[tokio::test]
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ impl PortfolioService {
|
||||||
|
|
||||||
/// Move files from cache to final directory and delete cache afterwards
|
/// Move files from cache to final directory and delete cache afterwards
|
||||||
pub async fn submit(public_key: &String, candidate: &candidate::Model, db: &DbConn) -> Result<(), ServiceError> {
|
pub async fn submit(public_key: &String, candidate: &candidate::Model, db: &DbConn) -> Result<(), ServiceError> {
|
||||||
let candidate_id = candidate.application;
|
let candidate_id = candidate.id;
|
||||||
let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf();
|
let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf();
|
||||||
let cache_path = path.join("cache");
|
let cache_path = path.join("cache");
|
||||||
|
|
||||||
|
|
@ -277,7 +277,7 @@ impl PortfolioService {
|
||||||
return Err(ServiceError::IncompletePortfolio);
|
return Err(ServiceError::IncompletePortfolio);
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("PORTFOLIO {} SUBMIT STARTED", candidate.application);
|
info!("PORTFOLIO {} SUBMIT STARTED", candidate.id);
|
||||||
|
|
||||||
let mut archive = tokio::fs::File::create(path.join(FileType::PortfolioZip.as_str())).await?;
|
let mut archive = tokio::fs::File::create(path.join(FileType::PortfolioZip.as_str())).await?;
|
||||||
let mut writer = async_zip::write::ZipFileWriter::new(&mut archive);
|
let mut writer = async_zip::write::ZipFileWriter::new(&mut archive);
|
||||||
|
|
@ -428,8 +428,8 @@ mod tests {
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(tokio::fs::metadata(temp_dir.join(candidate.application.to_string())).await.is_ok());
|
assert!(tokio::fs::metadata(temp_dir.join(candidate.id.to_string())).await.is_ok());
|
||||||
assert!(tokio::fs::metadata(temp_dir.join(candidate.application.to_string()).join("cache")).await.is_ok());
|
assert!(tokio::fs::metadata(temp_dir.join(candidate.id.to_string()).join("cache")).await.is_ok());
|
||||||
|
|
||||||
tokio::fs::remove_dir_all(temp_dir).await.unwrap();
|
tokio::fs::remove_dir_all(temp_dir).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -621,11 +621,11 @@ mod tests {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
let (application, candidate, _) = put_user_data(&db).await;
|
let (application, candidate, _) = put_user_data(&db).await;
|
||||||
|
|
||||||
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.application).await;
|
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.id).await;
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_cover_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_zip_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
|
|
||||||
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -640,17 +640,17 @@ mod tests {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
let (application, candidate, _) = put_user_data(&db).await;
|
let (application, candidate, _) = put_user_data(&db).await;
|
||||||
|
|
||||||
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.application).await;
|
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.id).await;
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_cover_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_zip_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
|
|
||||||
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
||||||
|
|
||||||
assert!(tokio::fs::metadata(application_dir.join("PORTFOLIO.age")).await.is_ok());
|
assert!(tokio::fs::metadata(application_dir.join("PORTFOLIO.age")).await.is_ok());
|
||||||
|
|
||||||
PortfolioService::delete_portfolio(candidate.application).await.unwrap();
|
PortfolioService::delete_portfolio(candidate.id).await.unwrap();
|
||||||
|
|
||||||
assert!(!tokio::fs::metadata(application_dir.join("PORTFOLIO.age")).await.is_ok());
|
assert!(!tokio::fs::metadata(application_dir.join("PORTFOLIO.age")).await.is_ok());
|
||||||
|
|
||||||
|
|
@ -663,29 +663,29 @@ mod tests {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
|
|
||||||
let (application, candidate, _) = put_user_data(&db).await;
|
let (application, candidate, _) = put_user_data(&db).await;
|
||||||
let (temp_dir, _, _) = create_data_store_temp_dir(candidate.application).await;
|
let (temp_dir, _, _) = create_data_store_temp_dir(candidate.id).await;
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_cover_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_zip_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
|
|
||||||
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
||||||
|
|
||||||
assert!(PortfolioService::is_portfolio_submitted(candidate.application).await);
|
assert!(PortfolioService::is_portfolio_submitted(candidate.id).await);
|
||||||
|
|
||||||
clear_data_store_temp_dir(temp_dir).await;
|
clear_data_store_temp_dir(temp_dir).await;
|
||||||
|
|
||||||
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.application).await;
|
let (temp_dir, application_dir, _) = create_data_store_temp_dir(candidate.id).await;
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_cover_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_letter_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.application, vec![0]).await.unwrap();
|
PortfolioService::add_portfolio_zip_to_cache(candidate.id, vec![0]).await.unwrap();
|
||||||
|
|
||||||
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
PortfolioService::submit(&application.public_key, &candidate, &db).await.unwrap();
|
||||||
|
|
||||||
tokio::fs::remove_file(application_dir.join("PORTFOLIO.age")).await.unwrap();
|
tokio::fs::remove_file(application_dir.join("PORTFOLIO.age")).await.unwrap();
|
||||||
|
|
||||||
assert!(!PortfolioService::is_portfolio_submitted(candidate.application).await);
|
assert!(!PortfolioService::is_portfolio_submitted(candidate.id).await);
|
||||||
|
|
||||||
clear_data_store_temp_dir(temp_dir).await;
|
clear_data_store_temp_dir(temp_dir).await;
|
||||||
}
|
}
|
||||||
|
|
@ -696,19 +696,19 @@ mod tests {
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
let (application, candidate, _parent) = put_user_data(&db).await;
|
let (application, candidate, _parent) = put_user_data(&db).await;
|
||||||
|
|
||||||
let (temp_dir, _, _) = create_data_store_temp_dir(candidate.application).await;
|
let (temp_dir, _, _) = create_data_store_temp_dir(candidate.id).await;
|
||||||
|
|
||||||
let private_key = crypto::decrypt_password(application.private_key.clone(), "test".to_string())
|
let private_key = crypto::decrypt_password(application.private_key.clone(), "test".to_string())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
PortfolioService::add_cover_letter_to_cache(candidate.application, vec![0])
|
PortfolioService::add_cover_letter_to_cache(candidate.id, vec![0])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
PortfolioService::add_portfolio_letter_to_cache(candidate.application, vec![0])
|
PortfolioService::add_portfolio_letter_to_cache(candidate.id, vec![0])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
PortfolioService::add_portfolio_zip_to_cache(candidate.application, vec![0])
|
PortfolioService::add_portfolio_zip_to_cache(candidate.id, vec![0])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -716,7 +716,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
PortfolioService::get_portfolio(candidate.application, private_key)
|
PortfolioService::get_portfolio(candidate.id, private_key)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub async fn export(
|
||||||
|
|
||||||
let candidates_with_parents = Query::list_candidates_full(&db).await?;
|
let candidates_with_parents = Query::list_candidates_full(&db).await?;
|
||||||
for candidate in candidates_with_parents {
|
for candidate in candidates_with_parents {
|
||||||
let application = candidate.application;
|
let application = candidate.id;
|
||||||
let parents = Query::find_candidate_parents(db, &candidate).await?;
|
let parents = Query::find_candidate_parents(db, &candidate).await?;
|
||||||
|
|
||||||
let row: Row = match EncryptedApplicationDetails::try_from((&candidate, parents)) {
|
let row: Row = match EncryptedApplicationDetails::try_from((&candidate, parents)) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub enum Relation {
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::candidate::Entity",
|
belongs_to = "super::candidate::Entity",
|
||||||
from = "Column::CandidateId",
|
from = "Column::CandidateId",
|
||||||
to = "super::candidate::Column::Application",
|
to = "super::candidate::Column::Id",
|
||||||
on_update = "Cascade",
|
on_update = "Cascade",
|
||||||
on_delete = "Cascade"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use sea_orm::entity::prelude::*;
|
||||||
#[sea_orm(table_name = "candidate")]
|
#[sea_orm(table_name = "candidate")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub application: i32,
|
pub id: i32,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub surname: Option<String>,
|
pub surname: Option<String>,
|
||||||
pub birth_surname: Option<String>,
|
pub birth_surname: Option<String>,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub enum Relation {
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::candidate::Entity",
|
belongs_to = "super::candidate::Entity",
|
||||||
from = "Column::Application",
|
from = "Column::Application",
|
||||||
to = "super::candidate::Column::Application",
|
to = "super::candidate::Column::Id",
|
||||||
on_update = "Cascade",
|
on_update = "Cascade",
|
||||||
on_delete = "Cascade"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ impl MigrationTrait for Migration {
|
||||||
.table(Candidate::Table)
|
.table(Candidate::Table)
|
||||||
.if_not_exists()
|
.if_not_exists()
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(Candidate::Application)
|
ColumnDef::new(Candidate::Id)
|
||||||
.integer()
|
.integer()
|
||||||
.not_null()
|
.not_null()
|
||||||
.primary_key()
|
.primary_key()
|
||||||
|
|
@ -49,7 +49,7 @@ impl MigrationTrait for Migration {
|
||||||
#[derive(Iden)]
|
#[derive(Iden)]
|
||||||
pub enum Candidate {
|
pub enum Candidate {
|
||||||
Table,
|
Table,
|
||||||
Application,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
Surname,
|
Surname,
|
||||||
BirthSurname,
|
BirthSurname,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl MigrationTrait for Migration {
|
||||||
manager.create_foreign_key(ForeignKey::create()
|
manager.create_foreign_key(ForeignKey::create()
|
||||||
.name("candidate_fk")
|
.name("candidate_fk")
|
||||||
.from(Parent::Table, Parent::Application)
|
.from(Parent::Table, Parent::Application)
|
||||||
.to(Candidate::Table, Candidate::Application)
|
.to(Candidate::Table, Candidate::Id)
|
||||||
.on_delete(ForeignKeyAction::Cascade)
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
.on_update(ForeignKeyAction::Cascade)
|
.on_update(ForeignKeyAction::Cascade)
|
||||||
.to_owned()).await
|
.to_owned()).await
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl MigrationTrait for Migration {
|
||||||
manager.create_foreign_key(ForeignKey::create()
|
manager.create_foreign_key(ForeignKey::create()
|
||||||
.name("candidate_fk")
|
.name("candidate_fk")
|
||||||
.from(Application::Table, Application::CandidateId)
|
.from(Application::Table, Application::CandidateId)
|
||||||
.to(Candidate::Table, Candidate::Application)
|
.to(Candidate::Table, Candidate::Id)
|
||||||
.on_delete(ForeignKeyAction::Cascade)
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
.on_update(ForeignKeyAction::Cascade)
|
.on_update(ForeignKeyAction::Cascade)
|
||||||
.to_owned()).await
|
.to_owned()).await
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue