update user functionality and cleanup

This commit is contained in:
Dietrich 2021-05-15 19:20:18 +02:00 committed by Franz Dietrich
parent 6837495eba
commit d503d49917
10 changed files with 297 additions and 80 deletions

218
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
@ -22,8 +24,8 @@ dependencies = [
"futures-sink",
"log",
"pin-project 0.4.28",
"tokio",
"tokio-util",
"tokio 0.2.25",
"tokio-util 0.3.1",
]
[[package]]
@ -91,7 +93,7 @@ dependencies = [
"futures-core",
"futures-util",
"fxhash",
"h2",
"h2 0.2.7",
"http",
"httparse",
"indexmap",
@ -161,7 +163,7 @@ dependencies = [
"futures-channel",
"futures-util",
"smallvec",
"tokio",
"tokio 0.2.25",
]
[[package]]
@ -177,11 +179,11 @@ dependencies = [
"futures-channel",
"futures-util",
"log",
"mio",
"mio 0.6.23",
"mio-uds",
"num_cpus",
"slab",
"socket2",
"socket2 0.3.19",
]
[[package]]
@ -218,7 +220,7 @@ dependencies = [
"actix-server",
"actix-service",
"log",
"socket2",
"socket2 0.3.19",
]
[[package]]
@ -301,7 +303,7 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
"socket2",
"socket2 0.3.19",
"time 0.2.26",
"tinyvec",
"url",
@ -1749,12 +1751,31 @@ dependencies = [
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tokio 0.2.25",
"tokio-util 0.3.1",
"tracing",
"tracing-futures",
]
[[package]]
name = "h2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726"
dependencies = [
"bytes 1.0.1",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio 1.6.0",
"tokio-util 0.6.7",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.1.8"
@ -1851,12 +1872,13 @@ dependencies = [
[[package]]
name = "http-body"
version = "0.3.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
dependencies = [
"bytes 0.5.6",
"bytes 1.0.1",
"http",
"pin-project-lite 0.2.6",
]
[[package]]
@ -1867,9 +1889,9 @@ checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
[[package]]
name = "httpdate"
version = "0.3.2"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9"
[[package]]
name = "humansize"
@ -1888,23 +1910,23 @@ dependencies = [
[[package]]
name = "hyper"
version = "0.13.10"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb"
checksum = "1e5f105c494081baa3bf9e200b279e27ec1623895cd504c7dbef8d0b080fcf54"
dependencies = [
"bytes 0.5.6",
"bytes 1.0.1",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"h2 0.3.3",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project 1.0.7",
"socket2",
"tokio",
"socket2 0.4.0",
"tokio 1.6.0",
"tower-service",
"tracing",
"want",
@ -1912,15 +1934,15 @@ dependencies = [
[[package]]
name = "hyper-tls"
version = "0.4.3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes 0.5.6",
"bytes 1.0.1",
"hyper",
"native-tls",
"tokio",
"tokio-tls",
"tokio 1.6.0",
"tokio-native-tls",
]
[[package]]
@ -2031,7 +2053,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7"
dependencies = [
"socket2",
"socket2 0.3.19",
"widestring",
"winapi 0.3.9",
"winreg 0.6.2",
@ -2261,12 +2283,25 @@ dependencies = [
"kernel32-sys",
"libc",
"log",
"miow",
"miow 0.2.2",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
name = "mio"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
dependencies = [
"libc",
"log",
"miow 0.3.7",
"ntapi",
"winapi 0.3.9",
]
[[package]]
name = "mio-uds"
version = "0.6.8"
@ -2275,7 +2310,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
"iovec",
"libc",
"mio",
"mio 0.6.23",
]
[[package]]
@ -2290,6 +2325,15 @@ dependencies = [
"ws2_32-sys",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "nanorand"
version = "0.5.2"
@ -2351,6 +2395,15 @@ dependencies = [
"version_check 0.9.3",
]
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -2475,6 +2528,23 @@ dependencies = [
"thiserror",
]
[[package]]
name = "opentelemetry"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "492848ff47f11b7f9de0443b404e2c5775f695e1af6b7076ca25f999581d547a"
dependencies = [
"async-trait",
"crossbeam-channel",
"futures 0.3.15",
"js-sys",
"lazy_static",
"percent-encoding",
"pin-project 1.0.7",
"rand 0.8.3",
"thiserror",
]
[[package]]
name = "opentelemetry-jaeger"
version = "0.12.1"
@ -2483,7 +2553,7 @@ checksum = "ddd4984441954f9ebbe3eebdfc6fd4fa95be6400d403171228779b949f3cd918"
dependencies = [
"async-trait",
"lazy_static",
"opentelemetry",
"opentelemetry 0.13.0",
"thiserror",
"thrift",
]
@ -2806,7 +2876,7 @@ dependencies = [
"fluent-langneg",
"fluent-templates",
"image",
"opentelemetry",
"opentelemetry 0.14.0",
"opentelemetry-jaeger",
"qrcode",
"rand 0.8.3",
@ -2819,7 +2889,7 @@ dependencies = [
"tera",
"test_bin",
"thiserror",
"tokio",
"tokio 0.2.25",
"tracing",
"tracing-actix-web",
"tracing-bunyan-formatter",
@ -3180,12 +3250,12 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.10.10"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c"
checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
dependencies = [
"base64 0.13.0",
"bytes 0.5.6",
"bytes 1.0.1",
"cookie",
"cookie_store",
"encoding_rs",
@ -3200,15 +3270,14 @@ dependencies = [
"lazy_static",
"log",
"mime",
"mime_guess",
"native-tls",
"percent-encoding",
"pin-project-lite 0.2.6",
"serde",
"serde_urlencoded",
"time 0.2.26",
"tokio",
"tokio-tls",
"tokio 1.6.0",
"tokio-native-tls",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
@ -3595,6 +3664,16 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "socket2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "spin"
version = "0.5.2"
@ -3710,7 +3789,7 @@ dependencies = [
"actix-rt",
"actix-threadpool",
"once_cell",
"tokio",
"tokio 0.2.25",
"tokio-rustls",
]
@ -4061,13 +4140,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
dependencies = [
"bytes 0.5.6",
"fnv",
"futures-core",
"iovec",
"lazy_static",
"libc",
"memchr",
"mio",
"mio 0.6.23",
"mio-uds",
"num_cpus",
"pin-project-lite 0.1.12",
@ -4077,6 +4155,20 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tokio"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd3076b5c8cc18138b8f8814895c11eb4de37114a5d127bafdc5e55798ceef37"
dependencies = [
"autocfg 1.0.1",
"bytes 1.0.1",
"libc",
"memchr",
"mio 0.7.11",
"pin-project-lite 0.2.6",
]
[[package]]
name = "tokio-macros"
version = "0.2.6"
@ -4088,6 +4180,16 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [
"native-tls",
"tokio 1.6.0",
]
[[package]]
name = "tokio-rustls"
version = "0.14.1"
@ -4096,20 +4198,10 @@ checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
dependencies = [
"futures-core",
"rustls",
"tokio",
"tokio 0.2.25",
"webpki",
]
[[package]]
name = "tokio-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.3.1"
@ -4121,7 +4213,21 @@ dependencies = [
"futures-sink",
"log",
"pin-project-lite 0.1.12",
"tokio",
"tokio 0.2.25",
]
[[package]]
name = "tokio-util"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
dependencies = [
"bytes 1.0.1",
"futures-core",
"futures-sink",
"log",
"pin-project-lite 0.2.6",
"tokio 1.6.0",
]
[[package]]
@ -4220,7 +4326,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99003208b647dae59dcefc49c98aecaa3512fbc29351685d4b9ef23a9218458e"
dependencies = [
"opentelemetry",
"opentelemetry 0.13.0",
"tracing",
"tracing-core",
"tracing-log",
@ -4275,7 +4381,7 @@ dependencies = [
"rand 0.7.3",
"smallvec",
"thiserror",
"tokio",
"tokio 0.2.25",
"url",
]
@ -4294,7 +4400,7 @@ dependencies = [
"resolv-conf",
"smallvec",
"thiserror",
"tokio",
"tokio 0.2.25",
"trust-dns-proto",
]

View File

@ -52,12 +52,12 @@ impl Page {
let result = match url.next_path_part() {
None | Some("list_links") => Self::Home(pages::list_links::init(
url,
&mut orders.proxy(Msg::ListLinksMsg),
&mut orders.proxy(Msg::ListLinks),
i18n,
)),
Some("list_users") => Self::ListUsers(pages::list_users::init(
url,
&mut orders.proxy(Msg::ListUsersMsg),
&mut orders.proxy(Msg::ListUsers),
i18n,
)),
_other => Self::NotFound,
@ -71,12 +71,11 @@ impl Page {
// ------ ------
// Update
// ------ ------
#[allow(renamed_and_removed_lints, pub_enum_variant_names)]
#[derive(Clone)]
pub enum Msg {
UrlChanged(subs::UrlChanged),
ListLinksMsg(list_links::Msg),
ListUsersMsg(list_users::Msg),
ListLinks(list_links::Msg),
ListUsers(list_users::Msg),
NoMessage,
}
@ -87,14 +86,14 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
model.page = Page::init(url.0, orders, model.i18n.clone());
}
Msg::ListLinksMsg(msg) => {
Msg::ListLinks(msg) => {
if let Page::Home(model) = &mut model.page {
list_links::update(msg, model, &mut orders.proxy(Msg::ListLinksMsg))
list_links::update(msg, model, &mut orders.proxy(Msg::ListLinks))
}
}
Msg::ListUsersMsg(msg) => {
Msg::ListUsers(msg) => {
if let Page::ListUsers(model) = &mut model.page {
list_users::update(msg, model, &mut orders.proxy(Msg::ListUsersMsg))
list_users::update(msg, model, &mut orders.proxy(Msg::ListUsers))
}
}
Msg::NoMessage => (),
@ -165,8 +164,8 @@ fn view_content(page: &Page, url: &Url) -> Node<Msg> {
div![
C!["container"],
match page {
Page::Home(model) => pages::list_links::view(model).map_msg(Msg::ListLinksMsg),
Page::ListUsers(model) => pages::list_users::view(model).map_msg(Msg::ListUsersMsg),
Page::Home(model) => pages::list_links::view(model).map_msg(Msg::ListLinks),
Page::ListUsers(model) => pages::list_users::view(model).map_msg(Msg::ListUsers),
Page::NotFound => div![div![url.to_string()], "Page not found!"],
}
]

View File

@ -26,7 +26,7 @@ pub fn navigation(i18n: &I18n, base_url: &Url) -> Node<Msg> {
li![a![ev(Ev::Click, |_| Msg::NoMessage), t!("add-link"),],],
li![a![
attrs! {At::Href => crate::Urls::new(base_url).create_user()},
ev(Ev::Click, |_| Msg::ListUsersMsg(
ev(Ev::Click, |_| Msg::ListUsers(
super::pages::list_users::Msg::Edit(
super::pages::list_users::UserEditMsg::CreateNewUser
)

View File

@ -49,6 +49,7 @@ struct FilterInput {
pub enum Msg {
Query(UserQueryMsg),
Edit(UserEditMsg),
ClearAll,
}
/// All the messages on user Querying
@ -81,6 +82,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg {
Msg::Query(msg) => process_query_messages(msg, model, orders),
Msg::Edit(msg) => process_user_edit_messages(msg, model, orders),
Msg::ClearAll => {
model.last_message = None;
model.user_edit = None;
}
}
}
@ -176,6 +181,7 @@ pub fn process_user_edit_messages(
match msg {
UserEditMsg::EditUserSelected(user) => {
log!("Editing user: ", user);
model.last_message = None;
model.user_edit = Some(RefCell::new(user))
}
UserEditMsg::CreateNewUser => {
@ -216,10 +222,13 @@ pub fn process_user_edit_messages(
orders.perform_cmd(async {
let data = data;
let response = match fetch(
Request::new("/admin/json/create_user/")
.method(Method::Post)
.json(&data)
.expect("serialization failed"),
Request::new(match data.edit {
EditMode::Create => "/admin/json/create_user/",
EditMode::Edit => "/admin/json/update_user/",
})
.method(Method::Post)
.json(&data)
.expect("serialization failed"),
)
.await
{
@ -256,11 +265,22 @@ pub fn view(model: &Model) -> Node<Msg> {
let lang = model.i18n.clone();
let t = move |key: &str| lang.translate(key, None);
section![
keyboard_ev(Ev::KeyDown, |keyboard_event| {
IF!(keyboard_event.key() == "Escape" => Msg::ClearAll)
}),
h1!("List Users Page from list_users"),
if let Some(message) = &model.last_message {
div![C!("Message"), &message.message]
div![
C!["message", "center"],
div![
C!["closebutton"],
a!["\u{d7}"],
ev(Ev::Click, |_| Msg::ClearAll)
],
&message.message
]
} else {
section!()
section![]
},
table![
// Column Headlines
@ -363,6 +383,11 @@ fn edit_or_create_user<F: Fn(&str) -> String>(l: &RefCell<UserDelta>, t: F) -> N
let user = l.borrow();
div![
C!["editdialog", "center"],
div![
C!["closebutton"],
a!["\u{d7}"],
ev(Ev::Click, |_| Msg::ClearAll)
],
h1![match &user.edit {
EditMode::Edit => t("edit-user"),
EditMode::Create => t("new-user"),

View File

@ -26,7 +26,7 @@ clap = "2.33"
dotenv = "0.15.0"
fluent-langneg = "0.13"
image = "0.23"
opentelemetry = "0.13"
opentelemetry = "0.14"
opentelemetry-jaeger = "0.12"
qrcode = "0.12"
rand = "0.8"
@ -70,4 +70,4 @@ tokio = "0.2.25"
[dev-dependencies.reqwest]
features = ["cookies"]
version = "0.10.10"
version = "0.11.3"

View File

@ -20,7 +20,7 @@ use tracing::{error, info, trace, warn};
static MIGRATOR: Migrator = sqlx::migrate!();
#[allow(clippy::clippy::too_many_lines)]
#[allow(clippy::too_many_lines)]
fn generate_cli() -> App<'static, 'static> {
app_from_crate!()
.arg(

View File

@ -374,6 +374,10 @@ pub async fn webservice(
.route(
"/create_user/",
web::post().to(views::process_create_user_json),
)
.route(
"/update_user/",
web::post().to(views::process_update_user_json),
),
)
// login to the admin area

View File

@ -4,7 +4,7 @@ use enum_map::EnumMap;
use serde::Serialize;
use shared::{
apirequests::{
general::{Filter, Operation, Ordering},
general::{EditMode, Filter, Operation, Ordering},
links::{LinkOverviewColumns, LinkRequestForm},
users::{UserDelta, UserOverviewColumns, UserRequestForm},
},
@ -310,7 +310,7 @@ pub struct Item<T> {
///
/// # Errors
/// Fails with [`ServerError`] if access to the database fails or this user does not have permissions.
#[allow(clippy::clippy::missing_panics_doc)]
#[allow(clippy::missing_panics_doc)]
#[instrument(skip(id))]
pub async fn get_user(
id: &Identity,
@ -400,6 +400,9 @@ pub async fn create_user_json(
server_config: &ServerConfig,
) -> Result<Item<User>, ServerError> {
info!("Creating a User: {:?}", &data);
if data.edit != EditMode::Create {
return Err(ServerError::User("Wrong Request".to_string()));
}
let auth = authenticate(id, server_config).await?;
// Require a password on user creation!
@ -440,7 +443,58 @@ pub async fn create_user_json(
///
/// # Errors
/// Fails with [`ServerError`] if access to the database fails, this user does not have permissions, or the given data is malformed.
#[allow(clippy::clippy::missing_panics_doc)]
#[instrument(skip(id))]
pub async fn update_user_json(
id: &Identity,
data: &web::Json<UserDelta>,
server_config: &ServerConfig,
) -> Result<Item<User>, ServerError> {
let auth = authenticate(id, server_config).await?;
if let Some(uid) = data.id {
let unmodified_user = User::get_user(uid, server_config).await?;
if auth.admin_or_self(uid) {
match auth {
Role::Admin { .. } | Role::Regular { .. } => {
info!("Updating userinfo: ");
let password = match &data.password {
Some(password) => NewUser::hash_password(password, &server_config.secret)?,
None => unmodified_user.password,
};
let new_user = User {
id: uid,
username: data.username.clone(),
email: data.email.clone(),
password,
role: unmodified_user.role,
language: unmodified_user.language,
};
new_user.update_user(server_config).await?;
let changed_user = User::get_user(uid, server_config).await?;
Ok(Item {
user: changed_user.clone(),
item: changed_user,
})
}
Role::NotAuthenticated | Role::Disabled => {
unreachable!("Should be unreachable because of the `admin_or_self`")
}
}
} else {
Err(ServerError::User("Not a valid UID".to_owned()))
}
} else {
Err(ServerError::User("Not a valid UID".to_owned()))
}
}
/// Take a [`actix_web::web::Form<NewUser>`] and update the corresponding entry in the database.
/// The password is only updated if a new password of at least 4 characters is provided.
/// The `user_id` is never changed.
///
/// # Errors
/// Fails with [`ServerError`] if access to the database fails, this user does not have permissions, or the given data is malformed.
#[allow(clippy::missing_panics_doc)]
#[instrument(skip(id))]
pub async fn update_user(
id: &Identity,

View File

@ -365,6 +365,21 @@ pub async fn process_create_user_json(
}
}
#[instrument(skip(id))]
pub async fn process_update_user_json(
config: web::Data<crate::ServerConfig>,
form: web::Json<UserDelta>,
id: Identity,
) -> Result<HttpResponse, ServerError> {
info!("Listing Users to Json api");
match queries::update_user_json(&id, &form, &config).await {
Ok(item) => Ok(HttpResponse::Ok().json2(&SuccessMessage {
message: format!("Successfully saved user: {}", item.item.username),
})),
Err(e) => Err(e),
}
}
#[instrument(skip(id))]
pub async fn toggle_admin(
data: web::Path<String>,

View File

@ -171,3 +171,17 @@ div.editdialog {
background-color: aliceblue;
border: 5px solid rgb(90, 90, 90);
}
div.closebutton a {
display: block;
position: absolute;
top: 10px;
right: 10px;
font-size: xx-large;
}
div.message {
background-color: aliceblue;
border: 5px solid rgb(90, 90, 90);
height: auto;
}