sessions
This commit is contained in:
+43
-2
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user