admin pages
Pages can now be locked behind admin privileges
This commit is contained in:
@@ -163,7 +163,8 @@ pub async fn get_current_user(
|
||||
"data": json!({
|
||||
"id": user.id,
|
||||
"first_name": user.first_name,
|
||||
"last_name": user.last_name
|
||||
"last_name": user.last_name,
|
||||
"is_admin": user.is_admin
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -5,22 +5,27 @@ use yew_router::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct AuthState {
|
||||
pub is_authenticated: bool,
|
||||
pub is_authenticated: Option<bool>,
|
||||
pub is_admin: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct ProtectedRouteProps {
|
||||
pub children: Children,
|
||||
pub admin_page: bool,
|
||||
}
|
||||
|
||||
#[component(ProtectedRoute)]
|
||||
pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
||||
let is_authenticated = use_state(|| None::<bool>);
|
||||
let auth_state = use_state(|| AuthState {
|
||||
is_authenticated: None,
|
||||
is_admin: None,
|
||||
});
|
||||
|
||||
{
|
||||
let is_authenticated = is_authenticated.clone();
|
||||
let auth_state = auth_state.clone();
|
||||
use_effect_with((), move |_| {
|
||||
let is_authenticated = is_authenticated.clone();
|
||||
let auth_state = auth_state.clone();
|
||||
spawn_local(async move {
|
||||
match Request::get("/api/users/current")
|
||||
.credentials(web_sys::RequestCredentials::Include)
|
||||
@@ -31,14 +36,27 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
||||
let status = resp.status();
|
||||
web_sys::console::log_1(&format!("Auth check: status {}", status).into());
|
||||
if status == 200 {
|
||||
is_authenticated.set(Some(true));
|
||||
let user_data: serde_json::Value =
|
||||
resp.json().await.unwrap_or_default();
|
||||
let is_admin = user_data["data"]["is_admin"].as_bool();
|
||||
|
||||
auth_state.set(AuthState {
|
||||
is_authenticated: Some(true),
|
||||
is_admin,
|
||||
});
|
||||
} else {
|
||||
is_authenticated.set(Some(false));
|
||||
auth_state.set(AuthState {
|
||||
is_authenticated: Some(false),
|
||||
is_admin: Some(false),
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::log_1(&format!("Auth check error: {:?}", err).into());
|
||||
is_authenticated.set(Some(false));
|
||||
auth_state.set(AuthState {
|
||||
is_authenticated: Some(false),
|
||||
is_admin: Some(false),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -46,13 +64,33 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
||||
});
|
||||
}
|
||||
|
||||
match *is_authenticated {
|
||||
None => html! { <div>{"Loading..."}</div> },
|
||||
match (*auth_state) {
|
||||
AuthState {
|
||||
is_authenticated: None,
|
||||
..
|
||||
} => html! { <div>{ "Loading..." } </div> },
|
||||
AuthState {
|
||||
is_authenticated: Some(false),
|
||||
..
|
||||
} => html! {
|
||||
<Redirect<crate::Route> to={crate::Route::Login}/>
|
||||
},
|
||||
AuthState {
|
||||
is_authenticated: Some(true),
|
||||
is_admin: admin_flag,
|
||||
} => {
|
||||
if props.admin_page {
|
||||
match admin_flag {
|
||||
Some(true) => props.children.clone().into(),
|
||||
Some(false) => {
|
||||
html! {
|
||||
<Redirect<crate::Route> to={crate::Route::Login} />
|
||||
html! { <Redirect<crate::Route> to={crate::Route::PermissionDenied}/> }
|
||||
}
|
||||
None => html! { <div>{ "Checking permissions..." }</div> },
|
||||
}
|
||||
} else {
|
||||
props.children.clone().into()
|
||||
}
|
||||
}
|
||||
_ => html! { <div>{ "Checking permissions..." }</div> },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod pages;
|
||||
mod auth;
|
||||
use crate::pages::*;
|
||||
mod pages;
|
||||
use crate::auth::ProtectedRoute;
|
||||
use crate::pages::*;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
@@ -23,6 +23,8 @@ enum Route {
|
||||
AllUsers,
|
||||
#[at("/users/:id")]
|
||||
UserByID { id: i16 },
|
||||
#[at("/denied")]
|
||||
PermissionDenied,
|
||||
#[not_found]
|
||||
#[at("/404")]
|
||||
NotFound,
|
||||
@@ -31,42 +33,43 @@ enum Route {
|
||||
fn switch(route: Route) -> Html {
|
||||
match route {
|
||||
Route::Home => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={false}>
|
||||
<basic_pages::Home/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::NotFound => html! { <basic_pages::NotFound/> },
|
||||
Route::Ticket => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={false}>
|
||||
<ticket::SubmitTicket/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::TicketById { id } => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<ticket::TicketByID {id}/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::AllTickets => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={false}>
|
||||
<ticket::AllTickets/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::Register => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<user::Register/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::Login => html! { <user::Login/> },
|
||||
Route::AllUsers => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<user::AllUsers/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::UserByID { id } => html! {
|
||||
<ProtectedRoute>
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<user::UserByID {id}/>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::PermissionDenied => html! { <basic_pages::PermissionDenied/> },
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,3 +28,13 @@ pub fn not_found_component() -> Html {
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component(PermissionDenied)]
|
||||
pub fn denied_component() -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<h1>{ "Sie haben nicht die benötigten Rechte um diese Seite aufzurufen" }</h1>
|
||||
<h3>{ "Wenn sie denken, dass dies ein Fehler ist kontaktieren sie Herrn Winter" }</h3>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use gloo_net::http::Request;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::use_navigator;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
@@ -177,6 +178,7 @@ pub fn login_component() -> Html {
|
||||
let loading = use_state(|| false);
|
||||
let error = use_state(|| String::new());
|
||||
let success = use_state(|| false);
|
||||
let navigator = use_navigator().unwrap();
|
||||
|
||||
let onsubmit = {
|
||||
let username = username.clone();
|
||||
@@ -184,6 +186,7 @@ pub fn login_component() -> Html {
|
||||
let loading = loading.clone();
|
||||
let error = error.clone();
|
||||
let success = success.clone();
|
||||
let navigator = navigator.clone();
|
||||
|
||||
Callback::from(move |e: SubmitEvent| {
|
||||
e.prevent_default();
|
||||
@@ -192,6 +195,7 @@ pub fn login_component() -> Html {
|
||||
let loading = loading.clone();
|
||||
let error = error.clone();
|
||||
let success = success.clone();
|
||||
let navigator = navigator.clone();
|
||||
|
||||
loading.set(true);
|
||||
error.set(String::new());
|
||||
@@ -211,7 +215,10 @@ pub fn login_component() -> Html {
|
||||
loading.set(false);
|
||||
|
||||
match response {
|
||||
Ok(r) if r.status() == 200 => success.set(true),
|
||||
Ok(r) if r.status() == 200 => {
|
||||
success.set(true);
|
||||
navigator.push(&crate::Route::Home);
|
||||
}
|
||||
Ok(r) => {
|
||||
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
||||
error.set(format!("HTTP {}: {}", r.status(), text));
|
||||
@@ -242,7 +249,6 @@ pub fn login_component() -> Html {
|
||||
})}
|
||||
/>
|
||||
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
||||
if *success { <p>{"Logged in — cookie set by server"}</p> }
|
||||
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
||||
</form>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user