]> Untitled Git - lemmy.git/blob - crates/structs/src/lib.rs
Use Url type for ap_id fields in database (fixes #1364) (#1371)
[lemmy.git] / crates / structs / src / lib.rs
1 pub mod comment;
2 pub mod community;
3 pub mod post;
4 pub mod site;
5 pub mod user;
6 pub mod websocket;
7
8 use diesel::PgConnection;
9 use lemmy_db_queries::{source::user::User, Crud, DbPool};
10 use lemmy_db_schema::source::{
11   comment::Comment,
12   post::Post,
13   user::User_,
14   user_mention::{UserMention, UserMentionForm},
15 };
16 use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
17 use log::error;
18 use serde::{Deserialize, Serialize};
19 use url::Url;
20
21 #[derive(Serialize, Deserialize, Debug)]
22 pub struct WebFingerLink {
23   pub rel: Option<String>,
24   #[serde(rename(serialize = "type", deserialize = "type"))]
25   pub type_: Option<String>,
26   pub href: Option<Url>,
27   #[serde(skip_serializing_if = "Option::is_none")]
28   pub template: Option<String>,
29 }
30
31 #[derive(Serialize, Deserialize, Debug)]
32 pub struct WebFingerResponse {
33   pub subject: String,
34   pub aliases: Vec<Url>,
35   pub links: Vec<WebFingerLink>,
36 }
37
38 pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
39 where
40   F: FnOnce(&diesel::PgConnection) -> T + Send + 'static,
41   T: Send + 'static,
42 {
43   let pool = pool.clone();
44   let res = actix_web::web::block(move || {
45     let conn = pool.get()?;
46     let res = (f)(&conn);
47     Ok(res) as Result<_, LemmyError>
48   })
49   .await?;
50
51   Ok(res)
52 }
53
54 pub async fn send_local_notifs(
55   mentions: Vec<MentionData>,
56   comment: Comment,
57   user: &User_,
58   post: Post,
59   pool: &DbPool,
60   do_send_email: bool,
61 ) -> Result<Vec<i32>, LemmyError> {
62   let user2 = user.clone();
63   let ids = blocking(pool, move |conn| {
64     do_send_local_notifs(conn, &mentions, &comment, &user2, &post, do_send_email)
65   })
66   .await?;
67
68   Ok(ids)
69 }
70
71 fn do_send_local_notifs(
72   conn: &PgConnection,
73   mentions: &[MentionData],
74   comment: &Comment,
75   user: &User_,
76   post: &Post,
77   do_send_email: bool,
78 ) -> Vec<i32> {
79   let mut recipient_ids = Vec::new();
80
81   // Send the local mentions
82   for mention in mentions
83     .iter()
84     .filter(|m| m.is_local() && m.name.ne(&user.name))
85     .collect::<Vec<&MentionData>>()
86   {
87     if let Ok(mention_user) = User_::read_from_name(&conn, &mention.name) {
88       // TODO
89       // At some point, make it so you can't tag the parent creator either
90       // This can cause two notifications, one for reply and the other for mention
91       recipient_ids.push(mention_user.id);
92
93       let user_mention_form = UserMentionForm {
94         recipient_id: mention_user.id,
95         comment_id: comment.id,
96         read: None,
97       };
98
99       // Allow this to fail softly, since comment edits might re-update or replace it
100       // Let the uniqueness handle this fail
101       let _ = UserMention::create(&conn, &user_mention_form);
102
103       // Send an email to those users that have notifications on
104       if do_send_email && mention_user.send_notifications_to_email {
105         send_email_to_user(
106           mention_user,
107           "Mentioned by",
108           "User Mention",
109           &comment.content,
110         )
111       }
112     }
113   }
114
115   // Send notifs to the parent commenter / poster
116   match comment.parent_id {
117     Some(parent_id) => {
118       if let Ok(parent_comment) = Comment::read(&conn, parent_id) {
119         if parent_comment.creator_id != user.id {
120           if let Ok(parent_user) = User_::read(&conn, parent_comment.creator_id) {
121             recipient_ids.push(parent_user.id);
122
123             if do_send_email && parent_user.send_notifications_to_email {
124               send_email_to_user(parent_user, "Reply from", "Comment Reply", &comment.content)
125             }
126           }
127         }
128       }
129     }
130     // Its a post
131     None => {
132       if post.creator_id != user.id {
133         if let Ok(parent_user) = User_::read(&conn, post.creator_id) {
134           recipient_ids.push(parent_user.id);
135
136           if do_send_email && parent_user.send_notifications_to_email {
137             send_email_to_user(parent_user, "Reply from", "Post Reply", &comment.content)
138           }
139         }
140       }
141     }
142   };
143   recipient_ids
144 }
145
146 pub fn send_email_to_user(user: User_, subject_text: &str, body_text: &str, comment_content: &str) {
147   if user.banned {
148     return;
149   }
150
151   if let Some(user_email) = user.email {
152     let subject = &format!(
153       "{} - {} {}",
154       subject_text,
155       Settings::get().hostname,
156       user.name,
157     );
158     let html = &format!(
159       "<h1>{}</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
160       body_text,
161       user.name,
162       comment_content,
163       Settings::get().get_protocol_and_hostname()
164     );
165     match send_email(subject, &user_email, &user.name, html) {
166       Ok(_o) => _o,
167       Err(e) => error!("{}", e),
168     };
169   }
170 }