182 lines
5.2 KiB
Rust
182 lines
5.2 KiB
Rust
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<User>,
|
|
pool: web::Data<PgPool>,
|
|
path: web::Path<IdPath>,
|
|
) -> Result<impl Responder, ApplicationError> {
|
|
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<User>,
|
|
pool: web::Data<PgPool>,
|
|
path: web::Path<IdPath>,
|
|
) -> Result<impl Responder, ApplicationError> {
|
|
handle_lock_state_for_user(user, pool, path, false).await
|
|
}
|
|
|
|
async fn handle_lock_state_for_user(
|
|
user: web::ReqData<User>,
|
|
pool: web::Data<PgPool>,
|
|
path: web::Path<IdPath>,
|
|
lock_state: bool,
|
|
) -> Result<impl Responder, ApplicationError> {
|
|
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))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{
|
|
models::{Area, Function, Role, User},
|
|
utils::test_helper::{
|
|
assert_snapshot, read_body, test_put, DbTestContext, RequestConfig, StatusCode,
|
|
},
|
|
};
|
|
use brass_macros::db_test;
|
|
use fake::{Fake, Faker};
|
|
|
|
#[db_test]
|
|
async fn admin_can_lock_and_unlock_user(context: &DbTestContext) {
|
|
let app = context.app().await;
|
|
User::create(&context.db_pool, Faker.fake()).await.unwrap();
|
|
|
|
let lock_config = RequestConfig {
|
|
uri: "/users/1/lock".to_string(),
|
|
role: Role::Admin,
|
|
function: vec![Function::Posten],
|
|
user_area: 1,
|
|
};
|
|
let lock_response =
|
|
test_put::<_, _, String>(&context.db_pool, &app, &lock_config, None).await;
|
|
|
|
assert_eq!(StatusCode::OK, lock_response.status());
|
|
|
|
let lock_body = read_body(lock_response).await;
|
|
assert_snapshot!(lock_body);
|
|
|
|
let unlock_config = RequestConfig {
|
|
uri: "/users/1/unlock".to_string(),
|
|
role: Role::Admin,
|
|
function: vec![Function::Posten],
|
|
user_area: 1,
|
|
};
|
|
let unlock_response =
|
|
test_put::<_, _, String>(&context.db_pool, &app, &unlock_config, None).await;
|
|
|
|
assert_eq!(StatusCode::OK, unlock_response.status());
|
|
|
|
let unlock_body = read_body(unlock_response).await;
|
|
assert_snapshot!(unlock_body);
|
|
}
|
|
|
|
#[db_test]
|
|
async fn area_manager_cant_lock_outside_of_his_area(context: &DbTestContext) {
|
|
let app = context.app().await;
|
|
Area::create(&context.db_pool, "Bereich 2").await.unwrap();
|
|
User::create(&context.db_pool, Faker.fake()).await.unwrap();
|
|
|
|
let config = RequestConfig {
|
|
uri: "/users/1/lock".to_string(),
|
|
role: Role::AreaManager,
|
|
function: vec![Function::Posten],
|
|
user_area: 2,
|
|
};
|
|
|
|
let response = test_put::<_, _, String>(&context.db_pool, &app, &config, None).await;
|
|
|
|
assert_eq!(StatusCode::UNAUTHORIZED, response.status())
|
|
}
|
|
|
|
#[db_test]
|
|
async fn one_cant_lock_oneself(context: &DbTestContext) {
|
|
let app = context.app().await;
|
|
|
|
let config = RequestConfig {
|
|
uri: "/users/1/lock".to_string(),
|
|
role: Role::Admin,
|
|
function: vec![Function::Posten],
|
|
user_area: 1,
|
|
};
|
|
|
|
let response = test_put::<_, _, String>(&context.db_pool, &app, &config, None).await;
|
|
|
|
assert_eq!(StatusCode::BAD_REQUEST, response.status())
|
|
}
|
|
|
|
#[db_test]
|
|
async fn one_cant_lock_non_existing_user(context: &DbTestContext) {
|
|
let app = context.app().await;
|
|
|
|
let config = RequestConfig {
|
|
uri: "/users/30/lock".to_string(),
|
|
role: Role::Admin,
|
|
function: vec![Function::Posten],
|
|
user_area: 1,
|
|
};
|
|
|
|
let response = test_put::<_, _, String>(&context.db_pool, &app, &config, None).await;
|
|
|
|
assert_eq!(StatusCode::NOT_FOUND, response.status())
|
|
}
|
|
}
|