fix(web): rely on user_id from server
this way we don't have to construct it ourselves every time with URL_BASE. i think it's a bit weaker this way tho
This commit is contained in:
parent
d290a5e083
commit
eba399abe5
7 changed files with 45 additions and 51 deletions
|
@ -130,7 +130,7 @@ pub fn App() -> impl IntoView {
|
||||||
<Route path=path!("home") view=move || if auth.present() {
|
<Route path=path!("home") view=move || if auth.present() {
|
||||||
Either::Left(view! {
|
Either::Left(view! {
|
||||||
<Loadable
|
<Loadable
|
||||||
base=format!("{URL_BASE}/actors/{}/inbox/page", auth.username())
|
base=format!("{}/inbox/page", auth.user_id())
|
||||||
element=move |obj| view! { <Item item=obj sep=true /> }
|
element=move |obj| view! { <Item item=obj sep=true /> }
|
||||||
/>
|
/>
|
||||||
})
|
})
|
||||||
|
@ -155,7 +155,7 @@ pub fn App() -> impl IntoView {
|
||||||
<Route path=path!("notifications") view=move || if auth.present() {
|
<Route path=path!("notifications") view=move || if auth.present() {
|
||||||
Either::Left(view! {
|
Either::Left(view! {
|
||||||
<Loadable
|
<Loadable
|
||||||
base=format!("{URL_BASE}/actors/{}/notifications/page", auth.username())
|
base=format!("{}/notifications/page", auth.user_id())
|
||||||
element=move |obj| view! { <Item item=obj sep=true always=true /> }
|
element=move |obj| view! { <Item item=obj sep=true always=true /> }
|
||||||
/>
|
/>
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl Auth {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outbox(&self) -> String {
|
pub fn outbox(&self) -> String {
|
||||||
format!("{URL_BASE}/actors/{}/outbox", self.username())
|
format!("{}/outbox", self.user_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn refresh(
|
pub async fn refresh(
|
||||||
|
|
|
@ -89,19 +89,20 @@ impl Privacy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address(&self, user: &str) -> (Vec<String>, Vec<String>) {
|
// TODO this is weird... should probably come from core or apb
|
||||||
|
pub fn address(&self, user_id: &str) -> (Vec<String>, Vec<String>) {
|
||||||
match self {
|
match self {
|
||||||
Self::Broadcast => (
|
Self::Broadcast => (
|
||||||
vec![apb::target::PUBLIC.to_string()],
|
vec![apb::target::PUBLIC.to_string()],
|
||||||
vec![format!("{URL_BASE}/actors/{user}/followers")],
|
vec![format!("{user_id}/followers")],
|
||||||
),
|
),
|
||||||
Self::Public => (
|
Self::Public => (
|
||||||
vec![],
|
vec![],
|
||||||
vec![apb::target::PUBLIC.to_string(), format!("{URL_BASE}/actors/{user}/followers")],
|
vec![apb::target::PUBLIC.to_string(), format!("{user_id}/followers")],
|
||||||
),
|
),
|
||||||
Self::Private => (
|
Self::Private => (
|
||||||
vec![],
|
vec![],
|
||||||
vec![format!("{URL_BASE}/actors/{user}/followers")],
|
vec![format!("{user_id}/followers")],
|
||||||
),
|
),
|
||||||
Self::Direct => (
|
Self::Direct => (
|
||||||
vec![],
|
vec![],
|
||||||
|
@ -133,7 +134,7 @@ pub fn PrivacySelector(setter: WriteSignal<Privacy>) -> impl IntoView {
|
||||||
<td>
|
<td>
|
||||||
{move || {
|
{move || {
|
||||||
let p = privacy.get();
|
let p = privacy.get();
|
||||||
let (to, cc) = p.address(&auth.username());
|
let (to, cc) = p.address(&auth.user_id());
|
||||||
view! {
|
view! {
|
||||||
<PrivacyMarker privacy=p to=to cc=cc big=true />
|
<PrivacyMarker privacy=p to=to cc=cc big=true />
|
||||||
}
|
}
|
||||||
|
@ -166,7 +167,7 @@ pub fn PostBox(advanced: WriteSignal<bool>) -> impl IntoView {
|
||||||
if let Some((name, domain)) = stripped.split_once('@') {
|
if let Some((name, domain)) = stripped.split_once('@') {
|
||||||
if let Some(tld) = domain.split('.').last() {
|
if let Some(tld) = domain.split('.').last() {
|
||||||
if tld::exist(tld) {
|
if tld::exist(tld) {
|
||||||
if let Some(uid) = cache::WEBFINGER.blocking_resolve(name, domain).await {
|
if let Some(uid) = cache::WEBFINGER.blocking_resolve(name, domain, auth).await {
|
||||||
out.push(TextMatch::Mention { name: name.to_string(), domain: domain.to_string(), href: uid });
|
out.push(TextMatch::Mention { name: name.to_string(), domain: domain.to_string(), href: uid });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +237,7 @@ pub fn PostBox(advanced: WriteSignal<bool>) -> impl IntoView {
|
||||||
set_posting.set(true);
|
set_posting.set(true);
|
||||||
leptos::task::spawn_local(async move {
|
leptos::task::spawn_local(async move {
|
||||||
let summary = get_if_some(summary_ref);
|
let summary = get_if_some(summary_ref);
|
||||||
let (mut to_vec, cc_vec) = privacy.get().address(&auth.username());
|
let (mut to_vec, cc_vec) = privacy.get().address(&auth.user_id());
|
||||||
let mut mention_tags : Vec<serde_json::Value> = mentions.get()
|
let mut mention_tags : Vec<serde_json::Value> = mentions.get()
|
||||||
.map(|x| x.take())
|
.map(|x| x.take())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -380,7 +381,7 @@ pub fn AdvancedPostBox(advanced: WriteSignal<bool>) -> impl IntoView {
|
||||||
<td class="w-66"><input class="w-100" type="text" node_ref=bto_ref title="bto" placeholder="bto" /></td>
|
<td class="w-66"><input class="w-100" type="text" node_ref=bto_ref title="bto" placeholder="bto" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="w-33"><input class="w-100" type="text" node_ref=cc_ref title="cc" placeholder="cc" value=format!("{URL_BASE}/actors/{}/followers", auth.username()) /></td>
|
<td class="w-33"><input class="w-100" type="text" node_ref=cc_ref title="cc" placeholder="cc" value=format!("{}/followers", auth.user_id()) /></td>
|
||||||
<td class="w-33"><input class="w-100" type="text" node_ref=bcc_ref title="bcc" placeholder="bcc" /></td>
|
<td class="w-33"><input class="w-100" type="text" node_ref=bcc_ref title="bcc" placeholder="bcc" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -424,7 +425,7 @@ pub fn AdvancedPostBox(advanced: WriteSignal<bool>) -> impl IntoView {
|
||||||
apb::Node::maybe_link(object_id)
|
apb::Node::maybe_link(object_id)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let target_url = format!("{URL_BASE}/actors/{}/outbox", auth.username());
|
let target_url = auth.outbox();
|
||||||
match Http::post(&target_url, &payload, auth).await {
|
match Http::post(&target_url, &payload, auth).await {
|
||||||
Err(e) => set_error.set(Some(e.to_string())),
|
Err(e) => set_error.set(Some(e.to_string())),
|
||||||
Ok(()) => set_error.set(None),
|
Ok(()) => set_error.set(None),
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn ActorBanner(object: crate::Doc) -> impl IntoView {
|
||||||
let uri = Uri::web(U::Actor, &uid);
|
let uri = Uri::web(U::Actor, &uid);
|
||||||
let avatar_url = object.icon_url().unwrap_or(FALLBACK_IMAGE_URL.into());
|
let avatar_url = object.icon_url().unwrap_or(FALLBACK_IMAGE_URL.into());
|
||||||
let username = object.preferred_username().unwrap_or_default().to_string();
|
let username = object.preferred_username().unwrap_or_default().to_string();
|
||||||
let domain = object.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string();
|
let domain = object.id().unwrap_or_default().replace("https://", "").replace("http://", "").split('/').next().unwrap_or_default().to_string();
|
||||||
let display_name = object.name().unwrap_or_default().to_string();
|
let display_name = object.name().unwrap_or_default().to_string();
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -179,16 +179,16 @@ impl DashmapCache<Doc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DashmapCache<String> {
|
impl DashmapCache<String> {
|
||||||
pub async fn blocking_resolve(&self, user: &str, domain: &str) -> Option<String> {
|
pub async fn blocking_resolve(&self, user: &str, domain: &str, auth: Auth) -> Option<String> {
|
||||||
if let Some(x) = self.resource(user, domain) { return Some(x); }
|
if let Some(x) = self.resource(user, domain) { return Some(x); }
|
||||||
self.fetch(user, domain).await;
|
self.fetch(user, domain, auth).await;
|
||||||
self.resource(user, domain)
|
self.resource(user, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&self, user: &str, domain: &str) -> Option<String> {
|
pub fn resolve(&self, user: &str, domain: &str, auth: Auth) -> Option<String> {
|
||||||
if let Some(x) = self.resource(user, domain) { return Some(x); }
|
if let Some(x) = self.resource(user, domain) { return Some(x); }
|
||||||
let (_self, user, domain) = (self.clone(), user.to_string(), domain.to_string());
|
let (_self, user, domain) = (self.clone(), user.to_string(), domain.to_string());
|
||||||
leptos::task::spawn_local(async move { _self.fetch(&user, &domain).await });
|
leptos::task::spawn_local(async move { _self.fetch(&user, &domain, auth).await });
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +197,10 @@ impl DashmapCache<String> {
|
||||||
self.get(&query)
|
self.get(&query)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch(&self, user: &str, domain: &str) {
|
async fn fetch(&self, user: &str, domain: &str, auth: Auth) {
|
||||||
let query = format!("{user}@{domain}");
|
let query = format!("{user}@{domain}");
|
||||||
self.0.insert(query.to_string(), LookupStatus::Resolving);
|
self.0.insert(query.to_string(), LookupStatus::Resolving);
|
||||||
match reqwest::get(format!("{URL_BASE}/.well-known/webfinger?resource=acct:{query}")).await {
|
match crate::Http::fetch::<jrd::JsonResourceDescriptor>(&format!("{URL_BASE}/.well-known/webfinger?resource=acct:{query}"), auth).await {
|
||||||
Ok(res) => match res.error_for_status() {
|
|
||||||
Ok(res) => match res.json::<jrd::JsonResourceDescriptor>().await {
|
|
||||||
Ok(doc) => {
|
Ok(doc) => {
|
||||||
if let Some(uid) = doc.links.into_iter().find(|x| x.rel == "self").and_then(|x| x.href) {
|
if let Some(uid) = doc.links.into_iter().find(|x| x.rel == "self").and_then(|x| x.href) {
|
||||||
self.0.insert(query, LookupStatus::Found(uid));
|
self.0.insert(query, LookupStatus::Found(uid));
|
||||||
|
@ -210,20 +208,10 @@ impl DashmapCache<String> {
|
||||||
self.0.insert(query, LookupStatus::NotFound);
|
self.0.insert(query, LookupStatus::NotFound);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("invalid webfinger response: {e:?}");
|
|
||||||
self.0.remove(&query);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("could not resolve webfinbger: {e:?}");
|
tracing::error!("could not resolve webfinbger: {e:?}");
|
||||||
self.0.insert(query, LookupStatus::NotFound);
|
self.0.insert(query, LookupStatus::NotFound);
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("failed accessing webfinger server: {e:?}");
|
|
||||||
self.0.remove(&query);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,12 +225,25 @@ pub struct IdParam {
|
||||||
pub struct Http;
|
pub struct Http;
|
||||||
|
|
||||||
impl Http {
|
impl Http {
|
||||||
|
// TODO not really great.... also checked only once
|
||||||
|
pub fn location() -> &'static str {
|
||||||
|
static LOCATION: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
||||||
|
LOCATION.get_or_init(||
|
||||||
|
web_sys::window()
|
||||||
|
.expect("could not access window element")
|
||||||
|
.location()
|
||||||
|
.origin()
|
||||||
|
.expect("could not access location origin")
|
||||||
|
).as_str()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn request<T: serde::ser::Serialize>(
|
pub async fn request<T: serde::ser::Serialize>(
|
||||||
method: reqwest::Method,
|
method: reqwest::Method,
|
||||||
url: &str,
|
url: &str,
|
||||||
data: Option<&T>,
|
data: Option<&T>,
|
||||||
auth: Auth,
|
auth: Auth,
|
||||||
) -> reqwest::Result<reqwest::Response> {
|
) -> reqwest::Result<reqwest::Response> {
|
||||||
|
tracing::info!("making request to {url}");
|
||||||
use leptos::prelude::GetUntracked;
|
use leptos::prelude::GetUntracked;
|
||||||
|
|
||||||
// TODO while in web environments it's ok (and i'd say good!) to fetch with relative urls,
|
// TODO while in web environments it's ok (and i'd say good!) to fetch with relative urls,
|
||||||
|
@ -252,15 +253,7 @@ impl Http {
|
||||||
// prod deployments). relevant issue: https://github.com/seanmonstar/reqwest/issues/1433
|
// prod deployments). relevant issue: https://github.com/seanmonstar/reqwest/issues/1433
|
||||||
let mut url = url.to_string();
|
let mut url = url.to_string();
|
||||||
if !url.starts_with("http") {
|
if !url.starts_with("http") {
|
||||||
static LOCATION: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
url = format!("{}{url}", Self::location());
|
||||||
let base = LOCATION.get_or_init(||
|
|
||||||
web_sys::window()
|
|
||||||
.expect("could not access window element")
|
|
||||||
.location()
|
|
||||||
.origin()
|
|
||||||
.expect("could not access location origin")
|
|
||||||
);
|
|
||||||
url = format!("{base}{url}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut req = reqwest::Client::new()
|
let mut req = reqwest::Client::new()
|
||||||
|
@ -311,7 +304,7 @@ impl Uri {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn short(url: &str) -> String {
|
pub fn short(url: &str) -> String {
|
||||||
if url.starts_with(URL_BASE) || url.starts_with('/') {
|
if url.starts_with(Http::location()) || url.starts_with('/') {
|
||||||
uriproxy::decompose(url)
|
uriproxy::decompose(url)
|
||||||
} else if url.starts_with("https://") || url.starts_with("http://") {
|
} else if url.starts_with("https://") || url.starts_with("http://") {
|
||||||
uriproxy::compact(url)
|
uriproxy::compact(url)
|
||||||
|
|
|
@ -267,7 +267,7 @@ pub fn LikeButton(
|
||||||
let (mut to, cc) = if private {
|
let (mut to, cc) = if private {
|
||||||
(vec![], vec![])
|
(vec![], vec![])
|
||||||
} else {
|
} else {
|
||||||
privacy.get().address(&auth.username())
|
privacy.get().address(&auth.user_id())
|
||||||
};
|
};
|
||||||
to.push(author.clone());
|
to.push(author.clone());
|
||||||
let payload = serde_json::Value::Object(serde_json::Map::default())
|
let payload = serde_json::Value::Object(serde_json::Map::default())
|
||||||
|
@ -343,7 +343,7 @@ pub fn RepostButton(n: i32, target: String, author: String) -> impl IntoView {
|
||||||
if !auth.present() { return; }
|
if !auth.present() { return; }
|
||||||
if !clicked.get() { return; }
|
if !clicked.get() { return; }
|
||||||
set_clicked.set(false);
|
set_clicked.set(false);
|
||||||
let (mut to, cc) = privacy.get().address(&auth.username());
|
let (mut to, cc) = privacy.get().address(&auth.user_id());
|
||||||
to.push(author.clone());
|
to.push(author.clone());
|
||||||
let payload = serde_json::Value::Object(serde_json::Map::default())
|
let payload = serde_json::Value::Object(serde_json::Map::default())
|
||||||
.set_activity_type(Some(apb::ActivityType::Announce))
|
.set_activity_type(Some(apb::ActivityType::Announce))
|
||||||
|
|
|
@ -187,7 +187,7 @@ pub fn ConfigPage(setter: WriteSignal<crate::Config>) -> impl IntoView {
|
||||||
));
|
));
|
||||||
|
|
||||||
leptos::task::spawn_local(async move {
|
leptos::task::spawn_local(async move {
|
||||||
if let Err(e) = Http::post(&format!("{id}/outbox"), &payload, auth).await {
|
if let Err(e) = Http::post(&auth.outbox(), &payload, auth).await {
|
||||||
tracing::error!("could not send update activity: {e}");
|
tracing::error!("could not send update activity: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue