get_local_user_view_from_jwt,
get_local_user_view_from_jwt_opt,
is_admin,
- resolve_actor_identifier,
send_application_approved_email,
site::*,
};
-use lemmy_apub::fetcher::search::{search_by_apub_id, SearchableObjects};
+use lemmy_apub::{
+ fetcher::{
+ resolve_actor_identifier,
+ search::{search_by_apub_id, SearchableObjects},
+ },
+ objects::community::ApubCommunity,
+};
use lemmy_db_schema::{
diesel_option_overwrite,
from_opt_str_to_opt_enum,
let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All);
let community_id = data.community_id;
let community_actor_id = if let Some(name) = &data.community_name {
- resolve_actor_identifier::<Community>(name, context.pool())
+ resolve_actor_identifier::<ApubCommunity, Community>(name, context)
.await
.ok()
.map(|c| c.actor_id)
pub mod websocket;
use crate::site::FederatedInstances;
-use itertools::Itertools;
use lemmy_db_schema::{
newtypes::{CommunityId, LocalUserId, PersonId, PostId},
source::{
secret::Secret,
site::Site,
},
- traits::{ApubActor, Crud, Readable},
+ traits::{Crud, Readable},
DbPool,
};
use lemmy_db_views::{
Ok(())
}
-/// Resolve actor identifier (eg `!news@example.com`) from local database to avoid network requests.
-/// This only works for local actors, and remote actors which were previously fetched (so it doesnt
-/// trigger any new fetch).
-#[tracing::instrument(skip_all)]
-pub async fn resolve_actor_identifier<Actor>(
- identifier: &str,
- pool: &DbPool,
-) -> Result<Actor, LemmyError>
-where
- Actor: ApubActor + Send + 'static,
-{
- // remote actor
- if identifier.contains('@') {
- let (name, domain) = identifier
- .splitn(2, '@')
- .collect_tuple()
- .expect("invalid query");
- let name = name.to_string();
- let domain = format!("{}://{}", Settings::get().get_protocol_string(), domain);
- Ok(
- blocking(pool, move |conn| {
- Actor::read_from_name_and_domain(conn, &name, &domain)
- })
- .await??,
- )
- }
- // local actor
- else {
- let identifier = identifier.to_string();
- Ok(blocking(pool, move |conn| Actor::read_from_name(conn, &identifier)).await??)
- }
-}
-
pub async fn remove_user_data(banned_person_id: PersonId, pool: &DbPool) -> Result<(), LemmyError> {
// Posts
blocking(pool, move |conn: &'_ _| {
check_private_instance,
comment::*,
get_local_user_view_from_jwt_opt,
- resolve_actor_identifier,
};
+use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
from_opt_str_to_opt_enum,
source::community::Community,
let community_id = data.community_id;
let community_actor_id = if let Some(name) = &data.community_name {
- resolve_actor_identifier::<Community>(name, context.pool())
+ resolve_actor_identifier::<ApubCommunity, Community>(name, context)
.await
.ok()
.map(|c| c.actor_id)
check_private_instance,
community::*,
get_local_user_view_from_jwt_opt,
- resolve_actor_identifier,
};
+use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
from_opt_str_to_opt_enum,
source::community::Community,
Some(id) => id,
None => {
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
- resolve_actor_identifier::<Community>(&name, context.pool())
+ resolve_actor_identifier::<ApubCommunity, Community>(&name, context)
.await
.map_err(|e| e.with_message("couldnt_find_community"))?
.id
get_local_user_view_from_jwt_opt,
mark_post_as_read,
post::*,
- resolve_actor_identifier,
};
+use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
from_opt_str_to_opt_enum,
source::community::Community,
let limit = data.limit;
let community_id = data.community_id;
let community_actor_id = if let Some(name) = &data.community_name {
- resolve_actor_identifier::<Community>(name, context.pool())
+ resolve_actor_identifier::<ApubCommunity, Community>(name, context)
.await
.ok()
.map(|c| c.actor_id)
check_private_instance,
get_local_user_view_from_jwt_opt,
person::*,
- resolve_actor_identifier,
};
+use lemmy_apub::{fetcher::resolve_actor_identifier, objects::person::ApubPerson};
use lemmy_db_schema::{from_opt_str_to_opt_enum, source::person::Person, SortType};
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
use lemmy_db_views_actor::{
.to_owned()
.unwrap_or_else(|| "admin".to_string());
- resolve_actor_identifier::<Person>(&name, context.pool())
+ resolve_actor_identifier::<ApubPerson, Person>(&name, context)
.await
.map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?
.id
impl ApubObject for SiteOrCommunity {
type DataType = LemmyContext;
type ApubType = InstanceOrGroup;
+ type DbType = ();
type TombstoneType = ();
#[tracing::instrument(skip_all)]
// This return value is unused, so just set an empty vec
Ok(ApubCommunityModerators { 0: vec![] })
}
+
+ type DbType = ();
}
#[cfg(test)]
// This return value is unused, so just set an empty vec
Ok(ApubCommunityOutbox { 0: vec![] })
}
+
+ type DbType = ();
}
+use crate::fetcher::webfinger::webfinger_resolve_actor;
+use itertools::Itertools;
+use lemmy_api_common::blocking;
+use lemmy_apub_lib::traits::{ActorType, ApubObject};
+use lemmy_db_schema::traits::ApubActor;
+use lemmy_utils::{settings::structs::Settings, LemmyError};
+use lemmy_websocket::LemmyContext;
+
pub mod post_or_comment;
pub mod search;
pub mod user_or_community;
pub mod webfinger;
+
+/// Resolve actor identifier (eg `!news@example.com`) from local database to avoid network requests.
+/// This only works for local actors, and remote actors which were previously fetched (so it doesnt
+/// trigger any new fetch).
+#[tracing::instrument(skip_all)]
+pub async fn resolve_actor_identifier<Actor, DbActor>(
+ identifier: &str,
+ context: &LemmyContext,
+) -> Result<DbActor, LemmyError>
+where
+ Actor:
+ ApubObject<DataType = LemmyContext> + ApubObject<DbType = DbActor> + ActorType + Send + 'static,
+ for<'de2> <Actor as ApubObject>::ApubType: serde::Deserialize<'de2>,
+ DbActor: ApubActor + Send + 'static,
+{
+ // remote actor
+ if identifier.contains('@') {
+ let (name, domain) = identifier
+ .splitn(2, '@')
+ .collect_tuple()
+ .expect("invalid query");
+ let name = name.to_string();
+ let domain = format!("{}://{}", Settings::get().get_protocol_string(), domain);
+ let actor = blocking(context.pool(), move |conn| {
+ DbActor::read_from_name_and_domain(conn, &name, &domain)
+ })
+ .await?;
+ if actor.is_ok() {
+ Ok(actor?)
+ } else {
+ // Fetch the actor from its home instance using webfinger
+ let id = webfinger_resolve_actor::<Actor>(identifier, context, &mut 0).await?;
+ let actor: DbActor = blocking(context.pool(), move |conn| {
+ DbActor::read_from_apub_id(conn, &id)
+ })
+ .await??
+ .expect("actor exists as we fetched just before");
+ Ok(actor)
+ }
+ }
+ // local actor
+ else {
+ let identifier = identifier.to_string();
+ Ok(
+ blocking(context.pool(), move |conn| {
+ DbActor::read_from_name(conn, &identifier)
+ })
+ .await??,
+ )
+ }
+}
impl ApubObject for PostOrComment {
type DataType = LemmyContext;
type ApubType = PageOrNote;
+ type DbType = ();
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for SearchableObjects {
type DataType = LemmyContext;
type ApubType = SearchableApubTypes;
+ type DbType = ();
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for UserOrCommunity {
type DataType = LemmyContext;
type ApubType = PersonOrGroup;
+ type DbType = ();
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for ApubComment {
type DataType = LemmyContext;
type ApubType = Note;
+ type DbType = Comment;
type TombstoneType = Tombstone;
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for ApubCommunity {
type DataType = LemmyContext;
type ApubType = Group;
+ type DbType = Community;
type TombstoneType = Tombstone;
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
) -> Result<Option<Self>, LemmyError> {
Ok(
blocking(context.pool(), move |conn| {
- Community::read_from_apub_id(conn, object_id)
+ Community::read_from_apub_id(conn, &object_id.into())
})
.await??
.map(Into::into),
impl ApubObject for ApubSite {
type DataType = LemmyContext;
type ApubType = Instance;
+ type DbType = Site;
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for ApubPerson {
type DataType = LemmyContext;
type ApubType = Person;
+ type DbType = DbPerson;
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
) -> Result<Option<Self>, LemmyError> {
Ok(
blocking(context.pool(), move |conn| {
- DbPerson::read_from_apub_id(conn, object_id)
+ DbPerson::read_from_apub_id(conn, &object_id.into())
})
.await??
.map(Into::into),
impl ApubObject for ApubPost {
type DataType = LemmyContext;
type ApubType = Page;
+ type DbType = Post;
type TombstoneType = Tombstone;
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
impl ApubObject for ApubPrivateMessage {
type DataType = LemmyContext;
type ApubType = ChatMessage;
+ type DbType = PrivateMessage;
type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
pub trait ApubObject {
type DataType;
type ApubType;
+ type DbType;
type TombstoneType;
/// If this object should be refetched after a certain interval, it should return the last refresh
RunQueryDsl,
TextExpressionMethods,
};
-use url::Url;
mod safe_type {
use crate::{schema::community::*, source::community::Community, traits::ToSafe};
}
impl ApubActor for Community {
- fn read_from_apub_id(conn: &PgConnection, object_id: Url) -> Result<Option<Self>, Error> {
+ fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error> {
use crate::schema::community::dsl::*;
- let object_id: DbUrl = object_id.into();
Ok(
community
.filter(actor_id.eq(object_id))
RunQueryDsl,
TextExpressionMethods,
};
-use url::Url;
mod safe_type {
use crate::{schema::person::columns::*, source::person::Person, traits::ToSafe};
}
impl ApubActor for Person {
- fn read_from_apub_id(conn: &PgConnection, object_id: Url) -> Result<Option<Self>, Error> {
+ fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error> {
use crate::schema::person::dsl::*;
- let object_id: DbUrl = object_id.into();
Ok(
person
.filter(deleted.eq(false))
-use crate::newtypes::{CommunityId, PersonId};
+use crate::{
+ newtypes::{CommunityId, PersonId},
+ DbUrl,
+};
use diesel::{result::Error, PgConnection};
-use url::Url;
pub trait Crud {
type Form;
pub trait ApubActor {
// TODO: this should be in a trait ApubObject (and implemented for Post, Comment, PrivateMessage as well)
- fn read_from_apub_id(conn: &PgConnection, object_id: Url) -> Result<Option<Self>, Error>
+ fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error>
where
Self: Sized;
fn read_from_name(conn: &PgConnection, actor_name: &str) -> Result<Self, Error>