2 comment::CommentResponse,
3 community::CommunityResponse,
6 private_message::PrivateMessageResponse,
7 utils::{check_person_block, get_interface_language, send_email_to_user},
9 messages::{SendComment, SendCommunityRoomMessage, SendPost, SendUserRoomMessage},
13 use lemmy_db_schema::{
14 newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
17 comment_reply::{CommentReply, CommentReplyInsertForm},
19 person_mention::{PersonMention, PersonMentionInsertForm},
22 traits::{Crud, DeleteableOrRemoveable},
25 use lemmy_db_views::structs::{CommentView, LocalUserView, PostView, PrivateMessageView};
26 use lemmy_db_views_actor::structs::CommunityView;
27 use lemmy_utils::{error::LemmyError, utils::MentionData, ConnectionId};
29 #[tracing::instrument(skip_all)]
30 pub async fn send_post_ws_message<OP: ToString + Send + OperationType + 'static>(
33 websocket_id: Option<ConnectionId>,
34 person_id: Option<PersonId>,
35 context: &LemmyContext,
36 ) -> Result<PostResponse, LemmyError> {
37 let post_view = PostView::read(context.pool(), post_id, person_id).await?;
39 let res = PostResponse { post_view };
41 context.chat_server().do_send(SendPost {
50 // TODO: in many call sites in apub crate, we are setting an empty vec for recipient_ids,
51 // we should get the actual recipient actors from somewhere
52 #[tracing::instrument(skip_all)]
53 pub async fn send_comment_ws_message_simple<OP: ToString + Send + OperationType + 'static>(
54 comment_id: CommentId,
56 context: &LemmyContext,
57 ) -> Result<CommentResponse, LemmyError> {
58 send_comment_ws_message(comment_id, op, None, None, None, vec![], context).await
61 #[tracing::instrument(skip_all)]
62 pub async fn send_comment_ws_message<OP: ToString + Send + OperationType + 'static>(
63 comment_id: CommentId,
65 websocket_id: Option<ConnectionId>,
66 form_id: Option<String>,
67 person_id: Option<PersonId>,
68 recipient_ids: Vec<LocalUserId>,
69 context: &LemmyContext,
70 ) -> Result<CommentResponse, LemmyError> {
71 let mut view = CommentView::read(context.pool(), comment_id, person_id).await?;
73 if view.comment.deleted || view.comment.removed {
74 view.comment = view.comment.blank_out_deleted_or_removed_info();
77 let mut res = CommentResponse {
80 // The sent out form id should be null
84 context.chat_server().do_send(SendComment {
90 // The recipient_ids should be empty for returns
91 res.recipient_ids = Vec::new();
92 res.form_id = form_id;
97 #[tracing::instrument(skip_all)]
98 pub async fn send_community_ws_message<OP: ToString + Send + OperationType + 'static>(
99 community_id: CommunityId,
101 websocket_id: Option<ConnectionId>,
102 person_id: Option<PersonId>,
103 context: &LemmyContext,
104 ) -> Result<CommunityResponse, LemmyError> {
105 let community_view = CommunityView::read(context.pool(), community_id, person_id).await?;
107 let res = CommunityResponse { community_view };
109 // Strip out the person id and subscribed when sending to others
110 let mut res_mut = res.clone();
111 res_mut.community_view.subscribed = SubscribedType::NotSubscribed;
113 context.chat_server().do_send(SendCommunityRoomMessage {
116 community_id: res.community_view.community.id,
123 #[tracing::instrument(skip_all)]
124 pub async fn send_pm_ws_message<OP: ToString + Send + OperationType + 'static>(
125 private_message_id: PrivateMessageId,
127 websocket_id: Option<ConnectionId>,
128 context: &LemmyContext,
129 ) -> Result<PrivateMessageResponse, LemmyError> {
130 let mut view = PrivateMessageView::read(context.pool(), private_message_id).await?;
132 // Blank out deleted or removed info
133 if view.private_message.deleted {
134 view.private_message = view.private_message.blank_out_deleted_or_removed_info();
137 let res = PrivateMessageResponse {
138 private_message_view: view,
141 // Send notifications to the local recipient, if one exists
142 if res.private_message_view.recipient.local {
143 let recipient_id = res.private_message_view.recipient.id;
144 let local_recipient = LocalUserView::read_person(context.pool(), recipient_id).await?;
145 context.chat_server().do_send(SendUserRoomMessage {
147 response: res.clone(),
148 local_recipient_id: local_recipient.local_user.id,
156 #[tracing::instrument(skip_all)]
157 pub async fn send_local_notifs(
158 mentions: Vec<MentionData>,
163 context: &LemmyContext,
164 ) -> Result<Vec<LocalUserId>, LemmyError> {
165 let mut recipient_ids = Vec::new();
166 let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
168 // Send the local mentions
169 for mention in mentions
171 .filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name))
172 .collect::<Vec<&MentionData>>()
174 let mention_name = mention.name.clone();
175 let user_view = LocalUserView::read_from_name(context.pool(), &mention_name).await;
176 if let Ok(mention_user_view) = user_view {
178 // At some point, make it so you can't tag the parent creator either
179 // This can cause two notifications, one for reply and the other for mention
180 recipient_ids.push(mention_user_view.local_user.id);
182 let user_mention_form = PersonMentionInsertForm {
183 recipient_id: mention_user_view.person.id,
184 comment_id: comment.id,
188 // Allow this to fail softly, since comment edits might re-update or replace it
189 // Let the uniqueness handle this fail
190 PersonMention::create(context.pool(), &user_mention_form)
194 // Send an email to those local users that have notifications on
196 let lang = get_interface_language(&mention_user_view);
199 &lang.notification_mentioned_by_subject(&person.name),
200 &lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
207 // Send comment_reply to the parent commenter / poster
208 if let Some(parent_comment_id) = comment.parent_comment_id() {
209 let parent_comment = Comment::read(context.pool(), parent_comment_id).await?;
211 // Get the parent commenter local_user
212 let parent_creator_id = parent_comment.creator_id;
214 // Only add to recipients if that person isn't blocked
215 let creator_blocked = check_person_block(person.id, parent_creator_id, context.pool())
219 // Don't send a notif to yourself
220 if parent_comment.creator_id != person.id && !creator_blocked {
221 let user_view = LocalUserView::read_person(context.pool(), parent_creator_id).await;
222 if let Ok(parent_user_view) = user_view {
223 recipient_ids.push(parent_user_view.local_user.id);
225 let comment_reply_form = CommentReplyInsertForm {
226 recipient_id: parent_user_view.person.id,
227 comment_id: comment.id,
231 // Allow this to fail softly, since comment edits might re-update or replace it
232 // Let the uniqueness handle this fail
233 CommentReply::create(context.pool(), &comment_reply_form)
238 let lang = get_interface_language(&parent_user_view);
241 &lang.notification_comment_reply_subject(&person.name),
242 &lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
249 // If there's no parent, its the post creator
250 // Only add to recipients if that person isn't blocked
251 let creator_blocked = check_person_block(person.id, post.creator_id, context.pool())
255 if post.creator_id != person.id && !creator_blocked {
256 let creator_id = post.creator_id;
257 let parent_user = LocalUserView::read_person(context.pool(), creator_id).await;
258 if let Ok(parent_user_view) = parent_user {
259 recipient_ids.push(parent_user_view.local_user.id);
261 let comment_reply_form = CommentReplyInsertForm {
262 recipient_id: parent_user_view.person.id,
263 comment_id: comment.id,
267 // Allow this to fail softly, since comment edits might re-update or replace it
268 // Let the uniqueness handle this fail
269 CommentReply::create(context.pool(), &comment_reply_form)
274 let lang = get_interface_language(&parent_user_view);
277 &lang.notification_post_reply_subject(&person.name),
278 &lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),