use crate::{
components::{
change_password::ChangePasswordForm,
create_group::CreateGroupForm,
create_user::CreateUserForm,
group_details::GroupDetails,
group_table::GroupTable,
login::LoginForm,
logout::LogoutButton,
reset_password_step1::ResetPasswordStep1Form,
reset_password_step2::ResetPasswordStep2Form,
router::{AppRoute, Link, Redirect},
user_details::UserDetails,
user_table::UserTable,
},
infra::{api::HostService, cookies::get_cookie},
};
use gloo_console::error;
use wasm_bindgen::prelude::*;
use yew::{
function_component,
html::Scope,
prelude::{html, Component, Html},
Context,
};
use yew_router::{
prelude::{History, Location},
scope_ext::RouterScopeExt,
BrowserRouter, Switch,
};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = darkmode)]
fn toggleDarkMode(doSave: bool);
#[wasm_bindgen]
fn inDarkMode() -> bool;
}
#[function_component(DarkModeToggle)]
pub fn dark_mode_toggle() -> Html {
html! {
}
}
#[function_component(AppContainer)]
pub fn app_container() -> Html {
html! {
}
}
pub struct App {
user_info: Option<(String, bool)>,
redirect_to: Option,
password_reset_enabled: Option,
}
pub enum Msg {
Login((String, bool)),
Logout,
PasswordResetProbeFinished(anyhow::Result),
}
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context) -> Self {
let app = Self {
user_info: get_cookie("user_id")
.unwrap_or_else(|e| {
error!(&e.to_string());
None
})
.and_then(|u| {
get_cookie("is_admin")
.map(|so| so.map(|s| (u, s == "true")))
.unwrap_or_else(|e| {
error!(&e.to_string());
None
})
}),
redirect_to: Self::get_redirect_route(ctx),
password_reset_enabled: None,
};
ctx.link().send_future(async move {
Msg::PasswordResetProbeFinished(HostService::probe_password_reset().await)
});
app.apply_initial_redirections(ctx);
app
}
fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool {
let history = ctx.link().history().unwrap();
match msg {
Msg::Login((user_name, is_admin)) => {
self.user_info = Some((user_name.clone(), is_admin));
history.push(self.redirect_to.take().unwrap_or_else(|| {
if is_admin {
AppRoute::ListUsers
} else {
AppRoute::UserDetails {
user_id: user_name.clone(),
}
}
}));
}
Msg::Logout => {
self.user_info = None;
self.redirect_to = None;
history.push(AppRoute::Login);
}
Msg::PasswordResetProbeFinished(Ok(enabled)) => {
self.password_reset_enabled = Some(enabled);
}
Msg::PasswordResetProbeFinished(Err(err)) => {
self.password_reset_enabled = Some(false);
error!(&format!(
"Could not probe for password reset support: {err:#}"
));
}
}
true
}
fn view(&self, ctx: &Context) -> Html {
let link = ctx.link().clone();
let is_admin = self.is_admin();
let password_reset_enabled = self.password_reset_enabled;
html! {
{self.view_banner(ctx)}
render={Switch::render(move |routes| Self::dispatch_route(routes, &link, is_admin, password_reset_enabled))}
/>
{self.view_footer()}
}
}
}
impl App {
// Get the page to land on after logging in, defaulting to the index.
fn get_redirect_route(ctx: &Context) -> Option {
let route = ctx.link().history().unwrap().location().route::();
route.filter(|route| {
!matches!(
route,
AppRoute::Index
| AppRoute::Login
| AppRoute::StartResetPassword
| AppRoute::FinishResetPassword { token: _ }
)
})
}
fn apply_initial_redirections(&self, ctx: &Context) {
let history = ctx.link().history().unwrap();
let route = history.location().route::();
let redirection = match (route, &self.user_info, &self.redirect_to) {
(
Some(AppRoute::StartResetPassword | AppRoute::FinishResetPassword { token: _ }),
_,
_,
) => {
if self.password_reset_enabled == Some(false) {
Some(AppRoute::Login)
} else {
None
}
}
(None, _, _) | (_, None, _) => Some(AppRoute::Login),
// User is logged in, a URL was given, don't redirect.
(_, Some(_), Some(_)) => None,
(_, Some((user_name, is_admin)), None) => {
if *is_admin {
Some(AppRoute::ListUsers)
} else {
Some(AppRoute::UserDetails {
user_id: user_name.clone(),
})
}
}
};
if let Some(redirect_to) = redirection {
history.push(redirect_to);
}
}
fn dispatch_route(
switch: &AppRoute,
link: &Scope,
is_admin: bool,
password_reset_enabled: Option,
) -> Html {
match switch {
AppRoute::Login => html! {
},
AppRoute::CreateUser => html! {
},
AppRoute::Index | AppRoute::ListUsers => html! {
{"Create a user"}
},
AppRoute::CreateGroup => html! {
},
AppRoute::ListGroups => html! {
{"Create a group"}
},
AppRoute::GroupDetails { group_id } => html! {
},
AppRoute::UserDetails { user_id } => html! {
},
AppRoute::ChangePassword { user_id } => html! {
},
AppRoute::StartResetPassword => match password_reset_enabled {
Some(true) => html! { },
Some(false) => {
html! { }
}
None => html! {},
},
AppRoute::FinishResetPassword { token } => match password_reset_enabled {
Some(true) => html! { },
Some(false) => {
html! { }
}
None => html! {},
},
}
}
fn view_banner(&self, ctx: &Context) -> Html {
html! {
{"LLDAP"}
{if self.is_admin() { html! {
<>
-
{"Users"}
-
{"Groups"}
>
} } else { html!{} } }
{ self.view_user_menu(ctx) }
}
}
fn view_user_menu(&self, ctx: &Context) -> Html {
if let Some((user_id, _)) = &self.user_info {
let link = ctx.link();
html! {
}
} else {
html! {}
}
}
fn view_footer(&self) -> Html {
html! {
}
}
fn is_admin(&self) -> bool {
match &self.user_info {
None => false,
Some((_, is_admin)) => *is_admin,
}
}
}