diff --git a/Cargo.lock b/Cargo.lock index 476c1c10a..e657a3154 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2708,6 +2708,7 @@ dependencies = [ "tokio", "tracing", "ts-rs", + "typed-builder", ] [[package]] @@ -2726,6 +2727,7 @@ dependencies = [ "strum_macros", "tokio", "ts-rs", + "typed-builder", ] [[package]] diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index 1964fcc49..3983a6821 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -31,7 +31,8 @@ pub async fn like_post( let post_id = data.post_id; let post = Post::read(&mut context.pool(), post_id).await?; - // TODO: need to read community both here are for check_community_user_action() + // TODO: need to read community both here are for check_community_user_action(), would be good to + // read it only once let community = Community::read(&mut context.pool(), post.community_id).await?; check_vote_permission( data.score, diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 3181e9a18..7fb01172a 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -840,7 +840,6 @@ pub async fn check_vote_permission( if community.only_followers_can_vote && !CommunityFollower::is_follower(&mut context.pool(), person.id, community.id).await? { - // TODO: lemmynsfw code checks that follow was at least 10 minutes ago Err(LemmyErrorType::DownvotesAreDisabled)? } Ok(()) diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index 0879421ba..06f14ca99 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -29,18 +29,18 @@ pub async fn list_communities( let page = data.page; let limit = data.limit; let local_user = local_user_view.map(|l| l.local_user); - let communities = CommunityQuery { - listing_type, - show_nsfw, - sort, - local_user: local_user.as_ref(), - page, - limit, - is_mod_or_admin: is_admin, - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let communities = CommunityQuery::builder() + .local_site(local_site) + .listing_type(listing_type) + .show_nsfw(show_nsfw) + .sort(sort) + .local_user(local_user.as_ref()) + .page(page) + .limit(limit) + .is_mod_or_admin(is_admin) + .build() + .list(&mut context.pool()) + .await?; // Return the jwt Ok(Json(ListCommunitiesResponse { communities })) diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 352f97fe1..252d417d7 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -89,12 +89,12 @@ pub async fn get_post( // Fetch the cross_posts let cross_posts = if let Some(url) = &post_view.post.url { - let mut x_posts = PostQuery { - url_search: Some(url.inner().as_str().into()), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let mut x_posts = PostQuery::builder() + .local_site(local_site) + .url_search(Some(url.inner().as_str().into())) + .build() + .list(&mut context.pool()) + .await?; // Don't return this post as one of the cross_posts x_posts.retain(|x| x.post.id != post_id); diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 0649b527c..6afa3c782 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -67,11 +67,9 @@ async fn vote_comment( person_id: actor.id, score: vote_type.into(), }; - let person_id = actor.id; - // TODO: inefficient let post = Post::read(&mut context.pool(), comment.post_id).await?; check_vote_permission(Some(vote_type), &actor, post.community_id, context).await?; - CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; + CommentLike::remove(&mut context.pool(), actor.id, comment_id).await?; CommentLike::like(&mut context.pool(), &like_form).await?; Ok(()) } @@ -102,12 +100,9 @@ async fn undo_vote_comment( comment: &ApubComment, context: &Data, ) -> Result<(), LemmyError> { - let comment_id = comment.id; - let person_id = actor.id; - // TODO: inefficient let post = Post::read(&mut context.pool(), comment.post_id).await?; check_vote_permission(None, &actor, post.community_id, context).await?; - CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; + CommentLike::remove(&mut context.pool(), actor.id, comment.id).await?; Ok(()) } @@ -117,10 +112,8 @@ async fn undo_vote_post( post: &ApubPost, context: &Data, ) -> Result<(), LemmyError> { - let post_id = post.id; - let person_id = actor.id; check_vote_permission(None, &actor, post.community_id, context).await?; - PostLike::remove(&mut context.pool(), person_id, post_id).await?; + PostLike::remove(&mut context.pool(), actor.id, post.id).await?; Ok(()) } diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index dc3618c50..2e4ef2ddc 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -57,22 +57,22 @@ pub async fn list_posts( None }; - let posts = PostQuery { - local_user: local_user_view.as_ref(), - listing_type, - sort, - community_id, - saved_only, - liked_only, - disliked_only, - page, - page_after, - limit, - ..Default::default() - } - .list(&mut context.pool()) - .await - .with_lemmy_type(LemmyErrorType::CouldntGetPosts)?; + let posts = PostQuery::builder() + .local_site(local_site) + .local_user(local_user_view.as_ref()) + .listing_type(listing_type) + .sort(sort) + .community_id(community_id) + .saved_only(saved_only) + .liked_only(liked_only) + .disliked_only(disliked_only) + .page(page) + .page_after(page_after) + .limit(limit) + .build() + .list(&mut context.pool()) + .await + .with_lemmy_type(LemmyErrorType::CouldntGetPosts)?; // if this page wasn't empty, then there is a next page after the last post on this page let next_page = posts.last().map(PaginationCursor::after_post); diff --git a/crates/apub/src/api/read_person.rs b/crates/apub/src/api/read_person.rs index b32fc5b5f..6b89974ed 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -60,18 +60,18 @@ pub async fn read_person( None }; - let posts = PostQuery { - sort, - saved_only, - local_user: local_user_view.as_ref(), - community_id, - page, - limit, - creator_id, - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let posts = PostQuery::builder() + .local_site(local_site) + .local_user(local_user_view.as_ref()) + .sort(sort) + .community_id(community_id) + .saved_only(saved_only) + .page(page) + .limit(limit) + .creator_id(creator_id) + .build() + .list(&mut context.pool()) + .await?; let comments = CommentQuery { local_user: local_user_view.as_ref(), diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index b854a91d1..8fefd4ba3 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -56,19 +56,19 @@ pub async fn search( let local_user = local_user_view.as_ref().map(|l| l.local_user.clone()); match search_type { SearchType::Posts => { - posts = PostQuery { - sort: (sort), - listing_type: (listing_type), - community_id: (community_id), - creator_id: (creator_id), - local_user: (local_user_view.as_ref()), - search_term: (Some(q)), - page: (page), - limit: (limit), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + PostQuery::builder() + .local_site(local_site) + .local_user(local_user_view.as_ref()) + .sort(sort) + .community_id(community_id) + .creator_id(creator_id) + .listing_type(listing_type) + .search_term(Some(q)) + .page(page) + .limit(limit) + .build() + .list(&mut context.pool()) + .await?; } SearchType::Comments => { comments = CommentQuery { @@ -86,18 +86,18 @@ pub async fn search( .await?; } SearchType::Communities => { - communities = CommunityQuery { - 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), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + communities = CommunityQuery::builder() + .local_site(local_site) + .listing_type(listing_type) + .sort(sort) + .local_user(local_user.as_ref()) + .page(page) + .limit(limit) + .search_term(Some(q)) + .is_mod_or_admin(is_admin) + .build() + .list(&mut context.pool()) + .await?; } SearchType::Users => { users = PersonQuery { @@ -116,19 +116,19 @@ pub async fn search( let q = data.q.clone(); - posts = PostQuery { - sort: (sort), - listing_type: (listing_type), - community_id: (community_id), - creator_id: (creator_id), - local_user: (local_user_view.as_ref()), - search_term: (Some(q)), - page: (page), - limit: (limit), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + posts = PostQuery::builder() + .local_site(local_site.clone()) + .local_user(local_user_view.as_ref()) + .sort(sort) + .community_id(community_id) + .creator_id(creator_id) + .listing_type(listing_type) + .search_term(Some(q)) + .page(page) + .limit(limit) + .build() + .list(&mut context.pool()) + .await?; let q = data.q.clone(); @@ -151,18 +151,18 @@ pub async fn search( communities = if community_or_creator_included { vec![] } else { - CommunityQuery { - 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), - ..Default::default() - } - .list(&mut context.pool()) - .await? + CommunityQuery::builder() + .local_site(local_site) + .listing_type(listing_type) + .sort(sort) + .local_user(local_user.as_ref()) + .page(page) + .limit(limit) + .search_term(Some(q)) + .is_mod_or_admin(is_admin) + .build() + .list(&mut context.pool()) + .await? }; let q = data.q.clone(); @@ -181,18 +181,19 @@ pub async fn search( }; } SearchType::Url => { - posts = PostQuery { - sort: (sort), - listing_type: (listing_type), - community_id: (community_id), - creator_id: (creator_id), - url_search: (Some(q)), - page: (page), - limit: (limit), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + posts = PostQuery::builder() + .local_site(local_site) + .local_user(local_user_view.as_ref()) + .sort(sort) + .community_id(community_id) + .creator_id(creator_id) + .listing_type(listing_type) + .search_term(Some(q)) + .page(page) + .limit(limit) + .build() + .list(&mut context.pool()) + .await?; } }; diff --git a/crates/db_views/Cargo.toml b/crates/db_views/Cargo.toml index e5bebed36..f3bfef61d 100644 --- a/crates/db_views/Cargo.toml +++ b/crates/db_views/Cargo.toml @@ -37,6 +37,7 @@ serde_with = { workspace = true } tracing = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true } actix-web = { workspace = true, optional = true } +typed-builder = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 12e5f8603..0ae09271c 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -26,7 +26,6 @@ use lemmy_db_schema::{ community_moderator, community_person_ban, instance_block, - local_site::dsl::local_site, local_user, local_user_language, person, @@ -55,6 +54,7 @@ use lemmy_db_schema::{ SortType, }; use tracing::debug; +use typed_builder::TypedBuilder; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Ord { @@ -386,12 +386,7 @@ fn queries<'a>() -> Queries< } // If there is a content warning, show nsfw content by default. - // TODO: inefficient - let has_content_warning = local_site - .first::(&mut conn) - .await? - .content_warning - .is_some(); + let has_content_warning = options.local_site.content_warning.is_some(); if !options .local_user .map(|l| l.local_user.show_nsfw) @@ -616,8 +611,11 @@ impl PaginationCursor { #[derive(Clone)] pub struct PaginationCursorData(PostAggregates); -#[derive(Default, Clone)] +#[derive(Clone, TypedBuilder)] +#[builder(field_defaults(default))] pub struct PostQuery<'a> { + #[builder(!default)] + pub local_site: LocalSite, pub listing_type: Option, pub sort: Option, pub creator_id: Option, diff --git a/crates/db_views_actor/Cargo.toml b/crates/db_views_actor/Cargo.toml index 066b6bfd3..64192231d 100644 --- a/crates/db_views_actor/Cargo.toml +++ b/crates/db_views_actor/Cargo.toml @@ -34,6 +34,7 @@ ts-rs = { workspace = true, optional = true } chrono.workspace = true strum = { workspace = true } strum_macros = { workspace = true } +typed-builder = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/db_views_actor/src/community_view.rs b/crates/db_views_actor/src/community_view.rs index a7e4350ea..b8ab6bc40 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -18,7 +18,6 @@ use lemmy_db_schema::{ community_block, community_follower, instance_block, - local_site::dsl::local_site, local_user, }, source::{community::CommunityFollower, local_site::LocalSite, local_user::LocalUser}, @@ -26,6 +25,7 @@ use lemmy_db_schema::{ ListingType, SortType, }; +use typed_builder::TypedBuilder; fn queries<'a>() -> Queries< impl ReadFn<'a, CommunityView, (CommunityId, Option, bool)>, @@ -155,12 +155,7 @@ fn queries<'a>() -> Queries< } else { // No person in request, only show nsfw communities if show_nsfw is passed into request or if // site has content warning. - // TODO: inefficient - let has_content_warning = local_site - .first::(&mut conn) - .await? - .content_warning - .is_some(); + let has_content_warning = options.local_site.content_warning.is_some(); if !options.show_nsfw && !has_content_warning { query = query.filter(community::nsfw.eq(false)); } @@ -220,8 +215,11 @@ impl CommunityView { } } -#[derive(Default)] +#[derive(TypedBuilder)] +#[builder(field_defaults(default))] pub struct CommunityQuery<'a> { + #[builder(!default)] + pub local_site: LocalSite, pub listing_type: Option, pub sort: Option, pub local_user: Option<&'a LocalUser>, diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index 56c75a625..3b74efcd7 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -128,15 +128,15 @@ async fn get_feed_data( check_private_instance(&None, &site_view.local_site)?; - let posts = PostQuery { - listing_type: (Some(listing_type)), - sort: (Some(sort_type)), - limit: (Some(limit)), - page: (Some(page)), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let posts = PostQuery::builder() + .local_site(site_view.local_site) + .listing_type(Some(listing_type)) + .sort(Some(sort_type)) + .limit(Some(limit)) + .page(Some(page)) + .build() + .list(&mut context.pool()) + .await?; let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?; @@ -234,16 +234,16 @@ async fn get_feed_user( check_private_instance(&None, &site_view.local_site)?; - let posts = PostQuery { - listing_type: (Some(ListingType::All)), - sort: (Some(*sort_type)), - creator_id: (Some(person.id)), - limit: (Some(*limit)), - page: (Some(*page)), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let posts = PostQuery::builder() + .local_site(site_view.local_site) + .listing_type(Some(ListingType::All)) + .creator_id(Some(person.id)) + .sort(Some(*sort_type)) + .limit(Some(*limit)) + .page(Some(*page)) + .build() + .list(&mut context.pool()) + .await?; let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?; @@ -271,15 +271,15 @@ async fn get_feed_community( check_private_instance(&None, &site_view.local_site)?; - let posts = PostQuery { - sort: (Some(*sort_type)), - community_id: (Some(community.id)), - limit: (Some(*limit)), - page: (Some(*page)), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let posts = PostQuery::builder() + .local_site(site_view.local_site) + .community_id(Some(community.id)) + .sort(Some(*sort_type)) + .limit(Some(*limit)) + .page(Some(*page)) + .build() + .list(&mut context.pool()) + .await?; let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?; @@ -311,16 +311,16 @@ async fn get_feed_front( check_private_instance(&Some(local_user.clone()), &site_view.local_site)?; - let posts = PostQuery { - listing_type: (Some(ListingType::Subscribed)), - local_user: (Some(&local_user)), - sort: (Some(*sort_type)), - limit: (Some(*limit)), - page: (Some(*page)), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + let posts = PostQuery::builder() + .local_site(site_view.local_site) + .listing_type(Some(ListingType::Subscribed)) + .local_user(Some(&local_user)) + .sort(Some(*sort_type)) + .limit(Some(*limit)) + .page(Some(*page)) + .build() + .list(&mut context.pool()) + .await?; let protocol_and_hostname = context.settings().get_protocol_and_hostname(); let items = create_post_items(posts, &protocol_and_hostname)?;