refactor: models, serde camelCase

This commit is contained in:
Sebastian Pravda 2022-11-30 15:13:02 +01:00
parent 9566bb1471
commit 52417d3c87
No known key found for this signature in database
GPG key ID: F3BC84F08EFA3F57
14 changed files with 164 additions and 153 deletions

View file

@ -2,7 +2,7 @@ use std::net::{SocketAddr, IpAddr, Ipv4Addr};
use portfolio_core::{ use portfolio_core::{
crypto::random_8_char_string, crypto::random_8_char_string,
services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, responses::{BaseCandidateResponse, CreateCandidateResponse}, candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, services::{admin_service::AdminService, candidate_service::CandidateService, application_service::ApplicationService, portfolio_service::PortfolioService}, models::candidate::{BaseCandidateResponse, CreateCandidateResponse, ApplicationDetails}, sea_orm::prelude::Uuid,
}; };
use requests::{AdminLoginRequest, RegisterRequest}; use requests::{AdminLoginRequest, RegisterRequest};
use rocket::http::{Cookie, Status, CookieJar}; use rocket::http::{Cookie, Status, CookieJar};
@ -192,7 +192,7 @@ pub async fn get_candidate_portfolio(
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use portfolio_core::responses::CreateCandidateResponse; use portfolio_core::models::candidate::CreateCandidateResponse;
use rocket::{local::blocking::Client, http::{Cookie, Status}}; use rocket::{local::blocking::Client, http::{Cookie, Status}};
use crate::test::tests::{test_client, ADMIN_PASSWORD, ADMIN_ID}; use crate::test::tests::{test_client, ADMIN_PASSWORD, ADMIN_ID};

View file

@ -1,6 +1,6 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use portfolio_core::candidate_details::ApplicationDetails; use portfolio_core::models::candidate::ApplicationDetails;
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::candidate_service::CandidateService;
@ -264,7 +264,7 @@ pub async fn download_portfolio(session: CandidateAuth) -> Result<Vec<u8>, Custo
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use portfolio_core::{candidate_details::ApplicationDetails, crypto, sea_orm::prelude::Uuid}; use portfolio_core::{models::candidate::ApplicationDetails, crypto, sea_orm::prelude::Uuid};
use rocket::{ use rocket::{
http::{Cookie, Status}, http::{Cookie, Status},
local::blocking::Client, local::blocking::Client,

View file

@ -1,4 +1,4 @@
use crate::{candidate_details::EncryptedApplicationDetails, Mutation}; use crate::{Mutation, models::candidate_details::EncryptedApplicationDetails};
use ::entity::candidate::{self}; use ::entity::candidate::{self};
use sea_orm::*; use sea_orm::*;
@ -67,8 +67,8 @@ impl Mutation {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::candidate_details::tests::APPLICATION_DETAILS; use crate::models::candidate_details::EncryptedApplicationDetails;
use crate::candidate_details::{EncryptedApplicationDetails}; use crate::models::candidate_details::tests::APPLICATION_DETAILS;
use crate::utils::db::get_memory_sqlite_connection; use crate::utils::db::get_memory_sqlite_connection;
use crate::{Mutation, Query}; use crate::{Mutation, Query};

View file

@ -1,4 +1,4 @@
use crate::{candidate_details::EncryptedApplicationDetails, Mutation}; use crate::{Mutation, models::candidate_details::EncryptedApplicationDetails};
use ::entity::parent::{self, Model}; use ::entity::parent::{self, Model};
use sea_orm::*; use sea_orm::*;
@ -34,8 +34,8 @@ impl Mutation {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::candidate_details::tests::APPLICATION_DETAILS; use crate::models::candidate_details::EncryptedApplicationDetails;
use crate::candidate_details::{EncryptedApplicationDetails}; use crate::models::candidate_details::tests::APPLICATION_DETAILS;
use crate::utils::db::get_memory_sqlite_connection; use crate::utils::db::get_memory_sqlite_connection;
use crate::{Mutation, Query}; use crate::{Mutation, Query};

View file

@ -1,45 +1,11 @@
use sea_orm::*; use sea_orm::*;
use serde::Serialize;
use ::entity::{candidate, candidate::Entity as Candidate, parent}; use ::entity::{candidate, candidate::Entity as Candidate, parent};
use crate::Query; use crate::{Query, models::candidate::CandidateWithParent};
pub const PAGE_SIZE: u64 = 20; pub const PAGE_SIZE: u64 = 20;
#[derive(FromQueryResult, Serialize)]
pub struct CandidateParentResult {
pub application: i32,
pub name: Option<String>,
pub surname: Option<String>,
pub study: Option<String>,
pub citizenship: Option<String>,
pub parent_name: Option<String>,
pub parent_surname: Option<String>,
}
#[derive(FromQueryResult, Serialize, Default)]
pub struct CandidateWithParent { // TODO: use this instead of (Candidate, Parent)???
pub application: i32,
pub name: Option<String>,
pub surname: Option<String>,
pub birthplace: Option<String>,
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>,
pub personal_identification_number: Option<String>,
pub parent_name: Option<String>,
pub parent_surname: Option<String>,
pub parent_telephone: Option<String>,
pub parent_email: Option<String>,
}
#[derive(FromQueryResult)] #[derive(FromQueryResult)]
pub struct ApplicationId { pub struct ApplicationId {
application: i32, application: i32,
@ -51,6 +17,18 @@ impl ApplicationId {
} }
} }
#[derive(FromQueryResult)]
pub struct CandidateParentResult {
pub application: i32,
pub name: Option<String>,
pub surname: Option<String>,
pub study: Option<String>,
pub citizenship: Option<String>,
pub parent_name: Option<String>,
pub parent_surname: Option<String>,
}
impl Query { impl Query {
pub async fn find_candidate_by_id( pub async fn find_candidate_by_id(
db: &DbConn, db: &DbConn,

View file

@ -7,7 +7,6 @@ pub mod database;
pub mod crypto; pub mod crypto;
pub mod services; pub mod services;
pub mod error; pub mod error;
pub mod candidate_details;
pub mod responses; pub mod responses;
pub mod utils; pub mod utils;
pub mod models;

View file

@ -0,0 +1,98 @@
use chrono::NaiveDate;
use sea_orm::FromQueryResult;
use serde::{Serialize, Deserialize};
use crate::{error::ServiceError};
use super::candidate_details::decrypt_if_exists;
/// Create candidate (admin endpoint)
/// Password change (admin endpoint)
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateCandidateResponse {
pub application_id: i32,
pub personal_id_number: String,
pub password: String,
}
/// List candidates (admin endpoint)
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BaseCandidateResponse {
pub application_id: i32,
pub name: String,
pub surname: String,
pub study: String,
pub submitted: bool,
}
/// Candidate details (admin and candidate endpoints)
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ApplicationDetails {
// Candidate
pub 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,
pub personal_id_number: String,
// Parent
pub parent_name: String,
pub parent_surname: String,
pub parent_telephone: String,
pub parent_email: String,
}
/// CSV export (admin endpoint)
#[derive(FromQueryResult, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CandidateWithParent { // TODO: use this instead of (Candidate, Parent)???
pub application: i32,
pub name: Option<String>,
pub surname: Option<String>,
pub birthplace: Option<String>,
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>,
pub personal_identification_number: Option<String>,
pub parent_name: Option<String>,
pub parent_surname: Option<String>,
pub parent_telephone: Option<String>,
pub parent_email: Option<String>,
}
impl BaseCandidateResponse {
pub async fn from_encrypted(
private_key: &String,
application_id: i32,
name_opt: Option<String>,
surname_opt: Option<String>,
study_opt: Option<String>,
submitted: bool,
) -> Result<Self, ServiceError> {
let name = decrypt_if_exists(private_key, name_opt).await?;
let surname = decrypt_if_exists(private_key, surname_opt).await?;
Ok(
Self {
name,
application_id,
surname,
study: study_opt.unwrap_or("".to_string()),
submitted,
}
)
}
}

View file

@ -1,15 +1,36 @@
use chrono::NaiveDate; use chrono::NaiveDate;
use serde::{Deserialize, Serialize};
use entity::{candidate, parent}; use entity::{candidate, parent};
use crate::{crypto, database::query::candidate::CandidateWithParent, error::ServiceError}; use crate::{crypto, models::candidate::{CandidateWithParent, ApplicationDetails}, error::ServiceError};
pub const NAIVE_DATE_FMT: &str = "%Y-%m-%d"; pub const NAIVE_DATE_FMT: &str = "%Y-%m-%d";
#[derive(Clone)] #[derive(Clone)]
pub struct EncryptedString(String); pub struct EncryptedString(String);
#[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 personal_id_number: EncryptedString,
pub study: String,
// Parent
pub parent_name: EncryptedString,
pub parent_surname: EncryptedString,
pub parent_telephone: EncryptedString,
pub parent_email: EncryptedString,
}
impl EncryptedString { impl EncryptedString {
pub async fn new(s: &str, recipients: &Vec<String>) -> Result<Self, ServiceError> { pub async fn new(s: &str, recipients: &Vec<String>) -> Result<Self, ServiceError> {
let recipients = recipients.iter().map(|s| &**s).collect(); let recipients = recipients.iter().map(|s| &**s).collect();
@ -65,28 +86,6 @@ impl TryFrom<Option<NaiveDate>> for EncryptedString {
} }
} }
#[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 personal_id_number: EncryptedString,
pub study: String,
// Parent
pub parent_name: EncryptedString,
pub parent_surname: EncryptedString,
pub parent_telephone: EncryptedString,
pub parent_email: EncryptedString,
}
impl EncryptedApplicationDetails { impl EncryptedApplicationDetails {
pub async fn new( pub async fn new(
form: &ApplicationDetails, form: &ApplicationDetails,
@ -224,27 +223,15 @@ impl TryFrom<CandidateWithParent> for EncryptedApplicationDetails {
} }
} }
// TODO: use this more???
pub async fn decrypt_if_exists(
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] private_key: &String,
pub struct ApplicationDetails { encrypted_string: Option<String>,
// Candidate ) -> Result<String, ServiceError> {
pub name: String, match EncryptedString::try_from(encrypted_string) {
pub surname: String, Ok(encrypted_string) => Ok(encrypted_string.decrypt(private_key).await?),
pub birthplace: String, Err(_) => Ok(String::from("")),
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,
pub personal_id_number: String,
// Parent
pub parent_name: String,
pub parent_surname: String,
pub parent_telephone: String,
pub parent_email: String,
} }
#[cfg(test)] #[cfg(test)]

2
core/src/models/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod candidate_details;
pub mod candidate;

View file

@ -1,53 +0,0 @@
use serde::{Serialize, Deserialize};
use crate::{candidate_details::EncryptedString, error::ServiceError};
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateCandidateResponse {
pub application_id: i32,
pub personal_id_number: String,
pub password: String,
}
#[derive(Debug, Serialize)]
pub struct BaseCandidateResponse {
pub application_id: i32,
pub name: String,
pub surname: String,
pub study: String,
pub submitted: bool,
}
impl BaseCandidateResponse {
pub async fn from_encrypted(
private_key: &String,
application_id: i32,
name_opt: Option<String>,
surname_opt: Option<String>,
study_opt: Option<String>,
submitted: bool,
) -> Result<Self, ServiceError> {
let name = decrypt_if_exists(private_key, name_opt).await?;
let surname = decrypt_if_exists(private_key, surname_opt).await?;
Ok(
Self {
name,
application_id,
surname,
study: study_opt.unwrap_or("".to_string()),
submitted,
}
)
}
}
async fn decrypt_if_exists(
private_key: &String,
encrypted_string: Option<String>,
) -> Result<String, ServiceError> {
match EncryptedString::try_from(encrypted_string) {
Ok(encrypted_string) => Ok(encrypted_string.decrypt(private_key).await?),
Err(_) => Ok(String::from("")),
}
}

View file

@ -1,7 +1,7 @@
use entity::{candidate, parent}; use entity::{candidate, parent};
use sea_orm::DbConn; use sea_orm::DbConn;
use crate::{error::ServiceError, candidate_details::{ApplicationDetails, EncryptedApplicationDetails}, Query, utils::db::get_recipients}; use crate::{error::ServiceError, Query, utils::db::get_recipients, models::candidate_details::{EncryptedApplicationDetails}, models::candidate::ApplicationDetails};
use super::{parent_service::ParentService, candidate_service::CandidateService}; use super::{parent_service::ParentService, candidate_service::CandidateService};

View file

@ -2,10 +2,10 @@ use entity::candidate;
use sea_orm::{prelude::Uuid, DbConn}; use sea_orm::{prelude::Uuid, DbConn};
use crate::{ use crate::{
candidate_details::{EncryptedApplicationDetails, EncryptedString}, models::candidate_details::{EncryptedApplicationDetails, EncryptedString},
crypto::{self, hash_password}, crypto::{self, hash_password},
error::ServiceError, error::ServiceError,
Mutation, Query, responses::{BaseCandidateResponse, CreateCandidateResponse}, utils::db::get_recipients, Mutation, Query, models::candidate::{BaseCandidateResponse, CreateCandidateResponse}, utils::db::get_recipients,
}; };
use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService, portfolio_service::PortfolioService}; use super::{session_service::{AdminUser, SessionService}, application_service::ApplicationService, portfolio_service::PortfolioService};
@ -254,11 +254,11 @@ impl CandidateService {
pub mod tests { pub mod tests {
use sea_orm::{DbConn}; use sea_orm::{DbConn};
use crate::candidate_details::tests::assert_all_application_details; use crate::models::candidate_details::tests::assert_all_application_details;
use crate::utils::db::get_memory_sqlite_connection; use crate::utils::db::get_memory_sqlite_connection;
use crate::{crypto, services::candidate_service::CandidateService, Mutation}; use crate::{crypto, services::candidate_service::CandidateService, Mutation};
use super::EncryptedApplicationDetails; use crate::models::candidate_details::EncryptedApplicationDetails;
use entity::{candidate, parent, admin}; use entity::{candidate, parent, admin};
use crate::services::application_service::ApplicationService; use crate::services::application_service::ApplicationService;
@ -374,7 +374,7 @@ pub mod tests {
#[cfg(test)] #[cfg(test)]
pub async fn put_user_data(db: &DbConn) -> (candidate::Model, parent::Model) { pub async fn put_user_data(db: &DbConn) -> (candidate::Model, parent::Model) {
use crate::candidate_details::tests::APPLICATION_DETAILS; 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}; use entity::{parent};
use sea_orm::DbConn; use sea_orm::DbConn;
use crate::{error::ServiceError, Mutation, candidate_details::EncryptedApplicationDetails}; use crate::{error::ServiceError, Mutation, models::candidate_details::EncryptedApplicationDetails};
pub struct ParentService; pub struct ParentService;

View file

@ -1,5 +1,5 @@
use sea_orm::{DbConn}; use sea_orm::{DbConn};
use crate::{error::ServiceError, candidate_details::{EncryptedApplicationDetails, ApplicationDetails}, Query, database::query::candidate::CandidateWithParent}; use crate::{error::ServiceError, models::candidate_details::{EncryptedApplicationDetails}, Query, models::candidate::{CandidateWithParent, ApplicationDetails}};
type Row = CandidateWithParent; type Row = CandidateWithParent;