WIP: make the interface aware of the admin role
This commit is contained in:
parent
61afbecda9
commit
eee0a8dba2
@ -1,6 +1,9 @@
|
||||
use fluent::fluent_args;
|
||||
use seed::{a, attrs, div, li, nav, ol, prelude::*, Url, C};
|
||||
use shared::datatypes::{Lang, User};
|
||||
use seed::{a, attrs, div, li, nav, nodes, ol, prelude::*, Url, C};
|
||||
use shared::{
|
||||
apirequests::users::Role,
|
||||
datatypes::{Lang, User},
|
||||
};
|
||||
|
||||
use crate::{i18n::I18n, Msg};
|
||||
|
||||
@ -33,21 +36,27 @@ pub fn navigation(i18n: &I18n, base_url: &Url, user: &User) -> Node<Msg> {
|
||||
)),
|
||||
t("add-link"),
|
||||
],],
|
||||
// A button to create a new user
|
||||
li![a![
|
||||
attrs! {At::Href => crate::Urls::new(base_url).create_user()},
|
||||
ev(Ev::Click, |_| Msg::ListUsers(
|
||||
super::pages::list_users::Msg::Edit(
|
||||
super::pages::list_users::UserEditMsg::CreateNewUser
|
||||
)
|
||||
)),
|
||||
t("invite-user"),
|
||||
],],
|
||||
// A button to list all users
|
||||
li![a![
|
||||
attrs! {At::Href => crate::Urls::new(base_url).list_users()},
|
||||
t("list-users"),
|
||||
],],
|
||||
if user.role == Role::Admin {
|
||||
nodes![
|
||||
// A button to create a new user
|
||||
li![a![
|
||||
attrs! {At::Href => crate::Urls::new(base_url).create_user()},
|
||||
ev(Ev::Click, |_| Msg::ListUsers(
|
||||
super::pages::list_users::Msg::Edit(
|
||||
super::pages::list_users::UserEditMsg::CreateNewUser
|
||||
)
|
||||
)),
|
||||
t("invite-user"),
|
||||
],],
|
||||
// A button to list all users
|
||||
li![a![
|
||||
attrs! {At::Href => crate::Urls::new(base_url).list_users()},
|
||||
t("list-users"),
|
||||
],],
|
||||
]
|
||||
} else {
|
||||
nodes!()
|
||||
},
|
||||
],
|
||||
ol![
|
||||
li![div![
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use enum_map::EnumMap;
|
||||
use seed::{
|
||||
a, attrs, button, div, h1, input, log, p, prelude::*, section, table, td, th, tr, Url, C, IF,
|
||||
@ -8,7 +6,7 @@ use shared::{
|
||||
apirequests::general::{Operation, Ordering},
|
||||
apirequests::{
|
||||
general::{EditMode, Status},
|
||||
users::{UserDelta, UserOverviewColumns, UserRequestForm},
|
||||
users::{Role, UserDelta, UserOverviewColumns, UserRequestForm},
|
||||
},
|
||||
datatypes::{Lang, User},
|
||||
};
|
||||
@ -20,7 +18,7 @@ use crate::{i18n::I18n, unwrap_or_return};
|
||||
pub fn init(mut url: Url, orders: &mut impl Orders<Msg>, i18n: I18n) -> Model {
|
||||
orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
|
||||
let user_edit = match url.next_path_part() {
|
||||
Some("create_user") => Some(RefCell::new(UserDelta::default())),
|
||||
Some("create_user") => Some(UserDelta::default()),
|
||||
None | Some(_) => None,
|
||||
};
|
||||
Model {
|
||||
@ -38,7 +36,7 @@ pub struct Model {
|
||||
i18n: I18n,
|
||||
formconfig: UserRequestForm,
|
||||
inputs: EnumMap<UserOverviewColumns, FilterInput>,
|
||||
user_edit: Option<RefCell<UserDelta>>,
|
||||
user_edit: Option<UserDelta>,
|
||||
last_message: Option<Status>,
|
||||
}
|
||||
|
||||
@ -87,6 +85,8 @@ pub enum UserEditMsg {
|
||||
EditUsernameChanged(String),
|
||||
EditEmailChanged(String),
|
||||
EditPasswordChanged(String),
|
||||
MakeAdmin(UserDelta),
|
||||
MakeRegular(UserDelta),
|
||||
SaveUser,
|
||||
FailedToCreateUser,
|
||||
}
|
||||
@ -203,38 +203,32 @@ pub fn process_user_edit_messages(
|
||||
match msg {
|
||||
UserEditMsg::EditUserSelected(user) => {
|
||||
model.clean_dialogs();
|
||||
model.user_edit = Some(RefCell::new(user))
|
||||
model.user_edit = Some(user)
|
||||
}
|
||||
UserEditMsg::CreateNewUser => {
|
||||
model.clean_dialogs();
|
||||
model.user_edit = Some(RefCell::new(UserDelta::default()))
|
||||
model.user_edit = Some(UserDelta::default())
|
||||
}
|
||||
UserEditMsg::EditUsernameChanged(s) => {
|
||||
if let Some(ref ue) = model.user_edit {
|
||||
ue.try_borrow_mut()
|
||||
.expect("Failed to borrow mutably")
|
||||
.username = s;
|
||||
if let Some(ref mut ue) = model.user_edit {
|
||||
ue.username = s;
|
||||
};
|
||||
}
|
||||
UserEditMsg::EditEmailChanged(s) => {
|
||||
if let Some(ref ue) = model.user_edit {
|
||||
ue.try_borrow_mut().expect("Failed to borrow mutably").email = s;
|
||||
if let Some(ref mut ue) = model.user_edit {
|
||||
ue.email = s;
|
||||
};
|
||||
}
|
||||
UserEditMsg::EditPasswordChanged(s) => {
|
||||
if let Some(ref ue) = model.user_edit {
|
||||
ue.try_borrow_mut()
|
||||
.expect("Failed to borrow mutably")
|
||||
.password = Some(s);
|
||||
if let Some(ref mut ue) = model.user_edit {
|
||||
ue.password = Some(s);
|
||||
};
|
||||
}
|
||||
UserEditMsg::SaveUser => {
|
||||
let data = model
|
||||
.user_edit
|
||||
.as_ref()
|
||||
.expect("Somehow a user should exist!")
|
||||
.borrow()
|
||||
.clone(); // complicated way to move into the closure
|
||||
.take()
|
||||
.expect("A user should allways be there on save"); // complicated way to move into the closure
|
||||
log!("Saving User: ", &data.username);
|
||||
save_user(data, orders);
|
||||
}
|
||||
@ -247,6 +241,8 @@ pub fn process_user_edit_messages(
|
||||
model.user_edit = None;
|
||||
orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
|
||||
}
|
||||
UserEditMsg::MakeAdmin(user) => todo!(),
|
||||
UserEditMsg::MakeRegular(user) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,7 +311,7 @@ pub fn view(model: &Model) -> Node<Msg> {
|
||||
// Add filter fields right below the headlines
|
||||
view_user_table_filter_input(model, &t),
|
||||
// Add all the users one line for each
|
||||
model.users.iter().map(view_user)
|
||||
model.users.iter().map(|u| { view_user(u, &t) })
|
||||
],
|
||||
// A refresh button. This will be removed in future versions.
|
||||
button![
|
||||
@ -324,7 +320,7 @@ pub fn view(model: &Model) -> Node<Msg> {
|
||||
],
|
||||
// Display the user edit dialog if available
|
||||
if let Some(l) = &model.user_edit {
|
||||
edit_or_create_user(l, t)
|
||||
edit_or_create_user(l.clone(), t)
|
||||
} else {
|
||||
section!()
|
||||
},
|
||||
@ -351,6 +347,7 @@ fn view_user_table_head<F: Fn(&str) -> String>(t: F) -> Node<Msg> {
|
||||
))),
|
||||
t("username")
|
||||
],
|
||||
th![t("role")],
|
||||
]
|
||||
}
|
||||
|
||||
@ -392,30 +389,64 @@ fn view_user_table_filter_input<F: Fn(&str) -> String>(model: &Model, t: F) -> N
|
||||
}),
|
||||
el_ref(&model.inputs[UserOverviewColumns::Username].filter_input),
|
||||
]],
|
||||
td![],
|
||||
]
|
||||
}
|
||||
|
||||
fn view_user(l: &User) -> Node<Msg> {
|
||||
fn view_user<F: Fn(&str) -> String>(l: &User, t: F) -> Node<Msg> {
|
||||
let user = UserDelta::from(l.clone());
|
||||
tr![
|
||||
ev(Ev::Click, |_| Msg::Edit(UserEditMsg::EditUserSelected(
|
||||
user
|
||||
))),
|
||||
{
|
||||
let user = user.clone();
|
||||
ev(Ev::Click, |_| {
|
||||
Msg::Edit(UserEditMsg::EditUserSelected(user))
|
||||
})
|
||||
},
|
||||
match l.role {
|
||||
Role::NotAuthenticated | Role::Disabled => C!("inactive"),
|
||||
Role::Regular => C!("regular"),
|
||||
Role::Admin => C!("admin"),
|
||||
},
|
||||
td![&l.id],
|
||||
td![&l.email],
|
||||
td![&l.username],
|
||||
match l.role {
|
||||
Role::NotAuthenticated | Role::Disabled | Role::Regular => td![
|
||||
ev(Ev::Click, |_| Msg::Edit(UserEditMsg::EditUserSelected(
|
||||
user
|
||||
))),
|
||||
t("make-user-admin")
|
||||
],
|
||||
Role::Admin => td![
|
||||
ev(Ev::Click, |_| Msg::Edit(UserEditMsg::EditUserSelected(
|
||||
user
|
||||
))),
|
||||
t("make-user-regular"),
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
fn edit_or_create_user<F: Fn(&str) -> String>(l: &RefCell<UserDelta>, t: F) -> Node<Msg> {
|
||||
let user = l.borrow();
|
||||
fn edit_or_create_user<F: Fn(&str) -> String>(l: UserDelta, t: F) -> Node<Msg> {
|
||||
let user = l;
|
||||
let headline: Node<Msg> = match &user.role {
|
||||
Role::NotAuthenticated | Role::Disabled | Role::Regular => {
|
||||
h1![match &user.edit {
|
||||
EditMode::Edit => t("edit-user"),
|
||||
EditMode::Create => t("new-user"),
|
||||
}]
|
||||
}
|
||||
Role::Admin => {
|
||||
h1![match &user.edit {
|
||||
EditMode::Edit => t("edit-admin"),
|
||||
EditMode::Create => t("new-admin"),
|
||||
}]
|
||||
}
|
||||
};
|
||||
div![
|
||||
C!["editdialog", "center"],
|
||||
close_button(),
|
||||
h1![match &user.edit {
|
||||
EditMode::Edit => t("edit-user"),
|
||||
EditMode::Create => t("new-user"),
|
||||
}],
|
||||
headline,
|
||||
table![
|
||||
tr![
|
||||
th![
|
||||
|
@ -36,10 +36,13 @@ password = Passwort
|
||||
leave-password-empty-hint = Leer lassen um das Passwort nicht zu ändern
|
||||
save-user = Benutzer speichern
|
||||
edit-user = Benutzer editieren
|
||||
edit-admin = Administrator editieren
|
||||
create-user = Benutzer Erstellen
|
||||
new-user = Neuer Benutzer
|
||||
new-admin = Neuer Administrator
|
||||
make-user-admin = Zum Administrator befördern
|
||||
make-user-regular = Zurückstufen zum normalen Nutzer
|
||||
role = Rolle
|
||||
|
||||
userid = Benutzernummer
|
||||
statistics = Statistik
|
@ -37,10 +37,13 @@ password = Password
|
||||
leave-password-empty-hint = Leave this empty to keep the current password
|
||||
save-user = Save this user
|
||||
edit-user = Edit this user
|
||||
edit-admin = Edit this administrator
|
||||
new-user = Neuer Benutzer
|
||||
create-user = Create user
|
||||
create-admin = Create administrator
|
||||
make-user-admin = Promote to admin
|
||||
make-user-regular = Demote to regular
|
||||
role = Role
|
||||
|
||||
userid = User ID
|
||||
statistics = Statistics
|
@ -32,12 +32,12 @@ pub enum RoleGuard {
|
||||
}
|
||||
|
||||
impl RoleGuard {
|
||||
fn create(user: User) -> Self {
|
||||
fn create(user: &User) -> Self {
|
||||
match user.role {
|
||||
shared::apirequests::users::Role::NotAuthenticated => Self::NotAuthenticated,
|
||||
shared::apirequests::users::Role::Disabled => Self::Disabled,
|
||||
shared::apirequests::users::Role::Regular => Self::Regular { user },
|
||||
shared::apirequests::users::Role::Admin => Self::Admin { user },
|
||||
shared::apirequests::users::Role::Regular => Self::Regular { user: user.clone() },
|
||||
shared::apirequests::users::Role::Admin => Self::Admin { user: user.clone() },
|
||||
}
|
||||
}
|
||||
/// Determin if the user is admin or the given user id is his own. This is used for things where users can edit or view their own entries, whereas admins can do so for all entries.
|
||||
@ -64,7 +64,7 @@ pub async fn authenticate(
|
||||
let user = User::get_user_by_name(&username, server_config).await?;
|
||||
info!("Found user {:?}", user);
|
||||
|
||||
return Ok(RoleGuard::create(user));
|
||||
return Ok(RoleGuard::create(&user));
|
||||
}
|
||||
Ok(RoleGuard::NotAuthenticated)
|
||||
}
|
||||
|
@ -76,6 +76,14 @@ table tr:nth-child(odd) {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
table tr:nth-child(even).admin {
|
||||
background-color: rgb(240, 142, 142);
|
||||
}
|
||||
|
||||
table tr:nth-child(odd).admin {
|
||||
background-color: rgb(255, 204, 169);
|
||||
}
|
||||
|
||||
table tr.filters input {
|
||||
background-image: url("/static/search.svg");
|
||||
background-repeat: no-repeat;
|
||||
|
@ -39,6 +39,7 @@ pub struct UserDelta {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub password: Option<String>,
|
||||
pub role: Role,
|
||||
}
|
||||
|
||||
impl From<User> for UserDelta {
|
||||
@ -50,6 +51,7 @@ impl From<User> for UserDelta {
|
||||
username: u.username,
|
||||
email: u.email,
|
||||
password: None,
|
||||
role: u.role,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,7 +75,8 @@ pub enum Role {
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub fn convert(i: i64) -> Self {
|
||||
#[must_use]
|
||||
pub const fn convert(i: i64) -> Self {
|
||||
match i {
|
||||
0 => Self::Disabled,
|
||||
1 => Self::Regular,
|
||||
@ -82,7 +85,8 @@ impl Role {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_i64(&self) -> i64 {
|
||||
#[must_use]
|
||||
pub const fn to_i64(self) -> i64 {
|
||||
match self {
|
||||
Role::NotAuthenticated => 3,
|
||||
Role::Disabled => 0,
|
||||
@ -91,3 +95,9 @@ impl Role {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Role {
|
||||
fn default() -> Self {
|
||||
Self::Regular
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user