]> Untitled Git - lemmy.git/blob - crates/db_queries/src/source/post.rs
f0cf109357ec949a98eff698be2f473a2b8fddce
[lemmy.git] / crates / db_queries / src / source / post.rs
1 use crate::{ApubObject, Crud, DeleteableOrRemoveable, Likeable, Readable, Saveable};
2 use diesel::{dsl::*, result::Error, *};
3 use lemmy_db_schema::{
4   naive_now,
5   source::post::{
6     Post,
7     PostForm,
8     PostLike,
9     PostLikeForm,
10     PostRead,
11     PostReadForm,
12     PostSaved,
13     PostSavedForm,
14   },
15   CommunityId,
16   DbUrl,
17   PersonId,
18   PostId,
19 };
20
21 impl Crud<PostForm, PostId> for Post {
22   fn read(conn: &PgConnection, post_id: PostId) -> Result<Self, Error> {
23     use lemmy_db_schema::schema::post::dsl::*;
24     post.find(post_id).first::<Self>(conn)
25   }
26
27   fn delete(conn: &PgConnection, post_id: PostId) -> Result<usize, Error> {
28     use lemmy_db_schema::schema::post::dsl::*;
29     diesel::delete(post.find(post_id)).execute(conn)
30   }
31
32   fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
33     use lemmy_db_schema::schema::post::dsl::*;
34     insert_into(post).values(new_post).get_result::<Self>(conn)
35   }
36
37   fn update(conn: &PgConnection, post_id: PostId, new_post: &PostForm) -> Result<Self, Error> {
38     use lemmy_db_schema::schema::post::dsl::*;
39     diesel::update(post.find(post_id))
40       .set(new_post)
41       .get_result::<Self>(conn)
42   }
43 }
44
45 pub trait Post_ {
46   //fn read(conn: &PgConnection, post_id: i32) -> Result<Post, Error>;
47   fn list_for_community(
48     conn: &PgConnection,
49     the_community_id: CommunityId,
50   ) -> Result<Vec<Post>, Error>;
51   fn update_ap_id(conn: &PgConnection, post_id: PostId, apub_id: DbUrl) -> Result<Post, Error>;
52   fn permadelete_for_creator(
53     conn: &PgConnection,
54     for_creator_id: PersonId,
55   ) -> Result<Vec<Post>, Error>;
56   fn update_deleted(conn: &PgConnection, post_id: PostId, new_deleted: bool)
57     -> Result<Post, Error>;
58   fn update_removed(conn: &PgConnection, post_id: PostId, new_removed: bool)
59     -> Result<Post, Error>;
60   fn update_removed_for_creator(
61     conn: &PgConnection,
62     for_creator_id: PersonId,
63     for_community_id: Option<CommunityId>,
64     new_removed: bool,
65   ) -> Result<Vec<Post>, Error>;
66   fn update_locked(conn: &PgConnection, post_id: PostId, new_locked: bool) -> Result<Post, Error>;
67   fn update_stickied(
68     conn: &PgConnection,
69     post_id: PostId,
70     new_stickied: bool,
71   ) -> Result<Post, Error>;
72   fn is_post_creator(person_id: PersonId, post_creator_id: PersonId) -> bool;
73 }
74
75 impl Post_ for Post {
76   fn list_for_community(
77     conn: &PgConnection,
78     the_community_id: CommunityId,
79   ) -> Result<Vec<Self>, Error> {
80     use lemmy_db_schema::schema::post::dsl::*;
81     post
82       .filter(community_id.eq(the_community_id))
83       .then_order_by(published.desc())
84       .then_order_by(stickied.desc())
85       .limit(20)
86       .load::<Self>(conn)
87   }
88
89   fn update_ap_id(conn: &PgConnection, post_id: PostId, apub_id: DbUrl) -> Result<Self, Error> {
90     use lemmy_db_schema::schema::post::dsl::*;
91
92     diesel::update(post.find(post_id))
93       .set(ap_id.eq(apub_id))
94       .get_result::<Self>(conn)
95   }
96
97   fn permadelete_for_creator(
98     conn: &PgConnection,
99     for_creator_id: PersonId,
100   ) -> Result<Vec<Self>, Error> {
101     use lemmy_db_schema::schema::post::dsl::*;
102
103     let perma_deleted = "*Permananently Deleted*";
104     let perma_deleted_url = "https://deleted.com";
105
106     diesel::update(post.filter(creator_id.eq(for_creator_id)))
107       .set((
108         name.eq(perma_deleted),
109         url.eq(perma_deleted_url),
110         body.eq(perma_deleted),
111         deleted.eq(true),
112         updated.eq(naive_now()),
113       ))
114       .get_results::<Self>(conn)
115   }
116
117   fn update_deleted(
118     conn: &PgConnection,
119     post_id: PostId,
120     new_deleted: bool,
121   ) -> Result<Self, Error> {
122     use lemmy_db_schema::schema::post::dsl::*;
123     diesel::update(post.find(post_id))
124       .set((deleted.eq(new_deleted), updated.eq(naive_now())))
125       .get_result::<Self>(conn)
126   }
127
128   fn update_removed(
129     conn: &PgConnection,
130     post_id: PostId,
131     new_removed: bool,
132   ) -> Result<Self, Error> {
133     use lemmy_db_schema::schema::post::dsl::*;
134     diesel::update(post.find(post_id))
135       .set((removed.eq(new_removed), updated.eq(naive_now())))
136       .get_result::<Self>(conn)
137   }
138
139   fn update_removed_for_creator(
140     conn: &PgConnection,
141     for_creator_id: PersonId,
142     for_community_id: Option<CommunityId>,
143     new_removed: bool,
144   ) -> Result<Vec<Self>, Error> {
145     use lemmy_db_schema::schema::post::dsl::*;
146
147     let mut update = diesel::update(post).into_boxed();
148     update = update.filter(creator_id.eq(for_creator_id));
149
150     if let Some(for_community_id) = for_community_id {
151       update = update.filter(community_id.eq(for_community_id));
152     }
153
154     update
155       .set((removed.eq(new_removed), updated.eq(naive_now())))
156       .get_results::<Self>(conn)
157   }
158
159   fn update_locked(conn: &PgConnection, post_id: PostId, new_locked: bool) -> Result<Self, Error> {
160     use lemmy_db_schema::schema::post::dsl::*;
161     diesel::update(post.find(post_id))
162       .set(locked.eq(new_locked))
163       .get_result::<Self>(conn)
164   }
165
166   fn update_stickied(
167     conn: &PgConnection,
168     post_id: PostId,
169     new_stickied: bool,
170   ) -> Result<Self, Error> {
171     use lemmy_db_schema::schema::post::dsl::*;
172     diesel::update(post.find(post_id))
173       .set(stickied.eq(new_stickied))
174       .get_result::<Self>(conn)
175   }
176
177   fn is_post_creator(person_id: PersonId, post_creator_id: PersonId) -> bool {
178     person_id == post_creator_id
179   }
180 }
181
182 impl ApubObject<PostForm> for Post {
183   fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
184     use lemmy_db_schema::schema::post::dsl::*;
185     post.filter(ap_id.eq(object_id)).first::<Self>(conn)
186   }
187
188   fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result<Post, Error> {
189     use lemmy_db_schema::schema::post::dsl::*;
190     insert_into(post)
191       .values(post_form)
192       .on_conflict(ap_id)
193       .do_update()
194       .set(post_form)
195       .get_result::<Self>(conn)
196   }
197 }
198
199 impl Likeable<PostLikeForm, PostId> for PostLike {
200   fn like(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<Self, Error> {
201     use lemmy_db_schema::schema::post_like::dsl::*;
202     insert_into(post_like)
203       .values(post_like_form)
204       .on_conflict((post_id, person_id))
205       .do_update()
206       .set(post_like_form)
207       .get_result::<Self>(conn)
208   }
209   fn remove(conn: &PgConnection, person_id: PersonId, post_id: PostId) -> Result<usize, Error> {
210     use lemmy_db_schema::schema::post_like::dsl;
211     diesel::delete(
212       dsl::post_like
213         .filter(dsl::post_id.eq(post_id))
214         .filter(dsl::person_id.eq(person_id)),
215     )
216     .execute(conn)
217   }
218 }
219
220 impl Saveable<PostSavedForm> for PostSaved {
221   fn save(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<Self, Error> {
222     use lemmy_db_schema::schema::post_saved::dsl::*;
223     insert_into(post_saved)
224       .values(post_saved_form)
225       .on_conflict((post_id, person_id))
226       .do_update()
227       .set(post_saved_form)
228       .get_result::<Self>(conn)
229   }
230   fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
231     use lemmy_db_schema::schema::post_saved::dsl::*;
232     diesel::delete(
233       post_saved
234         .filter(post_id.eq(post_saved_form.post_id))
235         .filter(person_id.eq(post_saved_form.person_id)),
236     )
237     .execute(conn)
238   }
239 }
240
241 impl Readable<PostReadForm> for PostRead {
242   fn mark_as_read(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<Self, Error> {
243     use lemmy_db_schema::schema::post_read::dsl::*;
244     insert_into(post_read)
245       .values(post_read_form)
246       .on_conflict((post_id, person_id))
247       .do_update()
248       .set(post_read_form)
249       .get_result::<Self>(conn)
250   }
251
252   fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> {
253     use lemmy_db_schema::schema::post_read::dsl::*;
254     diesel::delete(
255       post_read
256         .filter(post_id.eq(post_read_form.post_id))
257         .filter(person_id.eq(post_read_form.person_id)),
258     )
259     .execute(conn)
260   }
261 }
262
263 impl DeleteableOrRemoveable for Post {
264   fn blank_out_deleted_or_removed_info(mut self) -> Self {
265     self.name = "".into();
266     self.url = None;
267     self.body = None;
268     self.embed_title = None;
269     self.embed_description = None;
270     self.embed_html = None;
271     self.thumbnail_url = None;
272
273     self
274   }
275 }
276
277 #[cfg(test)]
278 mod tests {
279   use crate::{establish_unpooled_connection, source::post::*};
280   use lemmy_db_schema::source::{
281     community::{Community, CommunityForm},
282     person::*,
283   };
284   use serial_test::serial;
285
286   #[test]
287   #[serial]
288   fn test_crud() {
289     let conn = establish_unpooled_connection();
290
291     let new_person = PersonForm {
292       name: "jim".into(),
293       ..PersonForm::default()
294     };
295
296     let inserted_person = Person::create(&conn, &new_person).unwrap();
297
298     let new_community = CommunityForm {
299       name: "test community_3".to_string(),
300       title: "nada".to_owned(),
301       ..CommunityForm::default()
302     };
303
304     let inserted_community = Community::create(&conn, &new_community).unwrap();
305
306     let new_post = PostForm {
307       name: "A test post".into(),
308       creator_id: inserted_person.id,
309       community_id: inserted_community.id,
310       ..PostForm::default()
311     };
312
313     let inserted_post = Post::create(&conn, &new_post).unwrap();
314
315     let expected_post = Post {
316       id: inserted_post.id,
317       name: "A test post".into(),
318       url: None,
319       body: None,
320       creator_id: inserted_person.id,
321       community_id: inserted_community.id,
322       published: inserted_post.published,
323       removed: false,
324       locked: false,
325       stickied: false,
326       nsfw: false,
327       deleted: false,
328       updated: None,
329       embed_title: None,
330       embed_description: None,
331       embed_html: None,
332       thumbnail_url: None,
333       ap_id: inserted_post.ap_id.to_owned(),
334       local: true,
335     };
336
337     // Post Like
338     let post_like_form = PostLikeForm {
339       post_id: inserted_post.id,
340       person_id: inserted_person.id,
341       score: 1,
342     };
343
344     let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
345
346     let expected_post_like = PostLike {
347       id: inserted_post_like.id,
348       post_id: inserted_post.id,
349       person_id: inserted_person.id,
350       published: inserted_post_like.published,
351       score: 1,
352     };
353
354     // Post Save
355     let post_saved_form = PostSavedForm {
356       post_id: inserted_post.id,
357       person_id: inserted_person.id,
358     };
359
360     let inserted_post_saved = PostSaved::save(&conn, &post_saved_form).unwrap();
361
362     let expected_post_saved = PostSaved {
363       id: inserted_post_saved.id,
364       post_id: inserted_post.id,
365       person_id: inserted_person.id,
366       published: inserted_post_saved.published,
367     };
368
369     // Post Read
370     let post_read_form = PostReadForm {
371       post_id: inserted_post.id,
372       person_id: inserted_person.id,
373     };
374
375     let inserted_post_read = PostRead::mark_as_read(&conn, &post_read_form).unwrap();
376
377     let expected_post_read = PostRead {
378       id: inserted_post_read.id,
379       post_id: inserted_post.id,
380       person_id: inserted_person.id,
381       published: inserted_post_read.published,
382     };
383
384     let read_post = Post::read(&conn, inserted_post.id).unwrap();
385     let updated_post = Post::update(&conn, inserted_post.id, &new_post).unwrap();
386     let like_removed = PostLike::remove(&conn, inserted_person.id, inserted_post.id).unwrap();
387     let saved_removed = PostSaved::unsave(&conn, &post_saved_form).unwrap();
388     let read_removed = PostRead::mark_as_unread(&conn, &post_read_form).unwrap();
389     let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
390     Community::delete(&conn, inserted_community.id).unwrap();
391     Person::delete(&conn, inserted_person.id).unwrap();
392
393     assert_eq!(expected_post, read_post);
394     assert_eq!(expected_post, inserted_post);
395     assert_eq!(expected_post, updated_post);
396     assert_eq!(expected_post_like, inserted_post_like);
397     assert_eq!(expected_post_saved, inserted_post_saved);
398     assert_eq!(expected_post_read, inserted_post_read);
399     assert_eq!(1, like_removed);
400     assert_eq!(1, saved_removed);
401     assert_eq!(1, read_removed);
402     assert_eq!(1, num_deleted);
403   }
404 }