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