feat: locking and deletion of user
This commit is contained in:
parent
39a28038ca
commit
3d3e92cf38
39
Cargo.lock
generated
39
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
30
src/endpoints/user/delete.rs
Normal file
30
src/endpoints/user/delete.rs
Normal file
@ -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<PgPool>, path: web::Path<IdPath>) -> 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()
|
||||
}
|
@ -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;
|
||||
|
69
src/endpoints/user/patch.rs
Normal file
69
src/endpoints/user/patch.rs
Normal file
@ -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<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
patch_docs: web::Json<Vec<JsonPatchDoc>>,
|
||||
) -> 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<bool> = 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")
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -276,6 +276,7 @@ impl User {
|
||||
role: Option<Role>,
|
||||
function: Option<Function>,
|
||||
area_id: Option<i32>,
|
||||
locked: Option<bool>
|
||||
) -> 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<bool> {
|
||||
// todo!()
|
||||
// }
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> {
|
||||
sqlx::query!("DELETE FROM user_ WHERE id = $1", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<form method="post" action="/users/edit/{{ id }}">
|
||||
<h1 class="title">Nutzer {{ name }} bearbeiten</h1>
|
||||
<h1 class="title">Nutzer '{{ name }}' bearbeiten</h1>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
|
@ -37,7 +37,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<tr id="user-{{ u.id }}">
|
||||
<td>
|
||||
{{ u.email }}
|
||||
</td>
|
||||
@ -85,8 +85,9 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="buttons is-right">
|
||||
<button class="button is-link is-light" name="toggle-lock-user">{% if u.locked %}Entsperren{% else %}Sperren{% endif %}</button>
|
||||
<a class="button is-link" href="/users/edit/{{ u.id }}">Bearbeiten</a>
|
||||
<button class="button is-danger" name="delete-availabillity">Löschen</button>
|
||||
<button class="button is-danger" {% if !u.locked %}disabled{% endif %} name="delete-user">Löschen</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -100,5 +101,59 @@
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.getElementsByName("delete-user")
|
||||
.forEach(ele => ele.addEventListener("click", (event) => {
|
||||
const id = event.target.closest("tr").id.split('-')[1];
|
||||
event.target.classList.add("is-loading");
|
||||
|
||||
fetch(`/users/delete/${id}`, { method: "DELETE"})
|
||||
.then(response => {
|
||||
if (response.status == 204) {
|
||||
document.getElementById(`user-${id}`).remove()
|
||||
} else {
|
||||
event.target.classList.remove("is-loading");
|
||||
console.log("Fehler beim Löschen.")
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
document.getElementsByName("toggle-lock-user")
|
||||
.forEach(ele => ele.addEventListener("click", (event) => {
|
||||
const id = event.target.closest("tr").id.split('-')[1];
|
||||
event.target.classList.add("is-loading");
|
||||
|
||||
const locked = event.target.innerHTML == "Sperren" ? false : true;
|
||||
|
||||
fetch(`/users/edit/${id}`, {
|
||||
method: "PATCH",
|
||||
headers: new Headers({
|
||||
"Content-Type": "application/json-patch+json",
|
||||
}),
|
||||
body: JSON.stringify([
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/locked",
|
||||
"value": !locked
|
||||
}
|
||||
])
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status == 200) {
|
||||
event.target.classList.remove("is-loading");
|
||||
if (locked) {
|
||||
event.target.innerHTML = "Sperren";
|
||||
event.target.closest("tr").querySelector("td:nth-last-child(2)").innerHTML = "nein"
|
||||
event.target.closest("div.buttons").querySelector("button:nth-last-child(1)").setAttribute("disabled", "");
|
||||
} else {
|
||||
event.target.innerHTML = "Entsperren";
|
||||
event.target.closest("tr").querySelector("td:nth-last-child(2)").innerHTML = "ja"
|
||||
event.target.closest("div.buttons").querySelector("button:nth-last-child(1)").removeAttribute("disabled");
|
||||
}
|
||||
} else {
|
||||
event.target.classList.remove("is-loading");
|
||||
console.log("Fehler beim PATCH.")
|
||||
}
|
||||
});
|
||||
}));
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user