From 3d3e92cf3835ecdb1553b7524f04c1749a143355 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Wed, 6 Mar 2024 23:28:58 +0100 Subject: [PATCH] feat: locking and deletion of user --- Cargo.lock | 39 ++++++++++--------- Cargo.toml | 1 + src/endpoints/mod.rs | 2 + src/endpoints/user/delete.rs | 30 ++++++++++++++ src/endpoints/user/mod.rs | 2 + src/endpoints/user/patch.rs | 69 +++++++++++++++++++++++++++++++++ src/endpoints/user/post_edit.rs | 6 ++- src/main.rs | 1 + src/models/user.rs | 15 +++++-- templates/user/edit.html | 2 +- templates/user/overview.html | 59 +++++++++++++++++++++++++++- 11 files changed, 200 insertions(+), 26 deletions(-) create mode 100644 src/endpoints/user/delete.rs create mode 100644 src/endpoints/user/patch.rs diff --git a/Cargo.lock b/Cargo.lock index f575acc2..fe74be21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,7 +395,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] @@ -532,7 +532,7 @@ checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] @@ -650,6 +650,7 @@ dependencies = [ "dotenv", "futures-util", "serde", + "serde_json", "sqlx", ] @@ -1040,7 +1041,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] @@ -1670,18 +1671,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1860,29 +1861,29 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -2105,9 +2106,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -2131,7 +2132,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", ] [[package]] @@ -2354,7 +2355,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -2388,7 +2389,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index d66581e1..cadef8ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ chrono = { version = "0.4.33", features = ["serde"] } actix-files = "0.6.5" askama_actix = "0.14.0" futures-util = "0.3.30" +serde_json = "1.0.114" diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 54b7ed6f..95e8c18b 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -17,4 +17,6 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(user::post_new::post_new); cfg.service(user::get_edit::get_edit); cfg.service(user::post_edit::post_edit); + cfg.service(user::patch::patch); + cfg.service(user::delete::delete); } diff --git a/src/endpoints/user/delete.rs b/src/endpoints/user/delete.rs new file mode 100644 index 00000000..7ff86d95 --- /dev/null +++ b/src/endpoints/user/delete.rs @@ -0,0 +1,30 @@ +use actix_identity::Identity; +use actix_web::{web, HttpResponse, Responder}; +use sqlx::PgPool; + +use crate::{endpoints::IdPath, models::{Role, User}}; + +#[actix_web::delete("/users/delete/{id}")] +pub async fn delete(user: Identity, pool: web::Data, path: web::Path) -> impl Responder { + let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) + .await + .unwrap(); + + if current_user.role != Role::AreaManager && current_user.role != Role::Admin { + return HttpResponse::Unauthorized().finish(); + } + + if let Ok(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await { + if current_user.role == Role::AreaManager && current_user.area_id != user_in_db.area_id { + return HttpResponse::Unauthorized().finish(); + } + + if user_in_db.locked { + if let Ok(_) = User::delete(pool.get_ref(), user_in_db.id).await { + return HttpResponse::NoContent().finish(); + } + } + } + + HttpResponse::BadRequest().finish() +} diff --git a/src/endpoints/user/mod.rs b/src/endpoints/user/mod.rs index dc3c5d1a..72aef055 100644 --- a/src/endpoints/user/mod.rs +++ b/src/endpoints/user/mod.rs @@ -3,3 +3,5 @@ pub mod get_new; pub mod post_new; pub mod get_edit; pub mod post_edit; +pub mod patch; +pub mod delete; diff --git a/src/endpoints/user/patch.rs b/src/endpoints/user/patch.rs new file mode 100644 index 00000000..17fe91b8 --- /dev/null +++ b/src/endpoints/user/patch.rs @@ -0,0 +1,69 @@ +use actix_identity::Identity; +use actix_web::{web, HttpResponse, Responder}; +use serde::Deserialize; +use serde_json::value::Value; +use sqlx::PgPool; + +use crate::{ + endpoints::IdPath, + models::{Role, User}, +}; + +#[derive(Deserialize)] +pub struct JsonPatchDoc { + op: String, + path: String, + value: Value +} + +#[actix_web::patch("/users/edit/{id}")] +pub async fn patch( + user: Identity, + pool: web::Data, + path: web::Path, + patch_docs: web::Json>, +) -> impl Responder { + let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) + .await + .unwrap(); + + if current_user.role != Role::AreaManager && current_user.role != Role::Admin { + return HttpResponse::Unauthorized().finish(); + } + + if let Ok(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await { + if current_user.role == Role::AreaManager && current_user.area_id != user_in_db.area_id { + return HttpResponse::Unauthorized().finish(); + } + + let mut changed = false; + + let mut locked: Option = None; + + for doc in patch_docs.iter() { + if doc.op.as_str() != "replace" { + continue; + } + + match doc.path.as_str() { + "/locked" => { + changed = true; + if let Value::Bool(b) = doc.value { + locked = Some(b); + } + }, + _ => panic!("other patch paths are not supported!"), + }; + } + + if changed { + if let Ok(_) = User::update(pool.get_ref(), path.id, None, None, None, None, None, locked).await { + return HttpResponse::Ok().body(""); + } + } else { + return HttpResponse::Ok().body(""); + } + } + + HttpResponse::BadRequest().body("Fehler bei User PATCH") +} diff --git a/src/endpoints/user/post_edit.rs b/src/endpoints/user/post_edit.rs index bb9bfb7d..a0c1bc18 100644 --- a/src/endpoints/user/post_edit.rs +++ b/src/endpoints/user/post_edit.rs @@ -33,6 +33,10 @@ pub async fn post_edit( } if let Ok(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await { + if current_user.role == Role::AreaManager && current_user.area_id != user_in_db.area_id { + return HttpResponse::Unauthorized().finish(); + } + let mut changed = false; let email = if user_in_db.email != form.email { @@ -79,7 +83,7 @@ pub async fn post_edit( }; if changed { - match User::update(pool.get_ref(), path.id, email, name, role, function, area).await { + match User::update(pool.get_ref(), path.id, email, name, role, function, area, None).await { Ok(_) => return HttpResponse::Found().insert_header((LOCATION, "/users")).finish(), Err(err) => println!("{}", err) } diff --git a/src/main.rs b/src/main.rs index 10a962f6..4e541865 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ async fn main() -> anyhow::Result<()> { .app_data(web::Data::new(pool.clone())) .configure(auth::init) .configure(calendar::init) + .configure(endpoints::init) .wrap(redirect::CheckLogin) .wrap(IdentityMiddleware::default()) .wrap(SessionMiddleware::new( diff --git a/src/models/user.rs b/src/models/user.rs index 7017c979..642f0783 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -276,6 +276,7 @@ impl User { role: Option, function: Option, area_id: Option, + locked: Option ) -> anyhow::Result<()> { let mut query_builder = sqlx::QueryBuilder::new("UPDATE user_ SET "); let mut separated = query_builder.separated(", "); @@ -305,6 +306,11 @@ impl User { separated.push_bind_unseparated(area_id); } + if let Some(locked) = locked { + separated.push("locked = "); + separated.push_bind_unseparated(locked); + } + query_builder.push(" WHERE id = "); query_builder.push_bind(id); query_builder.push(";"); @@ -316,7 +322,10 @@ impl User { Ok(()) } - // pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result { - // todo!() - // } + pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> { + sqlx::query!("DELETE FROM user_ WHERE id = $1", id) + .execute(pool) + .await?; + Ok(()) + } } diff --git a/templates/user/edit.html b/templates/user/edit.html index 447bbfb5..f2e1ec39 100644 --- a/templates/user/edit.html +++ b/templates/user/edit.html @@ -4,7 +4,7 @@
-

Nutzer {{ name }} bearbeiten

+

Nutzer '{{ name }}' bearbeiten

diff --git a/templates/user/overview.html b/templates/user/overview.html index e6e82c75..b915ef46 100644 --- a/templates/user/overview.html +++ b/templates/user/overview.html @@ -37,7 +37,7 @@ {% for u in users %} - + {{ u.email }} @@ -85,8 +85,9 @@
+ Bearbeiten - +
@@ -100,5 +101,59 @@
{% endblock %}