diff --git a/api/src/lib.rs b/api/src/lib.rs index 2bc516d..22e6166 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -150,6 +150,7 @@ pub fn rocket() -> Rocket { routes::admin::get_candidate, routes::admin::reset_candidate_password, routes::admin::get_candidate_portfolio, + routes::admin::delete_candidate, ], ) .mount( diff --git a/api/src/routes/admin.rs b/api/src/routes/admin.rs index 5bea5e5..c8e807e 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin.rs @@ -181,6 +181,24 @@ pub async fn get_candidate( ) } +#[delete("/candidate/")] +pub async fn delete_candidate( + conn: Connection<'_, Db>, + _session: AdminAuth, + id: i32, +) -> Result<(), Custom> { + let db = conn.into_inner(); + + let candidate = Query::find_candidate_by_id(db, id) + .await + .map_err(|e| to_custom_error(ServiceError::DbError(e)))? + .ok_or(to_custom_error(ServiceError::CandidateNotFound))?; + + CandidateService::delete_candidate(db, candidate) + .await + .map_err(to_custom_error) +} + #[post("/candidate//reset_password")] pub async fn reset_candidate_password( conn: Connection<'_, Db>, diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index 411aa05..526a1de 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -30,6 +30,17 @@ impl Mutation { Ok(insert) } + pub async fn delete_candidate( + db: &DbConn, + candidate: candidate::Model, + ) -> Result { + let application = candidate.application; + let delete = candidate.delete(db).await?; + + warn!("CANDIDATE {} DELETED", application); + Ok(delete) + } + pub async fn update_candidate_password_and_keys( db: &DbConn, candidate: candidate::Model, diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index c7f52cd..d38d365 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -145,6 +145,13 @@ impl CandidateService { Ok(()) } + pub async fn delete_candidate(db: &DbConn, candidate: candidate::Model) -> Result<(), ServiceError> { + PortfolioService::delete_candidate_root(candidate.application).await?; + + Mutation::delete_candidate(db, candidate).await?; + Ok(()) + } + pub(in crate::services) async fn add_candidate_details( db: &DbConn, candidate: candidate::Model, @@ -374,7 +381,7 @@ pub mod tests { #[cfg(test)] pub async fn put_user_data(db: &DbConn) -> (candidate::Model, Vec) { - use crate::{models::candidate_details::tests::APPLICATION_DETAILS}; + use crate::models::candidate_details::tests::APPLICATION_DETAILS; let plain_text_password = "test".to_string(); let (candidate, _parent) = ApplicationService::create_candidate_with_parent( diff --git a/core/src/services/portfolio_service.rs b/core/src/services/portfolio_service.rs index e5b9618..58ce4f2 100644 --- a/core/src/services/portfolio_service.rs +++ b/core/src/services/portfolio_service.rs @@ -1,7 +1,7 @@ use std::{path::{PathBuf, Path}}; use entity::candidate; -use log::info; +use log::{info, warn}; use sea_orm::{DbConn}; use serde::{Serialize, ser::{SerializeStruct}}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -351,6 +351,18 @@ impl PortfolioService { Ok(()) } + /// Deletes all candidate folder. Used ONLY when candidate is deleted! + pub async fn delete_candidate_root(candidate_id: i32) -> Result<(), ServiceError> { + warn!("CANDIDATE {} ROOT DIRECTORY DELETE STARTED", candidate_id); + + let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf(); + tokio::fs::remove_dir_all(path).await?; + + warn!("CANDIDATE {} ROOT DIRECTORY DELETE FINISHED", candidate_id); + + Ok(()) + } + /// Returns true if portfolio is submitted pub async fn is_portfolio_submitted(candidate_id: i32) -> bool { let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf();