Compare commits
2 Commits
7f0b7982ec
...
fd3ca9f561
Author | SHA1 | Date | |
---|---|---|---|
fd3ca9f561 | |||
e8a8a12de3 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5484,6 +5484,7 @@ dependencies = [
|
||||
"serde 1.0.217",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"yew",
|
||||
|
@ -92,17 +92,16 @@ struct UserOverview {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(tag = "type", content = "content", rename_all = "kebab-case")]
|
||||
#[typeshare]
|
||||
enum AuthResponse<A> {
|
||||
Success(A),
|
||||
enum AuthResponse {
|
||||
Success(SessionId),
|
||||
PasswordReset(SessionId),
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
async fn check_password(
|
||||
request: Json<AuthRequest>,
|
||||
) -> (StatusCode, Json<Option<AuthResponse<SessionId>>>) {
|
||||
) -> (StatusCode, Json<Option<AuthResponse>>) {
|
||||
let Json(request) = request;
|
||||
if request.username == "vakarian" && request.password == "aoeu" {
|
||||
(
|
||||
@ -183,21 +182,20 @@ async fn main() {
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/api/test/health",
|
||||
get(|| async { (StatusCode::OK, Json(None::<String>)) }),
|
||||
)
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_methods([Method::GET])
|
||||
.allow_origin(Any),
|
||||
get(|| async { (StatusCode::OK, Json(None::<String>)) }).layer(
|
||||
CorsLayer::new()
|
||||
.allow_methods([Method::GET])
|
||||
.allow_origin(Any),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/test/auth",
|
||||
post(|req: Json<AuthRequest>| check_password(req)),
|
||||
)
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_methods([Method::POST])
|
||||
.allow_origin(Any),
|
||||
post(|req: Json<AuthRequest>| check_password(req)).layer(
|
||||
CorsLayer::new()
|
||||
.allow_methods([Method::POST])
|
||||
.allow_headers([CONTENT_TYPE])
|
||||
.allow_origin(Any),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/test/list-users",
|
||||
@ -226,13 +224,13 @@ async fn main() {
|
||||
]),
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_headers([AUTHORIZATION])
|
||||
.allow_methods([Method::GET])
|
||||
.allow_origin(Any),
|
||||
})
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_headers([AUTHORIZATION])
|
||||
.allow_methods([Method::GET])
|
||||
.allow_origin(Any),
|
||||
),
|
||||
);
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:8001")
|
||||
.await
|
||||
|
@ -9,6 +9,7 @@ gloo-net = "0.6.0"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
serde_json = "1.0.138"
|
||||
wasm-bindgen = "0.2.100"
|
||||
wasm-bindgen-futures = "0.4.50"
|
||||
web-sys = "0.3.77"
|
||||
yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] }
|
||||
|
3
visions/ui/Trunk.toml
Normal file
3
visions/ui/Trunk.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[[proxy]]
|
||||
backend = "http://localhost:8001/api"
|
||||
insecure = true
|
@ -1,3 +1,6 @@
|
||||
use std::future::Future;
|
||||
|
||||
use gloo_console::log;
|
||||
use gloo_net::http::{Request, Response};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasm_bindgen_futures::wasm_bindgen::{self, JsValue};
|
||||
@ -9,15 +12,15 @@ struct AuthRequest {
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum AuthResponse {
|
||||
Ok(SessionId),
|
||||
pub enum AuthResponse {
|
||||
Success(SessionId),
|
||||
PasswordReset(SessionId),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SessionId(String);
|
||||
pub struct SessionId(pub String);
|
||||
|
||||
enum ClientError {
|
||||
pub enum ClientError {
|
||||
Unauthorized,
|
||||
Err(u16),
|
||||
}
|
||||
@ -31,9 +34,9 @@ struct UserInfo {
|
||||
name: String,
|
||||
}
|
||||
|
||||
trait Client {
|
||||
async fn auth(username: String, password: String) -> Result<AuthResponse, ClientError>;
|
||||
async fn list_users(session_id: SessionId) -> Result<Vec<UserInfo>, ClientError>;
|
||||
pub trait Client {
|
||||
fn auth(&self, username: String, password: String) -> impl Future<Output = Result<AuthResponse, ClientError>>;
|
||||
fn list_users(&self, session_id: SessionId) -> impl Future<Output = Result<Vec<UserInfo>, ClientError>>;
|
||||
}
|
||||
|
||||
pub struct Connection;
|
||||
@ -43,9 +46,11 @@ impl Connection {
|
||||
}
|
||||
|
||||
impl Client for Connection {
|
||||
async fn auth(username: String, password: String) -> Result<AuthResponse, ClientError> {
|
||||
let response: Response = Request::post("http://localhost:8001")
|
||||
.body(serde_wasm_bindgen::to_value(&AuthRequest{ username, password }).unwrap())
|
||||
async fn auth(&self, username: String, password: String) -> Result<AuthResponse, ClientError> {
|
||||
log!("authenticating: ", &username, &password);
|
||||
let response: Response = Request::post("/api/test/auth")
|
||||
.header("Content-Type", "application/json")
|
||||
.body(serde_wasm_bindgen::to_value(&serde_json::to_string(&AuthRequest{ username, password }).unwrap()).unwrap())
|
||||
.unwrap()
|
||||
.send()
|
||||
.await
|
||||
@ -58,7 +63,7 @@ impl Client for Connection {
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_users(session_id: SessionId) -> Result<Vec<UserInfo>, ClientError> {
|
||||
async fn list_users(&self, session_id: SessionId) -> Result<Vec<UserInfo>, ClientError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gloo_console::log;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
@ -26,6 +27,7 @@ impl Reducible for AuthInfo {
|
||||
type Action = AuthAction;
|
||||
|
||||
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
|
||||
// log!("reduce", action);
|
||||
match action {
|
||||
AuthAction::Auth(session_id) => Self {
|
||||
session_id: Some(session_id),
|
||||
@ -43,9 +45,6 @@ struct LoginProps {
|
||||
|
||||
#[function_component]
|
||||
fn Login(LoginProps { on_login }: &LoginProps) -> Html {
|
||||
let username_node_ref = use_node_ref();
|
||||
let password_node_ref = use_node_ref();
|
||||
|
||||
let username = use_state(|| "".to_owned());
|
||||
let password = use_state(|| "".to_owned());
|
||||
|
||||
@ -58,21 +57,25 @@ fn Login(LoginProps { on_login }: &LoginProps) -> Html {
|
||||
|
||||
let on_username_changed = {
|
||||
let username = username.clone();
|
||||
let username_node_ref = username_node_ref.clone();
|
||||
Callback::from(move |_| {
|
||||
let input = username_node_ref.cast::<HtmlInputElement>().unwrap();
|
||||
log!("username changed: {}", input.value());
|
||||
username.set(input.value());
|
||||
Callback::from(move |event: Event| {
|
||||
let input = event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
||||
if let Some(input) = input {
|
||||
username.set(input.value());
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let on_password_changed = {
|
||||
let password = password.clone();
|
||||
let password_node_ref = password_node_ref.clone();
|
||||
Callback::from(move |_| {
|
||||
let input = password_node_ref.cast::<HtmlInputElement>().unwrap();
|
||||
log!("password changed: {}", input.value());
|
||||
password.set(input.value());
|
||||
Callback::from(move |event: Event| {
|
||||
let input = event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
||||
if let Some(input) = input {
|
||||
password.set(input.value());
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@ -80,8 +83,8 @@ fn Login(LoginProps { on_login }: &LoginProps) -> Html {
|
||||
<div class="login-form">
|
||||
<div class="card">
|
||||
<h1>{"Welcome to Visions VTT"}</h1>
|
||||
<input ref={username_node_ref} type="text" name="username" placeholder="username" onchange={on_username_changed} />
|
||||
<input ref={password_node_ref} type="password" name="password" placeholder="password" onchange={on_password_changed} />
|
||||
<input type="text" name="username" placeholder="username" onchange={on_username_changed} />
|
||||
<input type="password" name="password" placeholder="password" onchange={on_password_changed} />
|
||||
<button onclick={on_click}>{"Login"}</button>
|
||||
</div>
|
||||
|
||||
@ -96,11 +99,25 @@ fn Login(LoginProps { on_login }: &LoginProps) -> Html {
|
||||
#[function_component]
|
||||
fn App() -> Html {
|
||||
let auth_info = use_reducer(AuthInfo::default);
|
||||
let client = Connection::new();
|
||||
|
||||
let on_login = {
|
||||
let auth_info = auth_info.clone();
|
||||
Callback::from(move |(username, password)| auth_info.dispatch(AuthAction::Auth(username)))
|
||||
Callback::from(move |(username, password)| {
|
||||
let auth_info = auth_info.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let client = Connection::new();
|
||||
match client.auth(username, password).await {
|
||||
Ok(AuthResponse::Success(session_id)) => {
|
||||
auth_info.dispatch(AuthAction::Auth(session_id.0))
|
||||
}
|
||||
Ok(AuthResponse::PasswordReset(session_id)) => {
|
||||
auth_info.dispatch(AuthAction::Auth(session_id.0))
|
||||
}
|
||||
Err(ClientError::Unauthorized) => todo!(),
|
||||
Err(ClientError::Err(status)) => todo!(),
|
||||
};
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
if auth_info.session_id.is_some() {
|
||||
|
Loading…
Reference in New Issue
Block a user