After creating a comment, update the unread comments for the post. (#4742)

* After creating a comment, update the unread comments for the post.

- Fixes #3863

* Addressing PR comments.

* Add comment.

---------

Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
Dessalines 2024-05-27 06:55:44 -04:00 committed by GitHub
parent ec77c00ef8
commit 0d5db29bc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 58 additions and 33 deletions

View File

@ -68,7 +68,6 @@ pub async fn like_post(
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?; .with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
} }
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
let community = Community::read(&mut context.pool(), post.community_id) let community = Community::read(&mut context.pool(), post.community_id)

View File

@ -38,7 +38,6 @@ pub async fn save_post(
.await? .await?
.ok_or(LemmyErrorType::CouldntFindPost)?; .ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
Ok(Json(PostResponse { post_view })) Ok(Json(PostResponse { post_view }))

View File

@ -6,6 +6,7 @@ use crate::{
use chrono::{DateTime, Days, Local, TimeZone, Utc}; use chrono::{DateTime, Days, Local, TimeZone, Utc};
use enum_map::{enum_map, EnumMap}; use enum_map::{enum_map, EnumMap};
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
newtypes::{CommunityId, DbUrl, InstanceId, PersonId, PostId}, newtypes::{CommunityId, DbUrl, InstanceId, PersonId, PostId},
source::{ source::{
comment::{Comment, CommentUpdateForm}, comment::{Comment, CommentUpdateForm},
@ -139,13 +140,7 @@ pub fn is_top_mod(
} }
} }
#[tracing::instrument(skip_all)] /// Marks a post as read for a given person.
pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> LemmyResult<Post> {
Post::read(pool, post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost.into())
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn mark_post_as_read( pub async fn mark_post_as_read(
person_id: PersonId, person_id: PersonId,
@ -158,6 +153,28 @@ pub async fn mark_post_as_read(
Ok(()) Ok(())
} }
/// Updates the read comment count for a post. Usually done when reading or creating a new comment.
#[tracing::instrument(skip_all)]
pub async fn update_read_comments(
person_id: PersonId,
post_id: PostId,
read_comments: i64,
pool: &mut DbPool<'_>,
) -> LemmyResult<()> {
let person_post_agg_form = PersonPostAggregatesForm {
person_id,
post_id,
read_comments,
..PersonPostAggregatesForm::default()
};
PersonPostAggregates::upsert(pool, &person_post_agg_form)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
Ok(())
}
pub fn check_user_valid(person: &Person) -> LemmyResult<()> { pub fn check_user_valid(person: &Person) -> LemmyResult<()> {
// Check for a site ban // Check for a site ban
if person.banned { if person.banned {

View File

@ -9,11 +9,11 @@ use lemmy_api_common::{
check_community_user_action, check_community_user_action,
check_post_deleted_or_removed, check_post_deleted_or_removed,
generate_local_apub_endpoint, generate_local_apub_endpoint,
get_post,
get_url_blocklist, get_url_blocklist,
is_mod_or_admin, is_mod_or_admin,
local_site_to_slur_regex, local_site_to_slur_regex,
process_markdown, process_markdown,
update_read_comments,
EndpointType, EndpointType,
}, },
}; };
@ -28,7 +28,7 @@ use lemmy_db_schema::{
}, },
traits::{Crud, Likeable}, traits::{Crud, Likeable},
}; };
use lemmy_db_views::structs::LocalUserView; use lemmy_db_views::structs::{LocalUserView, PostView};
use lemmy_utils::{ use lemmy_utils::{
error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field}, utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
@ -51,8 +51,19 @@ pub async fn create_comment(
// Check for a community ban // Check for a community ban
let post_id = data.post_id; let post_id = data.post_id;
let post = get_post(post_id, &mut context.pool()).await?;
let community_id = post.community_id; // Read the full post view in order to get the comments count.
let post_view = PostView::read(
&mut context.pool(),
post_id,
Some(local_user_view.person.id),
true,
)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
let post = post_view.post;
let community_id = post_view.community.id;
check_community_user_action(&local_user_view.person, community_id, &mut context.pool()).await?; check_community_user_action(&local_user_view.person, community_id, &mut context.pool()).await?;
check_post_deleted_or_removed(&post)?; check_post_deleted_or_removed(&post)?;
@ -164,6 +175,15 @@ pub async fn create_comment(
) )
.await?; .await?;
// Update the read comments, so your own new comment doesn't appear as a +1 unread
update_read_comments(
local_user_view.person.id,
post_id,
post_view.counts.comments + 1,
&mut context.pool(),
)
.await?;
// If we're responding to a comment where we're the recipient, // If we're responding to a comment where we're the recipient,
// (ie we're the grandparent, or the recipient of the parent comment_reply), // (ie we're the grandparent, or the recipient of the parent comment_reply),
// then mark the parent as read. // then mark the parent as read.

View File

@ -176,7 +176,6 @@ pub async fn create_post(
.await .await
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?; .with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
if let Some(url) = updated_post.url.clone() { if let Some(url) = updated_post.url.clone() {

View File

@ -2,10 +2,9 @@ use actix_web::web::{Data, Json, Query};
use lemmy_api_common::{ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
post::{GetPost, GetPostResponse}, post::{GetPost, GetPostResponse},
utils::{check_private_instance, is_mod_or_admin_opt, mark_post_as_read}, utils::{check_private_instance, is_mod_or_admin_opt, mark_post_as_read, update_read_comments},
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
source::{comment::Comment, post::Post}, source::{comment::Comment, post::Post},
traits::Crud, traits::Crud,
}; };
@ -14,7 +13,7 @@ use lemmy_db_views::{
structs::{LocalUserView, PostView, SiteView}, structs::{LocalUserView, PostView, SiteView},
}; };
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; use lemmy_utils::error::{LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))] #[tracing::instrument(skip(context))]
pub async fn get_post( pub async fn get_post(
@ -60,10 +59,17 @@ pub async fn get_post(
.await? .await?
.ok_or(LemmyErrorType::CouldntFindPost)?; .ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
let post_id = post_view.post.id; let post_id = post_view.post.id;
if let Some(person_id) = person_id { if let Some(person_id) = person_id {
mark_post_as_read(person_id, post_id, &mut context.pool()).await?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
update_read_comments(
person_id,
post_id,
post_view.counts.comments,
&mut context.pool(),
)
.await?;
} }
// Necessary for the sidebar subscribed // Necessary for the sidebar subscribed
@ -76,21 +82,6 @@ pub async fn get_post(
.await? .await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?; .ok_or(LemmyErrorType::CouldntFindCommunity)?;
// Insert into PersonPostAggregates
// to update the read_comments count
if let Some(person_id) = person_id {
let read_comments = post_view.counts.comments;
let person_post_agg_form = PersonPostAggregatesForm {
person_id,
post_id,
read_comments,
..PersonPostAggregatesForm::default()
};
PersonPostAggregates::upsert(&mut context.pool(), &person_post_agg_form)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
}
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
// Fetch the cross_posts // Fetch the cross_posts