]> Untitled Git - lemmy.git/blobdiff - crates/apub/src/fetcher/mod.rs
Addressing slow profile queries. #2777 (#2830)
[lemmy.git] / crates / apub / src / fetcher / mod.rs
index d41ee4f71c140e9c6b5a0fb490241a2cb73f9886..4f72d1488d5d8d9995e5efc99c1c92cb624d4435 100644 (file)
@@ -1,3 +1,64 @@
+use activitypub_federation::{
+  config::Data,
+  fetch::webfinger::webfinger_resolve_actor,
+  traits::{Actor, Object},
+};
+use diesel::NotFound;
+use itertools::Itertools;
+use lemmy_api_common::context::LemmyContext;
+use lemmy_db_schema::traits::ApubActor;
+use lemmy_db_views::structs::LocalUserView;
+use lemmy_utils::error::LemmyError;
+
 pub mod post_or_comment;
 pub mod search;
 pub mod user_or_community;
+
+/// Resolve actor identifier like `!news@example.com` to user or community object.
+///
+/// In case the requesting user is logged in and the object was not found locally, it is attempted
+/// to fetch via webfinger from the original instance.
+#[tracing::instrument(skip_all)]
+pub async fn resolve_actor_identifier<ActorType, DbActor>(
+  identifier: &str,
+  context: &Data<LemmyContext>,
+  local_user_view: &Option<LocalUserView>,
+  include_deleted: bool,
+) -> Result<ActorType, LemmyError>
+where
+  ActorType: Object<DataType = LemmyContext, Error = LemmyError>
+    + Object
+    + Actor
+    + From<DbActor>
+    + Send
+    + 'static,
+  for<'de2> <ActorType as Object>::Kind: serde::Deserialize<'de2>,
+  DbActor: ApubActor + Send + 'static,
+{
+  // remote actor
+  if identifier.contains('@') {
+    let (name, domain) = identifier
+      .splitn(2, '@')
+      .collect_tuple()
+      .expect("invalid query");
+    let actor = DbActor::read_from_name_and_domain(context.pool(), name, domain).await;
+    if actor.is_ok() {
+      Ok(actor?.into())
+    } else if local_user_view.is_some() {
+      // Fetch the actor from its home instance using webfinger
+      let actor: ActorType = webfinger_resolve_actor(identifier, context).await?;
+      Ok(actor)
+    } else {
+      Err(NotFound.into())
+    }
+  }
+  // local actor
+  else {
+    let identifier = identifier.to_string();
+    Ok(
+      DbActor::read_from_name(context.pool(), &identifier, include_deleted)
+        .await?
+        .into(),
+    )
+  }
+}