]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/comment.rs
Translated using Weblate (Italian)
[lemmy.git] / server / lemmy_db / src / comment.rs
1 use super::{post::Post, *};
2 use crate::schema::{comment, comment_like, comment_saved};
3 use url::{ParseError, Url};
4
5 // WITH RECURSIVE MyTree AS (
6 //     SELECT * FROM comment WHERE parent_id IS NULL
7 //     UNION ALL
8 //     SELECT m.* FROM comment AS m JOIN MyTree AS t ON m.parent_id = t.id
9 // )
10 // SELECT * FROM MyTree;
11
12 #[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
13 #[belongs_to(Post)]
14 #[table_name = "comment"]
15 pub struct Comment {
16   pub id: i32,
17   pub creator_id: i32,
18   pub post_id: i32,
19   pub parent_id: Option<i32>,
20   pub content: String,
21   pub removed: bool,
22   pub read: bool, // Whether the recipient has read the comment or not
23   pub published: chrono::NaiveDateTime,
24   pub updated: Option<chrono::NaiveDateTime>,
25   pub deleted: bool,
26   pub ap_id: String,
27   pub local: bool,
28 }
29
30 #[derive(Insertable, AsChangeset, Clone)]
31 #[table_name = "comment"]
32 pub struct CommentForm {
33   pub creator_id: i32,
34   pub post_id: i32,
35   pub parent_id: Option<i32>,
36   pub content: String,
37   pub removed: Option<bool>,
38   pub read: Option<bool>,
39   pub published: Option<chrono::NaiveDateTime>,
40   pub updated: Option<chrono::NaiveDateTime>,
41   pub deleted: Option<bool>,
42   pub ap_id: String,
43   pub local: bool,
44 }
45
46 impl CommentForm {
47   pub fn get_ap_id(&self) -> Result<Url, ParseError> {
48     Url::parse(&self.ap_id)
49   }
50 }
51
52 impl Crud<CommentForm> for Comment {
53   fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
54     use crate::schema::comment::dsl::*;
55     comment.find(comment_id).first::<Self>(conn)
56   }
57
58   fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> {
59     use crate::schema::comment::dsl::*;
60     diesel::delete(comment.find(comment_id)).execute(conn)
61   }
62
63   fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
64     use crate::schema::comment::dsl::*;
65     insert_into(comment)
66       .values(comment_form)
67       .get_result::<Self>(conn)
68   }
69
70   fn update(
71     conn: &PgConnection,
72     comment_id: i32,
73     comment_form: &CommentForm,
74   ) -> Result<Self, Error> {
75     use crate::schema::comment::dsl::*;
76     diesel::update(comment.find(comment_id))
77       .set(comment_form)
78       .get_result::<Self>(conn)
79   }
80 }
81
82 impl Comment {
83   pub fn update_ap_id(
84     conn: &PgConnection,
85     comment_id: i32,
86     apub_id: String,
87   ) -> Result<Self, Error> {
88     use crate::schema::comment::dsl::*;
89
90     diesel::update(comment.find(comment_id))
91       .set(ap_id.eq(apub_id))
92       .get_result::<Self>(conn)
93   }
94
95   pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
96     use crate::schema::comment::dsl::*;
97     comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
98   }
99
100   pub fn permadelete(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
101     use crate::schema::comment::dsl::*;
102
103     diesel::update(comment.find(comment_id))
104       .set((
105         content.eq("*Permananently Deleted*"),
106         deleted.eq(true),
107         updated.eq(naive_now()),
108       ))
109       .get_result::<Self>(conn)
110   }
111
112   pub fn update_deleted(
113     conn: &PgConnection,
114     comment_id: i32,
115     new_deleted: bool,
116   ) -> Result<Self, Error> {
117     use crate::schema::comment::dsl::*;
118     diesel::update(comment.find(comment_id))
119       .set((
120         deleted.eq(new_deleted),
121         updated.eq(naive_now())
122       ))
123       .get_result::<Self>(conn)
124   }
125
126   pub fn update_removed(
127     conn: &PgConnection,
128     comment_id: i32,
129     new_removed: bool,
130   ) -> Result<Self, Error> {
131     use crate::schema::comment::dsl::*;
132     diesel::update(comment.find(comment_id))
133       .set((
134         removed.eq(new_removed),
135         updated.eq(naive_now())
136       ))
137       .get_result::<Self>(conn)
138   }
139
140   pub fn update_read(conn: &PgConnection, comment_id: i32, new_read: bool) -> Result<Self, Error> {
141     use crate::schema::comment::dsl::*;
142     diesel::update(comment.find(comment_id))
143       .set(read.eq(new_read))
144       .get_result::<Self>(conn)
145   }
146
147   pub fn update_content(
148     conn: &PgConnection,
149     comment_id: i32,
150     new_content: &str,
151   ) -> Result<Self, Error> {
152     use crate::schema::comment::dsl::*;
153     diesel::update(comment.find(comment_id))
154       .set((content.eq(new_content), updated.eq(naive_now())))
155       .get_result::<Self>(conn)
156   }
157 }
158
159 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
160 #[belongs_to(Comment)]
161 #[table_name = "comment_like"]
162 pub struct CommentLike {
163   pub id: i32,
164   pub user_id: i32,
165   pub comment_id: i32,
166   pub post_id: i32,
167   pub score: i16,
168   pub published: chrono::NaiveDateTime,
169 }
170
171 #[derive(Insertable, AsChangeset, Clone)]
172 #[table_name = "comment_like"]
173 pub struct CommentLikeForm {
174   pub user_id: i32,
175   pub comment_id: i32,
176   pub post_id: i32,
177   pub score: i16,
178 }
179
180 impl Likeable<CommentLikeForm> for CommentLike {
181   fn read(conn: &PgConnection, comment_id_from: i32) -> Result<Vec<Self>, Error> {
182     use crate::schema::comment_like::dsl::*;
183     comment_like
184       .filter(comment_id.eq(comment_id_from))
185       .load::<Self>(conn)
186   }
187
188   fn like(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<Self, Error> {
189     use crate::schema::comment_like::dsl::*;
190     insert_into(comment_like)
191       .values(comment_like_form)
192       .get_result::<Self>(conn)
193   }
194   fn remove(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<usize, Error> {
195     use crate::schema::comment_like::dsl::*;
196     diesel::delete(
197       comment_like
198         .filter(comment_id.eq(comment_like_form.comment_id))
199         .filter(user_id.eq(comment_like_form.user_id)),
200     )
201     .execute(conn)
202   }
203 }
204
205 impl CommentLike {
206   pub fn from_post(conn: &PgConnection, post_id_from: i32) -> Result<Vec<Self>, Error> {
207     use crate::schema::comment_like::dsl::*;
208     comment_like
209       .filter(post_id.eq(post_id_from))
210       .load::<Self>(conn)
211   }
212 }
213
214 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
215 #[belongs_to(Comment)]
216 #[table_name = "comment_saved"]
217 pub struct CommentSaved {
218   pub id: i32,
219   pub comment_id: i32,
220   pub user_id: i32,
221   pub published: chrono::NaiveDateTime,
222 }
223
224 #[derive(Insertable, AsChangeset, Clone)]
225 #[table_name = "comment_saved"]
226 pub struct CommentSavedForm {
227   pub comment_id: i32,
228   pub user_id: i32,
229 }
230
231 impl Saveable<CommentSavedForm> for CommentSaved {
232   fn save(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<Self, Error> {
233     use crate::schema::comment_saved::dsl::*;
234     insert_into(comment_saved)
235       .values(comment_saved_form)
236       .get_result::<Self>(conn)
237   }
238   fn unsave(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<usize, Error> {
239     use crate::schema::comment_saved::dsl::*;
240     diesel::delete(
241       comment_saved
242         .filter(comment_id.eq(comment_saved_form.comment_id))
243         .filter(user_id.eq(comment_saved_form.user_id)),
244     )
245     .execute(conn)
246   }
247 }
248
249 #[cfg(test)]
250 mod tests {
251   use crate::{comment::*, community::*, post::*, tests::establish_unpooled_connection, user::*};
252
253   #[test]
254   fn test_crud() {
255     let conn = establish_unpooled_connection();
256
257     let new_user = UserForm {
258       name: "terry".into(),
259       preferred_username: None,
260       password_encrypted: "nope".into(),
261       email: None,
262       matrix_user_id: None,
263       avatar: None,
264       admin: false,
265       banned: false,
266       updated: None,
267       show_nsfw: false,
268       theme: "darkly".into(),
269       default_sort_type: SortType::Hot as i16,
270       default_listing_type: ListingType::Subscribed as i16,
271       lang: "browser".into(),
272       show_avatars: true,
273       send_notifications_to_email: false,
274       actor_id: "changeme_283687".into(),
275       bio: None,
276       local: true,
277       private_key: None,
278       public_key: None,
279       last_refreshed_at: None,
280     };
281
282     let inserted_user = User_::create(&conn, &new_user).unwrap();
283
284     let new_community = CommunityForm {
285       name: "test community".to_string(),
286       title: "nada".to_owned(),
287       description: None,
288       category_id: 1,
289       creator_id: inserted_user.id,
290       removed: None,
291       deleted: None,
292       updated: None,
293       nsfw: false,
294       actor_id: "changeme_928738972".into(),
295       local: true,
296       private_key: None,
297       public_key: None,
298       last_refreshed_at: None,
299       published: None,
300     };
301
302     let inserted_community = Community::create(&conn, &new_community).unwrap();
303
304     let new_post = PostForm {
305       name: "A test post".into(),
306       creator_id: inserted_user.id,
307       url: None,
308       body: None,
309       community_id: inserted_community.id,
310       removed: None,
311       deleted: None,
312       locked: None,
313       stickied: None,
314       updated: None,
315       nsfw: false,
316       embed_title: None,
317       embed_description: None,
318       embed_html: None,
319       thumbnail_url: None,
320       ap_id: "http://fake.com".into(),
321       local: true,
322       published: None,
323     };
324
325     let inserted_post = Post::create(&conn, &new_post).unwrap();
326
327     let comment_form = CommentForm {
328       content: "A test comment".into(),
329       creator_id: inserted_user.id,
330       post_id: inserted_post.id,
331       removed: None,
332       deleted: None,
333       read: None,
334       parent_id: None,
335       published: None,
336       updated: None,
337       ap_id: "http://fake.com".into(),
338       local: true,
339     };
340
341     let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
342
343     let expected_comment = Comment {
344       id: inserted_comment.id,
345       content: "A test comment".into(),
346       creator_id: inserted_user.id,
347       post_id: inserted_post.id,
348       removed: false,
349       deleted: false,
350       read: false,
351       parent_id: None,
352       published: inserted_comment.published,
353       updated: None,
354       ap_id: "http://fake.com".into(),
355       local: true,
356     };
357
358     let child_comment_form = CommentForm {
359       content: "A child comment".into(),
360       creator_id: inserted_user.id,
361       post_id: inserted_post.id,
362       parent_id: Some(inserted_comment.id),
363       removed: None,
364       deleted: None,
365       read: None,
366       published: None,
367       updated: None,
368       ap_id: "http://fake.com".into(),
369       local: true,
370     };
371
372     let inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap();
373
374     // Comment Like
375     let comment_like_form = CommentLikeForm {
376       comment_id: inserted_comment.id,
377       post_id: inserted_post.id,
378       user_id: inserted_user.id,
379       score: 1,
380     };
381
382     let inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
383
384     let expected_comment_like = CommentLike {
385       id: inserted_comment_like.id,
386       comment_id: inserted_comment.id,
387       post_id: inserted_post.id,
388       user_id: inserted_user.id,
389       published: inserted_comment_like.published,
390       score: 1,
391     };
392
393     // Comment Saved
394     let comment_saved_form = CommentSavedForm {
395       comment_id: inserted_comment.id,
396       user_id: inserted_user.id,
397     };
398
399     let inserted_comment_saved = CommentSaved::save(&conn, &comment_saved_form).unwrap();
400
401     let expected_comment_saved = CommentSaved {
402       id: inserted_comment_saved.id,
403       comment_id: inserted_comment.id,
404       user_id: inserted_user.id,
405       published: inserted_comment_saved.published,
406     };
407
408     let read_comment = Comment::read(&conn, inserted_comment.id).unwrap();
409     let updated_comment = Comment::update(&conn, inserted_comment.id, &comment_form).unwrap();
410     let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap();
411     let saved_removed = CommentSaved::unsave(&conn, &comment_saved_form).unwrap();
412     let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap();
413     Comment::delete(&conn, inserted_child_comment.id).unwrap();
414     Post::delete(&conn, inserted_post.id).unwrap();
415     Community::delete(&conn, inserted_community.id).unwrap();
416     User_::delete(&conn, inserted_user.id).unwrap();
417
418     assert_eq!(expected_comment, read_comment);
419     assert_eq!(expected_comment, inserted_comment);
420     assert_eq!(expected_comment, updated_comment);
421     assert_eq!(expected_comment_like, inserted_comment_like);
422     assert_eq!(expected_comment_saved, inserted_comment_saved);
423     assert_eq!(
424       expected_comment.id,
425       inserted_child_comment.parent_id.unwrap()
426     );
427     assert_eq!(1, like_removed);
428     assert_eq!(1, saved_removed);
429     assert_eq!(1, num_deleted);
430   }
431 }