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, NavButton}, user_details::UserDetails, user_table::UserTable, }, infra::{api::HostService, cookies::get_cookie}, }; use yew::{ prelude::*, services::{fetch::FetchTask, ConsoleService}, }; use yew_router::{ agent::{RouteAgentDispatcher, RouteRequest}, route::Route, router::Router, service::RouteService, }; pub struct App { link: ComponentLink, user_info: Option<(String, bool)>, redirect_to: Option, route_dispatcher: RouteAgentDispatcher, password_reset_enabled: Option, task: Option, } pub enum Msg { Login((String, bool)), Logout, PasswordResetProbeFinished(anyhow::Result), } impl Component for App { type Message = Msg; type Properties = (); fn create(_: Self::Properties, link: ComponentLink) -> Self { let mut app = Self { link, user_info: get_cookie("user_id") .unwrap_or_else(|e| { ConsoleService::error(&e.to_string()); None }) .and_then(|u| { get_cookie("is_admin") .map(|so| so.map(|s| (u, s == "true"))) .unwrap_or_else(|e| { ConsoleService::error(&e.to_string()); None }) }), redirect_to: Self::get_redirect_route(), route_dispatcher: RouteAgentDispatcher::new(), password_reset_enabled: None, task: None, }; app.task = Some( HostService::probe_password_reset( app.link.callback_once(Msg::PasswordResetProbeFinished), ) .unwrap(), ); app.apply_initial_redirections(); app } fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { Msg::Login((user_name, is_admin)) => { self.user_info = Some((user_name.clone(), is_admin)); self.route_dispatcher .send(RouteRequest::ChangeRoute(Route::from( self.redirect_to.take().unwrap_or_else(|| { if is_admin { AppRoute::ListUsers } else { AppRoute::UserDetails(user_name.clone()) } }), ))); } Msg::Logout => { self.user_info = None; self.redirect_to = None; self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login))); } Msg::PasswordResetProbeFinished(Ok(enabled)) => { self.task = None; self.password_reset_enabled = Some(enabled); } Msg::PasswordResetProbeFinished(Err(err)) => { self.task = None; self.password_reset_enabled = Some(false); ConsoleService::error(&format!( "Could not probe for password reset support: {err:#}" )); } } true } fn change(&mut self, _: Self::Properties) -> ShouldRender { false } fn view(&self) -> Html { let link = self.link.clone(); let is_admin = self.is_admin(); let password_reset_enabled = self.password_reset_enabled; html! {
{self.view_banner()}
render = Router::render(move |s| Self::dispatch_route(s, &link, is_admin, password_reset_enabled)) />
{self.view_footer()}
} } } impl App { fn get_redirect_route() -> Option { let route_service = RouteService::<()>::new(); let current_route = route_service.get_path(); if current_route.is_empty() || current_route == "/" || current_route.contains("login") || current_route.contains("reset-password") { None } else { use yew_router::Switch; AppRoute::from_route_part::<()>(current_route, None).0 } } fn apply_initial_redirections(&mut self) { let route_service = RouteService::<()>::new(); let current_route = route_service.get_path(); if current_route.contains("reset-password") { if self.password_reset_enabled == Some(false) { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login))); } return; } match &self.user_info { None => { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login))); } Some((user_name, is_admin)) => match &self.redirect_to { Some(url) => { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from(url.clone()))); } None => { if *is_admin { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::ListUsers))); } else { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from( AppRoute::UserDetails(user_name.clone()), ))); } } }, } } fn dispatch_route( switch: AppRoute, link: &ComponentLink, 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(username) => html! { }, AppRoute::ChangePassword(username) => html! { }, AppRoute::StartResetPassword => match password_reset_enabled { Some(true) => html! { }, Some(false) => { App::dispatch_route(AppRoute::Login, link, is_admin, password_reset_enabled) } None => html! {}, }, AppRoute::FinishResetPassword(token) => match password_reset_enabled { Some(true) => html! { }, Some(false) => { App::dispatch_route(AppRoute::Login, link, is_admin, password_reset_enabled) } None => html! {}, }, } } fn view_banner(&self) -> Html { html! {

{"LLDAP"}

{ if let Some((user_id, _)) = &self.user_info { 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, } } }