This commit is contained in:
2025-07-15 16:13:52 +02:00
parent 4a24db0639
commit 8551a004a8
4 changed files with 82 additions and 38 deletions
+43 -2
View File
@@ -6,9 +6,14 @@ pub struct User {
password: String, password: String,
} }
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Session {
uuid: String,
}
#[server] #[server]
pub async fn login(username: String, password: String) -> Result<String, ServerFnError> { pub async fn login(username: String, password: String) -> Result<String, ServerFnError> {
let users = crate::backend::get_mongo::<User>("users").await?; let users = crate::backend::get_mongo::<mongodb::bson::Document>("users").await?;
match users match users
.find_one(mongodb::bson::doc! { .find_one(mongodb::bson::doc! {
@@ -17,7 +22,43 @@ pub async fn login(username: String, password: String) -> Result<String, ServerF
}) })
.await? .await?
{ {
Some(v) => Ok(String::new()), Some(v) => {
let sessions = crate::backend::get_mongo::<Session>("sessions").await?;
if let mongodb::bson::Bson::ObjectId(id) = sessions
.insert_one(Session {
uuid: v.get_object_id("_id")?.to_hex(),
})
.await?
.inserted_id
{
Ok(id.to_hex())
} else {
Err(ServerFnError::new(format!("Unable to extract session id")))
}
}
None => Err(ServerFnError::new(format!("Invalid credentials"))), None => Err(ServerFnError::new(format!("Invalid credentials"))),
} }
} }
#[cfg(feature = "server")]
pub async fn validate_session(id: String) -> bool {
use mongodb::bson::oid::ObjectId;
if let Ok(sessions) = crate::backend::get_mongo::<Session>("sessions").await {
if let Some(obj_id) = ObjectId::parse_str(id).ok() {
match sessions
.find_one(mongodb::bson::doc! {
"_id": obj_id,
})
.await
{
Ok(Some(_)) => true,
_ => false,
}
} else {
false
}
} else {
false
}
}
+5 -2
View File
@@ -48,7 +48,11 @@ fn build_or_filter(input: &str, fields: &[&str]) -> mongodb::bson::Document {
} }
#[server] #[server]
pub async fn get_servers(search: String) -> Result<Vec<Server>, ServerFnError> { pub async fn get_servers(session: String, search: String) -> Result<Vec<Server>, ServerFnError> {
if !auth::validate_session(session).await {
return Err(ServerFnError::new(format!("Invalid session")));
}
let servers = get_mongo::<Server>("servers").await?; let servers = get_mongo::<Server>("servers").await?;
let filter = if search.trim().is_empty() { let filter = if search.trim().is_empty() {
@@ -57,7 +61,6 @@ pub async fn get_servers(search: String) -> Result<Vec<Server>, ServerFnError> {
build_or_filter(&search, &["name", "ip"]) build_or_filter(&search, &["name", "ip"])
}; };
let mut cursor = servers.find(filter).await?; let mut cursor = servers.find(filter).await?;
let mut svo = Vec::new(); let mut svo = Vec::new();
+4 -30
View File
@@ -1,26 +1,14 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use crate::{ use crate::components::{server::ServerComponent, sidebar::SideBar, LineChart, ProgressBar};
backend,
components::{server::ServerComponent, sidebar::SideBar, LineChart, ProgressBar},
};
use lucide_dioxus; use lucide_dioxus;
const DASHBOARD_CSS: Asset = asset!("/assets/styles/dashboard.css"); const DASHBOARD_CSS: Asset = asset!("/assets/styles/dashboard.css");
#[component] #[component]
pub fn Dashboard() -> Element { pub fn Dashboard() -> Element {
let mut servers = use_signal(|| Vec::new()); let session = crate::utils::use_session();
let server_search = use_signal(|| String::new()); let (servers, server_query) = session.use_servers();
let session_id = crate::utils::use_cookie::<String>("session_id", || "Guest".to_string());
use_effect(move || {
spawn(async move {
if let Ok(v) = backend::get_servers(String::new()).await {
servers.set(v);
}
});
});
rsx! { rsx! {
document::Link { rel: "stylesheet", href: DASHBOARD_CSS } document::Link { rel: "stylesheet", href: DASHBOARD_CSS }
@@ -106,21 +94,7 @@ pub fn Dashboard() -> Element {
div { class: "search-input", div { class: "search-input",
lucide_dioxus::Search { size: 16, color: "currentColor" } lucide_dioxus::Search { size: 16, color: "currentColor" }
input { input {
onchange: {let mut server_search = server_search.clone(); move |e: Event<FormData>| {server_search.set(e.value())}}, onchange: {let mut server_query = server_query.clone(); move |e: Event<FormData>| {server_query.set(e.value())}},
onkeypress: {
let server_search = server_search.clone();
let mut servers = servers.clone();
move |e: Event<KeyboardData>| {
let query = (*server_search.read()).clone();
async move {
if e.key() == Key::Enter {
if let Ok(v) = backend::get_servers(query).await {
servers.set(v);
}
}
}
}
},
placeholder: "Search servers by name, location, or IP..." } placeholder: "Search servers by name, location, or IP..." }
} }
+30 -4
View File
@@ -3,6 +3,8 @@ use std::str::FromStr;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::{window, HtmlDocument}; use web_sys::{window, HtmlDocument};
use crate::{backend, components::server::Server};
pub fn set_cookie(name: &str, value: &str) { pub fn set_cookie(name: &str, value: &str) {
let Some(document) = window().and_then(|w| w.document()) else { let Some(document) = window().and_then(|w| w.document()) else {
return; return;
@@ -38,10 +40,7 @@ pub fn get_cookie(name: &str) -> Option<String> {
None None
} }
pub fn use_cookie<T: FromStr + Default + std::fmt::Display + 'static>( pub fn use_cookie<T: FromStr + 'static>(name: &str, default: fn() -> T) -> Signal<T> {
name: &str,
default: fn() -> T,
) -> Signal<T> {
let name = name.to_string(); let name = name.to_string();
let signal = use_signal(default); let signal = use_signal(default);
@@ -66,3 +65,30 @@ pub fn redirect(target: &str) {
.set_href(target) .set_href(target)
.unwrap(); .unwrap();
} }
pub struct Session(Signal<String>);
pub fn use_session() -> Session {
Session(use_cookie("session_id", || String::new()))
}
impl Session {
pub fn use_servers(&self) -> (Signal<Vec<Server>>, Signal<String>) {
let query = use_signal(|| String::new());
let servers = use_signal(|| Vec::new());
let id = self.0.clone();
use_effect(move || {
let query_value = query.read().clone();
let mut servers = servers.clone();
spawn(async move {
if let Ok(v) = backend::get_servers(id.read().clone(), query_value).await {
servers.set(v);
}
});
});
(servers, query)
}
}