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