Skip to content

Commit

Permalink
Hide comments on nsfw posts (fixes #4237)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nutomic committed Sep 19, 2024
1 parent 026e23c commit a289cde
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 34 deletions.
3 changes: 2 additions & 1 deletion crates/api_common/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -854,12 +854,13 @@ pub async fn remove_or_restore_user_data_in_community(

// Comments
// 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 {
creator_id: Some(banned_person_id),
community_id: Some(community_id),
..Default::default()
}
.list(pool)
.list(&site, pool)
.await?;

for comment_view in &comments {
Expand Down
17 changes: 10 additions & 7 deletions crates/apub/src/api/list_comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ use lemmy_api_common::{
utils::check_private_instance,
};
use lemmy_db_schema::{
source::{comment::Comment, community::Community, local_site::LocalSite},
source::{comment::Comment, community::Community},
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};

#[tracing::instrument(skip(context))]
Expand All @@ -24,8 +27,8 @@ pub async fn list_comments(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetCommentsResponse>> {
let local_site = LocalSite::read(&mut context.pool()).await?;
check_private_instance(&local_user_view, &local_site)?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
check_private_instance(&local_user_view, &site_view.local_site)?;

let community_id = if let Some(name) = &data.community_name {
Some(
Expand All @@ -40,7 +43,7 @@ pub async fn list_comments(
let sort = Some(comment_sort_type_with_default(
data.sort,
local_user_ref,
&local_site,
&site_view.local_site,
));
let max_depth = data.max_depth;
let saved_only = data.saved_only;
Expand All @@ -58,7 +61,7 @@ pub async fn list_comments(
let listing_type = Some(listing_type_with_default(
data.type_,
local_user_view.as_ref().map(|u| &u.local_user),
&local_site,
&site_view.local_site,
community_id,
));

Expand Down Expand Up @@ -93,7 +96,7 @@ pub async fn list_comments(
limit,
..Default::default()
}
.list(&mut context.pool())
.list(&site_view.site, &mut context.pool())
.await
.with_lemmy_type(LemmyErrorType::CouldntGetComments)?;

Expand Down
2 changes: 1 addition & 1 deletion crates/apub/src/api/read_person.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub async fn read_person(
creator_id,
..Default::default()
}
.list(&mut context.pool())
.list(&local_site.site, &mut context.pool())
.await?;

let moderates = CommunityModeratorView::for_person(
Expand Down
8 changes: 6 additions & 2 deletions crates/apub/src/api/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ pub async fn search(
.await?;
}
SearchType::Comments => {
comments = comment_query.list(&mut context.pool()).await?;
comments = comment_query
.list(&local_site.site, &mut context.pool())
.await?;
}
SearchType::Communities => {
communities = community_query
Expand All @@ -126,7 +128,9 @@ pub async fn search(
.list(&local_site.site, &mut context.pool())
.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 {
vec![]
Expand Down
93 changes: 70 additions & 23 deletions crates/db_views/src/comment_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ use lemmy_db_schema::{
person_block,
post,
},
source::local_user::LocalUser,
source::{local_user::LocalUser, site::Site},
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
CommentSortType,
ListingType,
};

fn queries<'a>() -> Queries<
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(
community_person_ban::table.filter(
Expand Down Expand Up @@ -182,7 +182,7 @@ fn queries<'a>() -> Queries<
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
let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1));
let local_user_id_join = options
Expand Down Expand Up @@ -295,6 +295,12 @@ fn queries<'a>() -> Queries<
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);

// A Max depth given means its a tree fetch
Expand Down Expand Up @@ -401,10 +407,10 @@ pub struct 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(
queries()
.list(pool, self)
.list(pool, (self, site))
.await?
.into_iter()
.map(|mut c| {
Expand Down Expand Up @@ -457,7 +463,8 @@ mod tests {
local_user_vote_display_mode::LocalUserVoteDisplayMode,
person::{Person, PersonInsertForm},
person_block::{PersonBlock, PersonBlockForm},
post::{Post, PostInsertForm},
post::{Post, PostInsertForm, PostUpdateForm},
site::{Site, SiteInsertForm, SiteUpdateForm},
},
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
utils::{build_db_pool_for_tests, RANK_DEFAULT},
Expand All @@ -477,6 +484,7 @@ mod tests {
timmy_local_user_view: LocalUserView,
inserted_sara_person: Person,
inserted_community: Community,
site: Site,
}

async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
Expand Down Expand Up @@ -608,6 +616,11 @@ mod tests {
person: inserted_timmy_person.clone(),
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 {
inserted_instance,
inserted_comment_0,
Expand All @@ -617,6 +630,7 @@ mod tests {
timmy_local_user_view,
inserted_sara_person,
inserted_community,
site,
})
}

Expand All @@ -637,7 +651,7 @@ mod tests {
post_id: (Some(data.inserted_post.id)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

assert_eq!(
Expand All @@ -653,7 +667,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

assert_eq!(
Expand Down Expand Up @@ -706,7 +720,7 @@ mod tests {
liked_only: Some(true),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?
.into_iter()
.map(|c| c.comment.content)
Expand All @@ -722,7 +736,7 @@ mod tests {
disliked_only: Some(true),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

assert!(read_disliked_comment_views.is_empty());
Expand All @@ -743,7 +757,7 @@ mod tests {
parent_path: (Some(top_path)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

let child_path = data.inserted_comment_1.path.clone();
Expand All @@ -752,7 +766,7 @@ mod tests {
parent_path: (Some(child_path)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

// Make sure the comment parent-limited fetch is correct
Expand All @@ -772,7 +786,7 @@ mod tests {
max_depth: (Some(1)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

// Make sure a depth limited one only has the top comment
Expand All @@ -790,7 +804,7 @@ mod tests {
sort: (Some(CommentSortType::New)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

// Make sure a depth limited one, and given child comment 1, has 3
Expand All @@ -816,7 +830,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_length!(5, all_languages);

Expand All @@ -834,7 +848,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_length!(2, finnish_comments);
let finnish_comment = finnish_comments
Expand All @@ -860,7 +874,7 @@ mod tests {
local_user: (Some(&data.timmy_local_user_view.local_user)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_length!(1, undetermined_comment);

Expand All @@ -884,7 +898,7 @@ mod tests {
post_id: Some(data.inserted_comment_2.post_id),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_eq!(comments[0].comment.id, data.inserted_comment_2.id);
assert!(comments[0].comment.distinguished);
Expand Down Expand Up @@ -913,7 +927,7 @@ mod tests {
sort: (Some(CommentSortType::Old)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

assert_eq!(comments[1].creator.name, "sara");
Expand All @@ -934,7 +948,7 @@ mod tests {
sort: (Some(CommentSortType::Old)),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

// Timmy is an admin, and make sure that field is true
Expand Down Expand Up @@ -974,7 +988,7 @@ mod tests {
saved_only: Some(true),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;

// There should only be two comments
Expand Down Expand Up @@ -1004,6 +1018,7 @@ mod tests {
LocalUser::delete(pool, data.timmy_local_user_view.local_user.id).await?;
Person::delete(pool, data.inserted_sara_person.id).await?;
Instance::delete(pool, data.inserted_instance.id).await?;
Site::delete(pool, data.site.id).await?;

Ok(())
}
Expand Down Expand Up @@ -1144,15 +1159,15 @@ mod tests {
let unauthenticated_query = CommentQuery {
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_eq!(0, unauthenticated_query.len());

let authenticated_query = CommentQuery {
local_user: Some(&data.timmy_local_user_view.local_user),
..Default::default()
}
.list(pool)
.list(&data.site, pool)
.await?;
assert_eq!(5, authenticated_query.len());

Expand Down Expand Up @@ -1213,6 +1228,38 @@ mod tests {
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!(1, comments.len());

// Mark site as nsfw
let form = SiteUpdateForm {
content_warning: Some(Some("nsfw".to_string())),
..Default::default()
};
Site::update(pool, data.site.id, &form).await?;

// Now comments of nsfw post are returned
let comments = CommentQuery::default().list(&data.site, pool).await?;
assert_eq!(1, comments.len());

cleanup(data, pool).await
}

#[tokio::test]
#[serial]
async fn comment_listing_local_user_not_banned_from_community() -> LemmyResult<()> {
Expand Down

0 comments on commit a289cde

Please sign in to comment.