diff --git a/api/src/guards/data/letter.rs b/api/src/guards/data/letter.rs index d70b00c..ed4f6e3 100644 --- a/api/src/guards/data/letter.rs +++ b/api/src/guards/data/letter.rs @@ -3,7 +3,7 @@ use rocket::http::{ContentType, Status}; use rocket::outcome::Outcome; use rocket::request::Request; -struct Letter(Vec); +pub struct Letter(Vec); impl Into> for Letter { fn into(self) -> Vec { @@ -16,9 +16,7 @@ impl<'r> FromData<'r> for Letter { type Error = Option; async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> { - let content_type_pdf = ContentType::new("application", "application/pdf"); - - if req.content_type() != Some(&content_type_pdf) { + if req.content_type() != Some(&ContentType::PDF) { return Outcome::Failure((Status::BadRequest, None)) } @@ -28,6 +26,7 @@ impl<'r> FromData<'r> for Letter { if !data_bytes.is_complete() { // TODO: Over limit + return Outcome::Failure((Status::BadRequest, None)) } let data_bytes = data_bytes.into_inner(); @@ -36,6 +35,7 @@ impl<'r> FromData<'r> for Letter { if !is_pdf { // TODO: Not PDF + return Outcome::Failure((Status::BadRequest, None)) } Outcome::Success(Letter(data_bytes)) diff --git a/api/src/guards/data/portfolio.rs b/api/src/guards/data/portfolio.rs index 3738ee1..623c589 100644 --- a/api/src/guards/data/portfolio.rs +++ b/api/src/guards/data/portfolio.rs @@ -3,7 +3,7 @@ use rocket::http::{ContentType, Status}; use rocket::outcome::Outcome; use rocket::request::Request; -struct Portfolio(Vec); +pub struct Portfolio(Vec); impl Into> for Portfolio { fn into(self) -> Vec { @@ -16,9 +16,7 @@ impl<'r> FromData<'r> for Portfolio { type Error = Option; async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> { - let content_type_zip = ContentType::new("application", "application/zip"); - - if req.content_type() != Some(&content_type_zip) { + if req.content_type() != Some(&ContentType::ZIP) { return Outcome::Failure((Status::BadRequest, None)) } @@ -28,6 +26,7 @@ impl<'r> FromData<'r> for Portfolio { if !data_bytes.is_complete() { // TODO: Over limit + return Outcome::Failure((Status::BadRequest, None)) } let data_bytes = data_bytes.into_inner(); @@ -36,6 +35,7 @@ impl<'r> FromData<'r> for Portfolio { if !is_zip { // TODO: Not ZIP + return Outcome::Failure((Status::BadRequest, None)) } Outcome::Success(Portfolio(data_bytes)) diff --git a/api/src/lib.rs b/api/src/lib.rs index cd1550d..61fbd5c 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -42,6 +42,9 @@ async fn start() -> Result<(), rocket::Error> { routes::candidate::login, routes::candidate::whoami, routes::candidate::fill_details, + routes::candidate::upload_cover_letter, + routes::candidate::upload_portfolio_letter, + routes::candidate::upload_portfolio_zip, ], ) .mount( diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 1f2ccfb..c6e3413 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -8,6 +8,8 @@ use rocket::serde::json::Json; use sea_orm_rocket::Connection; +use crate::guards::data::letter::Letter; +use crate::guards::data::portfolio::Portfolio; use crate::{guards::request::auth::CandidateAuth, pool::Db, requests}; #[post("/login", data = "")] @@ -47,7 +49,7 @@ pub async fn whoami(session: CandidateAuth) -> Result> { Ok(candidate.application.to_string()) } -#[put("/details", data = "
")] +#[post("/details", data = "
")] pub async fn fill_details( conn: Connection<'_, Db>, details: Json, @@ -70,3 +72,66 @@ pub async fn fill_details( Ok("Details added".to_string()) } + +#[post("/coverletter", data = "")] +pub async fn upload_cover_letter( + session: CandidateAuth, + letter: Letter, +) -> Result> { + let candidate: entity::candidate::Model = session.into(); + + let candidate = CandidateService::add_cover_letter(candidate.application, letter.into()).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(), + )); + } + + Ok("Letter added".to_string()) +} + +#[post("/portfolioletter", data = "")] +pub async fn upload_portfolio_letter( + session: CandidateAuth, + letter: Letter, +) -> Result> { + let candidate: entity::candidate::Model = session.into(); + + let candidate = CandidateService::add_portfolio_letter(candidate.application, letter.into()).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(), + )); + } + + Ok("Letter added".to_string()) +} + +#[post("/portfolio", data = "")] +pub async fn upload_portfolio_zip( + session: CandidateAuth, + portfolio: Portfolio, +) -> Result> { + let candidate: entity::candidate::Model = session.into(); + + let candidate = CandidateService::add_portfolio_zip(candidate.application, portfolio.into()).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(), + )); + } + + Ok("Letter added".to_string()) +} diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 6f6fd5c..1fe630a 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -67,7 +67,9 @@ impl EncryptedUserDetails { } } - fn extract_enc_candidate_details(candidate: candidate::Model) -> Result { + fn extract_enc_candidate_details( + candidate: candidate::Model, + ) -> Result { let ( // TODO: simplify?? Some(name), Some(surname), @@ -152,20 +154,18 @@ impl EncryptedUserDetails { 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, - } - ) + Ok(UserDetails { + name, + surname, + birthplace, + // birthdate: NaiveDate::from_ymd(2000, 1, 1), + address, + telephone, + citizenship, + email, + sex, + study, + }) } } @@ -183,7 +183,6 @@ pub struct UserDetails { pub study: String, } - pub struct CandidateService; impl CandidateService { @@ -259,13 +258,9 @@ impl CandidateService { let enc_details = EncryptedUserDetails::encrypt_form(form, recipients).await; - Mutation::add_candidate_details( - db, - user, - enc_details, - ) - .await - .map_err(|_| ServiceError::DbError) + Mutation::add_candidate_details(db, user, enc_details) + .await + .map_err(|_| ServiceError::DbError) } pub async fn decrypt_details( @@ -282,18 +277,36 @@ impl CandidateService { match crypto::verify_password((&password).to_string(), candidate.code.clone()).await { Ok(valid) => { if !valid { - return Err(ServiceError::InvalidCredentials) + return Err(ServiceError::InvalidCredentials); } - }, - Err(_) => {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 dec_priv_key = crypto::decrypt_password(candidate.private_key.clone(), password) + .await + .ok() + .unwrap(); let enc_details = EncryptedUserDetails::from_model(candidate)?; enc_details.decrypt(dec_priv_key).await } + pub async fn add_cover_letter(candidate_id: i32, letter: Vec) -> Result<(), ServiceError> { + // TODO + Ok(()) + } + + pub async fn add_portfolio_letter(candidate_id: i32, letter: Vec) -> Result<(), ServiceError> { + // TODO + Ok(()) + } + + pub async fn add_portfolio_zip(candidate_id: i32, zip: Vec) -> Result<(), ServiceError> { + // TODO + Ok(()) + } + pub async fn login( db: &DbConn, user_id: i32, @@ -326,10 +339,13 @@ impl CandidateService { #[cfg(test)] mod tests { - use sea_orm::{Database, DbConn}; use entity::candidate::Model; + use sea_orm::{Database, DbConn}; - use crate::{crypto, services::candidate_service::{CandidateService, UserDetails}}; + use crate::{ + crypto, + services::candidate_service::{CandidateService, UserDetails}, + }; use super::EncryptedUserDetails; @@ -398,7 +414,6 @@ mod tests { assert_eq!(secret_message, decrypted_message); } - #[cfg(test)] async fn put_user_data(db: &DbConn) -> Model { let plain_text_password = "test".to_string(); @@ -419,7 +434,10 @@ mod tests { sex: "test".to_string(), study: "test".to_string(), }; - CandidateService::add_user_details(&db, candidate, form).await.ok().unwrap() + CandidateService::add_user_details(&db, candidate, form) + .await + .ok() + .unwrap() } #[tokio::test] @@ -438,7 +456,11 @@ mod tests { 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 dec_candidate = EncryptedUserDetails::from_model(enc_candidate) + .unwrap() + .decrypt(dec_priv_key) + .await + .unwrap(); assert_eq!(dec_candidate.name, "test"); }