From 2bcef2d9ddeec278003a4a89bdbecf51eb76da42 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 24 Jan 2024 12:31:10 +0100 Subject: [PATCH] change post/community query params --- Cargo.lock | 3 +- crates/api_crud/src/community/list.rs | 31 +- crates/api_crud/src/post/read.rs | 20 +- crates/api_crud/src/site/create.rs | 4 +- crates/api_crud/src/site/update.rs | 4 +- crates/apub/src/api/list_posts.rs | 42 +-- crates/apub/src/api/read_person.rs | 37 +-- crates/apub/src/api/search.rs | 142 ++++----- crates/apub/src/objects/instance.rs | 2 + crates/apub/src/protocol/objects/instance.rs | 2 + crates/db_schema/src/schema.rs | 2 +- crates/db_schema/src/source/local_site.rs | 5 - crates/db_schema/src/source/site.rs | 5 + crates/db_views/Cargo.toml | 2 +- crates/db_views/src/post_view.rs | 282 +++++++++--------- crates/db_views_actor/Cargo.toml | 1 - crates/db_views_actor/src/community_view.rs | 22 +- crates/routes/src/feeds.rs | 76 ++--- crates/routes/src/images.rs | 8 - .../down.sql | 2 +- .../up.sql | 2 +- 21 files changed, 341 insertions(+), 353 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e657a31548..4b54af59da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2708,7 +2708,7 @@ dependencies = [ "tokio", "tracing", "ts-rs", - "typed-builder", + "url", ] [[package]] @@ -2727,7 +2727,6 @@ dependencies = [ "strum_macros", "tokio", "ts-rs", - "typed-builder", ] [[package]] diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index 06f14ca992..7990352fcb 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -4,8 +4,7 @@ use lemmy_api_common::{ context::LemmyContext, utils::{check_private_instance, is_admin}, }; -use lemmy_db_schema::source::local_site::LocalSite; -use lemmy_db_views::structs::LocalUserView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_db_views_actor::community_view::CommunityQuery; use lemmy_utils::error::LemmyError; @@ -15,13 +14,13 @@ pub async fn list_communities( context: Data, local_user_view: Option, ) -> Result, LemmyError> { - let local_site = LocalSite::read(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()).await?; let is_admin = local_user_view .as_ref() .map(|luv| is_admin(luv).is_ok()) .unwrap_or_default(); - check_private_instance(&local_user_view, &local_site)?; + check_private_instance(&local_user_view, &local_site.local_site)?; let sort = data.sort; let listing_type = data.type_; @@ -29,18 +28,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::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?; + 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(&local_site.site, &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 252d417d7b..e701008b73 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -6,12 +6,12 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm}, - source::{comment::Comment, local_site::LocalSite, post::Post}, + source::{comment::Comment, post::Post}, traits::Crud, }; use lemmy_db_views::{ post_view::PostQuery, - structs::{LocalUserView, PostView}, + structs::{LocalUserView, PostView, SiteView}, }; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -22,9 +22,9 @@ pub async fn get_post( context: Data, local_user_view: Option, ) -> Result, LemmyError> { - let local_site = LocalSite::read(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()).await?; - check_private_instance(&local_user_view, &local_site)?; + check_private_instance(&local_user_view, &local_site.local_site)?; let person_id = local_user_view.as_ref().map(|u| u.person.id); @@ -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::builder() - .local_site(local_site) - .url_search(Some(url.inner().as_str().into())) - .build() - .list(&mut context.pool()) - .await?; + let mut x_posts = PostQuery { + url_search: Some(url.inner().as_str().into()), + ..Default::default() + } + .list(&local_site.site, &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/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 7c1dc9e6c6..886f54e477 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -61,6 +61,7 @@ pub async fn create_site( inbox_url, private_key: Some(Some(keypair.private_key)), public_key: Some(keypair.public_key), + content_warning: diesel_option_overwrite(data.content_warning.clone()), ..Default::default() }; @@ -89,7 +90,6 @@ pub async fn create_site( federation_enabled: data.federation_enabled, captcha_enabled: data.captcha_enabled, captcha_difficulty: data.captcha_difficulty.clone(), - content_warning: diesel_option_overwrite(data.content_warning.clone()), default_post_listing_mode: data.default_post_listing_mode, ..Default::default() }; @@ -559,7 +559,7 @@ mod tests { taglines: None, registration_mode: site_registration_mode, content_warning: None, - auto_expand_images: None, + default_post_listing_mode: None, } } } diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index 454c879086..1c06fceec7 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -60,6 +60,7 @@ pub async fn update_site( description: diesel_option_overwrite(data.description.clone()), icon: diesel_option_overwrite_to_url(&data.icon)?, banner: diesel_option_overwrite_to_url(&data.banner)?, + content_warning: diesel_option_overwrite(data.content_warning.clone()), updated: Some(Some(naive_now())), ..Default::default() }; @@ -90,7 +91,6 @@ pub async fn update_site( captcha_enabled: data.captcha_enabled, captcha_difficulty: data.captcha_difficulty.clone(), reports_email_admins: data.reports_email_admins, - content_warning: diesel_option_overwrite(data.content_warning.clone()), default_post_listing_mode: data.default_post_listing_mode, ..Default::default() }; @@ -558,7 +558,7 @@ mod tests { registration_mode: site_registration_mode, reports_email_admins: None, content_warning: None, - auto_expand_images: None, + default_post_listing_mode: None, } } } diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 2e4ef2ddcd..d4ed566c49 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -10,10 +10,10 @@ use lemmy_api_common::{ post::{GetPosts, GetPostsResponse}, utils::check_private_instance, }; -use lemmy_db_schema::source::{community::Community, local_site::LocalSite}; +use lemmy_db_schema::source::community::Community; use lemmy_db_views::{ post_view::PostQuery, - structs::{LocalUserView, PaginationCursor}, + structs::{LocalUserView, PaginationCursor, SiteView}, }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -23,9 +23,9 @@ pub async fn list_posts( context: Data, local_user_view: Option, ) -> Result, LemmyError> { - let local_site = LocalSite::read(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()).await?; - check_private_instance(&local_user_view, &local_site)?; + check_private_instance(&local_user_view, &local_site.local_site)?; let sort = data.sort; @@ -47,7 +47,7 @@ pub async fn list_posts( let listing_type = Some(listing_type_with_default( data.type_, - &local_site, + &local_site.local_site, community_id, )?); // parse pagination token @@ -57,22 +57,22 @@ pub async fn list_posts( None }; - 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)?; + 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(&local_site.site, &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 6b89974edd..107212e890 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -6,11 +6,12 @@ use lemmy_api_common::{ person::{GetPersonDetails, GetPersonDetailsResponse}, utils::check_private_instance, }; -use lemmy_db_schema::{ - source::{local_site::LocalSite, person::Person}, - utils::post_to_comment_sort_type, +use lemmy_db_schema::{source::person::Person, utils::post_to_comment_sort_type}; +use lemmy_db_views::{ + comment_view::CommentQuery, + post_view::PostQuery, + structs::{LocalUserView, SiteView}, }; -use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery, structs::LocalUserView}; use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType}; @@ -25,9 +26,9 @@ pub async fn read_person( Err(LemmyErrorType::NoIdGiven)? } - let local_site = LocalSite::read(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()).await?; - check_private_instance(&local_user_view, &local_site)?; + check_private_instance(&local_user_view, &local_site.local_site)?; let person_details_id = match data.person_id { Some(id) => id, @@ -60,18 +61,18 @@ pub async fn read_person( None }; - 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 posts = PostQuery { + sort, + saved_only, + local_user: local_user_view.as_ref(), + community_id, + page, + limit, + creator_id, + ..Default::default() + } + .list(&local_site.site, &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 8fefd4ba3e..dff2dffeba 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -6,12 +6,12 @@ use lemmy_api_common::{ site::{Search, SearchResponse}, utils::{check_private_instance, is_admin}, }; -use lemmy_db_schema::{ - source::{community::Community, local_site::LocalSite}, - utils::post_to_comment_sort_type, - SearchType, +use lemmy_db_schema::{source::community::Community, utils::post_to_comment_sort_type, SearchType}; +use lemmy_db_views::{ + comment_view::CommentQuery, + post_view::PostQuery, + structs::{LocalUserView, SiteView}, }; -use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery, structs::LocalUserView}; use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery}; use lemmy_utils::error::LemmyError; @@ -21,9 +21,9 @@ pub async fn search( context: Data, local_user_view: Option, ) -> Result, LemmyError> { - let local_site = LocalSite::read(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()).await?; - check_private_instance(&local_user_view, &local_site)?; + check_private_instance(&local_user_view, &local_site.local_site)?; let is_admin = local_user_view .as_ref() @@ -53,22 +53,23 @@ pub async fn search( data.community_id }; let creator_id = data.creator_id; - let local_user = local_user_view.as_ref().map(|l| l.local_user.clone()); + let local_user = local_user_view.as_ref().map(|luv| &luv.local_user); + match search_type { SearchType::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?; + 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(&local_site.site, &mut context.pool()) + .await?; } SearchType::Comments => { comments = CommentQuery { @@ -86,18 +87,18 @@ pub async fn search( .await?; } SearchType::Communities => { - 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?; + communities = CommunityQuery { + sort: (sort), + listing_type: (listing_type), + search_term: (Some(q)), + local_user, + is_mod_or_admin: (is_admin), + page: (page), + limit: (limit), + ..Default::default() + } + .list(&local_site.site, &mut context.pool()) + .await?; } SearchType::Users => { users = PersonQuery { @@ -116,19 +117,19 @@ pub async fn search( let q = data.q.clone(); - 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?; + 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(&local_site.site, &mut context.pool()) + .await?; let q = data.q.clone(); @@ -151,18 +152,18 @@ pub async fn search( communities = if community_or_creator_included { vec![] } else { - 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? + CommunityQuery { + sort: (sort), + listing_type: (listing_type), + search_term: (Some(q)), + local_user, + is_mod_or_admin: (is_admin), + page: (page), + limit: (limit), + ..Default::default() + } + .list(&local_site.site, &mut context.pool()) + .await? }; let q = data.q.clone(); @@ -181,19 +182,18 @@ pub async fn search( }; } SearchType::Url => { - 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?; + 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(&local_site.site, &mut context.pool()) + .await?; } }; diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs index 392b86bd92..af00664d61 100644 --- a/crates/apub/src/objects/instance.rs +++ b/crates/apub/src/objects/instance.rs @@ -102,6 +102,7 @@ impl Object for ApubSite { outbox: Url::parse(&format!("{}/site_outbox", self.actor_id))?, public_key: self.public_key(), language, + content_warning: self.content_warning.clone(), published: self.published, updated: self.updated, }; @@ -145,6 +146,7 @@ impl Object for ApubSite { public_key: Some(apub.public_key.public_key_pem.clone()), private_key: None, instance_id: instance.id, + content_warning: apub.content_warning, }; let languages = LanguageTag::to_language_id_multiple(apub.language, &mut data.pool()).await?; diff --git a/crates/apub/src/protocol/objects/instance.rs b/crates/apub/src/protocol/objects/instance.rs index 8c9944306f..17623719cb 100644 --- a/crates/apub/src/protocol/objects/instance.rs +++ b/crates/apub/src/protocol/objects/instance.rs @@ -39,6 +39,8 @@ pub struct Instance { pub(crate) image: Option, #[serde(default)] pub(crate) language: Vec, + /// nonstandard field + pub(crate) content_warning: Option, pub(crate) published: DateTime, pub(crate) updated: Option>, } diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 47ea84dac4..990b38d6f8 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -373,7 +373,6 @@ diesel::table! { registration_mode -> RegistrationModeEnum, reports_email_admins -> Bool, federation_signed_fetch -> Bool, - content_warning -> Nullable, default_post_listing_mode -> PostListingModeEnum, } } @@ -855,6 +854,7 @@ diesel::table! { private_key -> Nullable, public_key -> Text, instance_id -> Int4, + content_warning -> Nullable, } } diff --git a/crates/db_schema/src/source/local_site.rs b/crates/db_schema/src/source/local_site.rs index a56ea55cb8..ea3dbc1790 100644 --- a/crates/db_schema/src/source/local_site.rs +++ b/crates/db_schema/src/source/local_site.rs @@ -65,9 +65,6 @@ pub struct LocalSite { /// Whether to sign outgoing Activitypub fetches with private key of local instance. Some /// Fediverse instances and platforms require this. pub federation_signed_fetch: bool, - /// If present, nsfw content is visible by default. Should be displayed by frontends/clients - /// when the site is first opened by a user. - pub content_warning: Option, /// Default value for [LocalUser.post_listing_mode] pub default_post_listing_mode: PostListingMode, } @@ -99,7 +96,6 @@ pub struct LocalSiteInsertForm { pub registration_mode: Option, pub reports_email_admins: Option, pub federation_signed_fetch: Option, - pub content_warning: Option, pub default_post_listing_mode: Option, } @@ -128,6 +124,5 @@ pub struct LocalSiteUpdateForm { pub reports_email_admins: Option, pub updated: Option>>, pub federation_signed_fetch: Option, - pub content_warning: Option>, pub default_post_listing_mode: Option, } diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 14b9318476..754acb2aa4 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -37,6 +37,9 @@ pub struct Site { pub private_key: Option, pub public_key: String, pub instance_id: InstanceId, + /// If present, nsfw content is visible by default. Should be displayed by frontends/clients + /// when the site is first opened by a user. + pub content_warning: Option, } #[derive(Clone, TypedBuilder)] @@ -58,6 +61,7 @@ pub struct SiteInsertForm { pub public_key: Option, #[builder(!default)] pub instance_id: InstanceId, + pub content_warning: Option, } #[derive(Clone, Default)] @@ -76,4 +80,5 @@ pub struct SiteUpdateForm { pub inbox_url: Option, pub private_key: Option>, pub public_key: Option, + pub content_warning: Option>, } diff --git a/crates/db_views/Cargo.toml b/crates/db_views/Cargo.toml index f3bfef61d9..8bce6de33a 100644 --- a/crates/db_views/Cargo.toml +++ b/crates/db_views/Cargo.toml @@ -37,7 +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 } +url = { 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 3fe81de18a..29e262cee7 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -37,7 +37,7 @@ use lemmy_db_schema::{ post_read, post_saved, }, - source::local_site::LocalSite, + source::site::Site, utils::{ functions::coalesce, fuzzy_search, @@ -54,7 +54,6 @@ use lemmy_db_schema::{ SortType, }; use tracing::debug; -use typed_builder::TypedBuilder; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Ord { @@ -86,7 +85,7 @@ macro_rules! field { fn queries<'a>() -> Queries< impl ReadFn<'a, PostView, (PostId, Option, bool)>, - impl ListFn<'a, PostView, PostQuery<'a>>, + impl ListFn<'a, PostView, (PostQuery<'a>, &'a Site)>, > { let is_creator_banned_from_community = exists( community_person_ban::table.filter( @@ -287,7 +286,7 @@ fn queries<'a>() -> Queries< query.first::(&mut conn).await }; - let list = move |mut conn: DbConn<'a>, options: PostQuery<'a>| async move { + let list = move |mut conn: DbConn<'a>, (options, site): (PostQuery<'a>, &'a Site)| async move { let my_person_id = options.local_user.map(|l| l.person.id); let my_local_user_id = options.local_user.map(|l| l.local_user.id); @@ -386,7 +385,7 @@ fn queries<'a>() -> Queries< } // If there is a content warning, show nsfw content by default. - let has_content_warning = options.local_site.content_warning.is_some(); + let has_content_warning = site.content_warning.is_some(); if !options .local_user .map(|l| l.local_user.show_nsfw) @@ -611,11 +610,8 @@ impl PaginationCursor { #[derive(Clone)] pub struct PaginationCursorData(PostAggregates); -#[derive(Clone, TypedBuilder)] -#[builder(field_defaults(default))] +#[derive(Clone, Default)] pub struct PostQuery<'a> { - #[builder(!default)] - pub local_site: LocalSite, pub listing_type: Option, pub sort: Option, pub creator_id: Option, @@ -637,6 +633,7 @@ pub struct PostQuery<'a> { impl<'a> PostQuery<'a> { async fn prefetch_upper_bound_for_page_before( &self, + site: &Site, pool: &mut DbPool<'_>, ) -> Result>, Error> { // first get one page for the most popular community to get an upper bound for the the page end for the real query @@ -687,11 +684,14 @@ impl<'a> PostQuery<'a> { let mut v = queries() .list( pool, - PostQuery { - community_id: Some(largest_subscribed), - community_id_just_for_prefetch: true, - ..self.clone() - }, + ( + PostQuery { + community_id: Some(largest_subscribed), + community_id_just_for_prefetch: true, + ..self.clone() + }, + site, + ), ) .await?; // take last element of array. if this query returned less than LIMIT elements, @@ -707,19 +707,22 @@ impl<'a> PostQuery<'a> { } } - pub async fn list(self, pool: &mut DbPool<'_>) -> Result, Error> { + pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result, Error> { if self.listing_type == Some(ListingType::Subscribed) && self.community_id.is_none() && self.local_user.is_some() && self.page_before_or_equal.is_none() { - if let Some(query) = self.prefetch_upper_bound_for_page_before(pool).await? { - queries().list(pool, query).await + if let Some(query) = self + .prefetch_upper_bound_for_page_before(site, pool) + .await? + { + queries().list(pool, (query, site)).await } else { Ok(vec![]) } } else { - queries().list(pool, self).await + queries().list(pool, (self, site)).await } } } @@ -727,7 +730,7 @@ impl<'a> PostQuery<'a> { #[cfg(test)] mod tests { use crate::{ - post_view::{PaginationCursorData, PostQuery, PostQueryBuilder, PostView}, + post_view::{PaginationCursorData, PostQuery, PostView}, structs::LocalUserView, }; use chrono::Utc; @@ -743,11 +746,11 @@ mod tests { instance::Instance, instance_block::{InstanceBlock, InstanceBlockForm}, language::Language, - local_site::LocalSite, local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm}, person::{Person, PersonInsertForm}, person_block::{PersonBlock, PersonBlockForm}, post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm}, + site::Site, }, traits::{Blockable, Crud, Joinable, Likeable}, utils::{build_db_pool, DbPool, RANK_DEFAULT}, @@ -758,6 +761,7 @@ mod tests { use pretty_assertions::assert_eq; use serial_test::serial; use std::{collections::HashSet, time::Duration}; + use url::Url; const POST_BY_BLOCKED_PERSON: &str = "post by blocked person"; const POST_BY_BOT: &str = "post by bot"; @@ -775,37 +779,16 @@ mod tests { inserted_community: Community, inserted_post: Post, inserted_bot_post: Post, + site: Site, } impl Data { - #[allow(clippy::type_complexity)] - fn default_post_query( - local_user: Option<&LocalUserView>, - ) -> PostQueryBuilder< - '_, - ( - (LocalSite,), - (), - (Option,), - (), - (), - (), - (Option<&LocalUserView>,), - (), - (), - (), - (), - (), - (), - (), - (), - (), - ), - > { - PostQuery::builder() - .local_site(Default::default()) - .sort(Some(SortType::New)) - .local_user(local_user) + fn default_post_query(&self) -> PostQuery<'_> { + PostQuery { + sort: Some(SortType::New), + local_user: Some(&self.local_user_view), + ..Default::default() + } } } @@ -906,6 +889,24 @@ mod tests { counts: Default::default(), }; + let site = Site { + id: Default::default(), + name: String::new(), + sidebar: None, + published: Default::default(), + updated: None, + icon: None, + banner: None, + description: None, + actor_id: Url::parse("http://example.com")?.into(), + last_refreshed_at: Default::default(), + inbox_url: Url::parse("http://example.com")?.into(), + private_key: None, + public_key: String::new(), + instance_id: Default::default(), + content_warning: None, + }; + Ok(Data { inserted_instance, local_user_view, @@ -914,6 +915,7 @@ mod tests { inserted_community, inserted_post, inserted_bot_post, + site, }) } @@ -932,11 +934,12 @@ mod tests { LocalUser::update(pool, data.local_user_view.local_user.id, &local_user_form).await?; data.local_user_view.local_user = inserted_local_user; - let read_post_listing = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await?; + let read_post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; let post_listing_single_with_person = PostView::read( pool, @@ -966,11 +969,12 @@ mod tests { LocalUser::update(pool, data.local_user_view.local_user.id, &local_user_form).await?; data.local_user_view.local_user = inserted_local_user; - let post_listings_with_bots = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await?; + let post_listings_with_bots = PostQuery { + community_id: Some(data.inserted_community.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; // should include bot post which has "undetermined" language assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_with_bots)); @@ -984,11 +988,13 @@ mod tests { let pool = &mut pool.into(); let data = init_data(pool).await?; - let read_post_listing_multiple_no_person = Data::default_post_query(None) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await?; + let read_post_listing_multiple_no_person = PostQuery { + community_id: Some(data.inserted_community.id), + local_user: None, + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; let read_post_listing_single_no_person = PostView::read(pool, data.inserted_post.id, None, false).await?; @@ -1026,12 +1032,12 @@ mod tests { }; CommunityBlock::block(pool, &community_block).await?; - let read_post_listings_with_person_after_block = - Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await?; + let read_post_listings_with_person_after_block = PostQuery { + community_id: Some(data.inserted_community.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; // Should be 0 posts after the community block assert_eq!(read_post_listings_with_person_after_block, vec![]); @@ -1084,27 +1090,30 @@ mod tests { LocalUser::update(pool, data.local_user_view.local_user.id, &local_user_form).await?; data.local_user_view.local_user = inserted_local_user; - let read_post_listing = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await?; + let read_post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; assert_eq!(vec![expected_post_with_upvote], read_post_listing); - let read_liked_post_listing = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .liked_only(true) - .build() - .list(pool) - .await?; + let read_liked_post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + liked_only: true, + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; assert_eq!(read_post_listing, read_liked_post_listing); - let read_disliked_post_listing = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .disliked_only(true) - .build() - .list(pool) - .await?; + let read_disliked_post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + disliked_only: true, + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; assert_eq!(read_disliked_post_listing, vec![]); let like_removed = @@ -1129,14 +1138,15 @@ mod tests { }; CommunityModerator::join(pool, &form).await?; - let post_listing = Data::default_post_query(Some(&data.local_user_view)) - .community_id(Some(data.inserted_community.id)) - .build() - .list(pool) - .await? - .into_iter() - .map(|p| (p.creator.name, p.creator_is_moderator, p.creator_is_admin)) - .collect::>(); + let post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await? + .into_iter() + .map(|p| (p.creator.name, p.creator_is_moderator, p.creator_is_admin)) + .collect::>(); let expected_post_listing = vec![ ("mybot".to_owned(), false, false), @@ -1174,20 +1184,14 @@ mod tests { Post::create(pool, &post_spanish).await?; - let post_listings_all = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_all = data.default_post_query().list(&data.site, pool).await?; // no language filters specified, all posts should be returned assert_eq!(vec![EL_POSTO, POST_BY_BOT, POST], names(&post_listings_all)); LocalUserLanguage::update(pool, vec![french_id], data.local_user_view.local_user.id).await?; - let post_listing_french = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listing_french = data.default_post_query().list(&data.site, pool).await?; // only one post in french and one undetermined should be returned assert_eq!(vec![POST_BY_BOT, POST], names(&post_listing_french)); @@ -1202,9 +1206,9 @@ mod tests { data.local_user_view.local_user.id, ) .await?; - let post_listings_french_und = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) + let post_listings_french_und = data + .default_post_query() + .list(&data.site, pool) .await? .into_iter() .map(|p| (p.post.name, p.post.language_id)) @@ -1239,19 +1243,17 @@ mod tests { .await?; // Make sure you don't see the removed post in the results - let post_listings_no_admin = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_no_admin = data.default_post_query().list(&data.site, pool).await?; assert_eq!(vec![POST], names(&post_listings_no_admin)); // Removed bot post is shown to admins on its profile page data.local_user_view.local_user.admin = true; - let post_listings_is_admin = Data::default_post_query(Some(&data.local_user_view)) - .creator_id(Some(data.inserted_bot.id)) - .build() - .list(pool) - .await?; + let post_listings_is_admin = PostQuery { + creator_id: Some(data.inserted_bot.id), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; assert_eq!(vec![POST_BY_BOT], names(&post_listings_is_admin)); cleanup(data, pool).await @@ -1281,12 +1283,14 @@ mod tests { (Some(&data.blocked_local_user_view), false), (Some(&data.local_user_view), true), ] { - let contains_deleted = Data::default_post_query(local_user) - .build() - .list(pool) - .await? - .iter() - .any(|p| p.post.id == data.inserted_post.id); + let contains_deleted = PostQuery { + local_user, + ..data.default_post_query() + } + .list(&data.site, pool) + .await? + .iter() + .any(|p| p.post.id == data.inserted_post.id); assert_eq!(expect_contains_deleted, contains_deleted); } @@ -1323,10 +1327,7 @@ mod tests { let post_from_blocked_instance = Post::create(pool, &post_form).await?; // no instance block, should return all posts - let post_listings_all = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_all = data.default_post_query().list(&data.site, pool).await?; assert_eq!( vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST], names(&post_listings_all) @@ -1340,10 +1341,7 @@ mod tests { InstanceBlock::block(pool, &block_form).await?; // now posts from communities on that instance should be hidden - let post_listings_blocked = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_blocked = data.default_post_query().list(&data.site, pool).await?; assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_blocked)); assert!(post_listings_blocked .iter() @@ -1351,10 +1349,7 @@ mod tests { // after unblocking it should return all posts again InstanceBlock::unblock(pool, &block_form).await?; - let post_listings_blocked = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_blocked = data.default_post_query().list(&data.site, pool).await?; assert_eq!( vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST], names(&post_listings_blocked) @@ -1411,15 +1406,15 @@ mod tests { let mut listed_post_ids = vec![]; let mut page_after = None; loop { - let post_listings = PostQuery::builder() - .local_site(LocalSite::default()) - .community_id(Some(inserted_community.id)) - .sort(Some(SortType::MostComments)) - .limit(Some(10)) - .page_after(page_after) - .build() - .list(pool) - .await?; + let post_listings = PostQuery { + community_id: Some(inserted_community.id), + sort: Some(SortType::MostComments), + limit: Some(10), + page_after, + ..Default::default() + } + .list(&data.site, pool) + .await?; listed_post_ids.extend(post_listings.iter().map(|p| p.post.id)); @@ -1464,10 +1459,7 @@ mod tests { .await?; // Make sure you don't see the read post in the results - let post_listings_hide_read = Data::default_post_query(Some(&data.local_user_view)) - .build() - .list(pool) - .await?; + let post_listings_hide_read = data.default_post_query().list(&data.site, pool).await?; assert_eq!(vec![POST], names(&post_listings_hide_read)); cleanup(data, pool).await diff --git a/crates/db_views_actor/Cargo.toml b/crates/db_views_actor/Cargo.toml index 64192231d0..066b6bfd39 100644 --- a/crates/db_views_actor/Cargo.toml +++ b/crates/db_views_actor/Cargo.toml @@ -34,7 +34,6 @@ 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 b8ab6bc409..1e165cdecd 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -20,16 +20,20 @@ use lemmy_db_schema::{ instance_block, local_user, }, - source::{community::CommunityFollower, local_site::LocalSite, local_user::LocalUser}, + source::{ + community::CommunityFollower, + local_site::LocalSite, + local_user::LocalUser, + site::Site, + }, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, ListingType, SortType, }; -use typed_builder::TypedBuilder; fn queries<'a>() -> Queries< impl ReadFn<'a, CommunityView, (CommunityId, Option, bool)>, - impl ListFn<'a, CommunityView, CommunityQuery<'a>>, + impl ListFn<'a, CommunityView, (CommunityQuery<'a>, &'a Site)>, > { let all_joins = |query: community::BoxedQuery<'a, Pg>, my_person_id: Option| { // The left join below will return None in this case @@ -91,7 +95,7 @@ fn queries<'a>() -> Queries< query.first::(&mut conn).await }; - let list = move |mut conn: DbConn<'a>, options: CommunityQuery<'a>| async move { + let list = move |mut conn: DbConn<'a>, (options, site): (CommunityQuery<'a>, &'a Site)| async move { use SortType::*; let my_person_id = options.local_user.map(|l| l.person_id); @@ -155,7 +159,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. - let has_content_warning = options.local_site.content_warning.is_some(); + let has_content_warning = site.content_warning.is_some(); if !options.show_nsfw && !has_content_warning { query = query.filter(community::nsfw.eq(false)); } @@ -215,10 +219,8 @@ impl CommunityView { } } -#[derive(TypedBuilder)] -#[builder(field_defaults(default))] +#[derive(Default)] pub struct CommunityQuery<'a> { - #[builder(!default)] pub local_site: LocalSite, pub listing_type: Option, pub sort: Option, @@ -231,7 +233,7 @@ pub struct CommunityQuery<'a> { } impl<'a> CommunityQuery<'a> { - pub async fn list(self, pool: &mut DbPool<'_>) -> Result, Error> { - queries().list(pool, self).await + pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result, Error> { + queries().list(pool, (self, site)).await } } diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index 3b74efcd7d..307d00af3f 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::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 posts = PostQuery { + listing_type: (Some(listing_type)), + sort: (Some(sort_type)), + limit: (Some(limit)), + page: (Some(page)), + ..Default::default() + } + .list(&site_view.site, &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::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 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(&site_view.site, &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::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 posts = PostQuery { + sort: (Some(*sort_type)), + community_id: (Some(community.id)), + limit: (Some(*limit)), + page: (Some(*page)), + ..Default::default() + } + .list(&site_view.site, &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::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 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(&site_view.site, &mut context.pool()) + .await?; let protocol_and_hostname = context.settings().get_protocol_and_hostname(); let items = create_post_items(posts, &protocol_and_hostname)?; diff --git a/crates/routes/src/images.rs b/crates/routes/src/images.rs index 6b5d9d958f..16b388ca6f 100644 --- a/crates/routes/src/images.rs +++ b/crates/routes/src/images.rs @@ -58,14 +58,6 @@ struct PictrsParams { thumbnail: Option, } -#[derive(Deserialize)] -enum PictrsPurgeParams { - #[serde(rename = "file")] - File(String), - #[serde(rename = "alias")] - Alias(String), -} - fn adapt_request( request: &HttpRequest, client: &ClientWithMiddleware, diff --git a/migrations/2024-01-22-105746_lemmynsfw-changes/down.sql b/migrations/2024-01-22-105746_lemmynsfw-changes/down.sql index 482784b8a0..717f935d87 100644 --- a/migrations/2024-01-22-105746_lemmynsfw-changes/down.sql +++ b/migrations/2024-01-22-105746_lemmynsfw-changes/down.sql @@ -1,4 +1,4 @@ -ALTER TABLE local_site +ALTER TABLE site DROP COLUMN content_warning; ALTER TABLE local_site diff --git a/migrations/2024-01-22-105746_lemmynsfw-changes/up.sql b/migrations/2024-01-22-105746_lemmynsfw-changes/up.sql index 9017a3954c..ccbd6d49c3 100644 --- a/migrations/2024-01-22-105746_lemmynsfw-changes/up.sql +++ b/migrations/2024-01-22-105746_lemmynsfw-changes/up.sql @@ -1,4 +1,4 @@ -ALTER TABLE local_site +ALTER TABLE site ADD COLUMN content_warning text; ALTER TABLE local_site