]> Untitled Git - lemmy.git/blob - crates/api_common/src/build_response.rs
328827b2ce99a720859e7cf7be23f7c5f4c77a3f
[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(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 = is_mod_or_admin(context.pool(), local_user_view.person.id, community_id)
47     .await
48     .is_ok();
49   let person_id = local_user_view.person.id;
50   let community_view = CommunityView::read(
51     context.pool(),
52     community_id,
53     Some(person_id),
54     Some(is_mod_or_admin),
55   )
56   .await?;
57   let discussion_languages = CommunityLanguage::read(context.pool(), community_id).await?;
58
59   Ok(CommunityResponse {
60     community_view,
61     discussion_languages,
62   })
63 }
64
65 pub async fn build_post_response(
66   context: &Data<LemmyContext>,
67   community_id: CommunityId,
68   person_id: PersonId,
69   post_id: PostId,
70 ) -> Result<PostResponse, LemmyError> {
71   let is_mod_or_admin = is_mod_or_admin(context.pool(), person_id, community_id)
72     .await
73     .is_ok();
74   let post_view = PostView::read(
75     context.pool(),
76     post_id,
77     Some(person_id),
78     Some(is_mod_or_admin),
79   )
80   .await?;
81   Ok(PostResponse { post_view })
82 }
83
84 // TODO: this function is a mess and should be split up to handle email seperately
85 #[tracing::instrument(skip_all)]
86 pub async fn send_local_notifs(
87   mentions: Vec<MentionData>,
88   comment: &Comment,
89   person: &Person,
90   post: &Post,
91   do_send_email: bool,
92   context: &LemmyContext,
93 ) -> Result<Vec<LocalUserId>, LemmyError> {
94   let mut recipient_ids = Vec::new();
95   let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
96
97   // Send the local mentions
98   for mention in mentions
99     .iter()
100     .filter(|m| m.is_local(&context.settings().hostname) && m.name.ne(&person.name))
101   {
102     let mention_name = mention.name.clone();
103     let user_view = LocalUserView::read_from_name(context.pool(), &mention_name).await;
104     if let Ok(mention_user_view) = user_view {
105       // TODO
106       // At some point, make it so you can't tag the parent creator either
107       // This can cause two notifications, one for reply and the other for mention
108       recipient_ids.push(mention_user_view.local_user.id);
109
110       let user_mention_form = PersonMentionInsertForm {
111         recipient_id: mention_user_view.person.id,
112         comment_id: comment.id,
113         read: None,
114       };
115
116       // Allow this to fail softly, since comment edits might re-update or replace it
117       // Let the uniqueness handle this fail
118       PersonMention::create(context.pool(), &user_mention_form)
119         .await
120         .ok();
121
122       // Send an email to those local users that have notifications on
123       if do_send_email {
124         let lang = get_interface_language(&mention_user_view);
125         send_email_to_user(
126           &mention_user_view,
127           &lang.notification_mentioned_by_subject(&person.name),
128           &lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
129           context.settings(),
130         )
131       }
132     }
133   }
134
135   // Send comment_reply to the parent commenter / poster
136   if let Some(parent_comment_id) = comment.parent_comment_id() {
137     let parent_comment = Comment::read(context.pool(), parent_comment_id).await?;
138
139     // Get the parent commenter local_user
140     let parent_creator_id = parent_comment.creator_id;
141
142     // Only add to recipients if that person isn't blocked
143     let creator_blocked = check_person_block(person.id, parent_creator_id, context.pool())
144       .await
145       .is_err();
146
147     // Don't send a notif to yourself
148     if parent_comment.creator_id != person.id && !creator_blocked {
149       let user_view = LocalUserView::read_person(context.pool(), parent_creator_id).await;
150       if let Ok(parent_user_view) = user_view {
151         recipient_ids.push(parent_user_view.local_user.id);
152
153         let comment_reply_form = CommentReplyInsertForm {
154           recipient_id: parent_user_view.person.id,
155           comment_id: comment.id,
156           read: None,
157         };
158
159         // Allow this to fail softly, since comment edits might re-update or replace it
160         // Let the uniqueness handle this fail
161         CommentReply::create(context.pool(), &comment_reply_form)
162           .await
163           .ok();
164
165         if do_send_email {
166           let lang = get_interface_language(&parent_user_view);
167           send_email_to_user(
168             &parent_user_view,
169             &lang.notification_comment_reply_subject(&person.name),
170             &lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
171             context.settings(),
172           )
173         }
174       }
175     }
176   } else {
177     // If there's no parent, its the post creator
178     // Only add to recipients if that person isn't blocked
179     let creator_blocked = check_person_block(person.id, post.creator_id, context.pool())
180       .await
181       .is_err();
182
183     if post.creator_id != person.id && !creator_blocked {
184       let creator_id = post.creator_id;
185       let parent_user = LocalUserView::read_person(context.pool(), creator_id).await;
186       if let Ok(parent_user_view) = parent_user {
187         recipient_ids.push(parent_user_view.local_user.id);
188
189         let comment_reply_form = CommentReplyInsertForm {
190           recipient_id: parent_user_view.person.id,
191           comment_id: comment.id,
192           read: None,
193         };
194
195         // Allow this to fail softly, since comment edits might re-update or replace it
196         // Let the uniqueness handle this fail
197         CommentReply::create(context.pool(), &comment_reply_form)
198           .await
199           .ok();
200
201         if do_send_email {
202           let lang = get_interface_language(&parent_user_view);
203           send_email_to_user(
204             &parent_user_view,
205             &lang.notification_post_reply_subject(&person.name),
206             &lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),
207             context.settings(),
208           )
209         }
210       }
211     }
212   }
213
214   Ok(recipient_ids)
215 }