feat: multiple parent csv export

This commit is contained in:
Sebastian Pravda 2022-12-16 11:44:32 +01:00
parent 38e96330ae
commit 53be6cb72d
No known key found for this signature in database
GPG key ID: F3BC84F08EFA3F57
8 changed files with 35 additions and 35 deletions

View file

@ -2,7 +2,7 @@ use sea_orm::*;
use ::entity::{candidate, candidate::Entity as Candidate, parent}; use ::entity::{candidate, candidate::Entity as Candidate, parent};
use crate::{Query, models::candidate::CandidateWithParent}; use crate::Query;
pub const PAGE_SIZE: u64 = 20; pub const PAGE_SIZE: u64 = 20;
@ -39,7 +39,7 @@ impl Query {
.await .await
} }
pub async fn list_candidates( pub async fn list_candidates_preview(
db: &DbConn, db: &DbConn,
field_of_study_opt: Option<String>, field_of_study_opt: Option<String>,
page: Option<u64>, page: Option<u64>,
@ -64,18 +64,11 @@ impl Query {
} }
} }
pub async fn list_candidates_full(
pub async fn list_all_candidates_with_parents( db: &DbConn
db: &DbConn, ) -> Result<Vec<candidate::Model>, DbErr> {
) -> Result<Vec<CandidateWithParent>, DbErr> {
Candidate::find() Candidate::find()
.order_by(candidate::Column::Application, Order::Asc) .order_by(candidate::Column::Application, Order::Asc)
.join(JoinType::InnerJoin, candidate::Relation::Parent.def())
.column_as(parent::Column::Name, "parent_name")
.column_as(parent::Column::Surname, "parent_surname")
.column_as(parent::Column::Telephone, "parent_telephone")
.column_as(parent::Column::Email, "parent_email")
.into_model::<CandidateWithParent>()
.all(db) .all(db)
.await .await
} }

View file

@ -21,7 +21,7 @@ impl Query {
pub async fn find_candidate_parents( pub async fn find_candidate_parents(
db: &DbConn, db: &DbConn,
candidate: candidate::Model, candidate: &candidate::Model,
) -> Result<Vec<Model>, DbErr> { ) -> Result<Vec<Model>, DbErr> {
candidate.find_related(parent::Entity) candidate.find_related(parent::Entity)

View file

@ -63,7 +63,7 @@ pub struct ApplicationDetails {
/// CSV export (admin endpoint) /// CSV export (admin endpoint)
#[derive(FromQueryResult, Serialize, Default)] #[derive(FromQueryResult, Serialize, Default)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CandidateWithParent { pub struct Row {
pub application: i32, pub application: i32,
pub name: Option<String>, pub name: Option<String>,
pub surname: Option<String>, pub surname: Option<String>,
@ -81,6 +81,11 @@ pub struct CandidateWithParent {
pub parent_surname: Option<String>, pub parent_surname: Option<String>,
pub parent_telephone: Option<String>, pub parent_telephone: Option<String>,
pub parent_email: Option<String>, pub parent_email: Option<String>,
pub second_parent_name: Option<String>,
pub second_parent_surname: Option<String>,
pub second_parent_telephone: Option<String>,
pub second_parent_email: Option<String>,
} }
impl BaseCandidateResponse { impl BaseCandidateResponse {

View file

@ -3,7 +3,7 @@ use chrono::NaiveDate;
use entity::{candidate, parent}; use entity::{candidate, parent};
use futures::future; use futures::future;
use crate::{crypto, models::candidate::{CandidateWithParent, ApplicationDetails}, error::ServiceError}; use crate::{crypto, models::candidate::{Row, ApplicationDetails}, error::ServiceError};
use super::candidate::{CandidateDetails, ParentDetails}; use super::candidate::{CandidateDetails, ParentDetails};
@ -290,11 +290,11 @@ impl TryFrom<(candidate::Model, Vec<parent::Model>)> for EncryptedApplicationDet
} }
} }
impl TryFrom<CandidateWithParent> for EncryptedApplicationDetails { impl TryFrom<Row> for EncryptedApplicationDetails {
type Error = ServiceError; type Error = ServiceError;
fn try_from( fn try_from(
cp: CandidateWithParent, cp: Row,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
Ok(EncryptedApplicationDetails { Ok(EncryptedApplicationDetails {
candidate: EncryptedCandidateDetails { candidate: EncryptedCandidateDetails {

View file

@ -43,7 +43,7 @@ impl ApplicationService {
candidate: candidate::Model, candidate: candidate::Model,
// parents: Vec<parent::Model>, // parents: Vec<parent::Model>,
) -> Result<ApplicationDetails, ServiceError> { ) -> Result<ApplicationDetails, ServiceError> {
let parents = Query::find_candidate_parents(db, candidate.clone()).await?; let parents = Query::find_candidate_parents(db, &candidate).await?;
let enc_details = EncryptedApplicationDetails::try_from((candidate, parents))?; let enc_details = EncryptedApplicationDetails::try_from((candidate, parents))?;
enc_details.decrypt(private_key).await enc_details.decrypt(private_key).await

View file

@ -102,7 +102,7 @@ impl CandidateService {
) -> Result<CreateCandidateResponse, ServiceError> { ) -> Result<CreateCandidateResponse, ServiceError> {
let candidate = Query::find_candidate_by_id(db, id).await? let candidate = Query::find_candidate_by_id(db, id).await?
.ok_or(ServiceError::CandidateNotFound)?; .ok_or(ServiceError::CandidateNotFound)?;
let parents = Query::find_candidate_parents(db, candidate.clone()).await?; let parents = Query::find_candidate_parents(db, &candidate).await?;
let new_password_plain = crypto::random_8_char_string(); let new_password_plain = crypto::random_8_char_string();
@ -163,7 +163,7 @@ impl CandidateService {
page: Option<u64>, page: Option<u64>,
) -> Result<Vec<BaseCandidateResponse>, ServiceError> { ) -> Result<Vec<BaseCandidateResponse>, ServiceError> {
let candidates = Query::list_candidates( let candidates = Query::list_candidates_preview(
db, db,
field_of_study, field_of_study,
page page
@ -374,7 +374,7 @@ pub mod tests {
#[cfg(test)] #[cfg(test)]
pub async fn put_user_data(db: &DbConn) -> (candidate::Model, Vec<parent::Model>) { pub async fn put_user_data(db: &DbConn) -> (candidate::Model, Vec<parent::Model>) {
use crate::{models::candidate_details::tests::APPLICATION_DETAILS, Query}; use crate::{models::candidate_details::tests::APPLICATION_DETAILS};
let plain_text_password = "test".to_string(); let plain_text_password = "test".to_string();
let (candidate, _parent) = ApplicationService::create_candidate_with_parent( let (candidate, _parent) = ApplicationService::create_candidate_with_parent(

View file

@ -1,7 +1,7 @@
use entity::{parent, candidate}; use entity::{parent, candidate};
use sea_orm::DbConn; use sea_orm::DbConn;
use crate::{error::ServiceError, Mutation, models::{candidate_details::{EncryptedParentDetails}, candidate::ParentDetails}, Query, utils::db::get_recipients}; use crate::{error::ServiceError, Mutation, models::{candidate_details::{EncryptedParentDetails}, candidate::ParentDetails}, Query};
pub struct ParentService; pub struct ParentService;
@ -22,7 +22,7 @@ impl ParentService {
parents_details: &Vec<ParentDetails>, parents_details: &Vec<ParentDetails>,
recipients: &Vec<String>, recipients: &Vec<String>,
) -> Result<Vec<parent::Model>, ServiceError> { ) -> Result<Vec<parent::Model>, ServiceError> {
let found_parents = Query::find_candidate_parents(db, ref_candidate.clone()).await?; let found_parents = Query::find_candidate_parents(db, &ref_candidate).await?;
if found_parents.len() > 2 { if found_parents.len() > 2 {
return Err(ServiceError::ParentOverflow); return Err(ServiceError::ParentOverflow);
} }
@ -48,7 +48,7 @@ mod tests {
use once_cell::sync::Lazy; 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 crate::{utils::db::get_memory_sqlite_connection, models::{candidate::{ParentDetails, ApplicationDetails, CandidateDetails}, candidate_details::EncryptedApplicationDetails}, services::{candidate_service::CandidateService, application_service::ApplicationService}, crypto};
use super::ParentService; use super::ParentService;

View file

@ -1,13 +1,9 @@
use sea_orm::{DbConn}; use sea_orm::{DbConn};
use crate::{error::ServiceError, models::candidate_details::{EncryptedApplicationDetails}, Query, models::candidate::{CandidateWithParent, ApplicationDetails}}; use crate::{error::ServiceError, models::candidate_details::{EncryptedApplicationDetails}, Query, models::candidate::{Row, ApplicationDetails}};
type Row = CandidateWithParent;
impl From<(i32, ApplicationDetails)> for Row { impl From<(i32, ApplicationDetails)> for Row {
fn from((application, d): (i32, ApplicationDetails)) -> Self { fn from((application, d): (i32, ApplicationDetails)) -> Self {
let c = d.candidate; let c = d.candidate;
let p = d.parents[0].clone();
Self { Self {
application, application,
name: Some(c.name), name: Some(c.name),
@ -22,10 +18,15 @@ impl From<(i32, ApplicationDetails)> for Row {
study: Some(c.study), study: Some(c.study),
personal_identification_number: Some(c.personal_id_number), personal_identification_number: Some(c.personal_id_number),
parent_name: Some(p.name), parent_name: d.parents.get(0).map(|p| p.name.clone()),
parent_surname: Some(p.surname), parent_surname: d.parents.get(0).map(|p| p.surname.clone()),
parent_telephone: Some(p.telephone), parent_telephone: d.parents.get(0).map(|p| p.telephone.clone()),
parent_email: Some(p.email), parent_email: d.parents.get(0).map(|p| p.email.clone()),
second_parent_name: d.parents.get(1).map(|p| p.name.clone()),
second_parent_surname: d.parents.get(1).map(|p| p.surname.clone()),
second_parent_telephone: d.parents.get(1).map(|p| p.telephone.clone()),
second_parent_email: d.parents.get(1).map(|p| p.email.clone()),
} }
} }
} }
@ -36,11 +37,12 @@ pub async fn export(
) -> Result<Vec<u8>, ServiceError> { ) -> Result<Vec<u8>, ServiceError> {
let mut wtr = csv::Writer::from_writer(vec![]); let mut wtr = csv::Writer::from_writer(vec![]);
let candidates_with_parents = Query::list_all_candidates_with_parents(&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.application;
let parents = Query::find_candidate_parents(db, &candidate).await?;
let row: Row = match EncryptedApplicationDetails::try_from(candidate) { let row: Row = match EncryptedApplicationDetails::try_from((candidate, parents)) {
Ok(d) => Row::from( Ok(d) => Row::from(
d d
.decrypt(private_key.to_string()) .decrypt(private_key.to_string())