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