mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-23 03:11:32 +00:00
Merge branch 'post_body_mentions' into combined_inbox
This commit is contained in:
commit
f133079f0b
39 changed files with 889 additions and 389 deletions
|
@ -5,10 +5,10 @@ use lemmy_api_common::{
|
|||
comment::{CommentResponse, CreateCommentLike},
|
||||
context::LemmyContext,
|
||||
send_activity::{ActivityChannel, SendActivityData},
|
||||
utils::{check_bot_account, check_community_user_action, check_local_vote_mode, VoteItem},
|
||||
utils::{check_bot_account, check_community_user_action, check_local_vote_mode},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::LocalUserId,
|
||||
newtypes::{LocalUserId, PostOrCommentId},
|
||||
source::{
|
||||
comment::{CommentLike, CommentLikeForm},
|
||||
comment_reply::CommentReply,
|
||||
|
@ -33,7 +33,7 @@ pub async fn like_comment(
|
|||
|
||||
check_local_vote_mode(
|
||||
data.score,
|
||||
VoteItem::Comment(comment_id),
|
||||
PostOrCommentId::Comment(comment_id),
|
||||
&local_site,
|
||||
local_user_view.person.id,
|
||||
&mut context.pool(),
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetPersonCommentMentions, GetPersonCommentMentionsResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::person_comment_mention_view::PersonCommentMentionQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_comment_mentions(
|
||||
data: Query<GetPersonCommentMentions>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetPersonCommentMentionsResponse>> {
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let unread_only = data.unread_only.unwrap_or_default();
|
||||
let person_id = Some(local_user_view.person.id);
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
|
||||
let comment_mentions = PersonCommentMentionQuery {
|
||||
recipient_id: person_id,
|
||||
my_person_id: person_id,
|
||||
sort,
|
||||
unread_only,
|
||||
show_bot_accounts,
|
||||
page,
|
||||
limit,
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(GetPersonCommentMentionsResponse { comment_mentions }))
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetPersonMentions, GetPersonMentionsResponse},
|
||||
person::{GetPersonPostMentions, GetPersonPostMentionsResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::person_mention_view::PersonMentionQuery;
|
||||
use lemmy_db_views_actor::person_post_mention_view::PersonPostMentionQuery;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_mentions(
|
||||
data: Query<GetPersonMentions>,
|
||||
pub async fn list_post_mentions(
|
||||
data: Query<GetPersonPostMentions>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<GetPersonMentionsResponse>> {
|
||||
) -> LemmyResult<Json<GetPersonPostMentionsResponse>> {
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
|
@ -20,7 +20,7 @@ pub async fn list_mentions(
|
|||
let person_id = Some(local_user_view.person.id);
|
||||
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||
|
||||
let mentions = PersonMentionQuery {
|
||||
let post_mentions = PersonPostMentionQuery {
|
||||
recipient_id: person_id,
|
||||
my_person_id: person_id,
|
||||
sort,
|
||||
|
@ -32,5 +32,5 @@ pub async fn list_mentions(
|
|||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
Ok(Json(GetPersonMentionsResponse { mentions }))
|
||||
Ok(Json(GetPersonPostMentionsResponse { post_mentions }))
|
||||
}
|
|
@ -2,7 +2,7 @@ use actix_web::web::{Data, Json};
|
|||
use lemmy_api_common::{context::LemmyContext, person::GetRepliesResponse};
|
||||
use lemmy_db_schema::source::{
|
||||
comment_reply::CommentReply,
|
||||
person_mention::PersonMention,
|
||||
person_comment_mention::PersonCommentMention,
|
||||
private_message::PrivateMessage,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
|
@ -20,8 +20,8 @@ pub async fn mark_all_notifications_read(
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||
|
||||
// Mark all user mentions as read
|
||||
PersonMention::mark_all_as_read(&mut context.pool(), person_id)
|
||||
// Mark all comment mentions as read
|
||||
PersonCommentMention::mark_all_as_read(&mut context.pool(), person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{MarkPersonCommentMentionAsRead, PersonCommentMentionResponse},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::person_comment_mention::{PersonCommentMention, PersonCommentMentionUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PersonCommentMentionView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn mark_comment_mention_as_read(
|
||||
data: Json<MarkPersonCommentMentionAsRead>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PersonCommentMentionResponse>> {
|
||||
let person_comment_mention_id = data.person_comment_mention_id;
|
||||
let read_person_comment_mention =
|
||||
PersonCommentMention::read(&mut context.pool(), person_comment_mention_id).await?;
|
||||
|
||||
if local_user_view.person.id != read_person_comment_mention.recipient_id {
|
||||
Err(LemmyErrorType::CouldntUpdateComment)?
|
||||
}
|
||||
|
||||
let person_comment_mention_id = read_person_comment_mention.id;
|
||||
let read = Some(data.read);
|
||||
PersonCommentMention::update(
|
||||
&mut context.pool(),
|
||||
person_comment_mention_id,
|
||||
&PersonCommentMentionUpdateForm { read },
|
||||
)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||
|
||||
let person_comment_mention_id = read_person_comment_mention.id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let person_comment_mention_view = PersonCommentMentionView::read(
|
||||
&mut context.pool(),
|
||||
person_comment_mention_id,
|
||||
Some(person_id),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(PersonCommentMentionResponse {
|
||||
person_comment_mention_view,
|
||||
}))
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{MarkPersonMentionAsRead, PersonMentionResponse},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::person_mention::{PersonMention, PersonMentionUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PersonMentionView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn mark_person_mention_as_read(
|
||||
data: Json<MarkPersonMentionAsRead>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PersonMentionResponse>> {
|
||||
let person_mention_id = data.person_mention_id;
|
||||
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?;
|
||||
|
||||
if local_user_view.person.id != read_person_mention.recipient_id {
|
||||
Err(LemmyErrorType::CouldntUpdateComment)?
|
||||
}
|
||||
|
||||
let person_mention_id = read_person_mention.id;
|
||||
let read = Some(data.read);
|
||||
PersonMention::update(
|
||||
&mut context.pool(),
|
||||
person_mention_id,
|
||||
&PersonMentionUpdateForm { read },
|
||||
)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||
|
||||
let person_mention_id = read_person_mention.id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let person_mention_view =
|
||||
PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?;
|
||||
|
||||
Ok(Json(PersonMentionResponse {
|
||||
person_mention_view,
|
||||
}))
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{MarkPersonPostMentionAsRead, PersonPostMentionResponse},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::person_post_mention::{PersonPostMention, PersonPostMentionUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_db_views_actor::structs::PersonPostMentionView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn mark_post_mention_as_read(
|
||||
data: Json<MarkPersonPostMentionAsRead>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PersonPostMentionResponse>> {
|
||||
let person_post_mention_id = data.person_post_mention_id;
|
||||
let read_person_post_mention =
|
||||
PersonPostMention::read(&mut context.pool(), person_post_mention_id).await?;
|
||||
|
||||
if local_user_view.person.id != read_person_post_mention.recipient_id {
|
||||
Err(LemmyErrorType::CouldntUpdatePost)?
|
||||
}
|
||||
|
||||
let person_post_mention_id = read_person_post_mention.id;
|
||||
let read = Some(data.read);
|
||||
PersonPostMention::update(
|
||||
&mut context.pool(),
|
||||
person_post_mention_id,
|
||||
&PersonPostMentionUpdateForm { read },
|
||||
)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||
|
||||
let person_post_mention_id = read_person_post_mention.id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let person_post_mention_view =
|
||||
PersonPostMentionView::read(&mut context.pool(), person_post_mention_id, Some(person_id))
|
||||
.await?;
|
||||
|
||||
Ok(Json(PersonPostMentionResponse {
|
||||
person_post_mention_view,
|
||||
}))
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
pub mod list_mentions;
|
||||
pub mod list_comment_mentions;
|
||||
pub mod list_post_mentions;
|
||||
pub mod list_replies;
|
||||
pub mod mark_all_read;
|
||||
pub mod mark_mention_read;
|
||||
pub mod mark_comment_mention_read;
|
||||
pub mod mark_post_mention_read;
|
||||
pub mod mark_reply_read;
|
||||
pub mod unread_count;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, person::GetUnreadCountResponse};
|
||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||
use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView};
|
||||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
PersonCommentMentionView,
|
||||
PersonPostMentionView,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
|
@ -12,18 +16,23 @@ pub async fn unread_count(
|
|||
let person_id = local_user_view.person.id;
|
||||
|
||||
let replies =
|
||||
CommentReplyView::get_unread_replies(&mut context.pool(), &local_user_view.local_user).await?;
|
||||
CommentReplyView::get_unread_count(&mut context.pool(), &local_user_view.local_user).await?;
|
||||
|
||||
let mentions =
|
||||
PersonMentionView::get_unread_mentions(&mut context.pool(), &local_user_view.local_user)
|
||||
let comment_mentions =
|
||||
PersonCommentMentionView::get_unread_count(&mut context.pool(), &local_user_view.local_user)
|
||||
.await?;
|
||||
|
||||
let post_mentions =
|
||||
PersonPostMentionView::get_unread_count(&mut context.pool(), &local_user_view.local_user)
|
||||
.await?;
|
||||
|
||||
let private_messages =
|
||||
PrivateMessageView::get_unread_messages(&mut context.pool(), person_id).await?;
|
||||
PrivateMessageView::get_unread_count(&mut context.pool(), person_id).await?;
|
||||
|
||||
Ok(Json(GetUnreadCountResponse {
|
||||
replies,
|
||||
mentions,
|
||||
comment_mentions,
|
||||
post_mentions,
|
||||
private_messages,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -5,9 +5,15 @@ use lemmy_api_common::{
|
|||
context::LemmyContext,
|
||||
post::{CreatePostLike, PostResponse},
|
||||
send_activity::{ActivityChannel, SendActivityData},
|
||||
utils::{check_bot_account, check_community_user_action, check_local_vote_mode, VoteItem},
|
||||
utils::{
|
||||
check_bot_account,
|
||||
check_community_user_action,
|
||||
check_local_vote_mode,
|
||||
mark_post_as_read,
|
||||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
local_site::LocalSite,
|
||||
post::{PostLike, PostLikeForm, PostRead, PostReadForm},
|
||||
|
@ -29,7 +35,7 @@ pub async fn like_post(
|
|||
|
||||
check_local_vote_mode(
|
||||
data.score,
|
||||
VoteItem::Post(post_id),
|
||||
PostOrCommentId::Post(post_id),
|
||||
&local_site,
|
||||
local_user_view.person.id,
|
||||
&mut context.pool(),
|
||||
|
|
|
@ -12,15 +12,15 @@ use crate::{
|
|||
};
|
||||
use actix_web::web::Json;
|
||||
use lemmy_db_schema::{
|
||||
newtypes::{CommentId, CommunityId, LocalUserId, PostId},
|
||||
newtypes::{CommentId, CommunityId, LocalUserId, PostId, PostOrCommentId},
|
||||
source::{
|
||||
actor_language::CommunityLanguage,
|
||||
comment::Comment,
|
||||
comment_reply::{CommentReply, CommentReplyInsertForm},
|
||||
community::Community,
|
||||
person::Person,
|
||||
person_mention::{PersonMention, PersonMentionInsertForm},
|
||||
post::Post,
|
||||
person_comment_mention::{PersonCommentMention, PersonCommentMentionInsertForm},
|
||||
person_post_mention::{PersonPostMention, PersonPostMentionInsertForm},
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
|
@ -94,7 +94,7 @@ pub async fn build_post_response(
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub async fn send_local_notifs(
|
||||
mentions: Vec<MentionData>,
|
||||
comment_id: CommentId,
|
||||
post_or_comment_id: PostOrCommentId,
|
||||
person: &Person,
|
||||
do_send_email: bool,
|
||||
context: &LemmyContext,
|
||||
|
@ -125,6 +125,34 @@ pub async fn send_local_notifs(
|
|||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
||||
(comment, post, community)
|
||||
};
|
||||
// let person = my_local_user.person;
|
||||
// Read the comment view to get extra info
|
||||
|
||||
let (comment_opt, post, community) = match post_or_comment_id {
|
||||
PostOrCommentId::Post(post_id) => {
|
||||
let post_view = PostView::read(
|
||||
&mut context.pool(),
|
||||
post_id,
|
||||
local_user_view.map(|view| &view.local_user),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
(None, post_view.post, post_view.community)
|
||||
}
|
||||
PostOrCommentId::Comment(comment_id) => {
|
||||
let comment_view = CommentView::read(
|
||||
&mut context.pool(),
|
||||
comment_id,
|
||||
local_user_view.map(|view| &view.local_user),
|
||||
)
|
||||
.await?;
|
||||
(
|
||||
Some(comment_view.comment),
|
||||
comment_view.post,
|
||||
comment_view.community,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Send the local mentions
|
||||
for mention in mentions
|
||||
|
@ -140,22 +168,38 @@ pub async fn send_local_notifs(
|
|||
// below by checking recipient ids
|
||||
recipient_ids.push(mention_user_view.local_user.id);
|
||||
|
||||
let user_mention_form = PersonMentionInsertForm {
|
||||
// Make the correct reply form depending on whether its a post or comment mention
|
||||
let comment_content_or_post_body = if let Some(comment) = &comment_opt {
|
||||
let person_comment_mention_form = PersonCommentMentionInsertForm {
|
||||
recipient_id: mention_user_view.person.id,
|
||||
comment_id,
|
||||
comment_id: comment.id,
|
||||
read: None,
|
||||
};
|
||||
|
||||
// Allow this to fail softly, since comment edits might re-update or replace it
|
||||
// Let the uniqueness handle this fail
|
||||
PersonMention::create(&mut context.pool(), &user_mention_form)
|
||||
PersonCommentMention::create(&mut context.pool(), &person_comment_mention_form)
|
||||
.await
|
||||
.ok();
|
||||
comment.content.clone()
|
||||
} else {
|
||||
let person_post_mention_form = PersonPostMentionInsertForm {
|
||||
recipient_id: mention_user_view.person.id,
|
||||
post_id: post.id,
|
||||
read: None,
|
||||
};
|
||||
|
||||
// Allow this to fail softly, since edits might re-update or replace it
|
||||
PersonPostMention::create(&mut context.pool(), &person_post_mention_form)
|
||||
.await
|
||||
.ok();
|
||||
post.body.clone().unwrap_or_default()
|
||||
};
|
||||
|
||||
// Send an email to those local users that have notifications on
|
||||
if do_send_email {
|
||||
let lang = get_interface_language(&mention_user_view);
|
||||
let content = markdown_to_html(&comment.content);
|
||||
let content = markdown_to_html(&comment_content_or_post_body);
|
||||
send_email_to_user(
|
||||
&mention_user_view,
|
||||
&lang.notification_mentioned_by_subject(&person.name),
|
||||
|
@ -168,6 +212,7 @@ pub async fn send_local_notifs(
|
|||
}
|
||||
|
||||
// Send comment_reply to the parent commenter / poster
|
||||
if let Some(comment) = &comment_opt {
|
||||
if let Some(parent_comment_id) = comment.parent_comment_id() {
|
||||
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
|
||||
|
||||
|
@ -266,6 +311,7 @@ pub async fn send_local_notifs(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(recipient_ids)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use lemmy_db_schema::{
|
||||
newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId},
|
||||
newtypes::{
|
||||
CommentReplyId,
|
||||
CommunityId,
|
||||
LanguageId,
|
||||
PersonCommentMentionId,
|
||||
PersonId,
|
||||
PersonPostMentionId,
|
||||
},
|
||||
sensitive::SensitiveString,
|
||||
source::{login_token::LoginToken, site::Site},
|
||||
CommentSortType,
|
||||
|
@ -16,7 +23,8 @@ use lemmy_db_views::structs::{
|
|||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
CommunityModeratorView,
|
||||
PersonMentionView,
|
||||
PersonCommentMentionView,
|
||||
PersonPostMentionView,
|
||||
PersonView,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -394,8 +402,7 @@ pub struct GetRepliesResponse {
|
|||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get mentions for your user.
|
||||
pub struct GetPersonMentions {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub struct GetPersonCommentMentions {
|
||||
pub sort: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
|
@ -409,16 +416,16 @@ pub struct GetPersonMentions {
|
|||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response of mentions for your user.
|
||||
pub struct GetPersonMentionsResponse {
|
||||
pub mentions: Vec<PersonMentionView>,
|
||||
pub struct GetPersonCommentMentionsResponse {
|
||||
pub comment_mentions: Vec<PersonCommentMentionView>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Mark a person mention as read.
|
||||
pub struct MarkPersonMentionAsRead {
|
||||
pub person_mention_id: PersonMentionId,
|
||||
pub struct MarkPersonCommentMentionAsRead {
|
||||
pub person_comment_mention_id: PersonCommentMentionId,
|
||||
pub read: bool,
|
||||
}
|
||||
|
||||
|
@ -426,8 +433,45 @@ pub struct MarkPersonMentionAsRead {
|
|||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response for a person mention action.
|
||||
pub struct PersonMentionResponse {
|
||||
pub person_mention_view: PersonMentionView,
|
||||
pub struct PersonCommentMentionResponse {
|
||||
pub person_comment_mention_view: PersonCommentMentionView,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Get mentions for your user.
|
||||
pub struct GetPersonPostMentions {
|
||||
pub sort: Option<PostSortType>,
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
pub unread_only: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response of mentions for your user.
|
||||
pub struct GetPersonPostMentionsResponse {
|
||||
pub post_mentions: Vec<PersonPostMentionView>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Mark a person mention as read.
|
||||
pub struct MarkPersonPostMentionAsRead {
|
||||
pub person_post_mention_id: PersonPostMentionId,
|
||||
pub read: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The response for a person mention action.
|
||||
pub struct PersonPostMentionResponse {
|
||||
pub person_post_mention_view: PersonPostMentionView,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
|
@ -499,7 +543,8 @@ pub struct GetReportCountResponse {
|
|||
/// A response containing counts for your notifications.
|
||||
pub struct GetUnreadCountResponse {
|
||||
pub replies: i64,
|
||||
pub mentions: i64,
|
||||
pub comment_mentions: i64,
|
||||
pub post_mentions: i64,
|
||||
pub private_messages: i64,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use chrono::{DateTime, Days, Local, TimeZone, Utc};
|
|||
use enum_map::{enum_map, EnumMap};
|
||||
use lemmy_db_schema::{
|
||||
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
|
||||
newtypes::{CommentId, CommunityId, DbUrl, InstanceId, PersonId, PostId},
|
||||
newtypes::{CommentId, CommunityId, DbUrl, InstanceId, PersonId, PostId, PostOrCommentId},
|
||||
source::{
|
||||
comment::{Comment, CommentLike, CommentUpdateForm},
|
||||
community::{Community, CommunityModerator, CommunityUpdateForm},
|
||||
|
@ -293,23 +293,17 @@ pub async fn check_person_instance_community_block(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// A vote item type used to check the vote mode.
|
||||
pub enum VoteItem {
|
||||
Post(PostId),
|
||||
Comment(CommentId),
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn check_local_vote_mode(
|
||||
score: i16,
|
||||
vote_item: VoteItem,
|
||||
post_or_comment_id: PostOrCommentId,
|
||||
local_site: &LocalSite,
|
||||
person_id: PersonId,
|
||||
pool: &mut DbPool<'_>,
|
||||
) -> LemmyResult<()> {
|
||||
let (downvote_setting, upvote_setting) = match vote_item {
|
||||
VoteItem::Post(_) => (local_site.post_downvotes, local_site.post_upvotes),
|
||||
VoteItem::Comment(_) => (local_site.comment_downvotes, local_site.comment_upvotes),
|
||||
let (downvote_setting, upvote_setting) = match post_or_comment_id {
|
||||
PostOrCommentId::Post(_) => (local_site.post_downvotes, local_site.post_upvotes),
|
||||
PostOrCommentId::Comment(_) => (local_site.comment_downvotes, local_site.comment_upvotes),
|
||||
};
|
||||
|
||||
let downvote_fail = score == -1 && downvote_setting == FederationMode::Disable;
|
||||
|
@ -317,9 +311,11 @@ pub async fn check_local_vote_mode(
|
|||
|
||||
// Undo previous vote for item if new vote fails
|
||||
if downvote_fail || upvote_fail {
|
||||
match vote_item {
|
||||
VoteItem::Post(post_id) => PostLike::remove(pool, person_id, post_id).await?,
|
||||
VoteItem::Comment(comment_id) => CommentLike::remove(pool, person_id, comment_id).await?,
|
||||
match post_or_comment_id {
|
||||
PostOrCommentId::Post(post_id) => PostLike::remove(pool, person_id, post_id).await?,
|
||||
PostOrCommentId::Comment(comment_id) => {
|
||||
CommentLike::remove(pool, person_id, comment_id).await?
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -16,12 +16,13 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::validate_post_language,
|
||||
impls::actor_language::default_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
|
||||
comment_reply::{CommentReply, CommentReplyUpdateForm},
|
||||
local_site::LocalSite,
|
||||
person_mention::{PersonMention, PersonMentionUpdateForm},
|
||||
person_comment_mention::{PersonCommentMention, PersonCommentMentionUpdateForm},
|
||||
},
|
||||
traits::{Crud, Likeable},
|
||||
};
|
||||
|
@ -117,7 +118,7 @@ pub async fn create_comment(
|
|||
let mentions = scrape_text_for_mentions(&content);
|
||||
let recipient_ids = send_local_notifs(
|
||||
mentions,
|
||||
inserted_comment_id,
|
||||
PostOrCommentId::Comment(inserted_comment_id),
|
||||
&local_user_view.person,
|
||||
true,
|
||||
&context,
|
||||
|
@ -169,17 +170,18 @@ pub async fn create_comment(
|
|||
.with_lemmy_type(LemmyErrorType::CouldntUpdateReplies)?;
|
||||
}
|
||||
|
||||
// If the parent has PersonMentions mark them as read too
|
||||
let person_mention =
|
||||
PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await;
|
||||
if let Ok(Some(mention)) = person_mention {
|
||||
PersonMention::update(
|
||||
// If the parent has PersonCommentMentions mark them as read too
|
||||
let person_comment_mention =
|
||||
PersonCommentMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id)
|
||||
.await;
|
||||
if let Ok(Some(mention)) = person_comment_mention {
|
||||
PersonCommentMention::update(
|
||||
&mut context.pool(),
|
||||
mention.id,
|
||||
&PersonMentionUpdateForm { read: Some(true) },
|
||||
&PersonCommentMentionUpdateForm { read: Some(true) },
|
||||
)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePersonMentions)?;
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePersonCommentMentions)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use lemmy_api_common::{
|
|||
utils::check_community_user_action,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PostOrCommentId,
|
||||
source::comment::{Comment, CommentUpdateForm},
|
||||
traits::Crud,
|
||||
};
|
||||
|
@ -60,7 +61,7 @@ pub async fn delete_comment(
|
|||
|
||||
let recipient_ids = send_local_notifs(
|
||||
vec![],
|
||||
comment_id,
|
||||
PostOrCommentId::Comment(comment_id),
|
||||
&local_user_view.person,
|
||||
false,
|
||||
&context,
|
||||
|
|
|
@ -8,6 +8,7 @@ use lemmy_api_common::{
|
|||
utils::check_community_mod_action,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
comment::{Comment, CommentUpdateForm},
|
||||
comment_report::CommentReport,
|
||||
|
@ -82,7 +83,7 @@ pub async fn remove_comment(
|
|||
|
||||
let recipient_ids = send_local_notifs(
|
||||
vec![],
|
||||
comment_id,
|
||||
PostOrCommentId::Comment(comment_id),
|
||||
&local_user_view.person,
|
||||
false,
|
||||
&context,
|
||||
|
|
|
@ -14,7 +14,7 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::validate_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
comment::{Comment, CommentUpdateForm},
|
||||
local_site::LocalSite,
|
||||
|
@ -86,7 +86,7 @@ pub async fn update_comment(
|
|||
let mentions = scrape_text_for_mentions(&updated_comment_content);
|
||||
let recipient_ids = send_local_notifs(
|
||||
mentions,
|
||||
comment_id,
|
||||
PostOrCommentId::Comment(comment_id),
|
||||
&local_user_view.person,
|
||||
false,
|
||||
&context,
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::convert_published_time;
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
build_response::build_post_response,
|
||||
build_response::{build_post_response, send_local_notifs},
|
||||
context::LemmyContext,
|
||||
post::{CreatePost, PostResponse},
|
||||
request::generate_post_link_metadata,
|
||||
|
@ -16,7 +16,8 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
impls::actor_language::validate_post_language,
|
||||
impls::actor_language::default_post_language,
|
||||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
community::Community,
|
||||
local_site::LocalSite,
|
||||
|
@ -32,6 +33,7 @@ use lemmy_utils::{
|
|||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
spawn_try_task,
|
||||
utils::{
|
||||
mention::scrape_text_for_mentions,
|
||||
slurs::check_slurs,
|
||||
validation::{
|
||||
is_url_blocked,
|
||||
|
@ -148,8 +150,21 @@ pub async fn create_post(
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||
|
||||
let read_form = PostReadForm::new(post_id, person_id);
|
||||
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||
// Scan the post body for user mentions, add those rows
|
||||
let mentions = scrape_text_for_mentions(&inserted_post.body.clone().unwrap_or_default());
|
||||
send_local_notifs(
|
||||
mentions,
|
||||
PostOrCommentId::Post(inserted_post.id),
|
||||
&local_user_view.person,
|
||||
true,
|
||||
&context,
|
||||
Some(&local_user_view),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// TODO
|
||||
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
||||
|
||||
build_post_response(&context, community_id, local_user_view, post_id).await
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use activitypub_federation::config::Data;
|
|||
use actix_web::web::Json;
|
||||
use chrono::Utc;
|
||||
use lemmy_api_common::{
|
||||
build_response::build_post_response,
|
||||
build_response::{build_post_response, send_local_notifs},
|
||||
context::LemmyContext,
|
||||
post::{EditPost, PostResponse},
|
||||
request::generate_post_link_metadata,
|
||||
|
@ -16,6 +16,7 @@ use lemmy_api_common::{
|
|||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PostOrCommentId,
|
||||
impls::actor_language::validate_post_language,
|
||||
source::{
|
||||
community::Community,
|
||||
|
@ -29,6 +30,7 @@ use lemmy_db_views::structs::{LocalUserView, PostView};
|
|||
use lemmy_utils::{
|
||||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
utils::{
|
||||
mention::scrape_text_for_mentions,
|
||||
slurs::check_slurs,
|
||||
validation::{
|
||||
is_url_blocked,
|
||||
|
@ -142,6 +144,18 @@ pub async fn update_post(
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||
|
||||
// Scan the post body for user mentions, add those rows
|
||||
let mentions = scrape_text_for_mentions(&updated_post.body.clone().unwrap_or_default());
|
||||
send_local_notifs(
|
||||
mentions,
|
||||
PostOrCommentId::Post(updated_post.id),
|
||||
&local_user_view.person,
|
||||
false,
|
||||
&context,
|
||||
Some(&local_user_view),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// send out federation/webmention if necessary
|
||||
match (
|
||||
orig_post.post.scheduled_publish_time,
|
||||
|
|
|
@ -29,7 +29,7 @@ use lemmy_api_common::{
|
|||
};
|
||||
use lemmy_db_schema::{
|
||||
aggregates::structs::CommentAggregates,
|
||||
newtypes::PersonId,
|
||||
newtypes::{PersonId, PostOrCommentId},
|
||||
source::{
|
||||
activity::ActivitySendTargets,
|
||||
comment::{Comment, CommentLike, CommentLikeForm},
|
||||
|
@ -176,10 +176,17 @@ impl ActivityHandler for CreateOrUpdateNote {
|
|||
// TODO: for compatibility with other projects, it would be much better to read this from cc or
|
||||
// tags
|
||||
let mentions = scrape_text_for_mentions(&comment.content);
|
||||
|
||||
// TODO: this fails in local community comment as CommentView::read() returns nothing
|
||||
// without passing LocalUser
|
||||
send_local_notifs(mentions, comment.id, &actor, do_send_email, context, None).await?;
|
||||
send_local_notifs(
|
||||
mentions,
|
||||
PostOrCommentId::Comment(comment.id),
|
||||
&actor,
|
||||
do_send_email,
|
||||
context,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ use activitypub_federation::{
|
|||
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||
traits::{ActivityHandler, Actor, Object},
|
||||
};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_api_common::{build_response::send_local_notifs, context::LemmyContext};
|
||||
use lemmy_db_schema::{
|
||||
aggregates::structs::PostAggregates,
|
||||
newtypes::PersonId,
|
||||
newtypes::{PersonId, PostOrCommentId},
|
||||
source::{
|
||||
activity::ActivitySendTargets,
|
||||
community::Community,
|
||||
|
@ -32,7 +32,10 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::{Crud, Likeable},
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyResult},
|
||||
utils::mention::scrape_text_for_mentions,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
impl CreateOrUpdatePage {
|
||||
|
@ -124,6 +127,21 @@ impl ActivityHandler for CreateOrUpdatePage {
|
|||
// Calculate initial hot_rank for post
|
||||
PostAggregates::update_ranks(&mut context.pool(), post.id).await?;
|
||||
|
||||
let do_send_email = self.kind == CreateOrUpdateType::Create;
|
||||
let actor = self.actor.dereference(context).await?;
|
||||
|
||||
// Send the post body mentions
|
||||
let mentions = scrape_text_for_mentions(&post.body.clone().unwrap_or_default());
|
||||
send_local_notifs(
|
||||
mentions,
|
||||
PostOrCommentId::Post(post.id),
|
||||
&actor,
|
||||
do_send_email,
|
||||
context,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ pub mod oauth_provider;
|
|||
pub mod password_reset_request;
|
||||
pub mod person;
|
||||
pub mod person_block;
|
||||
pub mod person_mention;
|
||||
pub mod person_comment_mention;
|
||||
pub mod person_post_mention;
|
||||
pub mod post;
|
||||
pub mod post_report;
|
||||
pub mod private_message;
|
||||
|
|
83
crates/db_schema/src/impls/person_comment_mention.rs
Normal file
83
crates/db_schema/src/impls/person_comment_mention.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use crate::{
|
||||
diesel::OptionalExtension,
|
||||
newtypes::{CommentId, PersonCommentMentionId, PersonId},
|
||||
schema::person_comment_mention,
|
||||
source::person_comment_mention::{
|
||||
PersonCommentMention,
|
||||
PersonCommentMentionInsertForm,
|
||||
PersonCommentMentionUpdateForm,
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for PersonCommentMention {
|
||||
type InsertForm = PersonCommentMentionInsertForm;
|
||||
type UpdateForm = PersonCommentMentionUpdateForm;
|
||||
type IdType = PersonCommentMentionId;
|
||||
|
||||
async fn create(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_comment_mention_form: &Self::InsertForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
// since the return here isnt utilized, we dont need to do an update
|
||||
// but get_result doesn't return the existing row here
|
||||
insert_into(person_comment_mention::table)
|
||||
.values(person_comment_mention_form)
|
||||
.on_conflict((
|
||||
person_comment_mention::recipient_id,
|
||||
person_comment_mention::comment_id,
|
||||
))
|
||||
.do_update()
|
||||
.set(person_comment_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_comment_mention_id: PersonCommentMentionId,
|
||||
person_comment_mention_form: &Self::UpdateForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(person_comment_mention::table.find(person_comment_mention_id))
|
||||
.set(person_comment_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl PersonCommentMention {
|
||||
pub async fn mark_all_as_read(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Vec<PersonCommentMention>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(
|
||||
person_comment_mention::table
|
||||
.filter(person_comment_mention::recipient_id.eq(for_recipient_id))
|
||||
.filter(person_comment_mention::read.eq(false)),
|
||||
)
|
||||
.set(person_comment_mention::read.eq(true))
|
||||
.get_results::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn read_by_comment_and_person(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_comment_id: CommentId,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
person_comment_mention::table
|
||||
.filter(person_comment_mention::comment_id.eq(for_comment_id))
|
||||
.filter(person_comment_mention::recipient_id.eq(for_recipient_id))
|
||||
.first(conn)
|
||||
.await
|
||||
.optional()
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
use crate::{
|
||||
diesel::OptionalExtension,
|
||||
newtypes::{CommentId, PersonId, PersonMentionId},
|
||||
schema::person_mention,
|
||||
source::person_mention::{PersonMention, PersonMentionInsertForm, PersonMentionUpdateForm},
|
||||
traits::Crud,
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for PersonMention {
|
||||
type InsertForm = PersonMentionInsertForm;
|
||||
type UpdateForm = PersonMentionUpdateForm;
|
||||
type IdType = PersonMentionId;
|
||||
|
||||
async fn create(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_mention_form: &Self::InsertForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
// since the return here isnt utilized, we dont need to do an update
|
||||
// but get_result doesn't return the existing row here
|
||||
insert_into(person_mention::table)
|
||||
.values(person_mention_form)
|
||||
.on_conflict((person_mention::recipient_id, person_mention::comment_id))
|
||||
.do_update()
|
||||
.set(person_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_mention_id: PersonMentionId,
|
||||
person_mention_form: &Self::UpdateForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(person_mention::table.find(person_mention_id))
|
||||
.set(person_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl PersonMention {
|
||||
pub async fn mark_all_as_read(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Vec<PersonMention>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(
|
||||
person_mention::table
|
||||
.filter(person_mention::recipient_id.eq(for_recipient_id))
|
||||
.filter(person_mention::read.eq(false)),
|
||||
)
|
||||
.set(person_mention::read.eq(true))
|
||||
.get_results::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn read_by_comment_and_person(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_comment_id: CommentId,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
person_mention::table
|
||||
.filter(person_mention::comment_id.eq(for_comment_id))
|
||||
.filter(person_mention::recipient_id.eq(for_recipient_id))
|
||||
.first(conn)
|
||||
.await
|
||||
.optional()
|
||||
}
|
||||
}
|
83
crates/db_schema/src/impls/person_post_mention.rs
Normal file
83
crates/db_schema/src/impls/person_post_mention.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use crate::{
|
||||
diesel::OptionalExtension,
|
||||
newtypes::{PersonId, PersonPostMentionId, PostId},
|
||||
schema::person_post_mention,
|
||||
source::person_post_mention::{
|
||||
PersonPostMention,
|
||||
PersonPostMentionInsertForm,
|
||||
PersonPostMentionUpdateForm,
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for PersonPostMention {
|
||||
type InsertForm = PersonPostMentionInsertForm;
|
||||
type UpdateForm = PersonPostMentionUpdateForm;
|
||||
type IdType = PersonPostMentionId;
|
||||
|
||||
async fn create(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_post_mention_form: &Self::InsertForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
// since the return here isnt utilized, we dont need to do an update
|
||||
// but get_result doesn't return the existing row here
|
||||
insert_into(person_post_mention::table)
|
||||
.values(person_post_mention_form)
|
||||
.on_conflict((
|
||||
person_post_mention::recipient_id,
|
||||
person_post_mention::post_id,
|
||||
))
|
||||
.do_update()
|
||||
.set(person_post_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_post_mention_id: PersonPostMentionId,
|
||||
person_post_mention_form: &Self::UpdateForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(person_post_mention::table.find(person_post_mention_id))
|
||||
.set(person_post_mention_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl PersonPostMention {
|
||||
pub async fn mark_all_as_read(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Vec<PersonPostMention>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(
|
||||
person_post_mention::table
|
||||
.filter(person_post_mention::recipient_id.eq(for_recipient_id))
|
||||
.filter(person_post_mention::read.eq(false)),
|
||||
)
|
||||
.set(person_post_mention::read.eq(true))
|
||||
.get_results::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn read_by_post_and_person(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_post_id: PostId,
|
||||
for_recipient_id: PersonId,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
person_post_mention::table
|
||||
.filter(person_post_mention::post_id.eq(for_post_id))
|
||||
.filter(person_post_mention::recipient_id.eq(for_recipient_id))
|
||||
.first(conn)
|
||||
.await
|
||||
.optional()
|
||||
}
|
||||
}
|
|
@ -55,6 +55,11 @@ impl fmt::Display for CommentId {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum PostOrCommentId {
|
||||
Post(PostId),
|
||||
Comment(CommentId),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
@ -82,8 +87,14 @@ impl fmt::Display for PrivateMessageId {
|
|||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The person mention id.
|
||||
pub struct PersonMentionId(i32);
|
||||
/// The person comment mention id.
|
||||
pub struct PersonCommentMentionId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The person post mention id.
|
||||
pub struct PersonPostMentionId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
|
|
|
@ -753,6 +753,16 @@ diesel::table! {
|
|||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
person_comment_mention (id) {
|
||||
id -> Int4,
|
||||
recipient_id -> Int4,
|
||||
comment_id -> Int4,
|
||||
read -> Bool,
|
||||
published -> Timestamptz,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
person_content_combined (id) {
|
||||
id -> Int4,
|
||||
|
@ -763,10 +773,10 @@ diesel::table! {
|
|||
}
|
||||
|
||||
diesel::table! {
|
||||
person_mention (id) {
|
||||
person_post_mention (id) {
|
||||
id -> Int4,
|
||||
recipient_id -> Int4,
|
||||
comment_id -> Int4,
|
||||
post_id -> Int4,
|
||||
read -> Bool,
|
||||
published -> Timestamptz,
|
||||
}
|
||||
|
@ -1090,10 +1100,12 @@ diesel::joinable!(password_reset_request -> local_user (local_user_id));
|
|||
diesel::joinable!(person -> instance (instance_id));
|
||||
diesel::joinable!(person_aggregates -> person (person_id));
|
||||
diesel::joinable!(person_ban -> person (person_id));
|
||||
diesel::joinable!(person_comment_mention -> comment (comment_id));
|
||||
diesel::joinable!(person_comment_mention -> person (recipient_id));
|
||||
diesel::joinable!(person_content_combined -> comment (comment_id));
|
||||
diesel::joinable!(person_content_combined -> post (post_id));
|
||||
diesel::joinable!(person_mention -> comment (comment_id));
|
||||
diesel::joinable!(person_mention -> person (recipient_id));
|
||||
diesel::joinable!(person_post_mention -> person (recipient_id));
|
||||
diesel::joinable!(person_post_mention -> post (post_id));
|
||||
diesel::joinable!(person_saved_combined -> comment (comment_id));
|
||||
diesel::joinable!(person_saved_combined -> person (person_id));
|
||||
diesel::joinable!(person_saved_combined -> post (post_id));
|
||||
|
@ -1172,8 +1184,9 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||
person_actions,
|
||||
person_aggregates,
|
||||
person_ban,
|
||||
person_comment_mention,
|
||||
person_content_combined,
|
||||
person_mention,
|
||||
person_post_mention,
|
||||
person_saved_combined,
|
||||
post,
|
||||
post_actions,
|
||||
|
|
|
@ -33,7 +33,8 @@ pub mod oauth_provider;
|
|||
pub mod password_reset_request;
|
||||
pub mod person;
|
||||
pub mod person_block;
|
||||
pub mod person_mention;
|
||||
pub mod person_comment_mention;
|
||||
pub mod person_post_mention;
|
||||
pub mod post;
|
||||
pub mod post_report;
|
||||
pub mod private_message;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::newtypes::{CommentId, PersonId, PersonMentionId};
|
||||
use crate::newtypes::{CommentId, PersonCommentMentionId, PersonId};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::person_mention;
|
||||
use crate::schema::person_comment_mention;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "full")]
|
||||
|
@ -12,12 +12,12 @@ use ts_rs::TS;
|
|||
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_mention))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_comment_mention))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A person mention.
|
||||
pub struct PersonMention {
|
||||
pub id: PersonMentionId,
|
||||
pub struct PersonCommentMention {
|
||||
pub id: PersonCommentMentionId,
|
||||
pub recipient_id: PersonId,
|
||||
pub comment_id: CommentId,
|
||||
pub read: bool,
|
||||
|
@ -25,15 +25,15 @@ pub struct PersonMention {
|
|||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_mention))]
|
||||
pub struct PersonMentionInsertForm {
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_comment_mention))]
|
||||
pub struct PersonCommentMentionInsertForm {
|
||||
pub recipient_id: PersonId,
|
||||
pub comment_id: CommentId,
|
||||
pub read: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_mention))]
|
||||
pub struct PersonMentionUpdateForm {
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_comment_mention))]
|
||||
pub struct PersonCommentMentionUpdateForm {
|
||||
pub read: Option<bool>,
|
||||
}
|
39
crates/db_schema/src/source/person_post_mention.rs
Normal file
39
crates/db_schema/src/source/person_post_mention.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use crate::newtypes::{PersonId, PersonPostMentionId, PostId};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::person_post_mention;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_post_mention))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A person mention.
|
||||
pub struct PersonPostMention {
|
||||
pub id: PersonPostMentionId,
|
||||
pub recipient_id: PersonId,
|
||||
pub post_id: PostId,
|
||||
pub read: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_post_mention))]
|
||||
pub struct PersonPostMentionInsertForm {
|
||||
pub recipient_id: PersonId,
|
||||
pub post_id: PostId,
|
||||
pub read: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = person_post_mention))]
|
||||
pub struct PersonPostMentionUpdateForm {
|
||||
pub read: Option<bool>,
|
||||
}
|
|
@ -114,7 +114,7 @@ impl PrivateMessageView {
|
|||
}
|
||||
|
||||
/// Gets the number of unread messages
|
||||
pub async fn get_unread_messages(
|
||||
pub async fn get_unread_count(
|
||||
pool: &mut DbPool<'_>,
|
||||
my_person_id: PersonId,
|
||||
) -> Result<i64, Error> {
|
||||
|
@ -348,7 +348,7 @@ mod tests {
|
|||
|
||||
assert_length!(1, &timmy_messages);
|
||||
|
||||
let timmy_unread_messages = PrivateMessageView::get_unread_messages(pool, timmy.id).await?;
|
||||
let timmy_unread_messages = PrivateMessageView::get_unread_count(pool, timmy.id).await?;
|
||||
assert_eq!(timmy_unread_messages, 1);
|
||||
|
||||
cleanup(instance.id, pool).await
|
||||
|
@ -390,7 +390,7 @@ mod tests {
|
|||
|
||||
assert_length!(0, &timmy_messages);
|
||||
|
||||
let timmy_unread_messages = PrivateMessageView::get_unread_messages(pool, timmy.id).await?;
|
||||
let timmy_unread_messages = PrivateMessageView::get_unread_count(pool, timmy.id).await?;
|
||||
assert_eq!(timmy_unread_messages, 0);
|
||||
cleanup(instance.id, pool).await
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ impl CommentReplyView {
|
|||
}
|
||||
|
||||
/// Gets the number of unread replies
|
||||
pub async fn get_unread_replies(
|
||||
pub async fn get_unread_count(
|
||||
pool: &mut DbPool<'_>,
|
||||
local_user: &LocalUser,
|
||||
) -> Result<i64, Error> {
|
||||
|
@ -305,7 +305,7 @@ mod tests {
|
|||
CommentReply::update(pool, inserted_reply.id, &comment_reply_update_form).await?;
|
||||
|
||||
// Test to make sure counts and blocks work correctly
|
||||
let unread_replies = CommentReplyView::get_unread_replies(pool, &recipient_local_user).await?;
|
||||
let unread_replies = CommentReplyView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
|
||||
let query = CommentReplyQuery {
|
||||
recipient_id: Some(recipient_id),
|
||||
|
@ -328,7 +328,7 @@ mod tests {
|
|||
PersonBlock::block(pool, &block_form).await?;
|
||||
|
||||
let unread_replies_after_block =
|
||||
CommentReplyView::get_unread_replies(pool, &recipient_local_user).await?;
|
||||
CommentReplyView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
let replies_after_block = query.clone().list(pool).await?;
|
||||
assert_eq!(0, unread_replies_after_block);
|
||||
assert_eq!(0, replies_after_block.len());
|
||||
|
@ -356,7 +356,7 @@ mod tests {
|
|||
let recipient_local_user_view = LocalUserView::read(pool, recipient_local_user.id).await?;
|
||||
|
||||
let unread_replies_after_hide_bots =
|
||||
CommentReplyView::get_unread_replies(pool, &recipient_local_user_view.local_user).await?;
|
||||
CommentReplyView::get_unread_count(pool, &recipient_local_user_view.local_user).await?;
|
||||
|
||||
let mut query_without_bots = query.clone();
|
||||
query_without_bots.show_bot_accounts = false;
|
||||
|
|
|
@ -9,7 +9,7 @@ pub mod community_person_ban_view;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod community_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod person_mention_view;
|
||||
pub mod person_comment_mention_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod person_view;
|
||||
pub mod structs;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::structs::PersonMentionView;
|
||||
use crate::structs::PersonCommentMentionView;
|
||||
use diesel::{
|
||||
dsl::{exists, not},
|
||||
pg::Pg,
|
||||
|
@ -12,7 +12,7 @@ use diesel::{
|
|||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
newtypes::{PersonId, PersonMentionId},
|
||||
newtypes::{PersonCommentMentionId, PersonId},
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
|
@ -22,7 +22,7 @@ use lemmy_db_schema::{
|
|||
local_user,
|
||||
person,
|
||||
person_actions,
|
||||
person_mention,
|
||||
person_comment_mention,
|
||||
post,
|
||||
},
|
||||
source::{community::CommunityFollower, local_user::LocalUser},
|
||||
|
@ -41,8 +41,8 @@ use lemmy_db_schema::{
|
|||
};
|
||||
|
||||
fn queries<'a>() -> Queries<
|
||||
impl ReadFn<'a, PersonMentionView, (PersonMentionId, Option<PersonId>)>,
|
||||
impl ListFn<'a, PersonMentionView, PersonMentionQuery>,
|
||||
impl ReadFn<'a, PersonCommentMentionView, (PersonCommentMentionId, Option<PersonId>)>,
|
||||
impl ListFn<'a, PersonCommentMentionView, PersonCommentMentionQuery>,
|
||||
> {
|
||||
let creator_is_admin = exists(
|
||||
local_user::table.filter(
|
||||
|
@ -52,7 +52,7 @@ fn queries<'a>() -> Queries<
|
|||
),
|
||||
);
|
||||
|
||||
let all_joins = move |query: person_mention::BoxedQuery<'a, Pg>,
|
||||
let all_joins = move |query: person_comment_mention::BoxedQuery<'a, Pg>,
|
||||
my_person_id: Option<PersonId>| {
|
||||
query
|
||||
.inner_join(comment::table)
|
||||
|
@ -78,7 +78,7 @@ fn queries<'a>() -> Queries<
|
|||
post::community_id,
|
||||
))
|
||||
.select((
|
||||
person_mention::all_columns,
|
||||
person_comment_mention::all_columns,
|
||||
comment::all_columns,
|
||||
person::all_columns,
|
||||
post::all_columns,
|
||||
|
@ -102,35 +102,42 @@ fn queries<'a>() -> Queries<
|
|||
))
|
||||
};
|
||||
|
||||
let read =
|
||||
move |mut conn: DbConn<'a>,
|
||||
(person_mention_id, my_person_id): (PersonMentionId, Option<PersonId>)| async move {
|
||||
let read = move |mut conn: DbConn<'a>,
|
||||
(person_comment_mention_id, my_person_id): (
|
||||
PersonCommentMentionId,
|
||||
Option<PersonId>,
|
||||
)| async move {
|
||||
all_joins(
|
||||
person_mention::table.find(person_mention_id).into_boxed(),
|
||||
person_comment_mention::table
|
||||
.find(person_comment_mention_id)
|
||||
.into_boxed(),
|
||||
my_person_id,
|
||||
)
|
||||
.first(&mut conn)
|
||||
.await
|
||||
};
|
||||
|
||||
let list = move |mut conn: DbConn<'a>, options: PersonMentionQuery| async move {
|
||||
let list = move |mut conn: DbConn<'a>, options: PersonCommentMentionQuery| async move {
|
||||
// These filters need to be kept in sync with the filters in
|
||||
// PersonMentionView::get_unread_mentions()
|
||||
let mut query = all_joins(person_mention::table.into_boxed(), options.my_person_id);
|
||||
// PersonCommentMentionView::get_unread_mentions()
|
||||
let mut query = all_joins(
|
||||
person_comment_mention::table.into_boxed(),
|
||||
options.my_person_id,
|
||||
);
|
||||
|
||||
if let Some(recipient_id) = options.recipient_id {
|
||||
query = query.filter(person_mention::recipient_id.eq(recipient_id));
|
||||
query = query.filter(person_comment_mention::recipient_id.eq(recipient_id));
|
||||
}
|
||||
|
||||
if options.unread_only {
|
||||
query = query.filter(person_mention::read.eq(false));
|
||||
query = query.filter(person_comment_mention::read.eq(false));
|
||||
}
|
||||
|
||||
if !options.show_bot_accounts {
|
||||
query = query.filter(not(person::bot_account));
|
||||
};
|
||||
|
||||
query = match options.sort.unwrap_or(CommentSortType::Hot) {
|
||||
query = match options.sort.unwrap_or(CommentSortType::New) {
|
||||
CommentSortType::Hot => query.then_order_by(comment_aggregates::hot_rank.desc()),
|
||||
CommentSortType::Controversial => {
|
||||
query.then_order_by(comment_aggregates::controversy_rank.desc())
|
||||
|
@ -148,33 +155,33 @@ fn queries<'a>() -> Queries<
|
|||
query
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.load::<PersonMentionView>(&mut conn)
|
||||
.load::<PersonCommentMentionView>(&mut conn)
|
||||
.await
|
||||
};
|
||||
|
||||
Queries::new(read, list)
|
||||
}
|
||||
|
||||
impl PersonMentionView {
|
||||
impl PersonCommentMentionView {
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_mention_id: PersonMentionId,
|
||||
person_comment_mention_id: PersonCommentMentionId,
|
||||
my_person_id: Option<PersonId>,
|
||||
) -> Result<Self, Error> {
|
||||
queries()
|
||||
.read(pool, (person_mention_id, my_person_id))
|
||||
.read(pool, (person_comment_mention_id, my_person_id))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets the number of unread mentions
|
||||
pub async fn get_unread_mentions(
|
||||
pub async fn get_unread_count(
|
||||
pool: &mut DbPool<'_>,
|
||||
local_user: &LocalUser,
|
||||
) -> Result<i64, Error> {
|
||||
use diesel::dsl::count;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let mut query = person_mention::table
|
||||
let mut query = person_comment_mention::table
|
||||
.inner_join(comment::table)
|
||||
.left_join(actions(
|
||||
person_actions::table,
|
||||
|
@ -192,18 +199,18 @@ impl PersonMentionView {
|
|||
query
|
||||
// Don't count replies from blocked users
|
||||
.filter(person_actions::blocked.is_null())
|
||||
.filter(person_mention::recipient_id.eq(local_user.person_id))
|
||||
.filter(person_mention::read.eq(false))
|
||||
.filter(person_comment_mention::recipient_id.eq(local_user.person_id))
|
||||
.filter(person_comment_mention::read.eq(false))
|
||||
.filter(comment::deleted.eq(false))
|
||||
.filter(comment::removed.eq(false))
|
||||
.select(count(person_mention::id))
|
||||
.select(count(person_comment_mention::id))
|
||||
.first::<i64>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct PersonMentionQuery {
|
||||
pub struct PersonCommentMentionQuery {
|
||||
pub my_person_id: Option<PersonId>,
|
||||
pub recipient_id: Option<PersonId>,
|
||||
pub sort: Option<CommentSortType>,
|
||||
|
@ -213,8 +220,8 @@ pub struct PersonMentionQuery {
|
|||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
impl PersonMentionQuery {
|
||||
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<PersonMentionView>, Error> {
|
||||
impl PersonCommentMentionQuery {
|
||||
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<PersonCommentMentionView>, Error> {
|
||||
queries().list(pool, self).await
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +229,10 @@ impl PersonMentionQuery {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::{person_mention_view::PersonMentionQuery, structs::PersonMentionView};
|
||||
use crate::{
|
||||
person_comment_mention_view::PersonCommentMentionQuery,
|
||||
structs::PersonCommentMentionView,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::{Comment, CommentInsertForm},
|
||||
|
@ -231,7 +241,11 @@ mod tests {
|
|||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
person::{Person, PersonInsertForm, PersonUpdateForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
person_mention::{PersonMention, PersonMentionInsertForm, PersonMentionUpdateForm},
|
||||
person_comment_mention::{
|
||||
PersonCommentMention,
|
||||
PersonCommentMentionInsertForm,
|
||||
PersonCommentMentionUpdateForm,
|
||||
},
|
||||
post::{Post, PostInsertForm},
|
||||
},
|
||||
traits::{Blockable, Crud},
|
||||
|
@ -284,15 +298,15 @@ mod tests {
|
|||
);
|
||||
let inserted_comment = Comment::create(pool, &comment_form, None).await?;
|
||||
|
||||
let person_mention_form = PersonMentionInsertForm {
|
||||
let person_comment_mention_form = PersonCommentMentionInsertForm {
|
||||
recipient_id: inserted_recipient.id,
|
||||
comment_id: inserted_comment.id,
|
||||
read: None,
|
||||
};
|
||||
|
||||
let inserted_mention = PersonMention::create(pool, &person_mention_form).await?;
|
||||
let inserted_mention = PersonCommentMention::create(pool, &person_comment_mention_form).await?;
|
||||
|
||||
let expected_mention = PersonMention {
|
||||
let expected_mention = PersonCommentMention {
|
||||
id: inserted_mention.id,
|
||||
recipient_id: inserted_mention.recipient_id,
|
||||
comment_id: inserted_mention.comment_id,
|
||||
|
@ -300,17 +314,21 @@ mod tests {
|
|||
published: inserted_mention.published,
|
||||
};
|
||||
|
||||
let read_mention = PersonMention::read(pool, inserted_mention.id).await?;
|
||||
let read_mention = PersonCommentMention::read(pool, inserted_mention.id).await?;
|
||||
|
||||
let person_mention_update_form = PersonMentionUpdateForm { read: Some(false) };
|
||||
let updated_mention =
|
||||
PersonMention::update(pool, inserted_mention.id, &person_mention_update_form).await?;
|
||||
let person_comment_mention_update_form = PersonCommentMentionUpdateForm { read: Some(false) };
|
||||
let updated_mention = PersonCommentMention::update(
|
||||
pool,
|
||||
inserted_mention.id,
|
||||
&person_comment_mention_update_form,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Test to make sure counts and blocks work correctly
|
||||
let unread_mentions =
|
||||
PersonMentionView::get_unread_mentions(pool, &recipient_local_user).await?;
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
|
||||
let query = PersonMentionQuery {
|
||||
let query = PersonCommentMentionQuery {
|
||||
recipient_id: Some(recipient_id),
|
||||
my_person_id: Some(recipient_id),
|
||||
sort: None,
|
||||
|
@ -331,7 +349,7 @@ mod tests {
|
|||
PersonBlock::block(pool, &block_form).await?;
|
||||
|
||||
let unread_mentions_after_block =
|
||||
PersonMentionView::get_unread_mentions(pool, &recipient_local_user).await?;
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user).await?;
|
||||
let mentions_after_block = query.clone().list(pool).await?;
|
||||
assert_eq!(0, unread_mentions_after_block);
|
||||
assert_eq!(0, mentions_after_block.len());
|
||||
|
@ -359,7 +377,8 @@ mod tests {
|
|||
let recipient_local_user_view = LocalUserView::read(pool, recipient_local_user.id).await?;
|
||||
|
||||
let unread_mentions_after_hide_bots =
|
||||
PersonMentionView::get_unread_mentions(pool, &recipient_local_user_view.local_user).await?;
|
||||
PersonCommentMentionView::get_unread_count(pool, &recipient_local_user_view.local_user)
|
||||
.await?;
|
||||
|
||||
let mut query_without_bots = query.clone();
|
||||
query_without_bots.show_bot_accounts = false;
|
|
@ -1,13 +1,14 @@
|
|||
#[cfg(feature = "full")]
|
||||
use diesel::Queryable;
|
||||
use lemmy_db_schema::{
|
||||
aggregates::structs::{CommentAggregates, CommunityAggregates, PersonAggregates},
|
||||
aggregates::structs::{CommentAggregates, CommunityAggregates, PersonAggregates, PostAggregates},
|
||||
source::{
|
||||
comment::Comment,
|
||||
comment_reply::CommentReply,
|
||||
community::Community,
|
||||
person::Person,
|
||||
person_mention::PersonMention,
|
||||
person_comment_mention::PersonCommentMention,
|
||||
person_post_mention::PersonPostMention,
|
||||
post::Post,
|
||||
},
|
||||
SubscribedType,
|
||||
|
@ -93,9 +94,9 @@ pub enum CommunitySortType {
|
|||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A person mention view.
|
||||
pub struct PersonMentionView {
|
||||
pub person_mention: PersonMention,
|
||||
/// A person comment mention view.
|
||||
pub struct PersonCommentMentionView {
|
||||
pub person_comment_mention: PersonCommentMention,
|
||||
pub comment: Comment,
|
||||
pub creator: Person,
|
||||
pub post: Post,
|
||||
|
@ -113,6 +114,29 @@ pub struct PersonMentionView {
|
|||
pub my_vote: Option<i16>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A person post mention view.
|
||||
pub struct PersonPostMentionView {
|
||||
pub person_post_mention: PersonPostMention,
|
||||
pub post: Post,
|
||||
pub creator: Person,
|
||||
pub community: Community,
|
||||
pub recipient: Person,
|
||||
pub counts: PostAggregates,
|
||||
pub creator_banned_from_community: bool,
|
||||
pub banned_from_community: bool,
|
||||
pub creator_is_moderator: bool,
|
||||
pub creator_is_admin: bool,
|
||||
pub subscribed: SubscribedType,
|
||||
pub saved: bool,
|
||||
pub creator_blocked: bool,
|
||||
pub my_vote: Option<i16>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||
|
|
|
@ -17,8 +17,9 @@ use lemmy_db_views::{
|
|||
};
|
||||
use lemmy_db_views_actor::{
|
||||
comment_reply_view::CommentReplyQuery,
|
||||
person_mention_view::PersonMentionQuery,
|
||||
structs::{CommentReplyView, PersonMentionView},
|
||||
person_comment_mention_view::PersonCommentMentionQuery,
|
||||
person_post_mention_view::PersonPostMentionQuery,
|
||||
structs::{CommentReplyView, PersonCommentMentionView, PersonPostMentionView},
|
||||
};
|
||||
use lemmy_utils::{
|
||||
cache_header::cache_1hour,
|
||||
|
@ -360,37 +361,53 @@ async fn get_feed_front(
|
|||
async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult<Channel> {
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
let local_user = local_user_view_from_jwt(jwt, context).await?;
|
||||
let person_id = local_user.local_user.person_id;
|
||||
let my_person_id = Some(local_user.person.id);
|
||||
let recipient_id = Some(local_user.local_user.person_id);
|
||||
let show_bot_accounts = local_user.local_user.show_bot_accounts;
|
||||
|
||||
let sort = CommentSortType::New;
|
||||
let limit = Some(RSS_FETCH_LIMIT);
|
||||
|
||||
check_private_instance(&Some(local_user.clone()), &site_view.local_site)?;
|
||||
|
||||
let replies = CommentReplyQuery {
|
||||
recipient_id: (Some(person_id)),
|
||||
my_person_id: (Some(person_id)),
|
||||
show_bot_accounts: (show_bot_accounts),
|
||||
sort: (Some(sort)),
|
||||
limit: (Some(RSS_FETCH_LIMIT)),
|
||||
recipient_id,
|
||||
my_person_id,
|
||||
show_bot_accounts,
|
||||
sort: Some(CommentSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let mentions = PersonMentionQuery {
|
||||
recipient_id: (Some(person_id)),
|
||||
my_person_id: (Some(person_id)),
|
||||
show_bot_accounts: (show_bot_accounts),
|
||||
sort: (Some(sort)),
|
||||
limit: (Some(RSS_FETCH_LIMIT)),
|
||||
let comment_mentions = PersonCommentMentionQuery {
|
||||
recipient_id,
|
||||
my_person_id,
|
||||
show_bot_accounts,
|
||||
sort: Some(CommentSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let post_mentions = PersonPostMentionQuery {
|
||||
recipient_id,
|
||||
my_person_id,
|
||||
show_bot_accounts,
|
||||
sort: Some(PostSortType::New),
|
||||
limit,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&mut context.pool())
|
||||
.await?;
|
||||
|
||||
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
||||
let items = create_reply_and_mention_items(replies, mentions, &protocol_and_hostname)?;
|
||||
let items = create_reply_and_mention_items(
|
||||
replies,
|
||||
comment_mentions,
|
||||
post_mentions,
|
||||
&protocol_and_hostname,
|
||||
)?;
|
||||
|
||||
let mut channel = Channel {
|
||||
namespaces: RSS_NAMESPACE.clone(),
|
||||
|
@ -410,7 +427,8 @@ async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult<Channe
|
|||
#[tracing::instrument(skip_all)]
|
||||
fn create_reply_and_mention_items(
|
||||
replies: Vec<CommentReplyView>,
|
||||
mentions: Vec<PersonMentionView>,
|
||||
comment_mentions: Vec<PersonCommentMentionView>,
|
||||
post_mentions: Vec<PersonPostMentionView>,
|
||||
protocol_and_hostname: &str,
|
||||
) -> LemmyResult<Vec<Item>> {
|
||||
let mut reply_items: Vec<Item> = replies
|
||||
|
@ -427,7 +445,7 @@ fn create_reply_and_mention_items(
|
|||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
let mut mention_items: Vec<Item> = mentions
|
||||
let mut comment_mention_items: Vec<Item> = comment_mentions
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let mention_url = format!("{}/comment/{}", protocol_and_hostname, m.comment.id);
|
||||
|
@ -441,7 +459,24 @@ fn create_reply_and_mention_items(
|
|||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
reply_items.append(&mut mention_items);
|
||||
reply_items.append(&mut comment_mention_items);
|
||||
|
||||
let mut post_mention_items: Vec<Item> = post_mentions
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let mention_url = format!("{}/post/{}", protocol_and_hostname, m.post.id);
|
||||
build_item(
|
||||
&m.creator.name,
|
||||
&m.post.published,
|
||||
&mention_url,
|
||||
&m.post.body.clone().unwrap_or_default(),
|
||||
protocol_and_hostname,
|
||||
)
|
||||
})
|
||||
.collect::<LemmyResult<Vec<Item>>>()?;
|
||||
|
||||
reply_items.append(&mut post_mention_items);
|
||||
|
||||
Ok(reply_items)
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ pub enum LemmyErrorType {
|
|||
CouldntHidePost,
|
||||
CouldntUpdateCommunity,
|
||||
CouldntUpdateReplies,
|
||||
CouldntUpdatePersonMentions,
|
||||
CouldntUpdatePersonCommentMentions,
|
||||
CouldntCreatePost,
|
||||
CouldntCreatePrivateMessage,
|
||||
CouldntUpdatePrivate,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
-- Rename the person_mention table to person_comment_mention
|
||||
ALTER TABLE person_comment_mention RENAME TO person_mention;
|
||||
|
||||
-- Drop the new table
|
||||
DROP TABLE person_post_mention;
|
12
migrations/2024-11-02-161125_add_post_body_mention/up.sql
Normal file
12
migrations/2024-11-02-161125_add_post_body_mention/up.sql
Normal file
|
@ -0,0 +1,12 @@
|
|||
-- Rename the person_mention table to person_comment_mention
|
||||
ALTER TABLE person_mention RENAME TO person_comment_mention;
|
||||
|
||||
-- Create the new post_mention table
|
||||
CREATE TABLE person_post_mention (
|
||||
id serial PRIMARY KEY,
|
||||
recipient_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
read boolean DEFAULT FALSE NOT NULL,
|
||||
published timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (recipient_id, post_id)
|
||||
);
|
Loading…
Reference in a new issue