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