forked from alemi/upub
feat: local users can request to fetch remote stuff
This commit is contained in:
parent
b2e6703b0e
commit
3a79ca05a2
5 changed files with 52 additions and 31 deletions
|
@ -1,9 +1,9 @@
|
|||
use axum::{extract::{Path, State}, http::StatusCode};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, QueryFilter};
|
||||
use crate::{model::{self, addressing::EmbeddedActivity}, server::{auth::AuthIdentity, Context}};
|
||||
use crate::{errors::UpubError, model::{self, addressing::EmbeddedActivity}, server::{auth::AuthIdentity, Context}};
|
||||
use apb::{ActivityMut, ObjectMut, BaseMut, Node};
|
||||
|
||||
use super::{jsonld::LD, JsonLD};
|
||||
use super::{jsonld::LD, JsonLD, TryFetch};
|
||||
|
||||
// TODO this is used outside /routes, maybe move in model?
|
||||
pub fn ap_activity(activity: model::activity::Model) -> serde_json::Value {
|
||||
|
@ -24,24 +24,25 @@ pub async fn view(
|
|||
State(ctx): State<Context>,
|
||||
Path(id): Path<String>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
) -> Result<JsonLD<serde_json::Value>, StatusCode> {
|
||||
Query(query): Query<TryFetch>,
|
||||
) -> crate::Result<JsonLD<serde_json::Value>> {
|
||||
let aid = if id.starts_with('+') {
|
||||
format!("https://{}", id.replacen('+', "", 1).replace('@', "/"))
|
||||
} else {
|
||||
ctx.aid(id.clone())
|
||||
};
|
||||
match model::addressing::Entity::find_activities()
|
||||
.filter(model::activity::Column::Id.eq(aid))
|
||||
.filter(model::activity::Column::Id.eq(&aid))
|
||||
.filter(auth.filter_condition())
|
||||
.into_model::<EmbeddedActivity>()
|
||||
.one(ctx.db())
|
||||
.await
|
||||
.await?
|
||||
{
|
||||
Ok(Some(activity)) => Ok(JsonLD(serde_json::Value::from(activity).ld_context())),
|
||||
Ok(None) => Err(StatusCode::NOT_FOUND),
|
||||
Err(e) => {
|
||||
tracing::error!("error querying for activity: {e}");
|
||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
Some(activity) => Ok(JsonLD(serde_json::Value::from(activity).ld_context())),
|
||||
None => if auth.is_local() && query.fetch {
|
||||
Ok(JsonLD(ap_activity(ctx.fetch().activity(&aid).await?).ld_context()))
|
||||
} else {
|
||||
Err(UpubError::not_found())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,12 @@ impl ActivityPubRouter for Router<crate::server::Context> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct TryFetch {
|
||||
#[serde(default)]
|
||||
pub fetch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
// TODO i don't really like how pleroma/mastodon do it actually, maybe change this?
|
||||
pub struct Pagination {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use axum::{extract::{Path, State}, http::StatusCode};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, QueryFilter};
|
||||
|
||||
use apb::{ObjectMut, BaseMut, Node};
|
||||
use crate::{model::{self, addressing::EmbeddedActivity}, server::{auth::AuthIdentity, Context}};
|
||||
use crate::{errors::UpubError, model::{self, addressing::EmbeddedActivity}, server::{auth::AuthIdentity, Context}};
|
||||
|
||||
use super::{jsonld::LD, JsonLD};
|
||||
use super::{jsonld::LD, JsonLD, TryFetch};
|
||||
|
||||
// TODO this is used outside /routes, maybe move in model?
|
||||
pub fn ap_object(object: model::object::Model) -> serde_json::Value {
|
||||
|
@ -28,25 +28,26 @@ pub async fn view(
|
|||
State(ctx): State<Context>,
|
||||
Path(id): Path<String>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
) -> Result<JsonLD<serde_json::Value>, StatusCode> {
|
||||
Query(query): Query<TryFetch>,
|
||||
) -> crate::Result<JsonLD<serde_json::Value>> {
|
||||
let oid = if id.starts_with('+') {
|
||||
format!("https://{}", id.replacen('+', "", 1).replace('@', "/"))
|
||||
} else {
|
||||
ctx.oid(id.clone())
|
||||
};
|
||||
match model::addressing::Entity::find_activities()
|
||||
.filter(model::object::Column::Id.eq(oid))
|
||||
.filter(model::object::Column::Id.eq(&oid))
|
||||
.filter(auth.filter_condition())
|
||||
.into_model::<EmbeddedActivity>()
|
||||
.one(ctx.db())
|
||||
.await
|
||||
.await?
|
||||
{
|
||||
Ok(Some(EmbeddedActivity { activity: _, object: Some(object) })) => Ok(JsonLD(ap_object(object).ld_context())),
|
||||
Ok(Some(EmbeddedActivity { activity: _, object: None })) => Err(StatusCode::NOT_FOUND),
|
||||
Ok(None) => Err(StatusCode::NOT_FOUND),
|
||||
Err(e) => {
|
||||
tracing::error!("error querying for object: {e}");
|
||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
Some(EmbeddedActivity { activity: _, object: Some(object) }) => Ok(JsonLD(ap_object(object).ld_context())),
|
||||
Some(EmbeddedActivity { activity: _, object: None }) => Err(UpubError::not_found()),
|
||||
None => if auth.is_local() && query.fetch {
|
||||
Ok(JsonLD(ap_object(ctx.fetch().object(&oid).await?).ld_context()))
|
||||
} else {
|
||||
Err(UpubError::not_found())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ pub mod outbox;
|
|||
|
||||
pub mod following;
|
||||
|
||||
use axum::extract::{Path, State};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::EntityTrait;
|
||||
|
||||
use apb::{ActorMut, BaseMut, CollectionMut, DocumentMut, DocumentType, Node, ObjectMut, PublicKeyMut};
|
||||
use crate::{errors::UpubError, model::{self, user}, server::{auth::AuthIdentity, Context}, url};
|
||||
|
||||
use super::{jsonld::LD, JsonLD};
|
||||
use super::{jsonld::LD, JsonLD, TryFetch};
|
||||
|
||||
pub fn ap_user(user: model::user::Model) -> serde_json::Value {
|
||||
serde_json::Value::new_object()
|
||||
|
@ -48,13 +48,14 @@ pub async fn view(
|
|||
State(ctx) : State<Context>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
Path(id): Path<String>,
|
||||
Query(query): Query<TryFetch>,
|
||||
) -> crate::Result<JsonLD<serde_json::Value>> {
|
||||
let uid = if id.starts_with('+') {
|
||||
format!("https://{}", id.replacen('+', "", 1).replace('@', "/"))
|
||||
} else {
|
||||
ctx.uid(id.clone())
|
||||
};
|
||||
match user::Entity::find_by_id(uid)
|
||||
match user::Entity::find_by_id(&uid)
|
||||
.find_also_related(model::config::Entity)
|
||||
.one(ctx.db()).await?
|
||||
{
|
||||
|
@ -75,7 +76,7 @@ pub async fn view(
|
|||
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
|
||||
.set_first(Node::link(url!(ctx, "/users/{id}/following/page")))
|
||||
.set_total_items(
|
||||
if auth.is_user(&user.id) || cfg.show_following {
|
||||
if auth.is_local_user(&user.id) || cfg.show_following {
|
||||
Some(user.following_count as u64)
|
||||
} else {
|
||||
None
|
||||
|
@ -88,7 +89,7 @@ pub async fn view(
|
|||
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
|
||||
.set_first(Node::link(url!(ctx, "/users/{id}/followers/page")))
|
||||
.set_total_items(
|
||||
if auth.is_user(&user.id) || cfg.show_followers {
|
||||
if auth.is_local_user(&user.id) || cfg.show_followers {
|
||||
Some(user.followers_count as u64)
|
||||
} else {
|
||||
None
|
||||
|
@ -101,7 +102,11 @@ pub async fn view(
|
|||
},
|
||||
// remote user TODDO doesn't work?
|
||||
Some((user, None)) => Ok(JsonLD(ap_user(user).ld_context())),
|
||||
None => Err(UpubError::not_found()),
|
||||
None => if auth.is_local() && query.fetch {
|
||||
Ok(JsonLD(ap_user(ctx.fetch().user(&uid).await?).ld_context()))
|
||||
} else {
|
||||
Err(UpubError::not_found())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,14 +30,22 @@ impl Identity {
|
|||
matches!(self, Self::Anonymous)
|
||||
}
|
||||
|
||||
pub fn is_user(&self, uid: &str) -> bool {
|
||||
pub fn is_local(&self) -> bool {
|
||||
matches!(self, Self::Local(_))
|
||||
}
|
||||
|
||||
pub fn is_remote(&self) -> bool {
|
||||
matches!(self, Self::Remote(_))
|
||||
}
|
||||
|
||||
pub fn is_local_user(&self, uid: &str) -> bool {
|
||||
match self {
|
||||
Self::Local(x) => x == uid,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_server(&self, uid: &str) -> bool {
|
||||
pub fn is_remote_server(&self, uid: &str) -> bool {
|
||||
match self {
|
||||
Self::Remote(x) => x == uid,
|
||||
_ => false,
|
||||
|
|
Loading…
Reference in a new issue