]> Untitled Git - lemmy.git/blobdiff - crates/db_views/src/comment_view.rs
Fixing hot_ranks and scores to append a published sort. (#3618)
[lemmy.git] / crates / db_views / src / comment_view.rs
index 3556f85011d51da23c5d2cd439db77718db87790..e98d9f879996222b3a842b1272a10fce387fd5d1 100644 (file)
@@ -1,4 +1,4 @@
-use crate::structs::CommentView;
+use crate::structs::{CommentView, LocalUserView};
 use diesel::{
   result::Error,
   BoolExpressionMethods,
@@ -30,7 +30,6 @@ use lemmy_db_schema::{
   source::{
     comment::{Comment, CommentSaved},
     community::{Community, CommunityFollower, CommunityPersonBan},
-    local_user::LocalUser,
     person::Person,
     person_block::PersonBlock,
     post::Post,
@@ -40,7 +39,6 @@ use lemmy_db_schema::{
   CommentSortType,
   ListingType,
 };
-use typed_builder::TypedBuilder;
 
 type CommentViewTuple = (
   Comment,
@@ -156,33 +154,34 @@ impl CommentView {
   }
 }
 
-#[derive(TypedBuilder)]
-#[builder(field_defaults(default))]
-pub struct CommentQuery<'a, 'b: 'a> {
-  #[builder(!default)]
-  pool: &'a mut DbPool<'b>,
-  listing_type: Option<ListingType>,
-  sort: Option<CommentSortType>,
-  community_id: Option<CommunityId>,
-  post_id: Option<PostId>,
-  parent_path: Option<Ltree>,
-  creator_id: Option<PersonId>,
-  local_user: Option<&'a LocalUser>,
-  search_term: Option<String>,
-  saved_only: Option<bool>,
-  show_deleted_and_removed: Option<bool>,
-  page: Option<i64>,
-  limit: Option<i64>,
-  max_depth: Option<i32>,
+#[derive(Default)]
+pub struct CommentQuery<'a> {
+  pub listing_type: Option<ListingType>,
+  pub sort: Option<CommentSortType>,
+  pub community_id: Option<CommunityId>,
+  pub post_id: Option<PostId>,
+  pub parent_path: Option<Ltree>,
+  pub creator_id: Option<PersonId>,
+  pub local_user: Option<&'a LocalUserView>,
+  pub search_term: Option<String>,
+  pub saved_only: Option<bool>,
+  pub is_profile_view: Option<bool>,
+  pub show_deleted_and_removed: Option<bool>,
+  pub page: Option<i64>,
+  pub limit: Option<i64>,
+  pub max_depth: Option<i32>,
 }
 
-impl<'a, 'b: 'a> CommentQuery<'a, 'b> {
-  pub async fn list(self) -> Result<Vec<CommentView>, Error> {
-    let conn = &mut get_conn(self.pool).await?;
+impl<'a> CommentQuery<'a> {
+  pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<CommentView>, Error> {
+    let conn = &mut get_conn(pool).await?;
 
     // The left join below will return None in this case
-    let person_id_join = self.local_user.map(|l| l.person_id).unwrap_or(PersonId(-1));
-    let local_user_id_join = self.local_user.map(|l| l.id).unwrap_or(LocalUserId(-1));
+    let person_id_join = self.local_user.map(|l| l.person.id).unwrap_or(PersonId(-1));
+    let local_user_id_join = self
+      .local_user
+      .map(|l| l.local_user.id)
+      .unwrap_or(LocalUserId(-1));
 
     let mut query = comment::table
       .inner_join(person::table)
@@ -298,12 +297,24 @@ impl<'a, 'b: 'a> CommentQuery<'a, 'b> {
       query = query.filter(comment_saved::comment_id.is_not_null());
     }
 
-    if !self.show_deleted_and_removed.unwrap_or(true) {
+    let is_profile_view = self.is_profile_view.unwrap_or(false);
+    let is_creator = self.creator_id == self.local_user.map(|l| l.person.id);
+    // only show deleted comments to creator
+    if !is_creator {
       query = query.filter(comment::deleted.eq(false));
+    }
+
+    let is_admin = self.local_user.map(|l| l.person.admin).unwrap_or(false);
+    // only show removed comments to admin when viewing user profile
+    if !(is_profile_view && is_admin) {
       query = query.filter(comment::removed.eq(false));
     }
 
-    if !self.local_user.map(|l| l.show_bot_accounts).unwrap_or(true) {
+    if !self
+      .local_user
+      .map(|l| l.local_user.show_bot_accounts)
+      .unwrap_or(true)
+    {
       query = query.filter(person::bot_account.eq(false));
     };
 
@@ -349,10 +360,14 @@ impl<'a, 'b: 'a> CommentQuery<'a, 'b> {
     };
 
     query = match self.sort.unwrap_or(CommentSortType::Hot) {
-      CommentSortType::Hot => query.then_order_by(comment_aggregates::hot_rank.desc()),
+      CommentSortType::Hot => query
+        .then_order_by(comment_aggregates::hot_rank.desc())
+        .then_order_by(comment_aggregates::published.desc()),
+      CommentSortType::Top => query
+        .order_by(comment_aggregates::score.desc())
+        .then_order_by(comment_aggregates::published.desc()),
       CommentSortType::New => query.then_order_by(comment::published.desc()),
       CommentSortType::Old => query.then_order_by(comment::published.asc()),
-      CommentSortType::Top => query.order_by(comment_aggregates::score.desc()),
     };
 
     // Note: deleted and removed comments are done on the front side
@@ -386,17 +401,22 @@ impl JoinView for CommentView {
 
 #[cfg(test)]
 mod tests {
-  use crate::comment_view::{
-    Comment,
-    CommentQuery,
-    CommentSortType,
-    CommentView,
-    Community,
-    DbPool,
-    LocalUser,
-    Person,
-    PersonBlock,
-    Post,
+  #![allow(clippy::unwrap_used)]
+  #![allow(clippy::indexing_slicing)]
+
+  use crate::{
+    comment_view::{
+      Comment,
+      CommentQuery,
+      CommentSortType,
+      CommentView,
+      Community,
+      DbPool,
+      Person,
+      PersonBlock,
+      Post,
+    },
+    structs::LocalUserView,
   };
   use lemmy_db_schema::{
     aggregates::structs::CommentAggregates,
@@ -408,7 +428,7 @@ mod tests {
       community::CommunityInsertForm,
       instance::Instance,
       language::Language,
-      local_user::LocalUserInsertForm,
+      local_user::{LocalUser, LocalUserInsertForm},
       person::PersonInsertForm,
       person_block::PersonBlockForm,
       post::PostInsertForm,
@@ -425,8 +445,7 @@ mod tests {
     inserted_comment_1: Comment,
     inserted_comment_2: Comment,
     inserted_post: Post,
-    inserted_person: Person,
-    inserted_local_user: LocalUser,
+    local_user_view: LocalUserView,
     inserted_person_2: Person,
     inserted_community: Community,
   }
@@ -577,14 +596,18 @@ mod tests {
 
     let _inserted_comment_like = CommentLike::like(pool, &comment_like_form).await.unwrap();
 
+    let local_user_view = LocalUserView {
+      local_user: inserted_local_user.clone(),
+      person: inserted_person.clone(),
+      counts: Default::default(),
+    };
     Data {
       inserted_instance,
       inserted_comment_0,
       inserted_comment_1,
       inserted_comment_2,
       inserted_post,
-      inserted_person,
-      inserted_local_user,
+      local_user_view,
       inserted_person_2,
       inserted_community,
     }
@@ -602,29 +625,29 @@ mod tests {
     let mut expected_comment_view_with_person = expected_comment_view_no_person.clone();
     expected_comment_view_with_person.my_vote = Some(1);
 
-    let read_comment_views_no_person = CommentQuery::builder()
-      .pool(pool)
-      .sort(Some(CommentSortType::Old))
-      .post_id(Some(data.inserted_post.id))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_no_person = CommentQuery {
+      sort: (Some(CommentSortType::Old)),
+      post_id: (Some(data.inserted_post.id)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     assert_eq!(
       expected_comment_view_no_person,
       read_comment_views_no_person[0]
     );
 
-    let read_comment_views_with_person = CommentQuery::builder()
-      .pool(pool)
-      .sort(Some(CommentSortType::Old))
-      .post_id(Some(data.inserted_post.id))
-      .local_user(Some(&data.inserted_local_user))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_with_person = CommentQuery {
+      sort: (Some(CommentSortType::Old)),
+      post_id: (Some(data.inserted_post.id)),
+      local_user: (Some(&data.local_user_view)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     assert_eq!(
       expected_comment_view_with_person,
@@ -637,7 +660,7 @@ mod tests {
     let read_comment_from_blocked_person = CommentView::read(
       pool,
       data.inserted_comment_1.id,
-      Some(data.inserted_person.id),
+      Some(data.local_user_view.person.id),
     )
     .await
     .unwrap();
@@ -656,24 +679,24 @@ mod tests {
     let data = init_data(pool).await;
 
     let top_path = data.inserted_comment_0.path.clone();
-    let read_comment_views_top_path = CommentQuery::builder()
-      .pool(pool)
-      .post_id(Some(data.inserted_post.id))
-      .parent_path(Some(top_path))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_top_path = CommentQuery {
+      post_id: (Some(data.inserted_post.id)),
+      parent_path: (Some(top_path)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     let child_path = data.inserted_comment_1.path.clone();
-    let read_comment_views_child_path = CommentQuery::builder()
-      .pool(pool)
-      .post_id(Some(data.inserted_post.id))
-      .parent_path(Some(child_path))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_child_path = CommentQuery {
+      post_id: (Some(data.inserted_post.id)),
+      parent_path: (Some(child_path)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     // Make sure the comment parent-limited fetch is correct
     assert_eq!(6, read_comment_views_top_path.len());
@@ -687,14 +710,14 @@ mod tests {
     assert!(child_comments.contains(&data.inserted_comment_1));
     assert!(!child_comments.contains(&data.inserted_comment_2));
 
-    let read_comment_views_top_max_depth = CommentQuery::builder()
-      .pool(pool)
-      .post_id(Some(data.inserted_post.id))
-      .max_depth(Some(1))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_top_max_depth = CommentQuery {
+      post_id: (Some(data.inserted_post.id)),
+      max_depth: (Some(1)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     // Make sure a depth limited one only has the top comment
     assert_eq!(
@@ -704,16 +727,16 @@ mod tests {
     assert_eq!(1, read_comment_views_top_max_depth.len());
 
     let child_path = data.inserted_comment_1.path.clone();
-    let read_comment_views_parent_max_depth = CommentQuery::builder()
-      .pool(pool)
-      .post_id(Some(data.inserted_post.id))
-      .parent_path(Some(child_path))
-      .max_depth(Some(1))
-      .sort(Some(CommentSortType::New))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let read_comment_views_parent_max_depth = CommentQuery {
+      post_id: (Some(data.inserted_post.id)),
+      parent_path: (Some(child_path)),
+      max_depth: (Some(1)),
+      sort: (Some(CommentSortType::New)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
 
     // Make sure a depth limited one, and given child comment 1, has 3
     assert!(read_comment_views_parent_max_depth[2]
@@ -734,13 +757,13 @@ mod tests {
 
     // by default, user has all languages enabled and should see all comments
     // (except from blocked user)
-    let all_languages = CommentQuery::builder()
-      .pool(pool)
-      .local_user(Some(&data.inserted_local_user))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    let all_languages = CommentQuery {
+      local_user: (Some(&data.local_user_view)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
     assert_eq!(5, all_languages.len());
 
     // change user lang to finnish, should only show one post in finnish and one undetermined
@@ -748,16 +771,16 @@ mod tests {
       .await
       .unwrap()
       .unwrap();
-    LocalUserLanguage::update(pool, vec![finnish_id], data.inserted_local_user.id)
-      .await
-      .unwrap();
-    let finnish_comments = CommentQuery::builder()
-      .pool(pool)
-      .local_user(Some(&data.inserted_local_user))
-      .build()
-      .list()
+    LocalUserLanguage::update(pool, vec![finnish_id], data.local_user_view.local_user.id)
       .await
       .unwrap();
+    let finnish_comments = CommentQuery {
+      local_user: (Some(&data.local_user_view)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
     assert_eq!(2, finnish_comments.len());
     let finnish_comment = finnish_comments
       .iter()
@@ -769,25 +792,33 @@ mod tests {
     );
 
     // now show all comments with undetermined language (which is the default value)
-    LocalUserLanguage::update(pool, vec![UNDETERMINED_ID], data.inserted_local_user.id)
-      .await
-      .unwrap();
-    let undetermined_comment = CommentQuery::builder()
-      .pool(pool)
-      .local_user(Some(&data.inserted_local_user))
-      .build()
-      .list()
-      .await
-      .unwrap();
+    LocalUserLanguage::update(
+      pool,
+      vec![UNDETERMINED_ID],
+      data.local_user_view.local_user.id,
+    )
+    .await
+    .unwrap();
+    let undetermined_comment = CommentQuery {
+      local_user: (Some(&data.local_user_view)),
+      ..Default::default()
+    }
+    .list(pool)
+    .await
+    .unwrap();
     assert_eq!(1, undetermined_comment.len());
 
     cleanup(data, pool).await;
   }
 
   async fn cleanup(data: Data, pool: &mut DbPool<'_>) {
-    CommentLike::remove(pool, data.inserted_person.id, data.inserted_comment_0.id)
-      .await
-      .unwrap();
+    CommentLike::remove(
+      pool,
+      data.local_user_view.person.id,
+      data.inserted_comment_0.id,
+    )
+    .await
+    .unwrap();
     Comment::delete(pool, data.inserted_comment_0.id)
       .await
       .unwrap();
@@ -798,7 +829,9 @@ mod tests {
     Community::delete(pool, data.inserted_community.id)
       .await
       .unwrap();
-    Person::delete(pool, data.inserted_person.id).await.unwrap();
+    Person::delete(pool, data.local_user_view.person.id)
+      .await
+      .unwrap();
     Person::delete(pool, data.inserted_person_2.id)
       .await
       .unwrap();
@@ -820,7 +853,7 @@ mod tests {
       comment: Comment {
         id: data.inserted_comment_0.id,
         content: "Comment 0".into(),
-        creator_id: data.inserted_person.id,
+        creator_id: data.local_user_view.person.id,
         post_id: data.inserted_post.id,
         removed: false,
         deleted: false,
@@ -833,12 +866,12 @@ mod tests {
         language_id: LanguageId(37),
       },
       creator: Person {
-        id: data.inserted_person.id,
+        id: data.local_user_view.person.id,
         name: "timmy".into(),
         display_name: None,
-        published: data.inserted_person.published,
+        published: data.local_user_view.person.published,
         avatar: None,
-        actor_id: data.inserted_person.actor_id.clone(),
+        actor_id: data.local_user_view.person.actor_id.clone(),
         local: true,
         banned: false,
         deleted: false,
@@ -847,19 +880,19 @@ mod tests {
         bio: None,
         banner: None,
         updated: None,
-        inbox_url: data.inserted_person.inbox_url.clone(),
+        inbox_url: data.local_user_view.person.inbox_url.clone(),
         shared_inbox_url: None,
         matrix_user_id: None,
         ban_expires: None,
         instance_id: data.inserted_instance.id,
-        private_key: data.inserted_person.private_key.clone(),
-        public_key: data.inserted_person.public_key.clone(),
-        last_refreshed_at: data.inserted_person.last_refreshed_at,
+        private_key: data.local_user_view.person.private_key.clone(),
+        public_key: data.local_user_view.person.public_key.clone(),
+        last_refreshed_at: data.local_user_view.person.last_refreshed_at,
       },
       post: Post {
         id: data.inserted_post.id,
         name: data.inserted_post.name.clone(),
-        creator_id: data.inserted_person.id,
+        creator_id: data.local_user_view.person.id,
         url: None,
         body: None,
         published: data.inserted_post.published,