Conditionally hide comments on nsfw posts (fixes #4237) (#5028)

* Conditionally hide comments on nsfw posts (fixes #4237)

* fix test
This commit is contained in:
Nutomic 2024-09-24 10:33:53 +02:00 committed by GitHub
parent d476d32200
commit bab5c93062
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 86 additions and 34 deletions

View File

@ -776,12 +776,13 @@ pub async fn remove_or_restore_user_data_in_community(
// Comments // Comments
// TODO Diesel doesn't allow updates with joins, so this has to be a loop // TODO Diesel doesn't allow updates with joins, so this has to be a loop
let site = Site::read_local(pool).await?;
let comments = CommentQuery { let comments = CommentQuery {
creator_id: Some(banned_person_id), creator_id: Some(banned_person_id),
community_id: Some(community_id), community_id: Some(community_id),
..Default::default() ..Default::default()
} }
.list(pool) .list(&site, pool)
.await?; .await?;
for comment_view in &comments { for comment_view in &comments {

View File

@ -12,10 +12,13 @@ use lemmy_api_common::{
utils::check_private_instance, utils::check_private_instance,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{comment::Comment, community::Community, local_site::LocalSite}, source::{comment::Comment, community::Community},
traits::Crud, traits::Crud,
}; };
use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView}; use lemmy_db_views::{
comment_view::CommentQuery,
structs::{LocalUserView, SiteView},
};
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))] #[tracing::instrument(skip(context))]
@ -24,8 +27,8 @@ pub async fn list_comments(
context: Data<LemmyContext>, context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>, local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetCommentsResponse>> { ) -> LemmyResult<Json<GetCommentsResponse>> {
let local_site = LocalSite::read(&mut context.pool()).await?; let site_view = SiteView::read_local(&mut context.pool()).await?;
check_private_instance(&local_user_view, &local_site)?; check_private_instance(&local_user_view, &site_view.local_site)?;
let community_id = if let Some(name) = &data.community_name { let community_id = if let Some(name) = &data.community_name {
Some( Some(
@ -40,7 +43,7 @@ pub async fn list_comments(
let sort = Some(comment_sort_type_with_default( let sort = Some(comment_sort_type_with_default(
data.sort, data.sort,
local_user_ref, local_user_ref,
&local_site, &site_view.local_site,
)); ));
let max_depth = data.max_depth; let max_depth = data.max_depth;
let saved_only = data.saved_only; let saved_only = data.saved_only;
@ -58,7 +61,7 @@ pub async fn list_comments(
let listing_type = Some(listing_type_with_default( let listing_type = Some(listing_type_with_default(
data.type_, data.type_,
local_user_view.as_ref().map(|u| &u.local_user), local_user_view.as_ref().map(|u| &u.local_user),
&local_site, &site_view.local_site,
community_id, community_id,
)); ));
@ -88,7 +91,7 @@ pub async fn list_comments(
limit, limit,
..Default::default() ..Default::default()
} }
.list(&mut context.pool()) .list(&site_view.site, &mut context.pool())
.await .await
.with_lemmy_type(LemmyErrorType::CouldntGetComments)?; .with_lemmy_type(LemmyErrorType::CouldntGetComments)?;

View File

@ -85,7 +85,7 @@ pub async fn read_person(
creator_id, creator_id,
..Default::default() ..Default::default()
} }
.list(&mut context.pool()) .list(&local_site.site, &mut context.pool())
.await?; .await?;
let moderates = CommunityModeratorView::for_person( let moderates = CommunityModeratorView::for_person(

View File

@ -127,7 +127,9 @@ pub async fn search(
.await?; .await?;
} }
SearchType::Comments => { SearchType::Comments => {
comments = comment_query.list(&mut context.pool()).await?; comments = comment_query
.list(&local_site.site, &mut context.pool())
.await?;
} }
SearchType::Communities => { SearchType::Communities => {
communities = community_query communities = community_query
@ -146,7 +148,9 @@ pub async fn search(
.list(&local_site.site, &mut context.pool()) .list(&local_site.site, &mut context.pool())
.await?; .await?;
comments = comment_query.list(&mut context.pool()).await?; comments = comment_query
.list(&local_site.site, &mut context.pool())
.await?;
communities = if community_or_creator_included { communities = if community_or_creator_included {
vec![] vec![]

View File

@ -35,7 +35,7 @@ use lemmy_db_schema::{
person_block, person_block,
post, post,
}, },
source::local_user::LocalUser, source::{local_user::LocalUser, site::Site},
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
CommentSortType, CommentSortType,
ListingType, ListingType,
@ -43,7 +43,7 @@ use lemmy_db_schema::{
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, CommentView, (CommentId, Option<&'a LocalUser>)>, impl ReadFn<'a, CommentView, (CommentId, Option<&'a LocalUser>)>,
impl ListFn<'a, CommentView, CommentQuery<'a>>, impl ListFn<'a, CommentView, (CommentQuery<'a>, &'a Site)>,
> { > {
let is_creator_banned_from_community = exists( let is_creator_banned_from_community = exists(
community_person_ban::table.filter( community_person_ban::table.filter(
@ -182,7 +182,7 @@ fn queries<'a>() -> Queries<
query.first(&mut conn).await query.first(&mut conn).await
}; };
let list = move |mut conn: DbConn<'a>, options: CommentQuery<'a>| async move { let list = move |mut conn: DbConn<'a>, (options, site): (CommentQuery<'a>, &'a Site)| async move {
// The left join below will return None in this case // The left join below will return None in this case
let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1)); let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1));
let local_user_id_join = options let local_user_id_join = options
@ -295,6 +295,12 @@ fn queries<'a>() -> Queries<
query = query.filter(not(is_creator_blocked(person_id_join))); query = query.filter(not(is_creator_blocked(person_id_join)));
}; };
if !options.local_user.show_nsfw(site) {
query = query
.filter(post::nsfw.eq(false))
.filter(community::nsfw.eq(false));
};
query = options.local_user.visible_communities_only(query); query = options.local_user.visible_communities_only(query);
// A Max depth given means its a tree fetch // A Max depth given means its a tree fetch
@ -398,10 +404,10 @@ pub struct CommentQuery<'a> {
} }
impl<'a> CommentQuery<'a> { impl<'a> CommentQuery<'a> {
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<CommentView>, Error> { pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result<Vec<CommentView>, Error> {
Ok( Ok(
queries() queries()
.list(pool, self) .list(pool, (self, site))
.await? .await?
.into_iter() .into_iter()
.map(|mut c| { .map(|mut c| {
@ -455,7 +461,8 @@ mod tests {
local_user_vote_display_mode::LocalUserVoteDisplayMode, local_user_vote_display_mode::LocalUserVoteDisplayMode,
person::{Person, PersonInsertForm}, person::{Person, PersonInsertForm},
person_block::{PersonBlock, PersonBlockForm}, person_block::{PersonBlock, PersonBlockForm},
post::{Post, PostInsertForm}, post::{Post, PostInsertForm, PostUpdateForm},
site::{Site, SiteInsertForm},
}, },
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable}, traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
utils::{build_db_pool_for_tests, RANK_DEFAULT}, utils::{build_db_pool_for_tests, RANK_DEFAULT},
@ -475,6 +482,7 @@ mod tests {
timmy_local_user_view: LocalUserView, timmy_local_user_view: LocalUserView,
inserted_sara_person: Person, inserted_sara_person: Person,
inserted_community: Community, inserted_community: Community,
site: Site,
} }
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> { async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
@ -611,6 +619,11 @@ mod tests {
person: inserted_timmy_person.clone(), person: inserted_timmy_person.clone(),
counts: Default::default(), counts: Default::default(),
}; };
let site_form = SiteInsertForm::builder()
.name("test site".to_string())
.instance_id(inserted_instance.id)
.build();
let site = Site::create(pool, &site_form).await?;
Ok(Data { Ok(Data {
inserted_instance, inserted_instance,
inserted_comment_0, inserted_comment_0,
@ -620,6 +633,7 @@ mod tests {
timmy_local_user_view, timmy_local_user_view,
inserted_sara_person, inserted_sara_person,
inserted_community, inserted_community,
site,
}) })
} }
@ -640,7 +654,7 @@ mod tests {
post_id: (Some(data.inserted_post.id)), post_id: (Some(data.inserted_post.id)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!( assert_eq!(
@ -654,7 +668,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)), local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!( assert_eq!(
@ -706,7 +720,7 @@ mod tests {
liked_only: Some(true), liked_only: Some(true),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await? .await?
.into_iter() .into_iter()
.map(|c| c.comment.content) .map(|c| c.comment.content)
@ -722,7 +736,7 @@ mod tests {
disliked_only: Some(true), disliked_only: Some(true),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert!(read_disliked_comment_views.is_empty()); assert!(read_disliked_comment_views.is_empty());
@ -743,7 +757,7 @@ mod tests {
parent_path: (Some(top_path)), parent_path: (Some(top_path)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
let child_path = data.inserted_comment_1.path.clone(); let child_path = data.inserted_comment_1.path.clone();
@ -752,7 +766,7 @@ mod tests {
parent_path: (Some(child_path)), parent_path: (Some(child_path)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
// Make sure the comment parent-limited fetch is correct // Make sure the comment parent-limited fetch is correct
@ -772,7 +786,7 @@ mod tests {
max_depth: (Some(1)), max_depth: (Some(1)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
// Make sure a depth limited one only has the top comment // Make sure a depth limited one only has the top comment
@ -790,7 +804,7 @@ mod tests {
sort: (Some(CommentSortType::New)), sort: (Some(CommentSortType::New)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
// Make sure a depth limited one, and given child comment 1, has 3 // Make sure a depth limited one, and given child comment 1, has 3
@ -816,7 +830,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)), local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_length!(5, all_languages); assert_length!(5, all_languages);
@ -834,7 +848,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)), local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_length!(2, finnish_comments); assert_length!(2, finnish_comments);
let finnish_comment = finnish_comments let finnish_comment = finnish_comments
@ -857,7 +871,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)), local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_length!(1, undetermined_comment); assert_length!(1, undetermined_comment);
@ -881,7 +895,7 @@ mod tests {
post_id: Some(data.inserted_comment_2.post_id), post_id: Some(data.inserted_comment_2.post_id),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!(comments[0].comment.id, data.inserted_comment_2.id); assert_eq!(comments[0].comment.id, data.inserted_comment_2.id);
assert!(comments[0].comment.distinguished); assert!(comments[0].comment.distinguished);
@ -910,7 +924,7 @@ mod tests {
sort: (Some(CommentSortType::Old)), sort: (Some(CommentSortType::Old)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!(comments[1].creator.name, "sara"); assert_eq!(comments[1].creator.name, "sara");
@ -931,7 +945,7 @@ mod tests {
sort: (Some(CommentSortType::Old)), sort: (Some(CommentSortType::Old)),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
// Timmy is an admin, and make sure that field is true // Timmy is an admin, and make sure that field is true
@ -971,7 +985,7 @@ mod tests {
saved_only: Some(true), saved_only: Some(true),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
// There should only be two comments // There should only be two comments
@ -1001,6 +1015,7 @@ mod tests {
LocalUser::delete(pool, data.timmy_local_user_view.local_user.id).await?; LocalUser::delete(pool, data.timmy_local_user_view.local_user.id).await?;
Person::delete(pool, data.inserted_sara_person.id).await?; Person::delete(pool, data.inserted_sara_person.id).await?;
Instance::delete(pool, data.inserted_instance.id).await?; Instance::delete(pool, data.inserted_instance.id).await?;
Site::delete(pool, data.site.id).await?;
Ok(()) Ok(())
} }
@ -1139,7 +1154,7 @@ mod tests {
let unauthenticated_query = CommentQuery { let unauthenticated_query = CommentQuery {
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!(0, unauthenticated_query.len()); assert_eq!(0, unauthenticated_query.len());
@ -1147,7 +1162,7 @@ mod tests {
local_user: Some(&data.timmy_local_user_view.local_user), local_user: Some(&data.timmy_local_user_view.local_user),
..Default::default() ..Default::default()
} }
.list(pool) .list(&data.site, pool)
.await?; .await?;
assert_eq!(5, authenticated_query.len()); assert_eq!(5, authenticated_query.len());
@ -1225,4 +1240,33 @@ mod tests {
cleanup(data, pool).await cleanup(data, pool).await
} }
#[tokio::test]
#[serial]
async fn comment_listings_hide_nsfw() -> LemmyResult<()> {
let pool = &build_db_pool_for_tests().await;
let pool = &mut pool.into();
let data = init_data(pool).await?;
// Mark a post as nsfw
let update_form = PostUpdateForm {
nsfw: Some(true),
..Default::default()
};
Post::update(pool, data.inserted_post.id, &update_form).await?;
// Make sure comments of this post are not returned
let comments = CommentQuery::default().list(&data.site, pool).await?;
assert_eq!(0, comments.len());
// Mark site as nsfw
let mut site = data.site.clone();
site.content_warning = Some("nsfw".to_string());
// Now comments of nsfw post are returned
let comments = CommentQuery::default().list(&site, pool).await?;
assert_eq!(6, comments.len());
cleanup(data, pool).await
}
} }