From 97aa7268ae3efd1b29a1f1dc66c5d7506823418e Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sat, 16 Oct 2021 06:43:41 -0400 Subject: [PATCH] Adding GetUnreadCount to the API. Fixes #1794 (#1842) * Adding GetUnreadCount to the API. Fixes #1794 * Reordering filters to fix unread replies. --- crates/api/src/lib.rs | 3 ++ crates/api/src/local_user.rs | 43 ++++++++++++++++++- crates/api_common/src/person.rs | 12 ++++++ crates/db_views/src/comment_view.rs | 40 +++++++++++++++++ crates/db_views/src/private_message_view.rs | 11 +++++ .../db_views_actor/src/person_mention_view.rs | 11 +++++ crates/websocket/src/lib.rs | 1 + src/api_routes.rs | 3 +- 8 files changed, 122 insertions(+), 2 deletions(-) diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index bfaceeb02..ccc817616 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -72,6 +72,9 @@ pub async fn match_websocket_operation( UserOperation::GetReportCount => { do_websocket_operation::(context, id, op, data).await } + UserOperation::GetUnreadCount => { + do_websocket_operation::(context, id, op, data).await + } // Private Message ops UserOperation::MarkPrivateMessageAsRead => { diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs index a7d2f0c3c..d5a1533f9 100644 --- a/crates/api/src/local_user.rs +++ b/crates/api/src/local_user.rs @@ -47,9 +47,10 @@ use lemmy_db_schema::{ }; use lemmy_db_views::{ comment_report_view::CommentReportView, - comment_view::CommentQueryBuilder, + comment_view::{CommentQueryBuilder, CommentView}, local_user_view::LocalUserView, post_report_view::PostReportView, + private_message_view::PrivateMessageView, }; use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, @@ -831,3 +832,43 @@ impl Perform for GetReportCount { Ok(res) } } + +#[async_trait::async_trait(?Send)] +impl Perform for GetUnreadCount { + type Response = GetUnreadCountResponse; + + async fn perform( + &self, + context: &Data, + _websocket_id: Option, + ) -> Result { + let data = self; + let local_user_view = + get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; + + let person_id = local_user_view.person.id; + + let replies = blocking(context.pool(), move |conn| { + CommentView::get_unread_replies(conn, person_id) + }) + .await??; + + let mentions = blocking(context.pool(), move |conn| { + PersonMentionView::get_unread_mentions(conn, person_id) + }) + .await??; + + let private_messages = blocking(context.pool(), move |conn| { + PrivateMessageView::get_unread_messages(conn, person_id) + }) + .await??; + + let res = Self::Response { + replies, + mentions, + private_messages, + }; + + Ok(res) + } +} diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 2dd9953b7..af7212bac 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -266,3 +266,15 @@ pub struct GetReportCountResponse { pub comment_reports: i64, pub post_reports: i64, } + +#[derive(Deserialize)] +pub struct GetUnreadCount { + pub auth: String, +} + +#[derive(Serialize, Clone)] +pub struct GetUnreadCountResponse { + pub replies: i64, + pub mentions: i64, + pub private_messages: i64, +} diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index f682a232c..e61752805 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -184,6 +184,46 @@ impl CommentView { None => self.post.creator_id, } } + + /// Gets the number of unread replies + pub fn get_unread_replies(conn: &PgConnection, my_person_id: PersonId) -> Result { + use diesel::dsl::*; + + comment::table + // recipient here + .left_join(comment_alias_1::table.on(comment_alias_1::id.nullable().eq(comment::parent_id))) + .left_join(person_alias_1::table.on(person_alias_1::id.eq(comment_alias_1::creator_id))) + .inner_join(post::table) + .inner_join(community::table.on(post::community_id.eq(community::id))) + .left_join( + person_block::table.on( + comment::creator_id + .eq(person_block::target_id) + .and(person_block::person_id.eq(my_person_id)), + ), + ) + .left_join( + community_block::table.on( + community::id + .eq(community_block::community_id) + .and(community_block::person_id.eq(my_person_id)), + ), + ) + .filter(person_alias_1::id.eq(my_person_id)) // Gets the comment replies + .or_filter( + comment::parent_id + .is_null() + .and(post::creator_id.eq(my_person_id)), + ) // Gets the top level replies + .filter(comment::read.eq(false)) + .filter(comment::deleted.eq(false)) + .filter(comment::removed.eq(false)) + // Don't show blocked communities or persons + .filter(community_block::person_id.is_null()) + .filter(person_block::person_id.is_null()) + .select(count(comment::id)) + .first::(conn) + } } pub struct CommentQueryBuilder<'a> { diff --git a/crates/db_views/src/private_message_view.rs b/crates/db_views/src/private_message_view.rs index 8fee2fc9b..86c1b79cb 100644 --- a/crates/db_views/src/private_message_view.rs +++ b/crates/db_views/src/private_message_view.rs @@ -41,6 +41,17 @@ impl PrivateMessageView { recipient, }) } + + /// Gets the number of unread messages + pub fn get_unread_messages(conn: &PgConnection, my_person_id: PersonId) -> Result { + use diesel::dsl::*; + private_message::table + .filter(private_message::read.eq(false)) + .filter(private_message::recipient_id.eq(my_person_id)) + .filter(private_message::deleted.eq(false)) + .select(count(private_message::id)) + .first::(conn) + } } pub struct PrivateMessageQueryBuilder<'a> { diff --git a/crates/db_views_actor/src/person_mention_view.rs b/crates/db_views_actor/src/person_mention_view.rs index 421c60a40..0d3cfc837 100644 --- a/crates/db_views_actor/src/person_mention_view.rs +++ b/crates/db_views_actor/src/person_mention_view.rs @@ -163,6 +163,17 @@ impl PersonMentionView { my_vote, }) } + + /// Gets the number of unread mentions + pub fn get_unread_mentions(conn: &PgConnection, my_person_id: PersonId) -> Result { + use diesel::dsl::*; + + person_mention::table + .filter(person_mention::recipient_id.eq(my_person_id)) + .filter(person_mention::read.eq(false)) + .select(count(person_mention::id)) + .first::(conn) + } } pub struct PersonMentionQueryBuilder<'a> { diff --git a/crates/websocket/src/lib.rs b/crates/websocket/src/lib.rs index 366512eb9..e9f488741 100644 --- a/crates/websocket/src/lib.rs +++ b/crates/websocket/src/lib.rs @@ -116,6 +116,7 @@ pub enum UserOperation { ResolvePostReport, ListPostReports, GetReportCount, + GetUnreadCount, FollowCommunity, GetReplies, GetPersonMentions, diff --git a/src/api_routes.rs b/src/api_routes.rs index 1d76af002..80d507ef8 100644 --- a/src/api_routes.rs +++ b/src/api_routes.rs @@ -193,7 +193,8 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { "/change_password", web::put().to(route_post::), ) - .route("/report_count", web::get().to(route_get::)), + .route("/report_count", web::get().to(route_get::)) + .route("/unread_count", web::get().to(route_get::)), ) // Admin Actions .service(