diff --git a/crates/apub/src/activities/unfederated.rs b/crates/apub/src/activities/unfederated.rs index 4b9e6b5a9..24ff9b686 100644 --- a/crates/apub/src/activities/unfederated.rs +++ b/crates/apub/src/activities/unfederated.rs @@ -5,8 +5,6 @@ use lemmy_api_common::{ CommentResponse, DistinguishComment, GetComment, - GetComments, - GetCommentsResponse, ListCommentReports, ListCommentReportsResponse, ResolveCommentReport, @@ -15,7 +13,6 @@ use lemmy_api_common::{ community::{ CommunityResponse, CreateCommunity, - GetCommunity, GetCommunityResponse, ListCommunities, ListCommunitiesResponse, @@ -39,8 +36,6 @@ use lemmy_api_common::{ GetBannedPersons, GetCaptcha, GetCaptchaResponse, - GetPersonDetails, - GetPersonDetailsResponse, GetPersonMentions, GetPersonMentionsResponse, GetReplies, @@ -66,8 +61,6 @@ use lemmy_api_common::{ post::{ GetPost, GetPostResponse, - GetPosts, - GetPostsResponse, GetSiteMetadata, GetSiteMetadataResponse, ListPostReports, @@ -110,10 +103,6 @@ use lemmy_api_common::{ PurgePerson, PurgePost, RegistrationApplicationResponse, - ResolveObject, - ResolveObjectResponse, - Search, - SearchResponse, SiteResponse, }, }; @@ -122,10 +111,6 @@ impl SendActivity for Register { type Response = LoginResponse; } -impl SendActivity for GetPersonDetails { - type Response = GetPersonDetailsResponse; -} - impl SendActivity for GetPrivateMessages { type Response = PrivateMessagesResponse; } @@ -142,10 +127,6 @@ impl SendActivity for GetSite { type Response = GetSiteResponse; } -impl SendActivity for GetCommunity { - type Response = GetCommunityResponse; -} - impl SendActivity for ListCommunities { type Response = ListCommunitiesResponse; } @@ -158,18 +139,10 @@ impl SendActivity for GetPost { type Response = GetPostResponse; } -impl SendActivity for GetPosts { - type Response = GetPostsResponse; -} - impl SendActivity for GetComment { type Response = CommentResponse; } -impl SendActivity for GetComments { - type Response = GetCommentsResponse; -} - impl SendActivity for Login { type Response = LoginResponse; } @@ -286,14 +259,6 @@ impl SendActivity for PurgeComment { type Response = PurgeItemResponse; } -impl SendActivity for Search { - type Response = SearchResponse; -} - -impl SendActivity for ResolveObject { - type Response = ResolveObjectResponse; -} - impl SendActivity for TransferCommunity { type Response = GetCommunityResponse; } diff --git a/crates/apub/src/api/list_comments.rs b/crates/apub/src/api/list_comments.rs index b3a1b7cf2..487aefa9e 100644 --- a/crates/apub/src/api/list_comments.rs +++ b/crates/apub/src/api/list_comments.rs @@ -1,9 +1,10 @@ use crate::{ - api::{listing_type_with_default, PerformApub}, + api::listing_type_with_default, fetcher::resolve_actor_identifier, objects::community::ApubCommunity, }; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ comment::{GetComments, GetCommentsResponse}, context::LemmyContext, @@ -16,61 +17,58 @@ use lemmy_db_schema::{ use lemmy_db_views::comment_view::CommentQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for GetComments { - type Response = GetCommentsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_comments( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(context.pool()).await?; + check_private_instance(&local_user_view, &local_site)?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &GetComments = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(context.pool()).await?; - check_private_instance(&local_user_view, &local_site)?; - - let community_id = if let Some(name) = &data.community_name { - resolve_actor_identifier::(name, context, &None, true) - .await - .ok() - .map(|c| c.id) - } else { - data.community_id - }; - let sort = data.sort; - let max_depth = data.max_depth; - let saved_only = data.saved_only; - let page = data.page; - let limit = data.limit; - let parent_id = data.parent_id; - - let listing_type = listing_type_with_default(data.type_, &local_site, community_id)?; - - // If a parent_id is given, fetch the comment to get the path - let parent_path = if let Some(parent_id) = parent_id { - Some(Comment::read(context.pool(), parent_id).await?.path) - } else { - None - }; - - let parent_path_cloned = parent_path.clone(); - let post_id = data.post_id; - let local_user = local_user_view.map(|l| l.local_user); - let comments = CommentQuery::builder() - .pool(context.pool()) - .listing_type(Some(listing_type)) - .sort(sort) - .max_depth(max_depth) - .saved_only(saved_only) - .community_id(community_id) - .parent_path(parent_path_cloned) - .post_id(post_id) - .local_user(local_user.as_ref()) - .page(page) - .limit(limit) - .build() - .list() + let community_id = if let Some(name) = &data.community_name { + resolve_actor_identifier::(name, &context, &None, true) .await - .map_err(|e| LemmyError::from_error_message(e, "couldnt_get_comments"))?; + .ok() + .map(|c| c.id) + } else { + data.community_id + }; + let sort = data.sort; + let max_depth = data.max_depth; + let saved_only = data.saved_only; + let page = data.page; + let limit = data.limit; + let parent_id = data.parent_id; - Ok(GetCommentsResponse { comments }) - } + let listing_type = listing_type_with_default(data.type_, &local_site, community_id)?; + + // If a parent_id is given, fetch the comment to get the path + let parent_path = if let Some(parent_id) = parent_id { + Some(Comment::read(context.pool(), parent_id).await?.path) + } else { + None + }; + + let parent_path_cloned = parent_path.clone(); + let post_id = data.post_id; + let local_user = local_user_view.map(|l| l.local_user); + let comments = CommentQuery::builder() + .pool(context.pool()) + .listing_type(Some(listing_type)) + .sort(sort) + .max_depth(max_depth) + .saved_only(saved_only) + .community_id(community_id) + .parent_path(parent_path_cloned) + .post_id(post_id) + .local_user(local_user.as_ref()) + .page(page) + .limit(limit) + .build() + .list() + .await + .map_err(|e| LemmyError::from_error_message(e, "couldnt_get_comments"))?; + + Ok(Json(GetCommentsResponse { comments })) } diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 99c790c73..bde373f65 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -1,9 +1,10 @@ use crate::{ - api::{listing_type_with_default, PerformApub}, + api::listing_type_with_default, fetcher::resolve_actor_identifier, objects::community::ApubCommunity, }; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, post::{GetPosts, GetPostsResponse}, @@ -13,54 +14,50 @@ use lemmy_db_schema::source::{community::Community, local_site::LocalSite}; use lemmy_db_views::post_view::PostQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for GetPosts { - type Response = GetPostsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_posts( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &GetPosts = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(context.pool()).await?; + check_private_instance(&local_user_view, &local_site)?; - check_private_instance(&local_user_view, &local_site)?; + let sort = data.sort; - let sort = data.sort; - - let page = data.page; - let limit = data.limit; - let community_id = if let Some(name) = &data.community_name { - resolve_actor_identifier::(name, context, &None, true) - .await - .ok() - .map(|c| c.id) - } else { - data.community_id - }; - let saved_only = data.saved_only; - - let listing_type = listing_type_with_default(data.type_, &local_site, community_id)?; - - let is_mod_or_admin = - is_mod_or_admin_opt(context.pool(), local_user_view.as_ref(), community_id) - .await - .is_ok(); - - let posts = PostQuery::builder() - .pool(context.pool()) - .local_user(local_user_view.map(|l| l.local_user).as_ref()) - .listing_type(Some(listing_type)) - .sort(sort) - .community_id(community_id) - .saved_only(saved_only) - .page(page) - .limit(limit) - .is_mod_or_admin(Some(is_mod_or_admin)) - .build() - .list() + let page = data.page; + let limit = data.limit; + let community_id = if let Some(name) = &data.community_name { + resolve_actor_identifier::(name, &context, &None, true) .await - .map_err(|e| LemmyError::from_error_message(e, "couldnt_get_posts"))?; + .ok() + .map(|c| c.id) + } else { + data.community_id + }; + let saved_only = data.saved_only; - Ok(GetPostsResponse { posts }) - } + let listing_type = listing_type_with_default(data.type_, &local_site, community_id)?; + + let is_mod_or_admin = is_mod_or_admin_opt(context.pool(), local_user_view.as_ref(), community_id) + .await + .is_ok(); + + let posts = PostQuery::builder() + .pool(context.pool()) + .local_user(local_user_view.map(|l| l.local_user).as_ref()) + .listing_type(Some(listing_type)) + .sort(sort) + .community_id(community_id) + .saved_only(saved_only) + .page(page) + .limit(limit) + .is_mod_or_admin(Some(is_mod_or_admin)) + .build() + .list() + .await + .map_err(|e| LemmyError::from_error_message(e, "couldnt_get_posts"))?; + + Ok(Json(GetPostsResponse { posts })) } diff --git a/crates/apub/src/api/mod.rs b/crates/apub/src/api/mod.rs index d95c9b51b..705e81a30 100644 --- a/crates/apub/src/api/mod.rs +++ b/crates/apub/src/api/mod.rs @@ -1,21 +1,12 @@ -use activitypub_federation::config::Data; -use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{newtypes::CommunityId, source::local_site::LocalSite, ListingType}; use lemmy_utils::error::LemmyError; -mod list_comments; -mod list_posts; -mod read_community; -mod read_person; -mod resolve_object; -mod search; - -#[async_trait::async_trait] -pub trait PerformApub { - type Response: serde::ser::Serialize + Send; - - async fn perform(&self, context: &Data) -> Result; -} +pub mod list_comments; +pub mod list_posts; +pub mod read_community; +pub mod read_person; +pub mod resolve_object; +pub mod search; /// Returns default listing type, depending if the query is for frontpage or community. fn listing_type_with_default( diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index a19758990..e524694d3 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -1,9 +1,6 @@ -use crate::{ - api::PerformApub, - fetcher::resolve_actor_identifier, - objects::community::ApubCommunity, -}; +use crate::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity}; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ community::{GetCommunity, GetCommunityResponse}, context::LemmyContext, @@ -18,78 +15,68 @@ use lemmy_db_schema::source::{ use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for GetCommunity { - type Response = GetCommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn read_community( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &GetCommunity = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(context.pool()).await?; + if data.name.is_none() && data.id.is_none() { + return Err(LemmyError::from_message("no_id_given")); + } - if data.name.is_none() && data.id.is_none() { - return Err(LemmyError::from_message("no_id_given")); - } + check_private_instance(&local_user_view, &local_site)?; - check_private_instance(&local_user_view, &local_site)?; + let person_id = local_user_view.as_ref().map(|u| u.person.id); - let person_id = local_user_view.as_ref().map(|u| u.person.id); - - let community_id = match data.id { - Some(id) => id, - None => { - let name = data.name.clone().unwrap_or_else(|| "main".to_string()); - resolve_actor_identifier::(&name, context, &local_user_view, true) - .await - .map_err(|e| e.with_message("couldnt_find_community"))? - .id - } - }; - - let is_mod_or_admin = - is_mod_or_admin_opt(context.pool(), local_user_view.as_ref(), Some(community_id)) + let community_id = match data.id { + Some(id) => id, + None => { + let name = data.name.clone().unwrap_or_else(|| "main".to_string()); + resolve_actor_identifier::(&name, &context, &local_user_view, true) .await - .is_ok(); + .map_err(|e| e.with_message("couldnt_find_community"))? + .id + } + }; - let community_view = CommunityView::read( - context.pool(), - community_id, - person_id, - Some(is_mod_or_admin), - ) + let is_mod_or_admin = + is_mod_or_admin_opt(context.pool(), local_user_view.as_ref(), Some(community_id)) + .await + .is_ok(); + + let community_view = CommunityView::read( + context.pool(), + community_id, + person_id, + Some(is_mod_or_admin), + ) + .await + .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?; + + let moderators = CommunityModeratorView::for_community(context.pool(), community_id) .await .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?; - let moderators = CommunityModeratorView::for_community(context.pool(), community_id) - .await - .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?; - - let site_id = - Site::instance_actor_id_from_url(community_view.community.actor_id.clone().into()); - let mut site = Site::read_from_apub_id(context.pool(), &site_id.into()).await?; - // no need to include metadata for local site (its already available through other endpoints). - // this also prevents us from leaking the federation private key. - if let Some(s) = &site { - if s.actor_id.domain() == Some(context.settings().hostname.as_ref()) { - site = None; - } + let site_id = Site::instance_actor_id_from_url(community_view.community.actor_id.clone().into()); + let mut site = Site::read_from_apub_id(context.pool(), &site_id.into()).await?; + // no need to include metadata for local site (its already available through other endpoints). + // this also prevents us from leaking the federation private key. + if let Some(s) = &site { + if s.actor_id.domain() == Some(context.settings().hostname.as_ref()) { + site = None; } - - let community_id = community_view.community.id; - let discussion_languages = CommunityLanguage::read(context.pool(), community_id).await?; - - let res = GetCommunityResponse { - community_view, - site, - moderators, - discussion_languages, - }; - - // Return the jwt - Ok(res) } + + let community_id = community_view.community.id; + let discussion_languages = CommunityLanguage::read(context.pool(), community_id).await?; + + Ok(Json(GetCommunityResponse { + community_view, + site, + moderators, + discussion_languages, + })) } diff --git a/crates/apub/src/api/read_person.rs b/crates/apub/src/api/read_person.rs index 1e4797fa4..fb4755e38 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -1,5 +1,6 @@ -use crate::{api::PerformApub, fetcher::resolve_actor_identifier, objects::person::ApubPerson}; +use crate::{fetcher::resolve_actor_identifier, objects::person::ApubPerson}; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetPersonDetails, GetPersonDetailsResponse}, @@ -13,108 +14,101 @@ use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery}; use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for GetPersonDetails { - type Response = GetPersonDetailsResponse; - - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &GetPersonDetails = self; - - // Check to make sure a person name or an id is given - if data.username.is_none() && data.person_id.is_none() { - return Err(LemmyError::from_message("no_id_given")); - } - - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(context.pool()).await?; - let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); - - check_private_instance(&local_user_view, &local_site)?; - - let person_details_id = match data.person_id { - Some(id) => id, - None => { - if let Some(username) = &data.username { - resolve_actor_identifier::(username, context, &local_user_view, true) - .await - .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))? - .id - } else { - return Err(LemmyError::from_message( - "couldnt_find_that_username_or_email", - )); - } - } - }; - - // You don't need to return settings for the user, since this comes back with GetSite - // `my_user` - let person_view = PersonView::read(context.pool(), person_details_id).await?; - - let sort = data.sort; - let page = data.page; - let limit = data.limit; - let saved_only = data.saved_only; - let community_id = data.community_id; - let local_user = local_user_view.map(|l| l.local_user); - let local_user_clone = local_user.clone(); - - let posts_query = PostQuery::builder() - .pool(context.pool()) - .sort(sort) - .saved_only(saved_only) - .local_user(local_user.as_ref()) - .community_id(community_id) - .is_mod_or_admin(is_admin) - .page(page) - .limit(limit); - - // If its saved only, you don't care what creator it was - // Or, if its not saved, then you only want it for that specific creator - let posts = if !saved_only.unwrap_or(false) { - posts_query - .creator_id(Some(person_details_id)) - .build() - .list() - } else { - posts_query.build().list() - } - .await?; - - let comments_query = CommentQuery::builder() - .pool(context.pool()) - .local_user(local_user_clone.as_ref()) - .sort(sort.map(post_to_comment_sort_type)) - .saved_only(saved_only) - .show_deleted_and_removed(Some(false)) - .community_id(community_id) - .page(page) - .limit(limit); - - // If its saved only, you don't care what creator it was - // Or, if its not saved, then you only want it for that specific creator - let comments = if !saved_only.unwrap_or(false) { - comments_query - .creator_id(Some(person_details_id)) - .build() - .list() - } else { - comments_query.build().list() - } - .await?; - - let moderates = CommunityModeratorView::for_person(context.pool(), person_details_id).await?; - - // Return the jwt - Ok(GetPersonDetailsResponse { - person_view, - moderates, - comments, - posts, - }) +#[tracing::instrument(skip(context))] +pub async fn read_person( + data: Query, + context: Data, +) -> Result, LemmyError> { + // Check to make sure a person name or an id is given + if data.username.is_none() && data.person_id.is_none() { + return Err(LemmyError::from_message("no_id_given")); } + + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(context.pool()).await?; + let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); + + check_private_instance(&local_user_view, &local_site)?; + + let person_details_id = match data.person_id { + Some(id) => id, + None => { + if let Some(username) = &data.username { + resolve_actor_identifier::(username, &context, &local_user_view, true) + .await + .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))? + .id + } else { + return Err(LemmyError::from_message( + "couldnt_find_that_username_or_email", + )); + } + } + }; + + // You don't need to return settings for the user, since this comes back with GetSite + // `my_user` + let person_view = PersonView::read(context.pool(), person_details_id).await?; + + let sort = data.sort; + let page = data.page; + let limit = data.limit; + let saved_only = data.saved_only; + let community_id = data.community_id; + let local_user = local_user_view.map(|l| l.local_user); + let local_user_clone = local_user.clone(); + + let posts_query = PostQuery::builder() + .pool(context.pool()) + .sort(sort) + .saved_only(saved_only) + .local_user(local_user.as_ref()) + .community_id(community_id) + .is_mod_or_admin(is_admin) + .page(page) + .limit(limit); + + // If its saved only, you don't care what creator it was + // Or, if its not saved, then you only want it for that specific creator + let posts = if !saved_only.unwrap_or(false) { + posts_query + .creator_id(Some(person_details_id)) + .build() + .list() + } else { + posts_query.build().list() + } + .await?; + + let comments_query = CommentQuery::builder() + .pool(context.pool()) + .local_user(local_user_clone.as_ref()) + .sort(sort.map(post_to_comment_sort_type)) + .saved_only(saved_only) + .show_deleted_and_removed(Some(false)) + .community_id(community_id) + .page(page) + .limit(limit); + + // If its saved only, you don't care what creator it was + // Or, if its not saved, then you only want it for that specific creator + let comments = if !saved_only.unwrap_or(false) { + comments_query + .creator_id(Some(person_details_id)) + .build() + .list() + } else { + comments_query.build().list() + } + .await?; + + let moderates = CommunityModeratorView::for_person(context.pool(), person_details_id).await?; + + // Return the jwt + Ok(Json(GetPersonDetailsResponse { + person_view, + moderates, + comments, + posts, + })) } diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index 951cd4551..09689def1 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -1,8 +1,6 @@ -use crate::{ - api::PerformApub, - fetcher::search::{search_query_to_object_id, SearchableObjects}, -}; +use crate::fetcher::search::{search_query_to_object_id, SearchableObjects}; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use diesel::NotFound; use lemmy_api_common::{ context::LemmyContext, @@ -14,34 +12,29 @@ use lemmy_db_views::structs::{CommentView, PostView}; use lemmy_db_views_actor::structs::{CommunityView, PersonView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for ResolveObject { - type Response = ResolveObjectResponse; +#[tracing::instrument(skip(context))] +pub async fn resolve_object( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(context.pool()).await?; + let person_id = local_user_view.person.id; + check_private_instance(&Some(local_user_view), &local_site)?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let local_user_view = local_user_view_from_jwt(&self.auth, context).await?; - let local_site = LocalSite::read(context.pool()).await?; - let person_id = local_user_view.person.id; - check_private_instance(&Some(local_user_view), &local_site)?; - - let res = search_query_to_object_id(&self.q, context) - .await - .map_err(|e| e.with_message("couldnt_find_object"))?; - convert_response(res, person_id, context.pool()) - .await - .map_err(|e| e.with_message("couldnt_find_object")) - } + let res = search_query_to_object_id(&data.q, &context) + .await + .map_err(|e| e.with_message("couldnt_find_object"))?; + convert_response(res, person_id, context.pool()) + .await + .map_err(|e| e.with_message("couldnt_find_object")) } async fn convert_response( object: SearchableObjects, user_id: PersonId, pool: &DbPool, -) -> Result { +) -> Result, LemmyError> { use SearchableObjects::*; let removed_or_deleted; let mut res = ResolveObjectResponse::default(); @@ -67,5 +60,5 @@ async fn convert_response( if removed_or_deleted { return Err(NotFound {}.into()); } - Ok(res) + Ok(Json(res)) } diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index 025d1408a..777a7013b 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -1,9 +1,6 @@ -use crate::{ - api::PerformApub, - fetcher::resolve_actor_identifier, - objects::community::ApubCommunity, -}; +use crate::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity}; use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{Search, SearchResponse}, @@ -18,78 +15,142 @@ use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery}; use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait] -impl PerformApub for Search { - type Response = SearchResponse; +#[tracing::instrument(skip(context))] +pub async fn search( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &Search = self; + check_private_instance(&local_user_view, &local_site)?; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(context.pool()).await?; + let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); - check_private_instance(&local_user_view, &local_site)?; + let mut posts = Vec::new(); + let mut comments = Vec::new(); + let mut communities = Vec::new(); + let mut users = Vec::new(); - let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); + // TODO no clean / non-nsfw searching rn - let mut posts = Vec::new(); - let mut comments = Vec::new(); - let mut communities = Vec::new(); - let mut users = Vec::new(); + let q = data.q.clone(); + let page = data.page; + let limit = data.limit; + let sort = data.sort; + let listing_type = data.listing_type; + let search_type = data.type_.unwrap_or(SearchType::All); + let community_id = if let Some(name) = &data.community_name { + resolve_actor_identifier::(name, &context, &local_user_view, false) + .await + .ok() + .map(|c| c.id) + } else { + data.community_id + }; + let creator_id = data.creator_id; + let local_user = local_user_view.map(|l| l.local_user); + match search_type { + SearchType::Posts => { + posts = PostQuery::builder() + .pool(context.pool()) + .sort(sort) + .listing_type(listing_type) + .community_id(community_id) + .creator_id(creator_id) + .local_user(local_user.as_ref()) + .search_term(Some(q)) + .is_mod_or_admin(is_admin) + .page(page) + .limit(limit) + .build() + .list() + .await?; + } + SearchType::Comments => { + comments = CommentQuery::builder() + .pool(context.pool()) + .sort(sort.map(post_to_comment_sort_type)) + .listing_type(listing_type) + .search_term(Some(q)) + .community_id(community_id) + .creator_id(creator_id) + .local_user(local_user.as_ref()) + .page(page) + .limit(limit) + .build() + .list() + .await?; + } + SearchType::Communities => { + communities = CommunityQuery::builder() + .pool(context.pool()) + .sort(sort) + .listing_type(listing_type) + .search_term(Some(q)) + .local_user(local_user.as_ref()) + .is_mod_or_admin(is_admin) + .page(page) + .limit(limit) + .build() + .list() + .await?; + } + SearchType::Users => { + users = PersonQuery::builder() + .pool(context.pool()) + .sort(sort) + .search_term(Some(q)) + .page(page) + .limit(limit) + .build() + .list() + .await?; + } + SearchType::All => { + // If the community or creator is included, dont search communities or users + let community_or_creator_included = + data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some(); - // TODO no clean / non-nsfw searching rn + let local_user_ = local_user.clone(); + posts = PostQuery::builder() + .pool(context.pool()) + .sort(sort) + .listing_type(listing_type) + .community_id(community_id) + .creator_id(creator_id) + .local_user(local_user_.as_ref()) + .search_term(Some(q)) + .is_mod_or_admin(is_admin) + .page(page) + .limit(limit) + .build() + .list() + .await?; - let q = data.q.clone(); - let page = data.page; - let limit = data.limit; - let sort = data.sort; - let listing_type = data.listing_type; - let search_type = data.type_.unwrap_or(SearchType::All); - let community_id = if let Some(name) = &data.community_name { - resolve_actor_identifier::(name, context, &local_user_view, false) - .await - .ok() - .map(|c| c.id) - } else { - data.community_id - }; - let creator_id = data.creator_id; - let local_user = local_user_view.map(|l| l.local_user); - match search_type { - SearchType::Posts => { - posts = PostQuery::builder() - .pool(context.pool()) - .sort(sort) - .listing_type(listing_type) - .community_id(community_id) - .creator_id(creator_id) - .local_user(local_user.as_ref()) - .search_term(Some(q)) - .is_mod_or_admin(is_admin) - .page(page) - .limit(limit) - .build() - .list() - .await?; - } - SearchType::Comments => { - comments = CommentQuery::builder() - .pool(context.pool()) - .sort(sort.map(post_to_comment_sort_type)) - .listing_type(listing_type) - .search_term(Some(q)) - .community_id(community_id) - .creator_id(creator_id) - .local_user(local_user.as_ref()) - .page(page) - .limit(limit) - .build() - .list() - .await?; - } - SearchType::Communities => { - communities = CommunityQuery::builder() + let q = data.q.clone(); + + let local_user_ = local_user.clone(); + comments = CommentQuery::builder() + .pool(context.pool()) + .sort(sort.map(post_to_comment_sort_type)) + .listing_type(listing_type) + .search_term(Some(q)) + .community_id(community_id) + .creator_id(creator_id) + .local_user(local_user_.as_ref()) + .page(page) + .limit(limit) + .build() + .list() + .await?; + + let q = data.q.clone(); + + communities = if community_or_creator_included { + vec![] + } else { + CommunityQuery::builder() .pool(context.pool()) .sort(sort) .listing_type(listing_type) @@ -100,10 +161,15 @@ impl PerformApub for Search { .limit(limit) .build() .list() - .await?; - } - SearchType::Users => { - users = PersonQuery::builder() + .await? + }; + + let q = data.q.clone(); + + users = if community_or_creator_included { + vec![] + } else { + PersonQuery::builder() .pool(context.pool()) .sort(sort) .search_term(Some(q)) @@ -111,105 +177,32 @@ impl PerformApub for Search { .limit(limit) .build() .list() - .await?; - } - SearchType::All => { - // If the community or creator is included, dont search communities or users - let community_or_creator_included = - data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some(); + .await? + }; + } + SearchType::Url => { + posts = PostQuery::builder() + .pool(context.pool()) + .sort(sort) + .listing_type(listing_type) + .community_id(community_id) + .creator_id(creator_id) + .url_search(Some(q)) + .is_mod_or_admin(is_admin) + .page(page) + .limit(limit) + .build() + .list() + .await?; + } + }; - let local_user_ = local_user.clone(); - posts = PostQuery::builder() - .pool(context.pool()) - .sort(sort) - .listing_type(listing_type) - .community_id(community_id) - .creator_id(creator_id) - .local_user(local_user_.as_ref()) - .search_term(Some(q)) - .is_mod_or_admin(is_admin) - .page(page) - .limit(limit) - .build() - .list() - .await?; - - let q = data.q.clone(); - - let local_user_ = local_user.clone(); - comments = CommentQuery::builder() - .pool(context.pool()) - .sort(sort.map(post_to_comment_sort_type)) - .listing_type(listing_type) - .search_term(Some(q)) - .community_id(community_id) - .creator_id(creator_id) - .local_user(local_user_.as_ref()) - .page(page) - .limit(limit) - .build() - .list() - .await?; - - let q = data.q.clone(); - - communities = if community_or_creator_included { - vec![] - } else { - CommunityQuery::builder() - .pool(context.pool()) - .sort(sort) - .listing_type(listing_type) - .search_term(Some(q)) - .local_user(local_user.as_ref()) - .is_mod_or_admin(is_admin) - .page(page) - .limit(limit) - .build() - .list() - .await? - }; - - let q = data.q.clone(); - - users = if community_or_creator_included { - vec![] - } else { - PersonQuery::builder() - .pool(context.pool()) - .sort(sort) - .search_term(Some(q)) - .page(page) - .limit(limit) - .build() - .list() - .await? - }; - } - SearchType::Url => { - posts = PostQuery::builder() - .pool(context.pool()) - .sort(sort) - .listing_type(listing_type) - .community_id(community_id) - .creator_id(creator_id) - .url_search(Some(q)) - .is_mod_or_admin(is_admin) - .page(page) - .limit(limit) - .build() - .list() - .await?; - } - }; - - // Return the jwt - Ok(SearchResponse { - type_: search_type, - comments, - posts, - communities, - users, - }) - } + // Return the jwt + Ok(Json(SearchResponse { + type_: search_type, + comments, + posts, + communities, + users, + })) } diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index 375630a92..ca0fa4c22 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -9,7 +9,6 @@ use lemmy_api_common::{ DistinguishComment, EditComment, GetComment, - GetComments, ListCommentReports, RemoveComment, ResolveCommentReport, @@ -23,7 +22,6 @@ use lemmy_api_common::{ DeleteCommunity, EditCommunity, FollowCommunity, - GetCommunity, HideCommunity, ListCommunities, RemoveCommunity, @@ -39,7 +37,6 @@ use lemmy_api_common::{ DeleteAccount, GetBannedPersons, GetCaptcha, - GetPersonDetails, GetPersonMentions, GetReplies, GetReportCount, @@ -62,7 +59,6 @@ use lemmy_api_common::{ EditPost, FeaturePost, GetPost, - GetPosts, GetSiteMetadata, ListPostReports, LockPost, @@ -95,12 +91,20 @@ use lemmy_api_common::{ PurgeCommunity, PurgePerson, PurgePost, - ResolveObject, - Search, }, }; use lemmy_api_crud::PerformCrud; -use lemmy_apub::{api::PerformApub, SendActivity}; +use lemmy_apub::{ + api::{ + list_comments::list_comments, + list_posts::list_posts, + read_community::read_community, + read_person::read_person, + resolve_object::resolve_object, + search::search, + }, + SendActivity, +}; use lemmy_utils::rate_limit::RateLimitCell; use serde::Deserialize; @@ -124,12 +128,12 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::resource("/search") .wrap(rate_limit.search()) - .route(web::get().to(route_get_apub::)), + .route(web::get().to(search)), ) .service( web::resource("/resolve_object") .wrap(rate_limit.message()) - .route(web::get().to(route_get_apub::)), + .route(web::get().to(resolve_object)), ) // Community .service( @@ -141,7 +145,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/community") .wrap(rate_limit.message()) - .route("", web::get().to(route_get_apub::)) + .route("", web::get().to(read_community)) .route("", web::put().to(route_post_crud::)) .route("/hide", web::put().to(route_post::)) .route("/list", web::get().to(route_get_crud::)) @@ -186,7 +190,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { ) .route("/lock", web::post().to(route_post::)) .route("/feature", web::post().to(route_post::)) - .route("/list", web::get().to(route_get_apub::)) + .route("/list", web::get().to(list_posts)) .route("/like", web::post().to(route_post::)) .route("/save", web::put().to(route_post::)) .route("/report", web::post().to(route_post::)) @@ -225,7 +229,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { ) .route("/like", web::post().to(route_post::)) .route("/save", web::put().to(route_post::)) - .route("/list", web::get().to(route_get_apub::)) + .route("/list", web::get().to(list_comments)) .route("/report", web::post().to(route_post::)) .route( "/report/resolve", @@ -283,7 +287,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/user") .wrap(rate_limit.message()) - .route("", web::get().to(route_get_apub::)) + .route("", web::get().to(read_person)) .route("/mention", web::get().to(route_get::)) .route( "/mention/mark_as_read", @@ -398,23 +402,6 @@ where perform::(data.0, context, apub_data).await } -async fn route_get_apub<'a, Data>( - data: web::Query, - context: activitypub_federation::config::Data, -) -> Result -where - Data: PerformApub - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - let res = data.perform(&context).await?; - SendActivity::send_activity(&data.0, &res, &context).await?; - Ok(HttpResponse::Ok().json(res)) -} - async fn route_post<'a, Data>( data: web::Json, context: web::Data,