mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-09-02 19:23:49 +00:00
This reverts commit 76fbb29079
.
This commit is contained in:
parent
0d149dd613
commit
3922f0f325
26 changed files with 420 additions and 393 deletions
|
@ -69,5 +69,8 @@ pub async fn distinguish_comment(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Json(CommentResponse { comment_view }))
|
Ok(Json(CommentResponse {
|
||||||
|
comment_view,
|
||||||
|
recipient_ids: Vec::new(),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@ use lemmy_api_utils::{
|
||||||
utils::{check_bot_account, check_community_user_action, check_local_vote_mode},
|
utils::{check_bot_account, check_community_user_action, check_local_vote_mode},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::PostOrCommentId,
|
newtypes::{LocalUserId, PostOrCommentId},
|
||||||
source::{
|
source::{
|
||||||
comment::{CommentActions, CommentLikeForm},
|
comment::{CommentActions, CommentLikeForm},
|
||||||
|
comment_reply::CommentReply,
|
||||||
person::PersonActions,
|
person::PersonActions,
|
||||||
},
|
},
|
||||||
traits::Likeable,
|
traits::Likeable,
|
||||||
|
@ -34,6 +35,8 @@ pub async fn like_comment(
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
let my_person_id = local_user_view.person.id;
|
let my_person_id = local_user_view.person.id;
|
||||||
|
|
||||||
|
let mut recipient_ids = Vec::<LocalUserId>::new();
|
||||||
|
|
||||||
check_local_vote_mode(
|
check_local_vote_mode(
|
||||||
data.score,
|
data.score,
|
||||||
PostOrCommentId::Comment(comment_id),
|
PostOrCommentId::Comment(comment_id),
|
||||||
|
@ -60,6 +63,16 @@ pub async fn like_comment(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// Add parent poster or commenter to recipients
|
||||||
|
let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await;
|
||||||
|
if let Ok(Some(reply)) = comment_reply {
|
||||||
|
let recipient_id = reply.recipient_id;
|
||||||
|
if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await
|
||||||
|
{
|
||||||
|
recipient_ids.push(local_recipient.local_user.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut like_form = CommentLikeForm::new(my_person_id, data.comment_id, data.score);
|
let mut like_form = CommentLikeForm::new(my_person_id, data.comment_id, data.score);
|
||||||
|
|
||||||
// Remove any likes first
|
// Remove any likes first
|
||||||
|
@ -106,6 +119,7 @@ pub async fn like_comment(
|
||||||
context.deref(),
|
context.deref(),
|
||||||
comment_id,
|
comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
|
recipient_ids,
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -34,5 +34,8 @@ pub async fn save_comment(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Json(CommentResponse { comment_view }))
|
Ok(Json(CommentResponse {
|
||||||
|
comment_view,
|
||||||
|
recipient_ids: Vec::new(),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,3 @@ pub mod lock;
|
||||||
pub mod mark_many_read;
|
pub mod mark_many_read;
|
||||||
pub mod mark_read;
|
pub mod mark_read;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
pub mod update_notifications;
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
use activitypub_federation::config::Data;
|
|
||||||
use actix_web::web::Json;
|
|
||||||
use lemmy_api_utils::context::LemmyContext;
|
|
||||||
use lemmy_db_schema::source::post::PostActions;
|
|
||||||
use lemmy_db_views_local_user::LocalUserView;
|
|
||||||
use lemmy_db_views_post::api::UpdatePostNotifications;
|
|
||||||
use lemmy_db_views_site::api::SuccessResponse;
|
|
||||||
use lemmy_utils::error::LemmyResult;
|
|
||||||
|
|
||||||
pub async fn update_post_notifications(
|
|
||||||
data: Json<UpdatePostNotifications>,
|
|
||||||
context: Data<LemmyContext>,
|
|
||||||
local_user_view: LocalUserView,
|
|
||||||
) -> LemmyResult<Json<SuccessResponse>> {
|
|
||||||
PostActions::update_notification_state(
|
|
||||||
data.post_id,
|
|
||||||
local_user_view.person.id,
|
|
||||||
data.new_state,
|
|
||||||
&mut context.pool(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
|
||||||
}
|
|
|
@ -19,6 +19,7 @@ use lemmy_api_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::validate_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::{
|
source::{
|
||||||
comment::{Comment, CommentActions, CommentInsertForm, CommentLikeForm},
|
comment::{Comment, CommentActions, CommentInsertForm, CommentLikeForm},
|
||||||
comment_reply::{CommentReply, CommentReplyUpdateForm},
|
comment_reply::{CommentReply, CommentReplyUpdateForm},
|
||||||
|
@ -32,7 +33,7 @@ use lemmy_db_views_post::PostView;
|
||||||
use lemmy_db_views_site::SiteView;
|
use lemmy_db_views_site::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyErrorType, LemmyResult},
|
error::{LemmyErrorType, LemmyResult},
|
||||||
utils::validation::is_valid_body_field,
|
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn create_comment(
|
pub async fn create_comment(
|
||||||
|
@ -112,14 +113,19 @@ pub async fn create_comment(
|
||||||
Comment::create(&mut context.pool(), &comment_form, parent_path.as_ref()).await?;
|
Comment::create(&mut context.pool(), &comment_form, parent_path.as_ref()).await?;
|
||||||
plugin_hook_after("after_create_local_comment", &inserted_comment)?;
|
plugin_hook_after("after_create_local_comment", &inserted_comment)?;
|
||||||
|
|
||||||
|
let inserted_comment_id = inserted_comment.id;
|
||||||
|
|
||||||
|
// Scan the comment for user mentions, add those rows
|
||||||
|
let mentions = scrape_text_for_mentions(&content);
|
||||||
let do_send_email = !local_site.disable_email_notifications;
|
let do_send_email = !local_site.disable_email_notifications;
|
||||||
send_local_notifs(
|
let recipient_ids = send_local_notifs(
|
||||||
&post,
|
mentions,
|
||||||
Some(&inserted_comment),
|
PostOrCommentId::Comment(inserted_comment_id),
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
&post_view.community,
|
|
||||||
do_send_email,
|
do_send_email,
|
||||||
&context,
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -179,6 +185,7 @@ pub async fn create_comment(
|
||||||
&context,
|
&context,
|
||||||
inserted_comment.id,
|
inserted_comment.id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
|
recipient_ids,
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_utils::{
|
use lemmy_api_utils::{
|
||||||
build_response::build_comment_response,
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::check_community_user_action,
|
utils::check_community_user_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::comment::{Comment, CommentUpdateForm},
|
source::comment::{Comment, CommentUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
|
@ -61,6 +62,16 @@ pub async fn delete_comment(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let recipient_ids = send_local_notifs(
|
||||||
|
vec![],
|
||||||
|
PostOrCommentId::Comment(comment_id),
|
||||||
|
&local_user_view.person,
|
||||||
|
false,
|
||||||
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let updated_comment_id = updated_comment.id;
|
let updated_comment_id = updated_comment.id;
|
||||||
|
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
|
@ -77,6 +88,7 @@ pub async fn delete_comment(
|
||||||
&context,
|
&context,
|
||||||
updated_comment_id,
|
updated_comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
|
recipient_ids,
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -21,6 +21,13 @@ pub async fn get_comment(
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site)?;
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(&context, data.id, local_user_view, local_instance_id).await?,
|
build_comment_response(
|
||||||
|
&context,
|
||||||
|
data.id,
|
||||||
|
local_user_view,
|
||||||
|
vec![],
|
||||||
|
local_instance_id,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_utils::{
|
use lemmy_api_utils::{
|
||||||
build_response::build_comment_response,
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::check_community_mod_action,
|
utils::check_community_mod_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::{
|
source::{
|
||||||
comment::{Comment, CommentUpdateForm},
|
comment::{Comment, CommentUpdateForm},
|
||||||
comment_report::CommentReport,
|
comment_report::CommentReport,
|
||||||
|
@ -83,6 +84,16 @@ pub async fn remove_comment(
|
||||||
};
|
};
|
||||||
ModRemoveComment::create(&mut context.pool(), &form).await?;
|
ModRemoveComment::create(&mut context.pool(), &form).await?;
|
||||||
|
|
||||||
|
let recipient_ids = send_local_notifs(
|
||||||
|
vec![],
|
||||||
|
PostOrCommentId::Comment(comment_id),
|
||||||
|
&local_user_view.person,
|
||||||
|
false,
|
||||||
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let updated_comment_id = updated_comment.id;
|
let updated_comment_id = updated_comment.id;
|
||||||
|
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
|
@ -100,6 +111,7 @@ pub async fn remove_comment(
|
||||||
&context,
|
&context,
|
||||||
updated_comment_id,
|
updated_comment_id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
|
recipient_ids,
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_api_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::validate_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::comment::{Comment, CommentUpdateForm},
|
source::comment::{Comment, CommentUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
|
@ -20,7 +21,7 @@ use lemmy_db_views_comment::{
|
||||||
use lemmy_db_views_local_user::LocalUserView;
|
use lemmy_db_views_local_user::LocalUserView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyErrorType, LemmyResult},
|
error::{LemmyErrorType, LemmyResult},
|
||||||
utils::validation::is_valid_body_field,
|
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn update_comment(
|
pub async fn update_comment(
|
||||||
|
@ -78,13 +79,16 @@ pub async fn update_comment(
|
||||||
plugin_hook_after("after_update_local_comment", &updated_comment)?;
|
plugin_hook_after("after_update_local_comment", &updated_comment)?;
|
||||||
|
|
||||||
// Do the mentions / recipients
|
// Do the mentions / recipients
|
||||||
send_local_notifs(
|
let updated_comment_content = updated_comment.content.clone();
|
||||||
&orig_comment.post,
|
let mentions = scrape_text_for_mentions(&updated_comment_content);
|
||||||
Some(&updated_comment),
|
let recipient_ids = send_local_notifs(
|
||||||
|
mentions,
|
||||||
|
PostOrCommentId::Comment(comment_id),
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
&orig_comment.community,
|
|
||||||
false,
|
false,
|
||||||
&context,
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -98,6 +102,7 @@ pub async fn update_comment(
|
||||||
&context,
|
&context,
|
||||||
updated_comment.id,
|
updated_comment.id,
|
||||||
Some(local_user_view),
|
Some(local_user_view),
|
||||||
|
recipient_ids,
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|
|
@ -21,6 +21,7 @@ use lemmy_api_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::validate_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::post::{Post, PostActions, PostInsertForm, PostLikeForm, PostReadForm},
|
source::post::{Post, PostActions, PostInsertForm, PostLikeForm, PostReadForm},
|
||||||
traits::{Crud, Likeable, Readable},
|
traits::{Crud, Likeable, Readable},
|
||||||
utils::diesel_url_create,
|
utils::diesel_url_create,
|
||||||
|
@ -33,6 +34,7 @@ use lemmy_db_views_site::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyResult,
|
error::LemmyResult,
|
||||||
utils::{
|
utils::{
|
||||||
|
mention::scrape_text_for_mentions,
|
||||||
slurs::check_slurs,
|
slurs::check_slurs,
|
||||||
validation::{
|
validation::{
|
||||||
is_url_blocked,
|
is_url_blocked,
|
||||||
|
@ -167,18 +169,22 @@ pub async fn create_post(
|
||||||
// They like their own post by default
|
// They like their own post by default
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let post_id = inserted_post.id;
|
let post_id = inserted_post.id;
|
||||||
|
let local_instance_id = local_user_view.person.instance_id;
|
||||||
let like_form = PostLikeForm::new(post_id, person_id, 1);
|
let like_form = PostLikeForm::new(post_id, person_id, 1);
|
||||||
|
|
||||||
PostActions::like(&mut context.pool(), &like_form).await?;
|
PostActions::like(&mut context.pool(), &like_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());
|
||||||
let do_send_email = !local_site.disable_email_notifications;
|
let do_send_email = !local_site.disable_email_notifications;
|
||||||
send_local_notifs(
|
send_local_notifs(
|
||||||
&inserted_post,
|
mentions,
|
||||||
None,
|
PostOrCommentId::Post(inserted_post.id),
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
community,
|
|
||||||
do_send_email,
|
do_send_email,
|
||||||
&context,
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ use lemmy_api_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::validate_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
|
newtypes::PostOrCommentId,
|
||||||
source::{
|
source::{
|
||||||
community::Community,
|
community::Community,
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
|
@ -37,6 +38,7 @@ use lemmy_db_views_site::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyErrorType, LemmyResult},
|
error::{LemmyErrorType, LemmyResult},
|
||||||
utils::{
|
utils::{
|
||||||
|
mention::scrape_text_for_mentions,
|
||||||
slurs::check_slurs,
|
slurs::check_slurs,
|
||||||
validation::{
|
validation::{
|
||||||
is_url_blocked,
|
is_url_blocked,
|
||||||
|
@ -161,13 +163,16 @@ pub async fn update_post(
|
||||||
let updated_post = Post::update(&mut context.pool(), post_id, &post_form).await?;
|
let updated_post = Post::update(&mut context.pool(), post_id, &post_form).await?;
|
||||||
plugin_hook_after("after_update_local_post", &post_form)?;
|
plugin_hook_after("after_update_local_post", &post_form)?;
|
||||||
|
|
||||||
|
// 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(
|
send_local_notifs(
|
||||||
&updated_post,
|
mentions,
|
||||||
None,
|
PostOrCommentId::Post(updated_post.id),
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
&orig_post.community,
|
|
||||||
false,
|
false,
|
||||||
&context,
|
&context,
|
||||||
|
Some(&local_user_view),
|
||||||
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,38 @@
|
||||||
use crate::{context::LemmyContext, utils::is_mod_or_admin};
|
use crate::{
|
||||||
|
context::LemmyContext,
|
||||||
|
utils::{check_person_instance_community_block, is_mod_or_admin},
|
||||||
|
};
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{CommentId, CommunityId, InstanceId, PersonId, PostId},
|
newtypes::{CommentId, CommunityId, InstanceId, LocalUserId, PostId, PostOrCommentId},
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
actor_language::CommunityLanguage,
|
||||||
comment::Comment,
|
comment::Comment,
|
||||||
comment_reply::{CommentReply, CommentReplyInsertForm},
|
comment_reply::{CommentReply, CommentReplyInsertForm},
|
||||||
community::{Community, CommunityActions},
|
community::Community,
|
||||||
instance::InstanceActions,
|
person::Person,
|
||||||
person::{Person, PersonActions},
|
|
||||||
person_comment_mention::{PersonCommentMention, PersonCommentMentionInsertForm},
|
person_comment_mention::{PersonCommentMention, PersonCommentMentionInsertForm},
|
||||||
person_post_mention::{PersonPostMention, PersonPostMentionInsertForm},
|
person_post_mention::{PersonPostMention, PersonPostMentionInsertForm},
|
||||||
post::{Post, PostActions},
|
post::Post,
|
||||||
},
|
},
|
||||||
traits::{Blockable, Crud},
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema_file::enums::PostNotifications;
|
|
||||||
use lemmy_db_views_comment::{api::CommentResponse, CommentView};
|
use lemmy_db_views_comment::{api::CommentResponse, CommentView};
|
||||||
use lemmy_db_views_community::{api::CommunityResponse, CommunityView};
|
use lemmy_db_views_community::{api::CommunityResponse, CommunityView};
|
||||||
use lemmy_db_views_local_user::LocalUserView;
|
use lemmy_db_views_local_user::LocalUserView;
|
||||||
use lemmy_db_views_post::{api::PostResponse, PostView};
|
use lemmy_db_views_post::{api::PostResponse, PostView};
|
||||||
use lemmy_email::notifications::{send_mention_email, send_reply_email};
|
use lemmy_email::notifications::{
|
||||||
use lemmy_utils::{
|
send_comment_reply_email,
|
||||||
error::{LemmyErrorType, LemmyResult},
|
send_mention_email,
|
||||||
utils::mention::scrape_text_for_mentions,
|
send_post_reply_email,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use lemmy_utils::{error::LemmyResult, utils::mention::MentionData};
|
||||||
|
|
||||||
pub async fn build_comment_response(
|
pub async fn build_comment_response(
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
comment_id: CommentId,
|
comment_id: CommentId,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
|
recipient_ids: Vec<LocalUserId>,
|
||||||
local_instance_id: InstanceId,
|
local_instance_id: InstanceId,
|
||||||
) -> LemmyResult<CommentResponse> {
|
) -> LemmyResult<CommentResponse> {
|
||||||
let local_user = local_user_view.map(|l| l.local_user);
|
let local_user = local_user_view.map(|l| l.local_user);
|
||||||
|
@ -41,7 +43,10 @@ pub async fn build_comment_response(
|
||||||
local_instance_id,
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(CommentResponse { comment_view })
|
Ok(CommentResponse {
|
||||||
|
comment_view,
|
||||||
|
recipient_ids,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn build_community_response(
|
pub async fn build_community_response(
|
||||||
|
@ -89,223 +94,220 @@ pub async fn build_post_response(
|
||||||
Ok(Json(PostResponse { post_view }))
|
Ok(Json(PostResponse { post_view }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scans the post/comment content for mentions, then sends notifications via db and email
|
// TODO: this function is a mess and should be split up to handle email separately
|
||||||
/// to mentioned users and parent creator.
|
|
||||||
pub async fn send_local_notifs(
|
pub async fn send_local_notifs(
|
||||||
post: &Post,
|
mentions: Vec<MentionData>,
|
||||||
comment_opt: Option<&Comment>,
|
post_or_comment_id: PostOrCommentId,
|
||||||
person: &Person,
|
person: &Person,
|
||||||
community: &Community,
|
|
||||||
do_send_email: bool,
|
do_send_email: bool,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> LemmyResult<()> {
|
local_user_view: Option<&LocalUserView>,
|
||||||
let parent_creator =
|
local_instance_id: InstanceId,
|
||||||
notify_parent_creator(person, post, comment_opt, community, do_send_email, context).await?;
|
) -> LemmyResult<Vec<LocalUserId>> {
|
||||||
|
let mut recipient_ids = Vec::new();
|
||||||
|
|
||||||
send_local_mentions(
|
let (comment_opt, post, community) = match post_or_comment_id {
|
||||||
post,
|
PostOrCommentId::Post(post_id) => {
|
||||||
comment_opt,
|
let post_view = PostView::read(
|
||||||
person,
|
&mut context.pool(),
|
||||||
parent_creator,
|
post_id,
|
||||||
community,
|
local_user_view.map(|view| &view.local_user),
|
||||||
do_send_email,
|
local_instance_id,
|
||||||
context,
|
false,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
(None, post_view.post, post_view.community)
|
||||||
Ok(())
|
}
|
||||||
}
|
PostOrCommentId::Comment(comment_id) => {
|
||||||
|
// When called from api code, we have local user view and can read with CommentView
|
||||||
async fn notify_parent_creator(
|
// to reduce db queries. But when receiving a federated comment the user view is None,
|
||||||
person: &Person,
|
// which means that comments inside private communities cant be read. As a workaround
|
||||||
post: &Post,
|
// we need to read the items manually to bypass this check.
|
||||||
comment_opt: Option<&Comment>,
|
if let Some(local_user_view) = local_user_view {
|
||||||
community: &Community,
|
// Read the comment view to get extra info
|
||||||
do_send_email: bool,
|
let comment_view = CommentView::read(
|
||||||
context: &LemmyContext,
|
&mut context.pool(),
|
||||||
) -> LemmyResult<Option<PersonId>> {
|
comment_id,
|
||||||
let Some(comment) = comment_opt else {
|
Some(&local_user_view.local_user),
|
||||||
return Ok(None);
|
local_instance_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
(
|
||||||
|
Some(comment_view.comment),
|
||||||
|
comment_view.post,
|
||||||
|
comment_view.community,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let comment = Comment::read(&mut context.pool(), comment_id).await?;
|
||||||
|
let post = Post::read(&mut context.pool(), comment.post_id).await?;
|
||||||
|
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
||||||
|
(Some(comment), post, community)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the parent data
|
// Send the local mentions
|
||||||
let (parent_creator_id, parent_comment) =
|
for mention in mentions
|
||||||
|
.iter()
|
||||||
|
.filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name))
|
||||||
|
{
|
||||||
|
let mention_name = mention.name.clone();
|
||||||
|
let user_view = LocalUserView::read_from_name(&mut context.pool(), &mention_name).await;
|
||||||
|
if let Ok(mention_user_view) = user_view {
|
||||||
|
// TODO
|
||||||
|
// At some point, make it so you can't tag the parent creator either
|
||||||
|
// Potential duplication of notifications, one for reply and the other for mention, is handled
|
||||||
|
// below by checking recipient ids
|
||||||
|
recipient_ids.push(mention_user_view.local_user.id);
|
||||||
|
|
||||||
|
// Make the correct reply form depending on whether its a post or comment mention
|
||||||
|
let (link, 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,
|
||||||
|
read: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allow this to fail softly, since comment edits might re-update or replace it
|
||||||
|
// Let the uniqueness handle this fail
|
||||||
|
PersonCommentMention::create(&mut context.pool(), &person_comment_mention_form)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
(
|
||||||
|
comment.local_url(context.settings())?,
|
||||||
|
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.local_url(context.settings())?,
|
||||||
|
post.body.clone().unwrap_or_default(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send an email to those local users that have notifications on
|
||||||
|
if do_send_email {
|
||||||
|
send_mention_email(
|
||||||
|
&mention_user_view,
|
||||||
|
&comment_content_or_post_body,
|
||||||
|
person,
|
||||||
|
link.into(),
|
||||||
|
context.settings(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send comment_reply to the parent commenter / poster
|
||||||
|
if let Some(comment) = &comment_opt {
|
||||||
if let Some(parent_comment_id) = comment.parent_comment_id() {
|
if let Some(parent_comment_id) = comment.parent_comment_id() {
|
||||||
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
|
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
|
||||||
(parent_comment.creator_id, Some(parent_comment))
|
|
||||||
} else {
|
|
||||||
(post.creator_id, None)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dont send notification to yourself
|
// Get the parent commenter local_user
|
||||||
if parent_creator_id == person.id {
|
let parent_creator_id = parent_comment.creator_id;
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_blocked = check_notifications_allowed(
|
let check_blocks = check_person_instance_community_block(
|
||||||
parent_creator_id,
|
person.id,
|
||||||
// Only block from the community's instance_id
|
parent_creator_id,
|
||||||
community.instance_id,
|
// Only block from the community's instance_id
|
||||||
post,
|
community.instance_id,
|
||||||
context,
|
community.id,
|
||||||
)
|
&mut context.pool(),
|
||||||
.await
|
|
||||||
.is_err();
|
|
||||||
if is_blocked {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Ok(user_view) = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let comment_reply_form = CommentReplyInsertForm {
|
|
||||||
recipient_id: user_view.person.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
|
|
||||||
CommentReply::create(&mut context.pool(), &comment_reply_form)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
if do_send_email {
|
|
||||||
send_reply_email(
|
|
||||||
&user_view,
|
|
||||||
comment,
|
|
||||||
person,
|
|
||||||
&parent_comment,
|
|
||||||
post,
|
|
||||||
context.settings(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Ok(Some(user_view.person.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_local_mentions(
|
|
||||||
post: &Post,
|
|
||||||
comment_opt: Option<&Comment>,
|
|
||||||
person: &Person,
|
|
||||||
parent_creator_id: Option<PersonId>,
|
|
||||||
community: &Community,
|
|
||||||
do_send_email: bool,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
let content = if let Some(comment) = comment_opt {
|
|
||||||
&comment.content
|
|
||||||
} else {
|
|
||||||
&post.body.clone().unwrap_or_default()
|
|
||||||
};
|
|
||||||
let mentions = scrape_text_for_mentions(content)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name));
|
|
||||||
for mention in mentions {
|
|
||||||
// Ignore error if user is remote
|
|
||||||
let Ok(user_view) = LocalUserView::read_from_name(&mut context.pool(), &mention.name).await
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dont send any mention notification to parent creator nor to yourself
|
|
||||||
if Some(user_view.person.id) == parent_creator_id || user_view.person.id == person.id {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_blocked = check_notifications_allowed(
|
|
||||||
user_view.person.id,
|
|
||||||
// Only block from the community's instance_id
|
|
||||||
community.instance_id,
|
|
||||||
post,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.is_err();
|
|
||||||
if is_blocked {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (link, comment_content_or_post_body) =
|
|
||||||
insert_post_or_comment_mention(&user_view, post, comment_opt, context).await?;
|
|
||||||
|
|
||||||
// Send an email to those local users that have notifications on
|
|
||||||
if do_send_email {
|
|
||||||
send_mention_email(
|
|
||||||
&user_view,
|
|
||||||
&comment_content_or_post_body,
|
|
||||||
person,
|
|
||||||
link.into(),
|
|
||||||
context.settings(),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
|
.is_err();
|
||||||
|
|
||||||
|
// Don't send a notif to yourself
|
||||||
|
if parent_comment.creator_id != person.id && !check_blocks {
|
||||||
|
let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
|
||||||
|
if let Ok(parent_user_view) = user_view {
|
||||||
|
// Don't duplicate notif if already mentioned by checking recipient ids
|
||||||
|
if !recipient_ids.contains(&parent_user_view.local_user.id) {
|
||||||
|
recipient_ids.push(parent_user_view.local_user.id);
|
||||||
|
|
||||||
|
let comment_reply_form = CommentReplyInsertForm {
|
||||||
|
recipient_id: parent_user_view.person.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
|
||||||
|
CommentReply::create(&mut context.pool(), &comment_reply_form)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
if do_send_email {
|
||||||
|
send_comment_reply_email(
|
||||||
|
&parent_user_view,
|
||||||
|
comment,
|
||||||
|
person,
|
||||||
|
&parent_comment,
|
||||||
|
&post,
|
||||||
|
context.settings(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use the post creator to check blocks
|
||||||
|
let check_blocks = check_person_instance_community_block(
|
||||||
|
person.id,
|
||||||
|
post.creator_id,
|
||||||
|
// Only block from the community's instance_id
|
||||||
|
community.instance_id,
|
||||||
|
community.id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.is_err();
|
||||||
|
|
||||||
|
if post.creator_id != person.id && !check_blocks {
|
||||||
|
let creator_id = post.creator_id;
|
||||||
|
let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
|
||||||
|
if let Ok(parent_user_view) = parent_user {
|
||||||
|
if !recipient_ids.contains(&parent_user_view.local_user.id) {
|
||||||
|
recipient_ids.push(parent_user_view.local_user.id);
|
||||||
|
|
||||||
|
let comment_reply_form = CommentReplyInsertForm {
|
||||||
|
recipient_id: parent_user_view.person.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
|
||||||
|
CommentReply::create(&mut context.pool(), &comment_reply_form)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
if do_send_email {
|
||||||
|
send_post_reply_email(
|
||||||
|
&parent_user_view,
|
||||||
|
comment,
|
||||||
|
person,
|
||||||
|
&post,
|
||||||
|
context.settings(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
Ok(recipient_ids)
|
||||||
|
|
||||||
/// Make the correct reply form depending on whether its a post or comment mention
|
|
||||||
async fn insert_post_or_comment_mention(
|
|
||||||
mention_user_view: &LocalUserView,
|
|
||||||
post: &Post,
|
|
||||||
comment_opt: Option<&Comment>,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> LemmyResult<(Url, String)> {
|
|
||||||
if let Some(comment) = &comment_opt {
|
|
||||||
let person_comment_mention_form = PersonCommentMentionInsertForm {
|
|
||||||
recipient_id: mention_user_view.person.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
|
|
||||||
PersonCommentMention::create(&mut context.pool(), &person_comment_mention_form)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
Ok((
|
|
||||||
comment.local_url(context.settings())?,
|
|
||||||
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();
|
|
||||||
Ok((
|
|
||||||
post.local_url(context.settings())?,
|
|
||||||
post.body.clone().unwrap_or_default(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn check_notifications_allowed(
|
|
||||||
potential_blocker_id: PersonId,
|
|
||||||
community_instance_id: InstanceId,
|
|
||||||
post: &Post,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
let pool = &mut context.pool();
|
|
||||||
PersonActions::read_block(pool, potential_blocker_id, post.creator_id).await?;
|
|
||||||
InstanceActions::read_block(pool, potential_blocker_id, community_instance_id).await?;
|
|
||||||
CommunityActions::read_block(pool, potential_blocker_id, post.community_id).await?;
|
|
||||||
let post_notifications = PostActions::read(pool, post.id, potential_blocker_id)
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
.and_then(|a| a.notifications)
|
|
||||||
.unwrap_or_default();
|
|
||||||
if post_notifications == PostNotifications::Mute {
|
|
||||||
// The specific error type is irrelevant
|
|
||||||
return Err(LemmyErrorType::NotFound.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,13 @@ use lemmy_db_schema::{
|
||||||
ModRemovePostForm,
|
ModRemovePostForm,
|
||||||
},
|
},
|
||||||
oauth_account::OAuthAccount,
|
oauth_account::OAuthAccount,
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonActions, PersonUpdateForm},
|
||||||
post::{Post, PostActions, PostReadCommentsForm},
|
post::{Post, PostActions, PostReadCommentsForm},
|
||||||
private_message::PrivateMessage,
|
private_message::PrivateMessage,
|
||||||
registration_application::RegistrationApplication,
|
registration_application::RegistrationApplication,
|
||||||
site::Site,
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable, ReadComments},
|
traits::{Blockable, Crud, Likeable, ReadComments},
|
||||||
utils::DbPool,
|
utils::DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema_file::enums::{FederationMode, RegistrationMode};
|
use lemmy_db_schema_file::enums::{FederationMode, RegistrationMode};
|
||||||
|
@ -321,6 +321,19 @@ pub fn check_comment_deleted_or_removed(comment: &Comment) -> LemmyResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn check_person_instance_community_block(
|
||||||
|
my_id: PersonId,
|
||||||
|
potential_blocker_id: PersonId,
|
||||||
|
community_instance_id: InstanceId,
|
||||||
|
community_id: CommunityId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
PersonActions::read_block(pool, potential_blocker_id, my_id).await?;
|
||||||
|
InstanceActions::read_block(pool, potential_blocker_id, community_instance_id).await?;
|
||||||
|
CommunityActions::read_block(pool, potential_blocker_id, community_id).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn check_local_vote_mode(
|
pub async fn check_local_vote_mode(
|
||||||
score: i16,
|
score: i16,
|
||||||
post_or_comment_id: PostOrCommentId,
|
post_or_comment_id: PostOrCommentId,
|
||||||
|
|
|
@ -27,7 +27,7 @@ use lemmy_apub_objects::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::PersonId,
|
newtypes::{PersonId, PostOrCommentId},
|
||||||
source::{
|
source::{
|
||||||
activity::ActivitySendTargets,
|
activity::ActivitySendTargets,
|
||||||
comment::{Comment, CommentActions, CommentLikeForm},
|
comment::{Comment, CommentActions, CommentLikeForm},
|
||||||
|
@ -38,7 +38,10 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_site::SiteView;
|
use lemmy_db_views_site::SiteView;
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyResult},
|
||||||
|
utils::mention::scrape_text_for_mentions,
|
||||||
|
};
|
||||||
use serde_json::{from_value, to_value};
|
use serde_json::{from_value, to_value};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -134,12 +137,12 @@ impl ActivityHandler for CreateOrUpdateNote {
|
||||||
// Need to do this check here instead of Note::from_json because we need the person who
|
// Need to do this check here instead of Note::from_json because we need the person who
|
||||||
// send the activity, not the comment author.
|
// send the activity, not the comment author.
|
||||||
let existing_comment = self.object.id.dereference_local(context).await.ok();
|
let existing_comment = self.object.id.dereference_local(context).await.ok();
|
||||||
let (post, _) = self.object.get_parents(context).await?;
|
|
||||||
if let (Some(distinguished), Some(existing_comment)) =
|
if let (Some(distinguished), Some(existing_comment)) =
|
||||||
(self.object.distinguished, existing_comment)
|
(self.object.distinguished, existing_comment)
|
||||||
{
|
{
|
||||||
if distinguished != existing_comment.distinguished {
|
if distinguished != existing_comment.distinguished {
|
||||||
let creator = self.actor.dereference(context).await?;
|
let creator = self.actor.dereference(context).await?;
|
||||||
|
let (post, _) = self.object.get_parents(context).await?;
|
||||||
check_is_mod_or_admin(
|
check_is_mod_or_admin(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
creator.id,
|
creator.id,
|
||||||
|
@ -169,14 +172,17 @@ impl ActivityHandler for CreateOrUpdateNote {
|
||||||
// anyway.
|
// anyway.
|
||||||
// TODO: for compatibility with other projects, it would be much better to read this from cc or
|
// TODO: for compatibility with other projects, it would be much better to read this from cc or
|
||||||
// tags
|
// tags
|
||||||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
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(
|
send_local_notifs(
|
||||||
&post.0,
|
mentions,
|
||||||
Some(&comment.0),
|
PostOrCommentId::Comment(comment.id),
|
||||||
&actor,
|
&actor,
|
||||||
&community,
|
|
||||||
do_send_email,
|
do_send_email,
|
||||||
context,
|
context,
|
||||||
|
None,
|
||||||
|
local_instance_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -21,7 +21,7 @@ use lemmy_apub_objects::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::PersonId,
|
newtypes::{PersonId, PostOrCommentId},
|
||||||
source::{
|
source::{
|
||||||
activity::ActivitySendTargets,
|
activity::ActivitySendTargets,
|
||||||
community::Community,
|
community::Community,
|
||||||
|
@ -31,7 +31,10 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_site::SiteView;
|
use lemmy_db_views_site::SiteView;
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyResult},
|
||||||
|
utils::mention::scrape_text_for_mentions,
|
||||||
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
impl CreateOrUpdatePage {
|
impl CreateOrUpdatePage {
|
||||||
|
@ -107,6 +110,7 @@ impl ActivityHandler for CreateOrUpdatePage {
|
||||||
|
|
||||||
async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
let local_instance_id = site_view.site.instance_id;
|
||||||
|
|
||||||
let post = ApubPost::from_json(self.object, context).await?;
|
let post = ApubPost::from_json(self.object, context).await?;
|
||||||
|
|
||||||
|
@ -121,8 +125,18 @@ impl ActivityHandler for CreateOrUpdatePage {
|
||||||
self.kind == CreateOrUpdateType::Create && !site_view.local_site.disable_email_notifications;
|
self.kind == CreateOrUpdateType::Create && !site_view.local_site.disable_email_notifications;
|
||||||
let actor = self.actor.dereference(context).await?;
|
let actor = self.actor.dereference(context).await?;
|
||||||
|
|
||||||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
// Send the post body mentions
|
||||||
send_local_notifs(&post.0, None, &actor, &community, do_send_email, context).await?;
|
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,
|
||||||
|
local_instance_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::{
|
||||||
SITEMAP_LIMIT,
|
SITEMAP_LIMIT,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use ::url::Url;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{count, insert_into, not, update},
|
dsl::{count, insert_into, not, update},
|
||||||
|
@ -38,15 +39,11 @@ use diesel::{
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema_file::{
|
use lemmy_db_schema_file::schema::{community, person, post, post_actions};
|
||||||
enums::PostNotifications,
|
|
||||||
schema::{community, person, post, post_actions},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult},
|
error::{LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult},
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
};
|
};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
impl Crud for Post {
|
impl Crud for Post {
|
||||||
type InsertForm = PostInsertForm;
|
type InsertForm = PostInsertForm;
|
||||||
|
@ -542,7 +539,9 @@ impl PostActions {
|
||||||
.map(|post_id| (PostReadForm::new(*post_id, person_id)))
|
.map(|post_id| (PostReadForm::new(*post_id, person_id)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PostActions {
|
||||||
pub async fn read(
|
pub async fn read(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
post_id: PostId,
|
post_id: PostId,
|
||||||
|
@ -568,29 +567,6 @@ impl PostActions {
|
||||||
.ok_or(LemmyErrorType::CouldntParsePaginationToken)?;
|
.ok_or(LemmyErrorType::CouldntParsePaginationToken)?;
|
||||||
Self::read(pool, PostId(*post_id), PersonId(*person_id)).await
|
Self::read(pool, PostId(*post_id), PersonId(*person_id)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_notification_state(
|
|
||||||
post_id: PostId,
|
|
||||||
person_id: PersonId,
|
|
||||||
new_state: PostNotifications,
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
) -> LemmyResult<PostActions> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
let form = (
|
|
||||||
post_actions::person_id.eq(person_id),
|
|
||||||
post_actions::post_id.eq(post_id),
|
|
||||||
post_actions::notifications.eq(new_state),
|
|
||||||
);
|
|
||||||
|
|
||||||
insert_into(post_actions::table)
|
|
||||||
.values(form.clone())
|
|
||||||
.on_conflict((post_actions::person_id, post_actions::post_id))
|
|
||||||
.do_update()
|
|
||||||
.set(form)
|
|
||||||
.get_result::<Self>(conn)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::NotFound)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::newtypes::{CommunityId, DbUrl, LanguageId, PersonId, PostId};
|
use crate::newtypes::{CommunityId, DbUrl, LanguageId, PersonId, PostId};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use lemmy_db_schema_file::enums::PostNotifications;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
|
@ -202,7 +201,6 @@ pub struct PostActions {
|
||||||
pub like_score: Option<i16>,
|
pub like_score: Option<i16>,
|
||||||
/// When the post was hidden.
|
/// When the post was hidden.
|
||||||
pub hidden_at: Option<DateTime<Utc>>,
|
pub hidden_at: Option<DateTime<Utc>>,
|
||||||
pub notifications: Option<PostNotifications>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, derive_new::new)]
|
#[derive(Clone, derive_new::new)]
|
||||||
|
|
|
@ -226,22 +226,3 @@ pub enum VoteShow {
|
||||||
ShowForOthers,
|
ShowForOthers,
|
||||||
Hide,
|
Hide,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
|
||||||
EnumString, Display, Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Hash,
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DbEnum))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "full",
|
|
||||||
ExistingTypePath = "crate::schema::sql_types::PostNotificationsModeEnum"
|
|
||||||
)]
|
|
||||||
#[cfg_attr(feature = "full", DbValueStyle = "verbatim")]
|
|
||||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(feature = "ts-rs", ts(export))]
|
|
||||||
/// Lets you show votes for others only, show all votes, or hide all votes.
|
|
||||||
pub enum PostNotifications {
|
|
||||||
#[default]
|
|
||||||
RepliesAndMentions,
|
|
||||||
AllComments,
|
|
||||||
Mute,
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,10 +33,6 @@ pub mod sql_types {
|
||||||
#[diesel(postgres_type(name = "post_listing_mode_enum"))]
|
#[diesel(postgres_type(name = "post_listing_mode_enum"))]
|
||||||
pub struct PostListingModeEnum;
|
pub struct PostListingModeEnum;
|
||||||
|
|
||||||
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
|
|
||||||
#[diesel(postgres_type(name = "post_notifications_mode_enum"))]
|
|
||||||
pub struct PostNotificationsModeEnum;
|
|
||||||
|
|
||||||
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
|
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
|
||||||
#[diesel(postgres_type(name = "post_sort_type_enum"))]
|
#[diesel(postgres_type(name = "post_sort_type_enum"))]
|
||||||
pub struct PostSortTypeEnum;
|
pub struct PostSortTypeEnum;
|
||||||
|
@ -938,9 +934,6 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
use diesel::sql_types::*;
|
|
||||||
use super::sql_types::PostNotificationsModeEnum;
|
|
||||||
|
|
||||||
post_actions (person_id, post_id) {
|
post_actions (person_id, post_id) {
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
|
@ -951,7 +944,6 @@ diesel::table! {
|
||||||
liked_at -> Nullable<Timestamptz>,
|
liked_at -> Nullable<Timestamptz>,
|
||||||
like_score -> Nullable<Int2>,
|
like_score -> Nullable<Int2>,
|
||||||
hidden_at -> Nullable<Timestamptz>,
|
hidden_at -> Nullable<Timestamptz>,
|
||||||
notifications -> Nullable<PostNotificationsModeEnum>,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
use crate::{CommentSlimView, CommentView};
|
use crate::{CommentSlimView, CommentView};
|
||||||
use lemmy_db_schema::newtypes::{CommentId, CommunityId, LanguageId, PaginationCursor, PostId};
|
use lemmy_db_schema::newtypes::{
|
||||||
|
CommentId,
|
||||||
|
CommunityId,
|
||||||
|
LanguageId,
|
||||||
|
LocalUserId,
|
||||||
|
PaginationCursor,
|
||||||
|
PostId,
|
||||||
|
};
|
||||||
use lemmy_db_schema_file::enums::{CommentSortType, ListingType};
|
use lemmy_db_schema_file::enums::{CommentSortType, ListingType};
|
||||||
use lemmy_db_views_vote::VoteView;
|
use lemmy_db_views_vote::VoteView;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -12,6 +19,7 @@ use serde_with::skip_serializing_none;
|
||||||
/// A comment response.
|
/// A comment response.
|
||||||
pub struct CommentResponse {
|
pub struct CommentResponse {
|
||||||
pub comment_view: CommentView,
|
pub comment_view: CommentView,
|
||||||
|
pub recipient_ids: Vec<LocalUserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
|
|
|
@ -12,7 +12,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
PostFeatureType,
|
PostFeatureType,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema_file::enums::{ListingType, PostNotifications, PostSortType};
|
use lemmy_db_schema_file::enums::{ListingType, PostSortType};
|
||||||
use lemmy_db_views_community::CommunityView;
|
use lemmy_db_views_community::CommunityView;
|
||||||
use lemmy_db_views_vote::VoteView;
|
use lemmy_db_views_vote::VoteView;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -93,15 +93,6 @@ pub struct FeaturePost {
|
||||||
pub feature_type: PostFeatureType,
|
pub feature_type: PostFeatureType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
|
||||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(feature = "ts-rs", ts(optional_fields, export))]
|
|
||||||
/// Disable reply notifications for a post and all comments inside it
|
|
||||||
pub struct UpdatePostNotifications {
|
|
||||||
pub post_id: PostId,
|
|
||||||
pub new_state: PostNotifications,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||||
|
|
|
@ -30,42 +30,57 @@ pub async fn send_mention_email(
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_reply_email(
|
pub async fn send_comment_reply_email(
|
||||||
parent_user_view: &LocalUserView,
|
parent_user_view: &LocalUserView,
|
||||||
comment: &Comment,
|
comment: &Comment,
|
||||||
person: &Person,
|
person: &Person,
|
||||||
parent_comment: &Option<Comment>,
|
parent_comment: &Comment,
|
||||||
post: &Post,
|
post: &Post,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let inbox_link = inbox_link(settings);
|
let inbox_link = inbox_link(settings);
|
||||||
let lang = user_language(parent_user_view);
|
let lang = user_language(parent_user_view);
|
||||||
let content = markdown_to_html(&comment.content);
|
let content = markdown_to_html(&comment.content);
|
||||||
let (subject, body) = if let Some(parent_comment) = parent_comment {
|
send_email_to_user(
|
||||||
(
|
parent_user_view,
|
||||||
lang.notification_comment_reply_subject(&person.name),
|
&lang.notification_comment_reply_subject(&person.name),
|
||||||
lang.notification_comment_reply_body(
|
&lang.notification_comment_reply_body(
|
||||||
comment.local_url(settings)?,
|
comment.local_url(settings)?,
|
||||||
&content,
|
&content,
|
||||||
&inbox_link,
|
&inbox_link,
|
||||||
&parent_comment.content,
|
&parent_comment.content,
|
||||||
&post.name,
|
&post.name,
|
||||||
&person.name,
|
&person.name,
|
||||||
),
|
),
|
||||||
)
|
settings,
|
||||||
} else {
|
)
|
||||||
(
|
.await;
|
||||||
lang.notification_post_reply_subject(&person.name),
|
Ok(())
|
||||||
lang.notification_post_reply_body(
|
}
|
||||||
comment.local_url(settings)?,
|
|
||||||
&content,
|
pub async fn send_post_reply_email(
|
||||||
&inbox_link,
|
parent_user_view: &LocalUserView,
|
||||||
&post.name,
|
comment: &Comment,
|
||||||
&person.name,
|
person: &Person,
|
||||||
),
|
post: &Post,
|
||||||
)
|
settings: &Settings,
|
||||||
};
|
) -> LemmyResult<()> {
|
||||||
send_email_to_user(parent_user_view, &subject, &body, settings).await;
|
let inbox_link = inbox_link(settings);
|
||||||
|
let lang = user_language(parent_user_view);
|
||||||
|
let content = markdown_to_html(&comment.content);
|
||||||
|
send_email_to_user(
|
||||||
|
parent_user_view,
|
||||||
|
&lang.notification_post_reply_subject(&person.name),
|
||||||
|
&lang.notification_post_reply_body(
|
||||||
|
comment.local_url(settings)?,
|
||||||
|
&content,
|
||||||
|
&inbox_link,
|
||||||
|
&post.name,
|
||||||
|
&person.name,
|
||||||
|
),
|
||||||
|
settings,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
ALTER TABLE post_actions
|
|
||||||
DROP COLUMN notifications;
|
|
||||||
|
|
||||||
DROP TYPE post_notifications_mode_enum;
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
CREATE TYPE post_notifications_mode_enum AS enum (
|
|
||||||
'RepliesAndMentions',
|
|
||||||
'AllComments',
|
|
||||||
'Mute'
|
|
||||||
);
|
|
||||||
|
|
||||||
ALTER TABLE post_actions
|
|
||||||
ADD COLUMN notifications post_notifications_mode_enum;
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ use lemmy_api::{
|
||||||
mark_many_read::mark_posts_as_read,
|
mark_many_read::mark_posts_as_read,
|
||||||
mark_read::mark_post_as_read,
|
mark_read::mark_post_as_read,
|
||||||
save::save_post,
|
save::save_post,
|
||||||
update_notifications::update_post_notifications,
|
|
||||||
},
|
},
|
||||||
private_message::mark_read::mark_pm_as_read,
|
private_message::mark_read::mark_pm_as_read,
|
||||||
reports::{
|
reports::{
|
||||||
|
@ -295,11 +294,7 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.route("/like/list", get().to(list_post_likes))
|
.route("/like/list", get().to(list_post_likes))
|
||||||
.route("/save", put().to(save_post))
|
.route("/save", put().to(save_post))
|
||||||
.route("/report", post().to(create_post_report))
|
.route("/report", post().to(create_post_report))
|
||||||
.route("/report/resolve", put().to(resolve_post_report))
|
.route("/report/resolve", put().to(resolve_post_report)),
|
||||||
.route(
|
|
||||||
"/disable_notifications",
|
|
||||||
post().to(update_post_notifications),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
// Comment
|
// Comment
|
||||||
.service(
|
.service(
|
||||||
|
|
Loading…
Reference in a new issue