From 08646ba97199bce30cbeb8823aabbc6438164ab8 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Fri, 25 Apr 2025 00:55:22 +0200 Subject: [PATCH] refactor: endpoint for user locking refs #21 --- web/src/endpoints/mod.rs | 3 +- web/src/endpoints/user/mod.rs | 3 +- web/src/endpoints/user/post_toggle.rs | 74 ----------- web/src/endpoints/user/put_lock.rs | 128 ++++++++++++++++++++ web/templates/user/overview.html | 41 +------ web/templates/user/overview_buttons_td.html | 31 +++++ web/templates/user/overview_locked_td.html | 7 ++ 7 files changed, 176 insertions(+), 111 deletions(-) delete mode 100644 web/src/endpoints/user/post_toggle.rs create mode 100644 web/src/endpoints/user/put_lock.rs create mode 100644 web/templates/user/overview_buttons_td.html create mode 100644 web/templates/user/overview_locked_td.html diff --git a/web/src/endpoints/mod.rs b/web/src/endpoints/mod.rs index 802811a2..c1d60bb1 100644 --- a/web/src/endpoints/mod.rs +++ b/web/src/endpoints/mod.rs @@ -43,7 +43,6 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(user::get_reset::get); cfg.service(user::post_reset::post); cfg.service(user::get_profile::get); - cfg.service(user::post_toggle::post); cfg.service(user::get_changepassword::get); cfg.service(user::post_changepassword::post); cfg.service(user::get_register::get); @@ -51,6 +50,8 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(user::post_resend_registration::post); cfg.service(user::put_receive_notifications::put_subscribe); cfg.service(user::put_receive_notifications::put_unsubscribe); + cfg.service(user::put_lock::put_lock_user); + cfg.service(user::put_lock::put_unlock_user); cfg.service(availability::delete::delete); cfg.service(availability::get_new::get); diff --git a/web/src/endpoints/user/mod.rs b/web/src/endpoints/user/mod.rs index df316598..30cd9b8e 100644 --- a/web/src/endpoints/user/mod.rs +++ b/web/src/endpoints/user/mod.rs @@ -22,7 +22,8 @@ pub mod post_new; pub mod post_register; pub mod post_resend_registration; pub mod post_reset; -pub mod post_toggle; +pub mod put_receive_notifications; +pub mod put_lock; #[derive(Template)] #[template(path = "user/new_or_edit.html")] diff --git a/web/src/endpoints/user/post_toggle.rs b/web/src/endpoints/user/post_toggle.rs deleted file mode 100644 index c3496cfb..00000000 --- a/web/src/endpoints/user/post_toggle.rs +++ /dev/null @@ -1,74 +0,0 @@ -use actix_web::{web, HttpResponse, Responder}; -use serde::Deserialize; -use sqlx::PgPool; - -use crate::{ - endpoints::IdPath, - models::{Role, User}, -}; - -#[derive(Deserialize)] -struct ToggleQuery { - field: String, -} - -#[actix_web::post("/users/{id}/toggle")] -pub async fn post( - user: web::ReqData, - pool: web::Data, - path: web::Path, - query: web::Query, -) -> impl Responder { - // Todo: rewrite - if user.id != path.id && user.role != Role::Admin && user.role != Role::AreaManager { - return HttpResponse::Unauthorized().finish(); - } - - let user = if user.id != path.id { - User::read_by_id(pool.get_ref(), path.id) - .await - .unwrap() - .unwrap() - } else { - user.into_inner() - }; - - match query.field.as_str() { - "locked" => { - User::update_locked(pool.get_ref(), user.id, !user.locked) - .await - .unwrap(); - - if !user.locked { - return HttpResponse::Ok().body(format!( - r##" - - - Entsperren -
ja
- "##, - id = user.id)); - } else { - return HttpResponse::Ok().body(format!( - r##" - - - Sperren -
nein
- "##, - id = user.id)); - } - } - _ => return HttpResponse::BadRequest().body("Other PATCH paths are not supported!"), - }; -} diff --git a/web/src/endpoints/user/put_lock.rs b/web/src/endpoints/user/put_lock.rs new file mode 100644 index 00000000..92e60e7b --- /dev/null +++ b/web/src/endpoints/user/put_lock.rs @@ -0,0 +1,128 @@ +use actix_web::{web, HttpResponse, Responder}; +use askama::Template; +use sqlx::PgPool; + +use crate::{ + endpoints::IdPath, + filters, + models::{Role, User}, + utils::ApplicationError, +}; + +#[derive(Template, Debug)] +#[template(path = "user/overview_locked_td.html")] +struct OverviewPartialLockedTemplate { + u: User, + is_oob: bool, +} + +#[derive(Template, Debug)] +#[template(path = "user/overview_buttons_td.html")] +struct OverviewPartialButtonsTemplate { + u: User, +} + +#[actix_web::put("/users/{id}/lock")] +pub async fn put_lock_user( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + handle_lock_state_for_user(user, pool, path, true).await +} + +#[actix_web::put("/users/{id}/unlock")] +pub async fn put_unlock_user( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + handle_lock_state_for_user(user, pool, path, false).await +} + +async fn handle_lock_state_for_user( + user: web::ReqData, + pool: web::Data, + path: web::Path, + lock_state: bool, +) -> Result { + if user.role != Role::AreaManager && user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + if user.id == path.id { + return Ok(HttpResponse::BadRequest().finish()); + } + + let Some(mut user_in_db) = User::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + if user.role == Role::AreaManager + && (user.area_id != user_in_db.area_id || user_in_db.role == Role::Admin) + { + return Err(ApplicationError::Unauthorized); + } + + if user_in_db.locked != lock_state { + User::update_locked(pool.get_ref(), user_in_db.id, lock_state).await?; + user_in_db.locked = lock_state; + } + + let buttons = OverviewPartialButtonsTemplate { + u: user_in_db.clone(), + }; + + let locked_oob = OverviewPartialLockedTemplate { + u: user_in_db, + is_oob: true, + }; + + let mut body = buttons.render()?; + body.push_str(&locked_oob.render()?); + + Ok(HttpResponse::Ok().body(body)) +} + +// TODO: Tests schreiben +// #[cfg(test)] +// mod tests { +// use crate::utils::test_helper::{ +// assert_snapshot, read_body, test_put, DbTestContext, RequestConfig, StatusCode, +// }; +// use brass_macros::db_test; +// +// #[db_test] +// async fn user_can_toggle_subscription_for_himself(context: &DbTestContext) { +// let app = context.app().await; +// +// let unsubscribe_config = RequestConfig::new("/users/1/unsubscribeNotifications"); +// let unsubscribe_response = +// test_put::<_, _, String>(&context.db_pool, &app, &unsubscribe_config, None).await; +// +// assert_eq!(StatusCode::OK, unsubscribe_response.status()); +// +// let unsubscribe_body = read_body(unsubscribe_response).await; +// assert_snapshot!(unsubscribe_body); +// +// let subscribe_config = RequestConfig::new("/users/1/subscribeNotifications"); +// let subscribe_response = +// test_put::<_, _, String>(&context.db_pool, &app, &subscribe_config, None).await; +// +// assert_eq!(StatusCode::OK, subscribe_response.status()); +// +// let subscribe_body = read_body(subscribe_response).await; +// assert_snapshot!(subscribe_body); +// } +// +// #[db_test] +// async fn user_cant_toggle_subscription_for_someone_else(context: &DbTestContext) { +// let app = context.app().await; +// +// let unsubscribe_config = RequestConfig::new("/users/3/unsubscribeNotifications"); +// let unsubscribe_response = +// test_put::<_, _, String>(&context.db_pool, &app, &unsubscribe_config, None).await; +// +// assert_eq!(StatusCode::UNAUTHORIZED, unsubscribe_response.status()); +// } +// } diff --git a/web/templates/user/overview.html b/web/templates/user/overview.html index bf435e10..55bf9510 100644 --- a/web/templates/user/overview.html +++ b/web/templates/user/overview.html @@ -72,44 +72,15 @@ {% endif %} -
- {% if u.locked %} - ja - {% else %} - nein - {% endif %} -
+ {% include "overview_locked_td.html" %} - {% if user.id != u.id %} + {% let current_user_is_area_manager_and_user_is_not_admin = user.role == Role::AreaManager && u.role != + Role::Admin %} + {% if user.id != u.id && (user.role == Role::Admin || current_user_is_area_manager_and_user_is_not_admin) + %}
- - - - - - Bearbeiten - - - {% if u.password.is_none() && u.salt.is_none() && u.last_login.is_none() %} - - {% endif %} + {% include "overview_buttons_td.html" %}
{% endif %} diff --git a/web/templates/user/overview_buttons_td.html b/web/templates/user/overview_buttons_td.html new file mode 100644 index 00000000..2d4d3aab --- /dev/null +++ b/web/templates/user/overview_buttons_td.html @@ -0,0 +1,31 @@ + + + + + + + Bearbeiten + + + + +{% if u.password.is_none() && u.salt.is_none() && u.last_login.is_none() %} + +{% endif %} diff --git a/web/templates/user/overview_locked_td.html b/web/templates/user/overview_locked_td.html new file mode 100644 index 00000000..84cc57da --- /dev/null +++ b/web/templates/user/overview_locked_td.html @@ -0,0 +1,7 @@ +
+ {%- if u.locked -%} + ja + {%- else -%} + nein + {%- endif -%} +