X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fdb_views%2Fsrc%2Fpost_view.rs;h=761925a9cd36ec6ce534db8abcee9c93f897fbab;hb=e4a49b6eabcf34fb4adfa7ccd4024e5ddda93d54;hp=c9b4721723b297c4b706e7c5d3bff4c9af1e19fe;hpb=c89006c94a4ec5aab2bf387d7605d92a565f8184;p=lemmy.git diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index c9b47217..761925a9 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -2,12 +2,14 @@ use crate::structs::PostView; use diesel::{dsl::*, pg::Pg, result::Error, *}; use lemmy_db_schema::{ aggregates::structs::PostAggregates, - newtypes::{CommunityId, DbUrl, PersonId, PostId}, + newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId}, schema::{ community, community_block, community_follower, community_person_ban, + language, + local_user_language, person, person_block, post, @@ -18,6 +20,7 @@ use lemmy_db_schema::{ }, source::{ community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe}, + language::Language, person::{Person, PersonSafe}, person_block::PersonBlock, post::{Post, PostRead, PostSaved}, @@ -41,6 +44,7 @@ type PostViewTuple = ( Option, Option, Option, + Language, ); impl PostView { @@ -51,7 +55,6 @@ impl PostView { ) -> Result { // The left join below will return None in this case let person_id_join = my_person_id.unwrap_or(PersonId(-1)); - let ( post, creator, @@ -63,6 +66,7 @@ impl PostView { read, creator_blocked, post_like, + language, ) = post::table .find(post_id) .inner_join(person::table) @@ -115,6 +119,7 @@ impl PostView { .and(post_like::person_id.eq(person_id_join)), ), ) + .inner_join(language::table) .select(( post::all_columns, Person::safe_columns_tuple(), @@ -126,6 +131,7 @@ impl PostView { post_read::all_columns.nullable(), person_block::all_columns.nullable(), post_like::score.nullable(), + language::all_columns, )) .first::(conn)?; @@ -148,6 +154,7 @@ impl PostView { read: read.is_some(), creator_blocked: creator_blocked.is_some(), my_vote, + language, }) } } @@ -163,6 +170,7 @@ pub struct PostQuery<'a> { community_id: Option, community_actor_id: Option, my_person_id: Option, + my_local_user_id: Option, search_term: Option, url_search: Option, show_nsfw: Option, @@ -179,6 +187,7 @@ impl<'a> PostQuery<'a> { // The left join below will return None in this case let person_id_join = self.my_person_id.unwrap_or(PersonId(-1)); + let local_user_id_join = self.my_local_user_id.unwrap_or(LocalUserId(-1)); let mut query = post::table .inner_join(person::table) @@ -238,6 +247,14 @@ impl<'a> PostQuery<'a> { .and(post_like::person_id.eq(person_id_join)), ), ) + .inner_join(language::table) + .left_join( + local_user_language::table.on( + post::language_id + .eq(local_user_language::language_id) + .and(local_user_language::local_user_id.eq(local_user_id_join)), + ), + ) .select(( post::all_columns, Person::safe_columns_tuple(), @@ -249,6 +266,7 @@ impl<'a> PostQuery<'a> { post_read::all_columns.nullable(), person_block::all_columns.nullable(), post_like::score.nullable(), + language::all_columns, )) .into_boxed(); @@ -323,6 +341,11 @@ impl<'a> PostQuery<'a> { query = query.filter(post_read::id.is_null()); } + // Filter out the rows with missing languages + if self.my_local_user_id.is_some() { + query = query.filter(local_user_language::id.is_not_null()); + } + // Don't show blocked communities or persons if self.my_person_id.is_some() { query = query.filter(community_block::person_id.is_null()); @@ -403,6 +426,7 @@ impl ViewToVec for PostView { read: a.7.is_some(), creator_blocked: a.8.is_some(), my_vote: a.9, + language: a.10, }) .collect::>() } @@ -411,11 +435,16 @@ impl ViewToVec for PostView { #[cfg(test)] mod tests { use crate::post_view::{PostQuery, PostView}; + use diesel::PgConnection; use lemmy_db_schema::{ aggregates::structs::PostAggregates, + newtypes::LanguageId, source::{ community::*, community_block::{CommunityBlock, CommunityBlockForm}, + language::Language, + local_user::{LocalUser, LocalUserForm}, + local_user_language::LocalUserLanguage, person::*, person_block::{PersonBlock, PersonBlockForm}, post::*, @@ -427,15 +456,16 @@ mod tests { }; use serial_test::serial; - #[test] - #[serial] - fn test_crud() { - let conn = establish_unpooled_connection(); + struct Data { + inserted_person: Person, + inserted_blocked_person: Person, + inserted_bot: Person, + inserted_community: Community, + inserted_post: Post, + } + fn init_data(conn: &PgConnection) -> Data { let person_name = "tegan".to_string(); - let community_name = "test_community_3".to_string(); - let post_name = "test post 3".to_string(); - let bot_post_name = "test bot post".to_string(); let new_person = PersonForm { name: person_name.to_owned(), @@ -443,43 +473,44 @@ mod tests { ..PersonForm::default() }; - let inserted_person = Person::create(&conn, &new_person).unwrap(); + let inserted_person = Person::create(conn, &new_person).unwrap(); let new_bot = PersonForm { - name: person_name.to_owned(), + name: "mybot".to_string(), bot_account: Some(true), public_key: Some("pubkey".to_string()), ..PersonForm::default() }; - let inserted_bot = Person::create(&conn, &new_bot).unwrap(); + let inserted_bot = Person::create(conn, &new_bot).unwrap(); let new_community = CommunityForm { - name: community_name.to_owned(), + name: "test_community_3".to_string(), title: "nada".to_owned(), public_key: Some("pubkey".to_string()), ..CommunityForm::default() }; - let inserted_community = Community::create(&conn, &new_community).unwrap(); + let inserted_community = Community::create(conn, &new_community).unwrap(); // Test a person block, make sure the post query doesn't include their post let blocked_person = PersonForm { - name: person_name.to_owned(), + name: person_name, public_key: Some("pubkey".to_string()), ..PersonForm::default() }; - let inserted_blocked_person = Person::create(&conn, &blocked_person).unwrap(); + let inserted_blocked_person = Person::create(conn, &blocked_person).unwrap(); let post_from_blocked_person = PostForm { name: "blocked_person_post".to_string(), creator_id: inserted_blocked_person.id, community_id: inserted_community.id, + language_id: Some(LanguageId(1)), ..PostForm::default() }; - Post::create(&conn, &post_from_blocked_person).unwrap(); + Post::create(conn, &post_from_blocked_person).unwrap(); // block that person let person_block = PersonBlockForm { @@ -487,72 +518,58 @@ mod tests { target_id: inserted_blocked_person.id, }; - PersonBlock::block(&conn, &person_block).unwrap(); + PersonBlock::block(conn, &person_block).unwrap(); // A sample post let new_post = PostForm { - name: post_name.to_owned(), + name: "test post 3".to_string(), creator_id: inserted_person.id, community_id: inserted_community.id, + language_id: Some(LanguageId(47)), ..PostForm::default() }; - let inserted_post = Post::create(&conn, &new_post).unwrap(); + let inserted_post = Post::create(conn, &new_post).unwrap(); let new_bot_post = PostForm { - name: bot_post_name, + name: "test bot post".to_string(), creator_id: inserted_bot.id, community_id: inserted_community.id, ..PostForm::default() }; - let _inserted_bot_post = Post::create(&conn, &new_bot_post).unwrap(); - - let post_like_form = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_person.id, - score: 1, - }; - - let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap(); + let _inserted_bot_post = Post::create(conn, &new_bot_post).unwrap(); - let expected_post_like = PostLike { - id: inserted_post_like.id, - post_id: inserted_post.id, - person_id: inserted_person.id, - published: inserted_post_like.published, - score: 1, - }; - - let read_post_listings_with_person = PostQuery::builder() - .conn(&conn) - .sort(Some(SortType::New)) - .show_bot_accounts(Some(false)) - .community_id(Some(inserted_community.id)) - .my_person_id(Some(inserted_person.id)) - .build() - .list() - .unwrap(); - - let read_post_listings_no_person = PostQuery::builder() - .conn(&conn) - .sort(Some(SortType::New)) - .community_id(Some(inserted_community.id)) - .build() - .list() - .unwrap(); + Data { + inserted_person, + inserted_blocked_person, + inserted_bot, + inserted_community, + inserted_post, + } + } - let read_post_listing_no_person = PostView::read(&conn, inserted_post.id, None).unwrap(); - let read_post_listing_with_person = - PostView::read(&conn, inserted_post.id, Some(inserted_person.id)).unwrap(); + fn cleanup(data: Data, conn: &PgConnection) { + let num_deleted = Post::delete(conn, data.inserted_post.id).unwrap(); + Community::delete(conn, data.inserted_community.id).unwrap(); + Person::delete(conn, data.inserted_person.id).unwrap(); + Person::delete(conn, data.inserted_bot.id).unwrap(); + Person::delete(conn, data.inserted_blocked_person.id).unwrap(); + assert_eq!(1, num_deleted); + } - let agg = PostAggregates::read(&conn, inserted_post.id).unwrap(); + fn expected_post_listing(data: &Data, conn: &PgConnection) -> PostView { + let (inserted_person, inserted_community, inserted_post) = ( + &data.inserted_person, + &data.inserted_community, + &data.inserted_post, + ); + let agg = PostAggregates::read(conn, inserted_post.id).unwrap(); - // the non person version - let expected_post_listing_no_person = PostView { + PostView { post: Post { id: inserted_post.id, - name: post_name, + name: inserted_post.name.clone(), creator_id: inserted_person.id, url: None, body: None, @@ -570,11 +587,12 @@ mod tests { thumbnail_url: None, ap_id: inserted_post.ap_id.to_owned(), local: true, + language_id: LanguageId(47), }, my_vote: None, creator: PersonSafe { id: inserted_person.id, - name: person_name, + name: inserted_person.name.clone(), display_name: None, published: inserted_person.published, avatar: None, @@ -595,7 +613,7 @@ mod tests { creator_banned_from_community: false, community: CommunitySafe { id: inserted_community.id, - name: community_name, + name: inserted_community.name.clone(), icon: None, removed: false, deleted: false, @@ -614,8 +632,8 @@ mod tests { id: agg.id, post_id: inserted_post.id, comments: 0, - score: 1, - upvotes: 1, + score: 0, + upvotes: 0, downvotes: 0, stickied: false, published: agg.published, @@ -626,66 +644,239 @@ mod tests { read: false, saved: false, creator_blocked: false, - }; + language: Language { + id: LanguageId(47), + code: "fr".to_string(), + name: "Français".to_string(), + }, + } + } - // Test a community block - let community_block = CommunityBlockForm { - person_id: inserted_person.id, - community_id: inserted_community.id, - }; - CommunityBlock::block(&conn, &community_block).unwrap(); + #[test] + #[serial] + fn post_listing_with_person() { + let conn = establish_unpooled_connection(); + let data = init_data(&conn); - let read_post_listings_with_person_after_block = PostQuery::builder() + let read_post_listing = PostQuery::builder() .conn(&conn) .sort(Some(SortType::New)) + .community_id(Some(data.inserted_community.id)) .show_bot_accounts(Some(false)) - .community_id(Some(inserted_community.id)) - .my_person_id(Some(inserted_person.id)) + .my_person_id(Some(data.inserted_person.id)) .build() .list() .unwrap(); - // TODO More needs to be added here - let mut expected_post_listing_with_user = expected_post_listing_no_person.to_owned(); - expected_post_listing_with_user.my_vote = Some(1); + let post_listing_single_with_person = + PostView::read(&conn, data.inserted_post.id, Some(data.inserted_person.id)).unwrap(); - let like_removed = PostLike::remove(&conn, inserted_person.id, inserted_post.id).unwrap(); - let num_deleted = Post::delete(&conn, inserted_post.id).unwrap(); - PersonBlock::unblock(&conn, &person_block).unwrap(); - CommunityBlock::unblock(&conn, &community_block).unwrap(); - Community::delete(&conn, inserted_community.id).unwrap(); - Person::delete(&conn, inserted_person.id).unwrap(); - Person::delete(&conn, inserted_bot.id).unwrap(); - Person::delete(&conn, inserted_blocked_person.id).unwrap(); + let mut expected_post_listing_with_user = expected_post_listing(&data, &conn); - // The with user - assert_eq!( - expected_post_listing_with_user, - read_post_listings_with_person[0] - ); + // Should be only one person, IE the bot post, and blocked should be missing + assert_eq!(1, read_post_listing.len()); + + assert_eq!(expected_post_listing_with_user, read_post_listing[0]); + expected_post_listing_with_user.my_vote = Some(0); assert_eq!( expected_post_listing_with_user, - read_post_listing_with_person + post_listing_single_with_person ); - // Should be only one person, IE the bot post, and blocked should be missing - assert_eq!(1, read_post_listings_with_person.len()); + let post_listings_with_bots = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .community_id(Some(data.inserted_community.id)) + .show_bot_accounts(Some(true)) + .my_person_id(Some(data.inserted_person.id)) + .build() + .list() + .unwrap(); + // should include bot post which has "undetermined" language + assert_eq!(2, post_listings_with_bots.len()); + + cleanup(data, &conn); + } + + #[test] + #[serial] + fn post_listing_no_person() { + let conn = establish_unpooled_connection(); + let data = init_data(&conn); + + let read_post_listing_multiple_no_person = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .community_id(Some(data.inserted_community.id)) + .build() + .list() + .unwrap(); + + let read_post_listing_single_no_person = + PostView::read(&conn, data.inserted_post.id, None).unwrap(); - // Without the user + let expected_post_listing_no_person = expected_post_listing(&data, &conn); + + // Should be 2 posts, with the bot post, and the blocked + assert_eq!(3, read_post_listing_multiple_no_person.len()); + + assert_eq!( + expected_post_listing_no_person, + read_post_listing_multiple_no_person[1] + ); assert_eq!( expected_post_listing_no_person, - read_post_listings_no_person[1] + read_post_listing_single_no_person ); - assert_eq!(expected_post_listing_no_person, read_post_listing_no_person); - // Should be 2 posts, with the bot post, and the blocked - assert_eq!(3, read_post_listings_no_person.len()); + cleanup(data, &conn); + } + + #[test] + #[serial] + fn post_listing_block_community() { + let conn = establish_unpooled_connection(); + let data = init_data(&conn); + + let community_block = CommunityBlockForm { + person_id: data.inserted_person.id, + community_id: data.inserted_community.id, + }; + CommunityBlock::block(&conn, &community_block).unwrap(); + let read_post_listings_with_person_after_block = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .community_id(Some(data.inserted_community.id)) + .show_bot_accounts(Some(true)) + .my_person_id(Some(data.inserted_person.id)) + .build() + .list() + .unwrap(); // Should be 0 posts after the community block assert_eq!(0, read_post_listings_with_person_after_block.len()); + CommunityBlock::unblock(&conn, &community_block).unwrap(); + cleanup(data, &conn); + } + + #[test] + #[serial] + fn post_listing_like() { + let conn = establish_unpooled_connection(); + let data = init_data(&conn); + + let post_like_form = PostLikeForm { + post_id: data.inserted_post.id, + person_id: data.inserted_person.id, + score: 1, + }; + + let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap(); + + let expected_post_like = PostLike { + id: inserted_post_like.id, + post_id: data.inserted_post.id, + person_id: data.inserted_person.id, + published: inserted_post_like.published, + score: 1, + }; assert_eq!(expected_post_like, inserted_post_like); + + let like_removed = + PostLike::remove(&conn, data.inserted_person.id, data.inserted_post.id).unwrap(); assert_eq!(1, like_removed); - assert_eq!(1, num_deleted); + cleanup(data, &conn); + } + + #[test] + #[serial] + fn post_listing_person_language() { + let conn = establish_unpooled_connection(); + let data = init_data(&conn); + + let spanish_id = Language::read_id_from_code(&conn, "es").unwrap(); + let post_spanish = PostForm { + name: "asffgdsc".to_string(), + creator_id: data.inserted_person.id, + community_id: data.inserted_community.id, + language_id: Some(spanish_id), + ..PostForm::default() + }; + + Post::create(&conn, &post_spanish).unwrap(); + + let my_person_form = PersonForm { + name: "Reverie Toiba".to_string(), + public_key: Some("pubkey".to_string()), + ..PersonForm::default() + }; + let my_person = Person::create(&conn, &my_person_form).unwrap(); + let local_user_form = LocalUserForm { + person_id: Some(my_person.id), + password_encrypted: Some("".to_string()), + ..Default::default() + }; + let local_user = LocalUser::create(&conn, &local_user_form).unwrap(); + + // Update the users languages to all + LocalUserLanguage::update_user_languages(&conn, None, local_user.id).unwrap(); + + let post_listings_all = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .show_bot_accounts(Some(true)) + .my_person_id(Some(my_person.id)) + .my_local_user_id(Some(local_user.id)) + .build() + .list() + .unwrap(); + + // no language filters specified, all posts should be returned + assert_eq!(4, post_listings_all.len()); + + let french_id = Language::read_id_from_code(&conn, "fr").unwrap(); + LocalUserLanguage::update_user_languages(&conn, Some(vec![french_id]), local_user.id).unwrap(); + + let post_listing_french = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .show_bot_accounts(Some(true)) + .my_person_id(Some(my_person.id)) + .my_local_user_id(Some(local_user.id)) + .build() + .list() + .unwrap(); + + // only one french language post should be returned + assert_eq!(1, post_listing_french.len()); + assert_eq!(french_id, post_listing_french[0].post.language_id); + + let undetermined_id = Language::read_id_from_code(&conn, "und").unwrap(); + LocalUserLanguage::update_user_languages( + &conn, + Some(vec![french_id, undetermined_id]), + local_user.id, + ) + .unwrap(); + let post_listings_french_und = PostQuery::builder() + .conn(&conn) + .sort(Some(SortType::New)) + .show_bot_accounts(Some(true)) + .my_person_id(Some(my_person.id)) + .my_local_user_id(Some(local_user.id)) + .build() + .list() + .unwrap(); + + // french post and undetermined language post should be returned + assert_eq!(2, post_listings_french_und.len()); + assert_eq!( + undetermined_id, + post_listings_french_und[0].post.language_id + ); + assert_eq!(french_id, post_listings_french_und[1].post.language_id); + + cleanup(data, &conn); } }