forked from projectmoon/tenebrous-dicebot
Add login API call for web UI
This commit is contained in:
parent
00742c14a9
commit
eeacf01cbe
|
@ -96,15 +96,20 @@ fn create_token<'a>(
|
|||
Ok(token)
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct LoginResponse {
|
||||
jwt_token: String,
|
||||
}
|
||||
|
||||
#[rocket::post("/login", data = "<request>")]
|
||||
async fn login(
|
||||
request: Json<LoginRequest<'_>>,
|
||||
config: &State<Config>,
|
||||
cookies: &CookieJar<'_>,
|
||||
) -> Result<String, Custom<String>> {
|
||||
) -> Result<Json<LoginResponse>, Custom<String>> {
|
||||
let token = create_token(request.username, Duration::minutes(1), &config.jwt_secret)?;
|
||||
let refresh_token = create_token(request.username, Duration::weeks(1), &config.jwt_secret)?;
|
||||
|
||||
cookies.add_private(Cookie::new("refresh_token", refresh_token));
|
||||
Ok(token)
|
||||
Ok(Json(LoginResponse { jwt_token: token }))
|
||||
}
|
||||
|
|
|
@ -27,12 +27,22 @@ wasm-bindgen = { version = "0.2" }
|
|||
wasm-bindgen-futures = "0.4"
|
||||
js-sys = "0.3"
|
||||
#grpc-web-client = "0.1"
|
||||
web-sys = "0.3"
|
||||
graphql_client = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
graphql_client_web = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
serde = { version = "1.0.67", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
'Headers',
|
||||
'Request',
|
||||
'RequestInit',
|
||||
'RequestMode',
|
||||
'Response',
|
||||
'Window',
|
||||
]
|
||||
|
||||
# hopefully we can add grpc-web later instead of graphql.
|
||||
# prost = { version = "0.7.0", default-features = false }
|
||||
# tonic = { git = "https://github.com/hyperium/tonic", branch = "master", default-features = false, features = ["codegen", "prost"] }
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
use crate::error::UiError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{console, Request, RequestInit, RequestMode, Response};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct LoginResponse {
|
||||
jwt_token: String,
|
||||
}
|
||||
|
||||
pub async fn fetch_jwt() -> Result<String, UiError> {
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("POST");
|
||||
opts.mode(RequestMode::Cors);
|
||||
opts.body(Some(&JsValue::from_str(
|
||||
r#"
|
||||
{ "username": "@projectmoon:agnos.is", "password": "lolol" }
|
||||
"#,
|
||||
)));
|
||||
|
||||
let url = format!("http://localhost:10000/login");
|
||||
|
||||
let request = Request::new_with_str_and_init(&url, &opts)?;
|
||||
request.headers().set("Content-Type", "application/json")?;
|
||||
request.headers().set("Accept", "application/json")?;
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||
|
||||
// `resp_value` is a `Response` object.
|
||||
assert!(resp_value.is_instance_of::<Response>());
|
||||
let resp: Response = resp_value.dyn_into().unwrap();
|
||||
|
||||
// Convert this other `Promise` into a rust `Future`.
|
||||
let json = JsFuture::from(resp.json()?).await?;
|
||||
|
||||
console::log_1(&json);
|
||||
|
||||
// Use serde to parse the JSON into a struct.
|
||||
let login_response: LoginResponse = json.into_serde().unwrap();
|
||||
|
||||
// Send the `Branch` struct back to JS as an `Object`.
|
||||
Ok(login_response.jwt_token)
|
||||
}
|
|
@ -2,6 +2,9 @@ use graphql_client_web::Response;
|
|||
|
||||
use crate::error::UiError;
|
||||
|
||||
pub mod auth;
|
||||
pub mod dicebot;
|
||||
|
||||
/// Extensions to the GraphQL web response type to add convenience,
|
||||
/// particularly when working with errors.
|
||||
trait ResponseExt<T> {
|
||||
|
@ -32,5 +35,3 @@ impl<T> ResponseExt<T> for Response<T> {
|
|||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod dicebot;
|
||||
|
|
|
@ -9,4 +9,17 @@ pub enum UiError {
|
|||
/// General API error, collecting errors from graphql server.
|
||||
#[error("error: {0}")]
|
||||
ApiError(String),
|
||||
|
||||
#[error("error: {0}")]
|
||||
JsError(String),
|
||||
}
|
||||
|
||||
impl From<wasm_bindgen::JsValue> for UiError {
|
||||
fn from(js_error: wasm_bindgen::JsValue) -> UiError {
|
||||
UiError::JsError(
|
||||
js_error
|
||||
.as_string()
|
||||
.unwrap_or("unknown JS error".to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,12 @@ async fn load_rooms(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn do_jwt_stuff(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||
let jwt = api::auth::fetch_jwt().await?;
|
||||
dispatch.send(Action::UpdateJwt(jwt));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Component for YewduxRoomList {
|
||||
type Message = ();
|
||||
type Properties = WebUiDispatcher;
|
||||
|
@ -72,9 +78,19 @@ impl Component for YewduxRoomList {
|
|||
fn view(&self) -> Html {
|
||||
let the_future = self.link.callback(move |_| {});
|
||||
|
||||
let dispatch = Arc::new(self.dispatch.clone());
|
||||
let jwt_update = self.link.callback(move |_| {
|
||||
let dispatch = dispatch.clone();
|
||||
spawn_local(async move {
|
||||
do_jwt_stuff(&*dispatch).await;
|
||||
});
|
||||
});
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=the_future>{ "Add Room" }</button>
|
||||
<button onclick=jwt_update>{ "Fetch JWT" }</button>
|
||||
<div> { "Current JWT: " } { self.dispatch.state().jwt_token.as_ref().unwrap_or(&"[not set]".to_string()) }</div>
|
||||
<ul>
|
||||
{
|
||||
for self.dispatch.state().rooms.iter().map(|room| {
|
||||
|
|
|
@ -8,10 +8,12 @@ pub(crate) struct Room {
|
|||
|
||||
#[derive(Default, Clone)]
|
||||
pub(crate) struct WebUiState {
|
||||
pub jwt_token: Option<String>,
|
||||
pub rooms: Vec<Room>,
|
||||
}
|
||||
|
||||
pub(crate) enum Action {
|
||||
UpdateJwt(String),
|
||||
AddRoom(Room),
|
||||
}
|
||||
|
||||
|
@ -19,16 +21,19 @@ impl Reducer for WebUiState {
|
|||
type Action = Action;
|
||||
|
||||
fn new() -> Self {
|
||||
Self { rooms: vec![] }
|
||||
Self {
|
||||
jwt_token: None,
|
||||
rooms: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce(&mut self, action: Self::Action) -> bool {
|
||||
match action {
|
||||
Action::AddRoom(room) => {
|
||||
self.rooms.push(room.clone());
|
||||
true
|
||||
}
|
||||
}
|
||||
Action::UpdateJwt(jwt_token) => self.jwt_token = Some(jwt_token),
|
||||
Action::AddRoom(room) => self.rooms.push(room.clone()),
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue