]> Untitled Git - lemmy.git/blob - crates/api_common/src/build_response.rs
acb7355bdea64c81c78f7c4a161dca42dd810bc7
[lemmy.git] / crates / api_common / src / build_response.rs
1 use crate::{
2   comment::CommentResponse,
3   community::CommunityResponse,
4   context::LemmyContext,
5   post::PostResponse,
6   utils::{check_person_block, get_interface_language, is_mod_or_admin, send_email_to_user},
7 };
8 use actix_web::web::Data;
9 use lemmy_db_schema::{
10   newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId},
11   source::{
12     actor_language::CommunityLanguage,
13     comment::Comment,
14     comment_reply::{CommentReply, CommentReplyInsertForm},
15     person::Person,
16     person_mention::{PersonMention, PersonMentionInsertForm},
17     post::Post,
18   },
19   traits::Crud,
20 };
21 use lemmy_db_views::structs::{CommentView, LocalUserView, PostView};
22 use lemmy_db_views_actor::structs::CommunityView;
23 use lemmy_utils::{error::LemmyError, utils::mention::MentionData};
24
25 pub async fn build_comment_response(
26   context: &Data<LemmyContext>,
27   comment_id: CommentId,
28   local_user_view: Option<LocalUserView>,
29   form_id: Option<String>,
30   recipient_ids: Vec<LocalUserId>,
31 ) -> Result<CommentResponse, LemmyError> {
32   let person_id = local_user_view.map(|l| l.person.id);
33   let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id).await?;
34   Ok(CommentResponse {
35     comment_view,
36     recipient_ids,
37     form_id,
38   })
39 }
40
41 pub async fn build_community_response(
42   context: &Data<LemmyContext>,
43   local_user_view: LocalUserView,
44   community_id: CommunityId,
45 ) -> Result<CommunityResponse, LemmyError> {
46   let is_mod_or_admin =
47     is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id)
48       .await
49       .is_ok();
50   let person_id = local_user_view.person.id;
51   let community_view = CommunityView::read(
52     &mut context.pool(),
53     community_id,
54     Some(person_id),
55     Some(is_mod_or_admin),
56   )
57   .await?;
58   let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?;
59
60   Ok(CommunityResponse {
61     community_view,
62     discussion_languages,
63   })
64 }
65
66 pub async fn build_post_response(
67   context: &Data<LemmyContext>,
68   community_id: CommunityId,
69   person_id: PersonId,
70   post_id: PostId,
71 ) -> Result<PostResponse, LemmyError> {
72   let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), person_id, community_id)
73     .await
74     .is_ok();
75   let post_view = PostView::read(
76     &mut context.pool(),
77     post_id,
78     Some(person_id),
79     Some(is_mod_or_admin),
80   )
81   .await?;
82   Ok(PostResponse { post_view })
83 }
84
85 // this is a variation of build_post_response that returns post even if end-user-delted or mod-removed.
86 // Assumption is that before this function is ever called, the user is already confirmed to be authorized to view post.
87 // See GitHub Issue #3588
88 pub async fn build_post_response_deleted_allowed(
89   context: &Data<LemmyContext>,
90   _community_id: CommunityId,
91   person_id: PersonId,
92   post_id: PostId,
93 ) -> Result<PostResponse, LemmyError> {
94   let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), Some(true)).await?;
95   Ok(PostResponse { post_view })
96 }
97
98 // TODO: this function is a mess and should be split up to handle email seperately
99 #[tracing::instrument(skip_all)]
100 pub async fn send_local_notifs(
101   mentions: Vec<MentionData>,
102   comment: &Comment,
103   person: &Person,
104   post: &Post,
105   do_send_email: bool,
106   context: &LemmyContext,
107 ) -> Result<Vec<LocalUserId>, LemmyError> {
108   let mut recipient_ids = Vec::new();
109   let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
110
111   // Send the local mentions
112   for mention in mentions
113     .iter()
114     .filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name))
115   {
116     let mention_name = mention.name.clone();
117     let user_view = LocalUserView::read_from_name(&mut context.pool(), &mention_name).await;
118     if let Ok(mention_user_view) = user_view {
119       // TODO
120       // At some point, make it so you can't tag the parent creator either
121       // This can cause two notifications, one for reply and the other for mention
122       recipient_ids.push(mention_user_view.local_user.id);
123
124       let user_mention_form = PersonMentionInsertForm {
125         recipient_id: mention_user_view.person.id,
126         comment_id: comment.id,
127         read: None,
128       };
129
130       // Allow this to fail softly, since comment edits might re-update or replace it
131       // Let the uniqueness handle this fail
132       PersonMention::create(&mut context.pool(), &user_mention_form)
133         .await
134         .ok();
135
136       // Send an email to those local users that have notifications on
137       if do_send_email {
138         let lang = get_interface_language(&mention_user_view);
139         send_email_to_user(
140           &mention_user_view,
141           &lang.notification_mentioned_by_subject(&person.name),
142           &lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
143           context.settings(),
144         )
145         .await
146       }
147     }
148   }
149
150   // Send comment_reply to the parent commenter / poster
151   if let Some(parent_comment_id) = comment.parent_comment_id() {
152     let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
153
154     // Get the parent commenter local_user
155     let parent_creator_id = parent_comment.creator_id;
156
157     // Only add to recipients if that person isn't blocked
158     let creator_blocked = check_person_block(person.id, parent_creator_id, &mut context.pool())
159       .await
160       .is_err();
161
162     // Don't send a notif to yourself
163     if parent_comment.creator_id != person.id && !creator_blocked {
164       let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
165       if let Ok(parent_user_view) = user_view {
166         recipient_ids.push(parent_user_view.local_user.id);
167
168         let comment_reply_form = CommentReplyInsertForm {
169           recipient_id: parent_user_view.person.id,
170           comment_id: comment.id,
171           read: None,
172         };
173
174         // Allow this to fail softly, since comment edits might re-update or replace it
175         // Let the uniqueness handle this fail
176         CommentReply::create(&mut context.pool(), &comment_reply_form)
177           .await
178           .ok();
179
180         if do_send_email {
181           let lang = get_interface_language(&parent_user_view);
182           send_email_to_user(
183             &parent_user_view,
184             &lang.notification_comment_reply_subject(&person.name),
185             &lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
186             context.settings(),
187           )
188           .await
189         }
190       }
191     }
192   } else {
193     // If there's no parent, its the post creator
194     // Only add to recipients if that person isn't blocked
195     let creator_blocked = check_person_block(person.id, post.creator_id, &mut context.pool())
196       .await
197       .is_err();
198
199     if post.creator_id != person.id && !creator_blocked {
200       let creator_id = post.creator_id;
201       let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
202       if let Ok(parent_user_view) = parent_user {
203         recipient_ids.push(parent_user_view.local_user.id);
204
205         let comment_reply_form = CommentReplyInsertForm {
206           recipient_id: parent_user_view.person.id,
207           comment_id: comment.id,
208           read: None,
209         };
210
211         // Allow this to fail softly, since comment edits might re-update or replace it
212         // Let the uniqueness handle this fail
213         CommentReply::create(&mut context.pool(), &comment_reply_form)
214           .await
215           .ok();
216
217         if do_send_email {
218           let lang = get_interface_language(&parent_user_view);
219           send_email_to_user(
220             &parent_user_view,
221             &lang.notification_post_reply_subject(&person.name),
222             &lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),
223             context.settings(),
224           )
225           .await
226         }
227       }
228     }
229   }
230
231   Ok(recipient_ids)
232 }