diff --git a/lemmy_api/src/comment.rs b/lemmy_api/src/comment.rs index fe5fe859a..eed2cb701 100644 --- a/lemmy_api/src/comment.rs +++ b/lemmy_api/src/comment.rs @@ -11,9 +11,11 @@ use actix_web::web::Data; use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_db::{ comment_report::*, - comment_view::*, source::{comment::*, moderator::*, post::*, user::*}, - views::site_view::SiteView, + views::{ + comment_view::{CommentQueryBuilder, CommentView}, + site_view::SiteView, + }, Crud, Likeable, ListingType, @@ -135,7 +137,7 @@ impl Perform for CreateComment { .await??; let mut res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: data.form_id.to_owned(), }; @@ -172,10 +174,10 @@ impl Perform for EditComment { }) .await??; - check_community_ban(user.id, orig_comment.community_id, context.pool()).await?; + check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; // Verify that only the creator can edit - if user.id != orig_comment.creator_id { + if user.id != orig_comment.creator.id { return Err(APIError::err("no_comment_edit_allowed").into()); } @@ -195,7 +197,7 @@ impl Perform for EditComment { updated_comment.send_update(&user, context).await?; // Do the mentions / recipients - let post_id = orig_comment.post_id; + let post_id = orig_comment.post.id; let post = get_post(post_id, context.pool()).await?; let updated_comment_content = updated_comment.content.to_owned(); @@ -218,7 +220,7 @@ impl Perform for EditComment { .await??; let mut res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: data.form_id.to_owned(), }; @@ -255,10 +257,10 @@ impl Perform for DeleteComment { }) .await??; - check_community_ban(user.id, orig_comment.community_id, context.pool()).await?; + check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; // Verify that only the creator can delete - if user.id != orig_comment.creator_id { + if user.id != orig_comment.creator.id { return Err(APIError::err("no_comment_edit_allowed").into()); } @@ -289,7 +291,7 @@ impl Perform for DeleteComment { .await??; // Build the recipients - let post_id = comment_view.post_id; + let post_id = comment_view.post.id; let post = get_post(post_id, context.pool()).await?; let mentions = vec![]; let recipient_ids = send_local_notifs( @@ -303,7 +305,7 @@ impl Perform for DeleteComment { .await?; let mut res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -340,10 +342,10 @@ impl Perform for RemoveComment { }) .await??; - check_community_ban(user.id, orig_comment.community_id, context.pool()).await?; + check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; // Verify that only a mod or admin can remove - is_mod_or_admin(context.pool(), user.id, orig_comment.community_id).await?; + is_mod_or_admin(context.pool(), user.id, orig_comment.community.id).await?; // Do the remove let removed = data.removed; @@ -384,7 +386,7 @@ impl Perform for RemoveComment { .await??; // Build the recipients - let post_id = comment_view.post_id; + let post_id = comment_view.post.id; let post = get_post(post_id, context.pool()).await?; let mentions = vec![]; let recipient_ids = send_local_notifs( @@ -398,7 +400,7 @@ impl Perform for RemoveComment { .await?; let mut res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -435,23 +437,23 @@ impl Perform for MarkCommentAsRead { }) .await??; - check_community_ban(user.id, orig_comment.community_id, context.pool()).await?; + check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; // Verify that only the recipient can mark as read // Needs to fetch the parent comment / post to get the recipient - let parent_id = orig_comment.parent_id; + let parent_id = orig_comment.comment.parent_id; match parent_id { Some(pid) => { let parent_comment = blocking(context.pool(), move |conn| { CommentView::read(&conn, pid, None) }) .await??; - if user.id != parent_comment.creator_id { + if user.id != parent_comment.creator.id { return Err(APIError::err("no_comment_edit_allowed").into()); } } None => { - let parent_post_id = orig_comment.post_id; + let parent_post_id = orig_comment.post.id; let parent_post = blocking(context.pool(), move |conn| Post::read(conn, parent_post_id)).await??; if user.id != parent_post.creator_id { @@ -480,7 +482,7 @@ impl Perform for MarkCommentAsRead { .await??; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids: Vec::new(), form_id: None, }; @@ -526,7 +528,7 @@ impl Perform for SaveComment { .await??; Ok(CommentResponse { - comment: comment_view, + comment_view, recipient_ids: Vec::new(), form_id: None, }) @@ -561,7 +563,7 @@ impl Perform for CreateCommentLike { }) .await??; - let post_id = orig_comment.post_id; + let post_id = orig_comment.post.id; let post = get_post(post_id, context.pool()).await?; check_community_ban(user.id, post.community_id, context.pool()).await?; @@ -627,7 +629,7 @@ impl Perform for CreateCommentLike { .await??; let mut res = CommentResponse { - comment: liked_comment, + comment_view: liked_comment, recipient_ids, form_id: None, }; @@ -667,12 +669,11 @@ impl Perform for GetComments { let page = data.page; let limit = data.limit; let comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) + CommentQueryBuilder::create(conn, user_id) .listing_type(type_) .sort(&sort) .for_community_id(community_id) .for_community_name(community_name) - .my_user_id(user_id) .page(page) .limit(limit) .list() @@ -711,17 +712,17 @@ impl Perform for CreateCommentReport { let user_id = user.id; let comment_id = data.comment_id; - let comment = blocking(context.pool(), move |conn| { + let comment_view = blocking(context.pool(), move |conn| { CommentView::read(&conn, comment_id, None) }) .await??; - check_community_ban(user_id, comment.community_id, context.pool()).await?; + check_community_ban(user_id, comment_view.community.id, context.pool()).await?; let report_form = CommentReportForm { creator_id: user_id, comment_id, - original_comment_text: comment.content, + original_comment_text: comment_view.comment.content, reason: data.reason.to_owned(), }; @@ -746,7 +747,7 @@ impl Perform for CreateCommentReport { context.chat_server().do_send(SendModRoomMessage { op: UserOperation::CreateCommentReport, response: report, - community_id: comment.community_id, + community_id: comment_view.community.id, websocket_id, }); diff --git a/lemmy_api/src/community.rs b/lemmy_api/src/community.rs index b704d24b9..d35a4a6c1 100644 --- a/lemmy_api/src/community.rs +++ b/lemmy_api/src/community.rs @@ -10,11 +10,11 @@ use actix_web::web::Data; use anyhow::Context; use lemmy_apub::ActorType; use lemmy_db::{ - comment_view::CommentQueryBuilder, diesel_option_overwrite, naive_now, source::{comment::Comment, community::*, moderator::*, post::Post, site::*}, views::{ + comment_view::CommentQueryBuilder, community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, community_view::{CommunityQueryBuilder, CommunityView}, @@ -591,7 +591,7 @@ impl Perform for BanFromCommunity { // Comments // Diesel doesn't allow updates with joins, so this has to be a loop let comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) + CommentQueryBuilder::create(conn, None) .for_creator_id(banned_user_id) .for_community_id(community_id) .limit(std::i64::MAX) @@ -599,8 +599,8 @@ impl Perform for BanFromCommunity { }) .await??; - for comment in &comments { - let comment_id = comment.id; + for comment_view in &comments { + let comment_id = comment_view.comment.id; blocking(context.pool(), move |conn: &'_ _| { Comment::update_removed(conn, comment_id, remove_data) }) diff --git a/lemmy_api/src/post.rs b/lemmy_api/src/post.rs index 2b3b4b5b4..b0af10a4b 100644 --- a/lemmy_api/src/post.rs +++ b/lemmy_api/src/post.rs @@ -10,11 +10,11 @@ use crate::{ use actix_web::web::Data; use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_db::{ - comment_view::*, naive_now, post_report::*, source::{moderator::*, post::*}, views::{ + comment_view::CommentQueryBuilder, community_moderator_view::CommunityModeratorView, community_view::CommunityView, post_view::{PostQueryBuilder, PostView}, @@ -181,9 +181,8 @@ impl Perform for GetPost { let id = data.id; let comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) + CommentQueryBuilder::create(conn, user_id) .for_post_id(id) - .my_user_id(user_id) .limit(9999) .list() }) diff --git a/lemmy_api/src/site.rs b/lemmy_api/src/site.rs index 98c501f1a..3c13b5a06 100644 --- a/lemmy_api/src/site.rs +++ b/lemmy_api/src/site.rs @@ -11,12 +11,12 @@ use anyhow::Context; use lemmy_apub::fetcher::search_by_apub_id; use lemmy_db::{ aggregates::site_aggregates::SiteAggregates, - comment_view::*, diesel_option_overwrite, moderator_views::*, naive_now, source::{category::*, moderator::*, site::*}, views::{ + comment_view::CommentQueryBuilder, community_view::CommunityQueryBuilder, post_view::PostQueryBuilder, site_view::SiteView, @@ -377,10 +377,9 @@ impl Perform for Search { } SearchType::Comments => { comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(&conn) + CommentQueryBuilder::create(&conn, user_id) .sort(&sort) .search_term(q) - .my_user_id(user_id) .page(page) .limit(limit) .list() @@ -427,10 +426,9 @@ impl Perform for Search { let sort = SortType::from_str(&data.sort)?; comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) + CommentQueryBuilder::create(conn, user_id) .sort(&sort) .search_term(q) - .my_user_id(user_id) .page(page) .limit(limit) .list() diff --git a/lemmy_api/src/user.rs b/lemmy_api/src/user.rs index e8099af89..df6284a53 100644 --- a/lemmy_api/src/user.rs +++ b/lemmy_api/src/user.rs @@ -16,7 +16,6 @@ use chrono::Duration; use lemmy_apub::ApubObjectType; use lemmy_db::{ comment_report::CommentReportView, - comment_view::*, diesel_option_overwrite, naive_now, post_report::PostReportView, @@ -34,6 +33,7 @@ use lemmy_db::{ }, user_mention_view::*, views::{ + comment_view::CommentQueryBuilder, community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, post_view::PostQueryBuilder, @@ -544,10 +544,9 @@ impl Perform for GetUserDetails { .page(page) .limit(limit); - let mut comments_query = CommentQueryBuilder::create(conn) + let mut comments_query = CommentQueryBuilder::create(conn, user_id) .sort(&sort) .saved_only(saved_only) - .my_user_id(user_id) .page(page) .limit(limit); @@ -742,9 +741,10 @@ impl Perform for GetReplies { let unread_only = data.unread_only; let user_id = user.id; let replies = blocking(context.pool(), move |conn| { - ReplyQueryBuilder::create(conn, user_id) + CommentQueryBuilder::create(conn, Some(user_id)) .sort(&sort) .unread_only(unread_only) + .for_recipient_id(user_id) .page(page) .limit(limit) .list() @@ -843,7 +843,8 @@ impl Perform for MarkAllAsRead { let user_id = user.id; let replies = blocking(context.pool(), move |conn| { - ReplyQueryBuilder::create(conn, user_id) + CommentQueryBuilder::create(conn, Some(user_id)) + .for_recipient_id(user_id) .unread_only(true) .page(1) .limit(999) @@ -854,8 +855,8 @@ impl Perform for MarkAllAsRead { // TODO: this should probably be a bulk operation // Not easy to do as a bulk operation, // because recipient_id isn't in the comment table - for reply in &replies { - let reply_id = reply.id; + for comment_view in &replies { + let reply_id = comment_view.comment.id; let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true); if blocking(context.pool(), mark_as_read).await?.is_err() { return Err(APIError::err("couldnt_update_comment").into()); diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index f545a0426..700a2653c 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -5,11 +5,11 @@ use activitystreams::{ }; use anyhow::Context; use lemmy_db::{ - comment_view::CommentView, source::{ comment::{Comment, CommentLike, CommentLikeForm}, post::Post, }, + views::comment_view::CommentView, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs}; @@ -45,7 +45,7 @@ pub(crate) async fn receive_create_comment( .await??; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -85,7 +85,7 @@ pub(crate) async fn receive_update_comment( .await??; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -130,7 +130,7 @@ pub(crate) async fn receive_like_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -175,7 +175,7 @@ pub(crate) async fn receive_dislike_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -208,7 +208,7 @@ pub(crate) async fn receive_delete_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -241,7 +241,7 @@ pub(crate) async fn receive_remove_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index bf91fe3dd..85dcc143d 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,8 +1,8 @@ use crate::activities::receive::get_actor_as_user; use activitystreams::activity::{Dislike, Like}; use lemmy_db::{ - comment_view::CommentView, source::comment::{Comment, CommentLike}, + views::comment_view::CommentView, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse}; @@ -33,7 +33,7 @@ pub(crate) async fn receive_undo_like_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -71,7 +71,7 @@ pub(crate) async fn receive_undo_dislike_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -104,7 +104,7 @@ pub(crate) async fn receive_undo_delete_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; @@ -137,7 +137,7 @@ pub(crate) async fn receive_undo_remove_comment( // TODO get those recipient actor ids from somewhere let recipient_ids = vec![]; let res = CommentResponse { - comment: comment_view, + comment_view, recipient_ids, form_id: None, }; diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index 2d40673fe..08735b4c2 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -13,7 +13,6 @@ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use diesel::result::Error::NotFound; use lemmy_db::{ - comment_view::CommentView, naive_now, source::{ comment::Comment, @@ -21,7 +20,12 @@ use lemmy_db::{ post::Post, user::User_, }, - views::{community_view::CommunityView, post_view::PostView, user_view::UserViewSafe}, + views::{ + comment_view::CommentView, + community_view::CommunityView, + post_view::PostView, + user_view::UserViewSafe, + }, ApubObject, Joinable, SearchType, diff --git a/lemmy_db/src/comment_view.rs b/lemmy_db/src/comment_view.rs deleted file mode 100644 index f463168b6..000000000 --- a/lemmy_db/src/comment_view.rs +++ /dev/null @@ -1,716 +0,0 @@ -// TODO, remove the cross join here, just join to user directly -use crate::{fuzzy_search, limit_and_offset, ListingType, MaybeOptional, SortType}; -use diesel::{dsl::*, pg::Pg, result::Error, *}; -use serde::{Deserialize, Serialize}; - -// The faked schema since diesel doesn't do views -table! { - comment_view (id) { - id -> Int4, - creator_id -> Int4, - post_id -> Int4, - post_name -> Varchar, - parent_id -> Nullable, - content -> Text, - removed -> Bool, - read -> Bool, - published -> Timestamp, - updated -> Nullable, - deleted -> Bool, - ap_id -> Text, - local -> Bool, - community_id -> Int4, - community_actor_id -> Text, - community_local -> Bool, - community_name -> Varchar, - community_icon -> Nullable, - banned -> Bool, - banned_from_community -> Bool, - creator_actor_id -> Text, - creator_local -> Bool, - creator_name -> Varchar, - creator_preferred_username -> Nullable, - creator_published -> Timestamp, - creator_avatar -> Nullable, - score -> BigInt, - upvotes -> BigInt, - downvotes -> BigInt, - hot_rank -> Int4, - hot_rank_active -> Int4, - user_id -> Nullable, - my_vote -> Nullable, - subscribed -> Nullable, - saved -> Nullable, - } -} - -table! { - comment_fast_view (id) { - id -> Int4, - creator_id -> Int4, - post_id -> Int4, - post_name -> Varchar, - parent_id -> Nullable, - content -> Text, - removed -> Bool, - read -> Bool, - published -> Timestamp, - updated -> Nullable, - deleted -> Bool, - ap_id -> Text, - local -> Bool, - community_id -> Int4, - community_actor_id -> Text, - community_local -> Bool, - community_name -> Varchar, - community_icon -> Nullable, - banned -> Bool, - banned_from_community -> Bool, - creator_actor_id -> Text, - creator_local -> Bool, - creator_name -> Varchar, - creator_preferred_username -> Nullable, - creator_published -> Timestamp, - creator_avatar -> Nullable, - score -> BigInt, - upvotes -> BigInt, - downvotes -> BigInt, - hot_rank -> Int4, - hot_rank_active -> Int4, - user_id -> Nullable, - my_vote -> Nullable, - subscribed -> Nullable, - saved -> Nullable, - } -} - -#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)] -#[table_name = "comment_fast_view"] -pub struct CommentView { - pub id: i32, - pub creator_id: i32, - pub post_id: i32, - pub post_name: String, - pub parent_id: Option, - pub content: String, - pub removed: bool, - pub read: bool, - pub published: chrono::NaiveDateTime, - pub updated: Option, - pub deleted: bool, - pub ap_id: String, - pub local: bool, - pub community_id: i32, - pub community_actor_id: String, - pub community_local: bool, - pub community_name: String, - pub community_icon: Option, - pub banned: bool, - pub banned_from_community: bool, - pub creator_actor_id: String, - pub creator_local: bool, - pub creator_name: String, - pub creator_preferred_username: Option, - pub creator_published: chrono::NaiveDateTime, - pub creator_avatar: Option, - pub score: i64, - pub upvotes: i64, - pub downvotes: i64, - pub hot_rank: i32, - pub hot_rank_active: i32, - pub user_id: Option, - pub my_vote: Option, - pub subscribed: Option, - pub saved: Option, -} - -pub struct CommentQueryBuilder<'a> { - conn: &'a PgConnection, - query: super::comment_view::comment_fast_view::BoxedQuery<'a, Pg>, - listing_type: ListingType, - sort: &'a SortType, - for_community_id: Option, - for_community_name: Option, - for_post_id: Option, - for_creator_id: Option, - search_term: Option, - my_user_id: Option, - saved_only: bool, - page: Option, - limit: Option, -} - -impl<'a> CommentQueryBuilder<'a> { - pub fn create(conn: &'a PgConnection) -> Self { - use super::comment_view::comment_fast_view::dsl::*; - - let query = comment_fast_view.into_boxed(); - - CommentQueryBuilder { - conn, - query, - listing_type: ListingType::All, - sort: &SortType::New, - for_community_id: None, - for_community_name: None, - for_post_id: None, - for_creator_id: None, - search_term: None, - my_user_id: None, - saved_only: false, - page: None, - limit: None, - } - } - - pub fn listing_type(mut self, listing_type: ListingType) -> Self { - self.listing_type = listing_type; - self - } - - pub fn sort(mut self, sort: &'a SortType) -> Self { - self.sort = sort; - self - } - - pub fn for_post_id>(mut self, for_post_id: T) -> Self { - self.for_post_id = for_post_id.get_optional(); - self - } - - pub fn for_creator_id>(mut self, for_creator_id: T) -> Self { - self.for_creator_id = for_creator_id.get_optional(); - self - } - - pub fn for_community_id>(mut self, for_community_id: T) -> Self { - self.for_community_id = for_community_id.get_optional(); - self - } - - pub fn for_community_name>(mut self, for_community_name: T) -> Self { - self.for_community_name = for_community_name.get_optional(); - self - } - - pub fn search_term>(mut self, search_term: T) -> Self { - self.search_term = search_term.get_optional(); - self - } - - pub fn my_user_id>(mut self, my_user_id: T) -> Self { - self.my_user_id = my_user_id.get_optional(); - self - } - - pub fn saved_only(mut self, saved_only: bool) -> Self { - self.saved_only = saved_only; - self - } - - pub fn page>(mut self, page: T) -> Self { - self.page = page.get_optional(); - self - } - - pub fn limit>(mut self, limit: T) -> Self { - self.limit = limit.get_optional(); - self - } - - pub fn list(self) -> Result, Error> { - use super::comment_view::comment_fast_view::dsl::*; - - let mut query = self.query; - - // The view lets you pass a null user_id, if you're not logged in - if let Some(my_user_id) = self.my_user_id { - query = query.filter(user_id.eq(my_user_id)); - } else { - query = query.filter(user_id.is_null()); - } - - if let Some(for_creator_id) = self.for_creator_id { - query = query.filter(creator_id.eq(for_creator_id)); - }; - - if let Some(for_community_id) = self.for_community_id { - query = query.filter(community_id.eq(for_community_id)); - } - - if let Some(for_community_name) = self.for_community_name { - query = query - .filter(community_name.eq(for_community_name)) - .filter(local.eq(true)); - } - - if let Some(for_post_id) = self.for_post_id { - query = query.filter(post_id.eq(for_post_id)); - }; - - if let Some(search_term) = self.search_term { - query = query.filter(content.ilike(fuzzy_search(&search_term))); - }; - - query = match self.listing_type { - ListingType::Subscribed => query.filter(subscribed.eq(true)), - ListingType::Local => query.filter(community_local.eq(true)), - _ => query, - }; - - if self.saved_only { - query = query.filter(saved.eq(true)); - } - - query = match self.sort { - SortType::Hot => query - .order_by(hot_rank.desc()) - .then_order_by(published.desc()), - SortType::Active => query - .order_by(hot_rank_active.desc()) - .then_order_by(published.desc()), - SortType::New => query.order_by(published.desc()), - SortType::TopAll => query.order_by(score.desc()), - SortType::TopYear => query - .filter(published.gt(now - 1.years())) - .order_by(score.desc()), - SortType::TopMonth => query - .filter(published.gt(now - 1.months())) - .order_by(score.desc()), - SortType::TopWeek => query - .filter(published.gt(now - 1.weeks())) - .order_by(score.desc()), - SortType::TopDay => query - .filter(published.gt(now - 1.days())) - .order_by(score.desc()), - // _ => query.order_by(published.desc()), - }; - - let (limit, offset) = limit_and_offset(self.page, self.limit); - - // Note: deleted and removed comments are done on the front side - query - .limit(limit) - .offset(offset) - .load::(self.conn) - } -} - -impl CommentView { - pub fn read( - conn: &PgConnection, - from_comment_id: i32, - my_user_id: Option, - ) -> Result { - use super::comment_view::comment_fast_view::dsl::*; - let mut query = comment_fast_view.into_boxed(); - - // The view lets you pass a null user_id, if you're not logged in - if let Some(my_user_id) = my_user_id { - query = query.filter(user_id.eq(my_user_id)); - } else { - query = query.filter(user_id.is_null()); - } - - query = query - .filter(id.eq(from_comment_id)) - .order_by(published.desc()); - - query.first::(conn) - } -} - -// The faked schema since diesel doesn't do views -table! { - reply_fast_view (id) { - id -> Int4, - creator_id -> Int4, - post_id -> Int4, - post_name -> Varchar, - parent_id -> Nullable, - content -> Text, - removed -> Bool, - read -> Bool, - published -> Timestamp, - updated -> Nullable, - deleted -> Bool, - ap_id -> Text, - local -> Bool, - community_id -> Int4, - community_actor_id -> Text, - community_local -> Bool, - community_name -> Varchar, - community_icon -> Nullable, - banned -> Bool, - banned_from_community -> Bool, - creator_actor_id -> Text, - creator_local -> Bool, - creator_name -> Varchar, - creator_preferred_username -> Nullable, - creator_avatar -> Nullable, - creator_published -> Timestamp, - score -> BigInt, - upvotes -> BigInt, - downvotes -> BigInt, - hot_rank -> Int4, - hot_rank_active -> Int4, - user_id -> Nullable, - my_vote -> Nullable, - subscribed -> Nullable, - saved -> Nullable, - recipient_id -> Int4, - } -} - -#[derive( - Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone, -)] -#[table_name = "reply_fast_view"] -pub struct ReplyView { - pub id: i32, - pub creator_id: i32, - pub post_id: i32, - pub post_name: String, - pub parent_id: Option, - pub content: String, - pub removed: bool, - pub read: bool, - pub published: chrono::NaiveDateTime, - pub updated: Option, - pub deleted: bool, - pub ap_id: String, - pub local: bool, - pub community_id: i32, - pub community_actor_id: String, - pub community_local: bool, - pub community_name: String, - pub community_icon: Option, - pub banned: bool, - pub banned_from_community: bool, - pub creator_actor_id: String, - pub creator_local: bool, - pub creator_name: String, - pub creator_preferred_username: Option, - pub creator_avatar: Option, - pub creator_published: chrono::NaiveDateTime, - pub score: i64, - pub upvotes: i64, - pub downvotes: i64, - pub hot_rank: i32, - pub hot_rank_active: i32, - pub user_id: Option, - pub my_vote: Option, - pub subscribed: Option, - pub saved: Option, - pub recipient_id: i32, -} - -pub struct ReplyQueryBuilder<'a> { - conn: &'a PgConnection, - query: super::comment_view::reply_fast_view::BoxedQuery<'a, Pg>, - for_user_id: i32, - sort: &'a SortType, - unread_only: bool, - page: Option, - limit: Option, -} - -impl<'a> ReplyQueryBuilder<'a> { - pub fn create(conn: &'a PgConnection, for_user_id: i32) -> Self { - use super::comment_view::reply_fast_view::dsl::*; - - let query = reply_fast_view.into_boxed(); - - ReplyQueryBuilder { - conn, - query, - for_user_id, - sort: &SortType::New, - unread_only: false, - page: None, - limit: None, - } - } - - pub fn sort(mut self, sort: &'a SortType) -> Self { - self.sort = sort; - self - } - - pub fn unread_only(mut self, unread_only: bool) -> Self { - self.unread_only = unread_only; - self - } - - pub fn page>(mut self, page: T) -> Self { - self.page = page.get_optional(); - self - } - - pub fn limit>(mut self, limit: T) -> Self { - self.limit = limit.get_optional(); - self - } - - pub fn list(self) -> Result, Error> { - use super::comment_view::reply_fast_view::dsl::*; - - let mut query = self.query; - - query = query - .filter(user_id.eq(self.for_user_id)) - .filter(recipient_id.eq(self.for_user_id)) - .filter(deleted.eq(false)) - .filter(removed.eq(false)); - - if self.unread_only { - query = query.filter(read.eq(false)); - } - - query = match self.sort { - // SortType::Hot => query.order_by(hot_rank.desc()), // TODO why is this commented - SortType::New => query.order_by(published.desc()), - SortType::TopAll => query.order_by(score.desc()), - SortType::TopYear => query - .filter(published.gt(now - 1.years())) - .order_by(score.desc()), - SortType::TopMonth => query - .filter(published.gt(now - 1.months())) - .order_by(score.desc()), - SortType::TopWeek => query - .filter(published.gt(now - 1.weeks())) - .order_by(score.desc()), - SortType::TopDay => query - .filter(published.gt(now - 1.days())) - .order_by(score.desc()), - _ => query.order_by(published.desc()), - }; - - let (limit, offset) = limit_and_offset(self.page, self.limit); - query - .limit(limit) - .offset(offset) - .load::(self.conn) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - comment_view::*, - source::{comment::*, community::*, post::*, user::*}, - tests::establish_unpooled_connection, - Crud, - Likeable, - *, - }; - - #[test] - fn test_crud() { - let conn = establish_unpooled_connection(); - - let new_user = UserForm { - name: "timmy".into(), - preferred_username: None, - password_encrypted: "nope".into(), - email: None, - matrix_user_id: None, - avatar: None, - banner: None, - admin: false, - banned: Some(false), - published: None, - updated: None, - show_nsfw: false, - theme: "browser".into(), - default_sort_type: SortType::Hot as i16, - default_listing_type: ListingType::Subscribed as i16, - lang: "browser".into(), - show_avatars: true, - send_notifications_to_email: false, - actor_id: None, - bio: None, - local: true, - private_key: None, - public_key: None, - last_refreshed_at: None, - }; - - let inserted_user = User_::create(&conn, &new_user).unwrap(); - - let new_community = CommunityForm { - name: "test community 5".to_string(), - title: "nada".to_owned(), - description: None, - category_id: 1, - creator_id: inserted_user.id, - removed: None, - deleted: None, - updated: None, - nsfw: false, - actor_id: None, - local: true, - private_key: None, - public_key: None, - last_refreshed_at: None, - published: None, - icon: None, - banner: None, - }; - - let inserted_community = Community::create(&conn, &new_community).unwrap(); - - let new_post = PostForm { - name: "A test post 2".into(), - creator_id: inserted_user.id, - url: None, - body: None, - community_id: inserted_community.id, - removed: None, - deleted: None, - locked: None, - stickied: None, - updated: None, - nsfw: false, - embed_title: None, - embed_description: None, - embed_html: None, - thumbnail_url: None, - ap_id: None, - local: true, - published: None, - }; - - let inserted_post = Post::create(&conn, &new_post).unwrap(); - - let comment_form = CommentForm { - content: "A test comment 32".into(), - creator_id: inserted_user.id, - post_id: inserted_post.id, - parent_id: None, - removed: None, - deleted: None, - read: None, - published: None, - updated: None, - ap_id: None, - local: true, - }; - - let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); - - let comment_like_form = CommentLikeForm { - comment_id: inserted_comment.id, - post_id: inserted_post.id, - user_id: inserted_user.id, - score: 1, - }; - - let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap(); - - let expected_comment_view_no_user = CommentView { - id: inserted_comment.id, - content: "A test comment 32".into(), - creator_id: inserted_user.id, - post_id: inserted_post.id, - post_name: inserted_post.name.to_owned(), - community_id: inserted_community.id, - community_name: inserted_community.name.to_owned(), - community_icon: None, - parent_id: None, - removed: false, - deleted: false, - read: false, - banned: false, - banned_from_community: false, - published: inserted_comment.published, - updated: None, - creator_name: inserted_user.name.to_owned(), - creator_preferred_username: None, - creator_published: inserted_user.published, - creator_avatar: None, - score: 1, - downvotes: 0, - hot_rank: 0, - hot_rank_active: 0, - upvotes: 1, - user_id: None, - my_vote: None, - subscribed: None, - saved: None, - ap_id: inserted_comment.ap_id.to_owned(), - local: true, - community_actor_id: inserted_community.actor_id.to_owned(), - community_local: true, - creator_actor_id: inserted_user.actor_id.to_owned(), - creator_local: true, - }; - - let expected_comment_view_with_user = CommentView { - id: inserted_comment.id, - content: "A test comment 32".into(), - creator_id: inserted_user.id, - post_id: inserted_post.id, - post_name: inserted_post.name.to_owned(), - community_id: inserted_community.id, - community_name: inserted_community.name.to_owned(), - community_icon: None, - parent_id: None, - removed: false, - deleted: false, - read: false, - banned: false, - banned_from_community: false, - published: inserted_comment.published, - updated: None, - creator_name: inserted_user.name.to_owned(), - creator_preferred_username: None, - creator_published: inserted_user.published, - creator_avatar: None, - score: 1, - downvotes: 0, - hot_rank: 0, - hot_rank_active: 0, - upvotes: 1, - user_id: Some(inserted_user.id), - my_vote: Some(1), - subscribed: Some(false), - saved: Some(false), - ap_id: inserted_comment.ap_id.to_owned(), - local: true, - community_actor_id: inserted_community.actor_id.to_owned(), - community_local: true, - creator_actor_id: inserted_user.actor_id.to_owned(), - creator_local: true, - }; - - let mut read_comment_views_no_user = CommentQueryBuilder::create(&conn) - .for_post_id(inserted_post.id) - .list() - .unwrap(); - read_comment_views_no_user[0].hot_rank = 0; - read_comment_views_no_user[0].hot_rank_active = 0; - - let mut read_comment_views_with_user = CommentQueryBuilder::create(&conn) - .for_post_id(inserted_post.id) - .my_user_id(inserted_user.id) - .list() - .unwrap(); - read_comment_views_with_user[0].hot_rank = 0; - read_comment_views_with_user[0].hot_rank_active = 0; - - let like_removed = CommentLike::remove(&conn, inserted_user.id, inserted_comment.id).unwrap(); - let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); - Post::delete(&conn, inserted_post.id).unwrap(); - Community::delete(&conn, inserted_community.id).unwrap(); - User_::delete(&conn, inserted_user.id).unwrap(); - - assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]); - assert_eq!( - expected_comment_view_with_user, - read_comment_views_with_user[0] - ); - assert_eq!(1, num_deleted); - assert_eq!(1, like_removed); - } -} diff --git a/lemmy_db/src/lib.rs b/lemmy_db/src/lib.rs index 098a88e4a..449cfc2b4 100644 --- a/lemmy_db/src/lib.rs +++ b/lemmy_db/src/lib.rs @@ -12,7 +12,6 @@ use serde::{Deserialize, Serialize}; use std::{env, env::VarError}; pub mod comment_report; -pub mod comment_view; pub mod moderator_views; pub mod post_report; pub mod private_message_view; diff --git a/lemmy_db/src/views/comment_view.rs b/lemmy_db/src/views/comment_view.rs index 3e812699a..129970aff 100644 --- a/lemmy_db/src/views/comment_view.rs +++ b/lemmy_db/src/views/comment_view.rs @@ -660,3 +660,229 @@ impl ViewToVec for CommentView { .collect::>() } } + +#[cfg(test)] +mod tests { + use crate::{ + source::{comment::*, community::*, post::*, user::*}, + tests::establish_unpooled_connection, + views::comment_view::*, + Crud, + Likeable, + *, + }; + + #[test] + fn test_crud() { + let conn = establish_unpooled_connection(); + + let new_user = UserForm { + name: "timmy".into(), + preferred_username: None, + password_encrypted: "nope".into(), + email: None, + matrix_user_id: None, + avatar: None, + banner: None, + admin: false, + banned: Some(false), + published: None, + updated: None, + show_nsfw: false, + theme: "browser".into(), + default_sort_type: SortType::Hot as i16, + default_listing_type: ListingType::Subscribed as i16, + lang: "browser".into(), + show_avatars: true, + send_notifications_to_email: false, + actor_id: None, + bio: None, + local: true, + private_key: None, + public_key: None, + last_refreshed_at: None, + }; + + let inserted_user = User_::create(&conn, &new_user).unwrap(); + + let new_community = CommunityForm { + name: "test community 5".to_string(), + title: "nada".to_owned(), + description: None, + category_id: 1, + creator_id: inserted_user.id, + removed: None, + deleted: None, + updated: None, + nsfw: false, + actor_id: None, + local: true, + private_key: None, + public_key: None, + last_refreshed_at: None, + published: None, + icon: None, + banner: None, + }; + + let inserted_community = Community::create(&conn, &new_community).unwrap(); + + let new_post = PostForm { + name: "A test post 2".into(), + creator_id: inserted_user.id, + url: None, + body: None, + community_id: inserted_community.id, + removed: None, + deleted: None, + locked: None, + stickied: None, + updated: None, + nsfw: false, + embed_title: None, + embed_description: None, + embed_html: None, + thumbnail_url: None, + ap_id: None, + local: true, + published: None, + }; + + let inserted_post = Post::create(&conn, &new_post).unwrap(); + + let comment_form = CommentForm { + content: "A test comment 32".into(), + creator_id: inserted_user.id, + post_id: inserted_post.id, + parent_id: None, + removed: None, + deleted: None, + read: None, + published: None, + updated: None, + ap_id: None, + local: true, + }; + + let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); + + let comment_like_form = CommentLikeForm { + comment_id: inserted_comment.id, + post_id: inserted_post.id, + user_id: inserted_user.id, + score: 1, + }; + + let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap(); + + let expected_comment_view_no_user = CommentView { + creator_banned_from_community: false, + my_vote: None, + subscribed: false, + saved: false, + comment: Comment { + id: inserted_comment.id, + content: "A test comment 32".into(), + creator_id: inserted_user.id, + post_id: inserted_post.id, + parent_id: None, + removed: false, + deleted: false, + read: false, + published: inserted_comment.published, + ap_id: inserted_comment.ap_id, + updated: None, + local: true, + }, + creator: UserSafe { + id: inserted_user.id, + name: "timmy".into(), + preferred_username: None, + published: inserted_user.published, + avatar: None, + actor_id: inserted_user.actor_id.to_owned(), + local: true, + banned: false, + deleted: false, + bio: None, + banner: None, + admin: false, + updated: None, + matrix_user_id: None, + }, + recipient: None, + post: Post { + id: inserted_post.id, + name: inserted_post.name.to_owned(), + creator_id: inserted_user.id, + url: None, + body: None, + published: inserted_post.published, + updated: None, + community_id: inserted_community.id, + removed: false, + deleted: false, + locked: false, + stickied: false, + nsfw: false, + embed_title: None, + embed_description: None, + embed_html: None, + thumbnail_url: None, + ap_id: inserted_post.ap_id.to_owned(), + local: true, + }, + community: CommunitySafe { + id: inserted_community.id, + name: "test community 5".to_string(), + icon: None, + removed: false, + deleted: false, + nsfw: false, + actor_id: inserted_community.actor_id.to_owned(), + local: true, + title: "nada".to_owned(), + description: None, + creator_id: inserted_user.id, + category_id: 1, + updated: None, + banner: None, + published: inserted_community.published, + }, + counts: CommentAggregates { + id: inserted_comment.id, // TODO + comment_id: inserted_comment.id, + score: 1, + upvotes: 1, + downvotes: 0, + }, + }; + + let mut expected_comment_view_with_user = expected_comment_view_no_user.to_owned(); + expected_comment_view_with_user.my_vote = Some(1); + + let read_comment_views_no_user = CommentQueryBuilder::create(&conn, None) + .for_post_id(inserted_post.id) + .list() + .unwrap(); + + let read_comment_views_with_user = CommentQueryBuilder::create(&conn, Some(inserted_user.id)) + .for_post_id(inserted_post.id) + .list() + .unwrap(); + + let like_removed = CommentLike::remove(&conn, inserted_user.id, inserted_comment.id).unwrap(); + let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); + Post::delete(&conn, inserted_post.id).unwrap(); + Community::delete(&conn, inserted_community.id).unwrap(); + User_::delete(&conn, inserted_user.id).unwrap(); + + assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]); + assert_eq!( + expected_comment_view_with_user, + read_comment_views_with_user[0] + ); + assert_eq!(1, num_deleted); + assert_eq!(1, like_removed); + } +} diff --git a/lemmy_structs/src/comment.rs b/lemmy_structs/src/comment.rs index 6479124f8..277499f49 100644 --- a/lemmy_structs/src/comment.rs +++ b/lemmy_structs/src/comment.rs @@ -1,4 +1,4 @@ -use lemmy_db::{comment_report::CommentReportView, comment_view::CommentView}; +use lemmy_db::{comment_report::CommentReportView, views::comment_view::CommentView}; use serde::{Deserialize, Serialize}; #[derive(Deserialize)] @@ -49,7 +49,7 @@ pub struct SaveComment { #[derive(Serialize, Clone)] pub struct CommentResponse { - pub comment: CommentView, + pub comment_view: CommentView, pub recipient_ids: Vec, pub form_id: Option, } diff --git a/lemmy_structs/src/post.rs b/lemmy_structs/src/post.rs index 49ae14c2e..eea107a7e 100644 --- a/lemmy_structs/src/post.rs +++ b/lemmy_structs/src/post.rs @@ -1,7 +1,7 @@ use lemmy_db::{ - comment_view::CommentView, post_report::PostReportView, views::{ + comment_view::CommentView, community_moderator_view::CommunityModeratorView, community_view::CommunityView, post_view::PostView, diff --git a/lemmy_structs/src/site.rs b/lemmy_structs/src/site.rs index 002c3ace2..f32b84134 100644 --- a/lemmy_structs/src/site.rs +++ b/lemmy_structs/src/site.rs @@ -1,9 +1,9 @@ use lemmy_db::{ aggregates::site_aggregates::SiteAggregates, - comment_view::*, moderator_views::*, source::{category::*, user::*}, views::{ + comment_view::CommentView, community_view::CommunityView, post_view::PostView, site_view::SiteView, diff --git a/lemmy_structs/src/user.rs b/lemmy_structs/src/user.rs index eb891c2f7..600bf660c 100644 --- a/lemmy_structs/src/user.rs +++ b/lemmy_structs/src/user.rs @@ -1,8 +1,8 @@ use lemmy_db::{ - comment_view::{CommentView, ReplyView}, private_message_view::PrivateMessageView, user_mention_view::UserMentionView, views::{ + comment_view::CommentView, community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, post_view::PostView, @@ -94,7 +94,7 @@ pub struct GetUserDetailsResponse { #[derive(Serialize)] pub struct GetRepliesResponse { - pub replies: Vec, + pub replies: Vec, } #[derive(Serialize)] diff --git a/lemmy_websocket/src/chat_server.rs b/lemmy_websocket/src/chat_server.rs index 86025ade7..ece5d3534 100644 --- a/lemmy_websocket/src/chat_server.rs +++ b/lemmy_websocket/src/chat_server.rs @@ -328,9 +328,10 @@ impl ChatServer { comment: &CommentResponse, websocket_id: Option, ) -> Result<(), LemmyError> { - let mut comment_reply_sent = comment.clone(); - comment_reply_sent.comment.my_vote = None; - comment_reply_sent.comment.user_id = None; + let comment_reply_sent = comment.clone(); + // TODO what is this here + // comment_reply_sent.comment_view.my_vote = None; + // comment_reply_sent.comment.user_id = None; let mut comment_post_sent = comment_reply_sent.clone(); comment_post_sent.recipient_ids = Vec::new(); @@ -339,7 +340,7 @@ impl ChatServer { self.send_post_room_message( user_operation, &comment_post_sent, - comment_post_sent.comment.post_id, + comment_post_sent.comment_view.post.id, websocket_id, )?; @@ -358,7 +359,7 @@ impl ChatServer { self.send_community_room_message( user_operation, &comment_post_sent, - comment.comment.community_id, + comment.comment_view.community.id, websocket_id, )?; diff --git a/src/routes/feeds.rs b/src/routes/feeds.rs index 887faa88d..e8ab10375 100644 --- a/src/routes/feeds.rs +++ b/src/routes/feeds.rs @@ -4,10 +4,10 @@ use chrono::{DateTime, NaiveDateTime, Utc}; use diesel::PgConnection; use lemmy_api::claims::Claims; use lemmy_db::{ - comment_view::{ReplyQueryBuilder, ReplyView}, source::{community::Community, user::User_}, user_mention_view::{UserMentionQueryBuilder, UserMentionView}, views::{ + comment_view::{CommentQueryBuilder, CommentView}, post_view::{PostQueryBuilder, PostView}, site_view::SiteView, }, @@ -248,7 +248,8 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result Result, + replies: Vec, mentions: Vec, ) -> Result, LemmyError> { let mut reply_items: Vec = replies @@ -285,10 +286,15 @@ fn create_reply_and_mention_items( let reply_url = format!( "{}/post/{}/comment/{}", Settings::get().get_protocol_and_hostname(), - r.post_id, - r.id + r.post.id, + r.comment.id ); - build_item(&r.creator_name, &r.published, &reply_url, &r.content) + build_item( + &r.creator.name, + &r.comment.published, + &reply_url, + &r.comment.content, + ) }) .collect::, LemmyError>>()?;