mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 09:01:09 +00:00
working login and logout
This commit is contained in:
parent
f41cc01ad3
commit
469ca6f718
9 changed files with 35 additions and 55 deletions
|
@ -57,7 +57,7 @@ uuid = { version = "1.6.1", features = ["serde"] }
|
|||
tower-http = { version = "0.4.0", features = ["cors", "fs"], optional = true }
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
url = { version = "2.4.1", features = ["serde"] }
|
||||
reqwest = { version = "0.11.22", features = ["json"] }
|
||||
reqwest = { version = "0.11.22", features = ["json", "cookies"] }
|
||||
log = "0.4"
|
||||
tracing = "0.1.40"
|
||||
once_cell = "1.18.0"
|
||||
|
@ -68,7 +68,6 @@ time = "0.3.31"
|
|||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
reqwest = { version = "0.11.22", features = ["cookies"] }
|
||||
|
||||
[package.metadata.leptos]
|
||||
output-name = "ibis"
|
||||
|
|
|
@ -3,4 +3,4 @@ filehash = false
|
|||
target = "assets/index.html"
|
||||
|
||||
[[proxy]]
|
||||
backend = "http://[::1]:8131"
|
||||
backend = "http://127.0.0.1:8131"
|
||||
|
|
|
@ -91,6 +91,7 @@ fn create_cookie(jwt: String, data: &Data<MyDataHandle>) -> Cookie<'static> {
|
|||
.same_site(SameSite::Strict)
|
||||
.path("/")
|
||||
.http_only(true)
|
||||
.secure(true)
|
||||
.expires(Expiration::DateTime(
|
||||
OffsetDateTime::now_utc() + Duration::weeks(52),
|
||||
))
|
||||
|
|
|
@ -6,13 +6,10 @@ use crate::common::{DbArticle, GetArticleData};
|
|||
use crate::common::{DbInstance, FollowInstance, InstanceView, SearchArticleData};
|
||||
use crate::frontend::error::MyResult;
|
||||
use anyhow::anyhow;
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::{Client, RequestBuilder, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ApiClient {
|
||||
client: Client,
|
||||
|
@ -116,8 +113,9 @@ impl ApiClient {
|
|||
let resolve_form = ResolveObject {
|
||||
id: Url::parse(&format!("http://{}", follow_instance))?,
|
||||
};
|
||||
let instance_resolved: DbInstance =
|
||||
get_query(&self.hostname, "instance/resolve", Some(resolve_form)).await?;
|
||||
let instance_resolved: DbInstance = self
|
||||
.get_query("instance/resolve", Some(resolve_form))
|
||||
.await?;
|
||||
|
||||
// send follow
|
||||
let follow_form = FollowInstance {
|
||||
|
@ -170,35 +168,29 @@ impl ApiClient {
|
|||
|
||||
pub async fn resolve_article(&self, id: Url) -> MyResult<ArticleView> {
|
||||
let resolve_object = ResolveObject { id };
|
||||
get_query(&self.hostname, "article/resolve", Some(resolve_object)).await
|
||||
self.get_query("article/resolve", Some(resolve_object))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn resolve_instance(&self, id: Url) -> MyResult<DbInstance> {
|
||||
let resolve_object = ResolveObject { id };
|
||||
get_query(&self.hostname, "instance/resolve", Some(resolve_object)).await
|
||||
self.get_query("instance/resolve", Some(resolve_object))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_query<T, R>(hostname: &str, endpoint: &str, query: Option<R>) -> MyResult<T>
|
||||
where
|
||||
T: for<'de> Deserialize<'de>,
|
||||
R: Serialize,
|
||||
{
|
||||
let mut req = CLIENT.get(format!("http://{}/api/v1/{}", hostname, endpoint));
|
||||
if let Some(query) = query {
|
||||
req = req.query(&query);
|
||||
}
|
||||
handle_json_res::<T>(req).await
|
||||
}
|
||||
|
||||
async fn handle_json_res<T>(req: RequestBuilder) -> MyResult<T>
|
||||
async fn handle_json_res<T>(#[allow(unused_mut)] mut req: RequestBuilder) -> MyResult<T>
|
||||
where
|
||||
T: for<'de> Deserialize<'de>,
|
||||
{
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
req = req.fetch_credentials_include();
|
||||
}
|
||||
let res = req.send().await?;
|
||||
let status = res.status();
|
||||
let text = res.text().await?;
|
||||
if status == reqwest::StatusCode::OK {
|
||||
if status == StatusCode::OK {
|
||||
Ok(serde_json::from_str(&text).map_err(|e| anyhow!("Json error on {text}: {e}"))?)
|
||||
} else {
|
||||
Err(anyhow!("API error: {text}").into())
|
||||
|
|
|
@ -43,10 +43,9 @@ impl GlobalState {
|
|||
create_local_resource(
|
||||
move || (),
|
||||
|_| async move {
|
||||
if let Ok(my_profile) = GlobalState::api_client().my_profile().await {
|
||||
let my_profile = GlobalState::api_client().my_profile().await.ok();
|
||||
expect_context::<RwSignal<GlobalState>>()
|
||||
.update(|state| state.my_profile = Some(my_profile.clone()))
|
||||
};
|
||||
.update(|state| state.my_profile = my_profile.clone());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -54,7 +53,7 @@ impl GlobalState {
|
|||
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
let backend_hostname = "localhost:8080".to_string();
|
||||
let backend_hostname = "127.0.0.1:8080".to_string();
|
||||
|
||||
provide_meta_context();
|
||||
let backend_hostname = GlobalState {
|
||||
|
|
|
@ -6,6 +6,12 @@ use leptos_router::*;
|
|||
#[component]
|
||||
pub fn Nav() -> impl IntoView {
|
||||
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
|
||||
let logout_action = create_action(move |_| async move {
|
||||
GlobalState::api_client().logout().await.unwrap();
|
||||
expect_context::<RwSignal<GlobalState>>()
|
||||
.get_untracked()
|
||||
.update_my_profile();
|
||||
});
|
||||
view! {
|
||||
<nav class="inner">
|
||||
<li>
|
||||
|
@ -19,11 +25,7 @@ pub fn Nav() -> impl IntoView {
|
|||
{
|
||||
move || global_state.with(|state| state.my_profile.clone().unwrap().person.username)
|
||||
}
|
||||
<button on:click=move |_| {
|
||||
// TODO: not executed
|
||||
dbg!(1);
|
||||
do_logout()
|
||||
}>
|
||||
<button on:click=move |_| logout_action.dispatch(())>
|
||||
Logout
|
||||
</button>
|
||||
</p>
|
||||
|
@ -40,14 +42,3 @@ pub fn Nav() -> impl IntoView {
|
|||
</nav>
|
||||
}
|
||||
}
|
||||
|
||||
fn do_logout() {
|
||||
dbg!("do logout");
|
||||
create_action(move |()| async move {
|
||||
dbg!("run logout action");
|
||||
GlobalState::api_client().logout().await.unwrap();
|
||||
expect_context::<RwSignal<GlobalState>>()
|
||||
.get()
|
||||
.update_my_profile();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,12 +26,19 @@ pub fn Article() -> impl IntoView {
|
|||
},
|
||||
);
|
||||
|
||||
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
|
||||
let (count, set_count) = create_signal(0);
|
||||
view! {
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
{move || article.get().map(|article|
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article.article.title}</h1>
|
||||
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<button on:click=move |_| {
|
||||
set_count.update(|n| *n += 1);
|
||||
}>Edit {move || count.get()}</button>
|
||||
</Show>
|
||||
<div>{article.article.text}</div>
|
||||
</div>
|
||||
})}
|
||||
|
|
|
@ -8,7 +8,7 @@ pub async fn main() -> ibis_lib::backend::error::MyResult<()> {
|
|||
.filter_module("ibis", LevelFilter::Info)
|
||||
.init();
|
||||
let database_url = "postgres://ibis:password@localhost:5432/ibis";
|
||||
ibis_lib::backend::start("localhost:8131", database_url).await?;
|
||||
ibis_lib::backend::start("127.0.0.1:8131", database_url).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -115,16 +115,7 @@ impl IbisInstance {
|
|||
username: username.to_string(),
|
||||
password: "hunter2".to_string(),
|
||||
};
|
||||
// use a separate http client for each backend instance, with cookie store for auth
|
||||
// how to pass the client/hostname to api client methods?
|
||||
// probably create a struct ApiClient(hostname, client) with all api methods in impl
|
||||
// TODO: seems that cookie isnt being stored? or maybe wrong hostname?
|
||||
let jar = Arc::new(Jar::default());
|
||||
let client = ClientBuilder::new()
|
||||
.cookie_store(true)
|
||||
.cookie_provider(jar.clone())
|
||||
.build()
|
||||
.unwrap();
|
||||
let client = ClientBuilder::new().cookie_store(true).build().unwrap();
|
||||
let api_client = ApiClient::new(client, hostname.clone());
|
||||
api_client.register(form).await.unwrap();
|
||||
Self {
|
||||
|
|
Loading…
Reference in a new issue