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