diff --git a/src/main.rs b/src/main.rs index a47a685..de365f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,6 +73,7 @@ async fn main() -> std::io::Result<()> { .service(routes::v1::code_3fa::get_3fa_code) .service(routes::v1::user_add::add_user_request) .service(routes::v1::user_get::get_user_request) + .service(routes::v1::user_del::delete_user_request) }) .bind(("127.0.0.1", 8080))? .run() diff --git a/src/routes/v1/mod.rs b/src/routes/v1/mod.rs index aa19a1a..3dc4878 100644 --- a/src/routes/v1/mod.rs +++ b/src/routes/v1/mod.rs @@ -1,3 +1,4 @@ pub mod code_3fa; pub mod user_add; -pub mod user_get; \ No newline at end of file +pub mod user_get; +pub mod user_del; \ No newline at end of file diff --git a/src/routes/v1/user_del.rs b/src/routes/v1/user_del.rs new file mode 100644 index 0000000..62d888d --- /dev/null +++ b/src/routes/v1/user_del.rs @@ -0,0 +1,77 @@ +use actix_web::{HttpResponse, web}; +use actix_web::post; +use actix_web::web::{Data, Json}; +use log::error; +use serde::{Serialize, Deserialize}; + +use crate::error::{APIError, APIErrorResponse}; +use crate::models::{NewUser, User}; +use crate::PgPool; +use diesel::prelude::*; +use crate::tokens::{Scope, token_has_scope}; + +#[derive(Serialize, Deserialize, Clone)] +pub struct UserDeleteRequest { + pub token: String, + pub id: i32 +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct UserDeleteResponse { + pub num_deleted: usize +} + +#[post("/v1/user/remove")] +pub async fn delete_user_request(pool: Data, req: Json) -> HttpResponse { + use crate::schema::users; + + if !token_has_scope(&req.token, &Scope::UserRemove) { + return HttpResponse::Unauthorized().json(APIErrorResponse { + errors: vec![ + APIError { + code: "ERR_MISSING_SCOPE".to_string(), + message: "This endpoint requires the user:remove scope".to_string(), + } + ], + }) + } + + let req_clone = req.clone(); + let pool_clone = pool.clone(); + let results = match web::block(move || { + let mut conn = pool_clone.get().expect("Unable to get db pool"); + + diesel::delete(users::table.filter(users::id.eq(req_clone.id))).execute(&mut conn) + }).await { + Ok(r) => r, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorResponse { + errors: vec![ + APIError { + code: "ERR_BLOCKING_ERROR".to_string(), + message: "There was an error running the database request. Please try again later.".to_string() + } + ] + }) + } + }; + let num_deleted = match results { + Ok(r) => r, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error deleting the user. Please try again later.".to_string() + } + ] + }) + } + }; + + HttpResponse::Ok().json(UserDeleteResponse { + num_deleted, + }) +} \ No newline at end of file