mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-18 22:11:14 +00:00
feat: 2/9 semester support
This commit is contained in:
parent
54cdca8a11
commit
88febd5e20
5 changed files with 90 additions and 12 deletions
|
|
@ -78,6 +78,8 @@ pub enum ServiceError {
|
|||
CsvError(#[from] csv::Error),
|
||||
#[error("Csv into inner error")]
|
||||
CsvIntoInnerError,
|
||||
#[error("Format error")]
|
||||
FormatError,
|
||||
}
|
||||
|
||||
impl ServiceError {
|
||||
|
|
@ -122,6 +124,7 @@ impl ServiceError {
|
|||
ServiceError::ZipError(_) => 500,
|
||||
ServiceError::CsvError(_) => 500,
|
||||
ServiceError::CsvIntoInnerError => 500,
|
||||
ServiceError::FormatError => 500,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,40 +42,71 @@ impl ApplicationResponse {
|
|||
|
||||
/// CSV export (admin endpoint)
|
||||
#[derive(Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApplicationRow {
|
||||
#[serde(rename = "Ev. č. přihlášky")]
|
||||
pub application: i32,
|
||||
#[serde(rename = "Jméno")]
|
||||
pub name: Option<String>,
|
||||
#[serde(rename = "Příjmení")]
|
||||
pub surname: Option<String>,
|
||||
#[serde(rename = "Rodné příjmení (pokud odlišné)")]
|
||||
pub birth_surname: Option<String>,
|
||||
#[serde(rename = "Místo narození")]
|
||||
pub birthplace: Option<String>,
|
||||
#[serde(rename = "Datum narození")]
|
||||
pub birthdate: Option<String>,
|
||||
#[serde(rename = "Adresa trvalého pobytu")]
|
||||
pub address: Option<String>,
|
||||
#[serde(rename = "Adresa pro doručování písemností (pokud odlišné)")]
|
||||
pub letter_address: Option<String>,
|
||||
#[serde(rename = "Telefon")]
|
||||
pub telephone: Option<String>,
|
||||
#[serde(rename = "Státní občanství")]
|
||||
pub citizenship: Option<String>,
|
||||
#[serde(rename = "Email")]
|
||||
pub email: Option<String>,
|
||||
#[serde(rename = "Pohlaví")]
|
||||
pub sex: Option<String>,
|
||||
#[serde(rename = "Rodné číslo")]
|
||||
pub personal_identification_number: Option<String>,
|
||||
#[serde(rename = "Název školy")]
|
||||
pub school_name: Option<String>,
|
||||
#[serde(rename = "Zdravotní pojištění")]
|
||||
pub health_insurance: Option<String>,
|
||||
|
||||
#[serde(rename = "Vysvědčení 1/8")]
|
||||
pub diploma_1_8: String,
|
||||
#[serde(rename = "Vysvědčení 2/8")]
|
||||
pub diploma_2_8: String,
|
||||
#[serde(rename = "Vysvědčení 1/9")]
|
||||
pub diploma_1_9: String,
|
||||
#[serde(rename = "Vysvědčení 2/9")]
|
||||
pub diploma_2_9: String,
|
||||
|
||||
#[serde(rename = "První škola - název")]
|
||||
pub first_school_name: Option<String>,
|
||||
#[serde(rename = "První škola - obor")]
|
||||
pub first_school_field: Option<String>,
|
||||
#[serde(rename = "Druhá škola - název")]
|
||||
pub second_school_name: Option<String>,
|
||||
#[serde(rename = "Druhá škola - obor")]
|
||||
pub second_school_field: Option<String>,
|
||||
|
||||
#[serde(rename = "Jméno zákonného zástupce")]
|
||||
pub parent_name: Option<String>,
|
||||
#[serde(rename = "Příjmení zákonného zástupce")]
|
||||
pub parent_surname: Option<String>,
|
||||
#[serde(rename = "Telefon zákonného zástupce")]
|
||||
pub parent_telephone: Option<String>,
|
||||
#[serde(rename = "Email zákonného zástupce")]
|
||||
pub parent_email: Option<String>,
|
||||
|
||||
#[serde(rename = "Jméno druhého zákonného zástupce")]
|
||||
pub second_parent_name: Option<String>,
|
||||
#[serde(rename = "Příjmení druhého zákonného zástupce")]
|
||||
pub second_parent_surname: Option<String>,
|
||||
#[serde(rename = "Telefon druhého zákonného zástupce")]
|
||||
pub second_parent_telephone: Option<String>,
|
||||
#[serde(rename = "Email druhého zákonného zástupce")]
|
||||
pub second_parent_email: Option<String>,
|
||||
}
|
||||
|
|
@ -98,6 +98,7 @@ impl CandidateDetails {
|
|||
pub fn validate_self(&self) -> Result<(), ServiceError> {
|
||||
self.first_school.validate()?;
|
||||
self.second_school.validate()?;
|
||||
self.grades.validate_self()?;
|
||||
self.validate()
|
||||
.map_err(ServiceError::ValidationError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,70 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use validator::{Validate, ValidationError};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
use crate::error::ServiceError;
|
||||
|
||||
|
||||
fn validate_semester(semester: &str) -> Result<(), ValidationError> {
|
||||
match semester {
|
||||
"1/8" | "2/8" | "1/9" | "2/9" => Ok(()),
|
||||
_ => Err(ValidationError::new("Invalid semester"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate, PartialEq, Eq)]
|
||||
pub struct Grade {
|
||||
#[validate(length(min = 1, max = 255))]
|
||||
subject: String,
|
||||
#[validate(length(min = 1, max = 255), custom = "validate_semester")]
|
||||
semester: String,
|
||||
#[validate(range(min = 1, max = 5))]
|
||||
value: i32,
|
||||
}
|
||||
|
||||
|
||||
impl Grade {
|
||||
pub fn validate_self(&self) -> Result<(), ServiceError> {
|
||||
self.validate()
|
||||
.map_err(ServiceError::ValidationError)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct GradeList(Vec<Grade>);
|
||||
|
||||
impl GradeList {
|
||||
pub fn validate_self(&self) -> Result<(), ServiceError> {
|
||||
self.0.iter()
|
||||
.map(|grade| grade.validate_self())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub fn from_opt_str(grades: Option<String>) -> Option<Self> {
|
||||
grades.map(
|
||||
|grades| serde_json::from_str(&grades).unwrap() // TODO: handle error
|
||||
)
|
||||
}
|
||||
|
||||
pub fn group_by_semester(&self) -> (GradeList, GradeList, GradeList) {
|
||||
pub fn group_by_semester(&self) -> Result<(GradeList, GradeList, GradeList, GradeList), ServiceError> {
|
||||
let mut first_semester = GradeList::default();
|
||||
let mut second_semester = GradeList::default();
|
||||
let mut third_semester = GradeList::default();
|
||||
let mut fourth_semester = GradeList::default();
|
||||
|
||||
for grade in &self.0 {
|
||||
match grade.semester.as_str() {
|
||||
"1/8" => first_semester.0.push(grade.clone()),
|
||||
"2/8" => second_semester.0.push(grade.clone()),
|
||||
"1/9" => third_semester.0.push(grade.clone()),
|
||||
_ => panic!("Invalid semester"),
|
||||
"2/9" => fourth_semester.0.push(grade.clone()),
|
||||
_ => return Err(ServiceError::FormatError),
|
||||
}
|
||||
}
|
||||
|
||||
(first_semester, second_semester, third_semester)
|
||||
Ok(
|
||||
(first_semester, second_semester, third_semester, fourth_semester)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,16 @@ use crate::{
|
|||
};
|
||||
use sea_orm::DbConn;
|
||||
|
||||
impl From<(i32, ApplicationDetails)> for ApplicationRow {
|
||||
fn from((application, d): (i32, ApplicationDetails)) -> Self {
|
||||
impl TryFrom<(i32, ApplicationDetails)> for ApplicationRow {
|
||||
type Error = ServiceError;
|
||||
fn try_from((application, d): (i32, ApplicationDetails)) -> Result<Self, ServiceError> {
|
||||
let c = d.candidate;
|
||||
let (diploma_1_8, diploma_2_8, diploma_1_9) = c.grades.group_by_semester();
|
||||
Self {
|
||||
let (diploma_1_8,
|
||||
diploma_2_8,
|
||||
diploma_1_9,
|
||||
diploma_2_9
|
||||
) = c.grades.group_by_semester()?;
|
||||
Ok(Self {
|
||||
application,
|
||||
name: Some(c.name),
|
||||
surname: Some(c.surname),
|
||||
|
|
@ -30,6 +35,7 @@ impl From<(i32, ApplicationDetails)> for ApplicationRow {
|
|||
diploma_1_8: diploma_1_8.to_string(),
|
||||
diploma_2_8: diploma_2_8.to_string(),
|
||||
diploma_1_9: diploma_1_9.to_string(),
|
||||
diploma_2_9: diploma_2_9.to_string(),
|
||||
|
||||
first_school_name: Some(c.first_school.name().to_owned()),
|
||||
first_school_field: Some(c.first_school.field().to_owned()),
|
||||
|
|
@ -45,7 +51,7 @@ impl From<(i32, ApplicationDetails)> for ApplicationRow {
|
|||
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()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,11 +65,15 @@ pub async fn export(db: &DbConn, private_key: String) -> Result<Vec<u8>, Service
|
|||
|
||||
let row: ApplicationRow = match EncryptedApplicationDetails::try_from((&candidate, &parents))
|
||||
{
|
||||
Ok(d) => ApplicationRow::from(
|
||||
Ok(d) => ApplicationRow::try_from(
|
||||
d.decrypt(private_key.to_string())
|
||||
.await
|
||||
.map(|d| (application.id, d))?,
|
||||
),
|
||||
)
|
||||
.unwrap_or(ApplicationRow {
|
||||
application: application.id,
|
||||
..Default::default()
|
||||
}),
|
||||
|
||||
Err(_) => ApplicationRow {
|
||||
application: application.id,
|
||||
|
|
|
|||
Loading…
Reference in a new issue