parent
5446fcb128
commit
08646ba971
@ -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);
|
||||
|
@ -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")]
|
||||
|
@ -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<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
query: web::Query<ToggleQuery>,
|
||||
) -> 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##"<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#unlock" />
|
||||
</svg>
|
||||
<span>Entsperren</span>
|
||||
<div id="user-{id}-locked" hx-swap-oob="true">ja</div>
|
||||
<button id="user-{id}-delete" hx-swap-oob="true" class="button is-danger is-light" hx-delete="/users/{id}" hx-target="closest tr" hx-swap="delete" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
<span>Löschen</span>
|
||||
</button>"##,
|
||||
id = user.id));
|
||||
} else {
|
||||
return HttpResponse::Ok().body(format!(
|
||||
r##"<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#lock" />
|
||||
</svg>
|
||||
<span>Sperren</span>
|
||||
<div id="user-{id}-locked" hx-swap-oob="true">nein</div>
|
||||
<button id="user-{id}-delete" hx-swap-oob="true" class="button is-danger is-light" disabled hx-delete="/users/{id}" hx-target="closest tr" hx-swap="delete" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
<span>Löschen</span>
|
||||
</button>"##,
|
||||
id = user.id));
|
||||
}
|
||||
}
|
||||
_ => return HttpResponse::BadRequest().body("Other PATCH paths are not supported!"),
|
||||
};
|
||||
}
|
128
web/src/endpoints/user/put_lock.rs
Normal file
128
web/src/endpoints/user/put_lock.rs
Normal file
@ -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<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))
|
||||
}
|
||||
|
||||
// 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());
|
||||
// }
|
||||
// }
|
@ -72,44 +72,15 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div id="user-{{ u.id }}-locked">
|
||||
{% if u.locked %}
|
||||
ja
|
||||
{% else %}
|
||||
nein
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include "overview_locked_td.html" %}
|
||||
</td>
|
||||
<td>
|
||||
{% 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)
|
||||
%}
|
||||
<div class="buttons is-right">
|
||||
<button class="button is-link is-light" hx-post="/users/{{ u.id }}/toggle?field=locked">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#{% if u.locked %}unlock{% else %}lock{% endif %}" />
|
||||
</svg>
|
||||
<span>{% if u.locked %}Entsperren{% else %}Sperren{% endif %}</span>
|
||||
</button>
|
||||
<a class="button is-primary is-light" hx-boost="true" href="/users/edit/{{ u.id }}">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#edit" />
|
||||
</svg>
|
||||
<span>Bearbeiten</span>
|
||||
</a>
|
||||
<button id="user-{{ u.id }}-delete" class="button is-danger is-light" {% if !u.locked %}disabled{% endif
|
||||
%} hx-delete="/users/{{ u.id }}" hx-target="closest tr" hx-swap="delete" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
<span>Löschen</span>
|
||||
</button>
|
||||
{% if u.password.is_none() && u.salt.is_none() && u.last_login.is_none() %}
|
||||
<button class="button is-warning is-light" hx-post="/users/{{ u.id }}/resend-registration">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#send" />
|
||||
</svg>
|
||||
<span>Registrierungsmail erneut senden</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% include "overview_buttons_td.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
31
web/templates/user/overview_buttons_td.html
Normal file
31
web/templates/user/overview_buttons_td.html
Normal file
@ -0,0 +1,31 @@
|
||||
<button class="button is-link is-light" hx-put="/users/{{ u.id }}/{%- if u.locked -%}un{%- endif -%}lock"
|
||||
hx-target="closest div" hx-swap="innerHTML">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#{%- if u.locked -%}un{%- endif -%}lock" />
|
||||
</svg>
|
||||
<span>{%- if u.locked -%}Entsperren{%- else -%}Sperren{%- endif -%}</span>
|
||||
</button>
|
||||
|
||||
<a class="button is-primary is-light" hx-boost="true" href="/users/edit/{{ u.id }}">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#edit" />
|
||||
</svg>
|
||||
<span>Bearbeiten</span>
|
||||
</a>
|
||||
|
||||
<button id="user-{{ u.id }}-delete" class="button is-danger is-light" {{ !u.locked|cond_show("disabled") }}
|
||||
hx-delete="/users/{{ u.id }}" hx-target="closest tr" hx-swap="delete" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
<span>Löschen</span>
|
||||
</button>
|
||||
|
||||
{% if u.password.is_none() && u.salt.is_none() && u.last_login.is_none() %}
|
||||
<button class="button is-warning is-light" hx-post="/users/{{ u.id }}/resend-registration">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#send" />
|
||||
</svg>
|
||||
<span>Registrierungsmail erneut senden</span>
|
||||
</button>
|
||||
{% endif %}
|
7
web/templates/user/overview_locked_td.html
Normal file
7
web/templates/user/overview_locked_td.html
Normal file
@ -0,0 +1,7 @@
|
||||
<div id="user-{{ u.id }}-locked" {% if is_oob -%}hx-swap-oob="true" {%- endif -%}>
|
||||
{%- if u.locked -%}
|
||||
ja
|
||||
{%- else -%}
|
||||
nein
|
||||
{%- endif -%}
|
||||
</div>
|
Loading…
x
Reference in New Issue
Block a user