]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/community.rs
Translated using Weblate (Italian)
[lemmy.git] / server / lemmy_db / src / community.rs
1 use crate::{
2   naive_now,
3   schema::{community, community_follower, community_moderator, community_user_ban},
4   Bannable,
5   Crud,
6   Followable,
7   Joinable,
8 };
9 use diesel::{dsl::*, result::Error, *};
10 use serde::{Deserialize, Serialize};
11
12 #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
13 #[table_name = "community"]
14 pub struct Community {
15   pub id: i32,
16   pub name: String,
17   pub title: String,
18   pub description: Option<String>,
19   pub category_id: i32,
20   pub creator_id: i32,
21   pub removed: bool,
22   pub published: chrono::NaiveDateTime,
23   pub updated: Option<chrono::NaiveDateTime>,
24   pub deleted: bool,
25   pub nsfw: bool,
26   pub actor_id: String,
27   pub local: bool,
28   pub private_key: Option<String>,
29   pub public_key: Option<String>,
30   pub last_refreshed_at: chrono::NaiveDateTime,
31 }
32
33 #[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize, Debug)]
34 #[table_name = "community"]
35 pub struct CommunityForm {
36   pub name: String,
37   pub title: String,
38   pub description: Option<String>,
39   pub category_id: i32,
40   pub creator_id: i32,
41   pub removed: Option<bool>,
42   pub published: Option<chrono::NaiveDateTime>,
43   pub updated: Option<chrono::NaiveDateTime>,
44   pub deleted: Option<bool>,
45   pub nsfw: bool,
46   pub actor_id: String,
47   pub local: bool,
48   pub private_key: Option<String>,
49   pub public_key: Option<String>,
50   pub last_refreshed_at: Option<chrono::NaiveDateTime>,
51 }
52
53 impl Crud<CommunityForm> for Community {
54   fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> {
55     use crate::schema::community::dsl::*;
56     community.find(community_id).first::<Self>(conn)
57   }
58
59   fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> {
60     use crate::schema::community::dsl::*;
61     diesel::delete(community.find(community_id)).execute(conn)
62   }
63
64   fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
65     use crate::schema::community::dsl::*;
66     insert_into(community)
67       .values(new_community)
68       .get_result::<Self>(conn)
69   }
70
71   fn update(
72     conn: &PgConnection,
73     community_id: i32,
74     new_community: &CommunityForm,
75   ) -> Result<Self, Error> {
76     use crate::schema::community::dsl::*;
77     diesel::update(community.find(community_id))
78       .set(new_community)
79       .get_result::<Self>(conn)
80   }
81 }
82
83 impl Community {
84   pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result<Self, Error> {
85     use crate::schema::community::dsl::*;
86     community
87       .filter(name.eq(community_name))
88       .first::<Self>(conn)
89   }
90
91   pub fn read_from_actor_id(conn: &PgConnection, for_actor_id: &str) -> Result<Self, Error> {
92     use crate::schema::community::dsl::*;
93     community
94       .filter(actor_id.eq(for_actor_id))
95       .first::<Self>(conn)
96   }
97
98   pub fn list_local(conn: &PgConnection) -> Result<Vec<Self>, Error> {
99     use crate::schema::community::dsl::*;
100     community.filter(local.eq(true)).load::<Community>(conn)
101   }
102
103   pub fn update_deleted(
104     conn: &PgConnection,
105     community_id: i32,
106     new_deleted: bool,
107   ) -> Result<Self, Error> {
108     use crate::schema::community::dsl::*;
109     diesel::update(community.find(community_id))
110       .set((
111         deleted.eq(new_deleted),
112         updated.eq(naive_now())
113       ))
114       .get_result::<Self>(conn)
115   }
116
117   pub fn update_removed(
118     conn: &PgConnection,
119     community_id: i32,
120     new_removed: bool,
121   ) -> Result<Self, Error> {
122     use crate::schema::community::dsl::*;
123     diesel::update(community.find(community_id))
124       .set((
125         removed.eq(new_removed),
126         updated.eq(naive_now())
127       ))
128       .get_result::<Self>(conn)
129   }
130
131   pub fn update_creator(
132     conn: &PgConnection,
133     community_id: i32,
134     new_creator_id: i32,
135   ) -> Result<Self, Error> {
136     use crate::schema::community::dsl::*;
137     diesel::update(community.find(community_id))
138       .set((creator_id.eq(new_creator_id), updated.eq(naive_now())))
139       .get_result::<Self>(conn)
140   }
141
142   fn community_mods_and_admins(conn: &PgConnection, community_id: i32) -> Result<Vec<i32>, Error> {
143     use crate::{community_view::CommunityModeratorView, user_view::UserView};
144     let mut mods_and_admins: Vec<i32> = Vec::new();
145     mods_and_admins.append(
146       &mut CommunityModeratorView::for_community(conn, community_id)
147         .map(|v| v.into_iter().map(|m| m.user_id).collect())?,
148     );
149     mods_and_admins
150       .append(&mut UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())?);
151     Ok(mods_and_admins)
152   }
153
154   pub fn is_mod_or_admin(conn: &PgConnection, user_id: i32, community_id: i32) -> bool {
155     Self::community_mods_and_admins(conn, community_id)
156       .unwrap_or_default()
157       .contains(&user_id)
158   }
159 }
160
161 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
162 #[belongs_to(Community)]
163 #[table_name = "community_moderator"]
164 pub struct CommunityModerator {
165   pub id: i32,
166   pub community_id: i32,
167   pub user_id: i32,
168   pub published: chrono::NaiveDateTime,
169 }
170
171 #[derive(Insertable, AsChangeset, Clone)]
172 #[table_name = "community_moderator"]
173 pub struct CommunityModeratorForm {
174   pub community_id: i32,
175   pub user_id: i32,
176 }
177
178 impl Joinable<CommunityModeratorForm> for CommunityModerator {
179   fn join(
180     conn: &PgConnection,
181     community_user_form: &CommunityModeratorForm,
182   ) -> Result<Self, Error> {
183     use crate::schema::community_moderator::dsl::*;
184     insert_into(community_moderator)
185       .values(community_user_form)
186       .get_result::<Self>(conn)
187   }
188
189   fn leave(
190     conn: &PgConnection,
191     community_user_form: &CommunityModeratorForm,
192   ) -> Result<usize, Error> {
193     use crate::schema::community_moderator::dsl::*;
194     diesel::delete(
195       community_moderator
196         .filter(community_id.eq(community_user_form.community_id))
197         .filter(user_id.eq(community_user_form.user_id)),
198     )
199     .execute(conn)
200   }
201 }
202
203 impl CommunityModerator {
204   pub fn delete_for_community(conn: &PgConnection, for_community_id: i32) -> Result<usize, Error> {
205     use crate::schema::community_moderator::dsl::*;
206     diesel::delete(community_moderator.filter(community_id.eq(for_community_id))).execute(conn)
207   }
208 }
209
210 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
211 #[belongs_to(Community)]
212 #[table_name = "community_user_ban"]
213 pub struct CommunityUserBan {
214   pub id: i32,
215   pub community_id: i32,
216   pub user_id: i32,
217   pub published: chrono::NaiveDateTime,
218 }
219
220 #[derive(Insertable, AsChangeset, Clone)]
221 #[table_name = "community_user_ban"]
222 pub struct CommunityUserBanForm {
223   pub community_id: i32,
224   pub user_id: i32,
225 }
226
227 impl Bannable<CommunityUserBanForm> for CommunityUserBan {
228   fn ban(
229     conn: &PgConnection,
230     community_user_ban_form: &CommunityUserBanForm,
231   ) -> Result<Self, Error> {
232     use crate::schema::community_user_ban::dsl::*;
233     insert_into(community_user_ban)
234       .values(community_user_ban_form)
235       .get_result::<Self>(conn)
236   }
237
238   fn unban(
239     conn: &PgConnection,
240     community_user_ban_form: &CommunityUserBanForm,
241   ) -> Result<usize, Error> {
242     use crate::schema::community_user_ban::dsl::*;
243     diesel::delete(
244       community_user_ban
245         .filter(community_id.eq(community_user_ban_form.community_id))
246         .filter(user_id.eq(community_user_ban_form.user_id)),
247     )
248     .execute(conn)
249   }
250 }
251
252 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
253 #[belongs_to(Community)]
254 #[table_name = "community_follower"]
255 pub struct CommunityFollower {
256   pub id: i32,
257   pub community_id: i32,
258   pub user_id: i32,
259   pub published: chrono::NaiveDateTime,
260 }
261
262 #[derive(Insertable, AsChangeset, Clone)]
263 #[table_name = "community_follower"]
264 pub struct CommunityFollowerForm {
265   pub community_id: i32,
266   pub user_id: i32,
267 }
268
269 impl Followable<CommunityFollowerForm> for CommunityFollower {
270   fn follow(
271     conn: &PgConnection,
272     community_follower_form: &CommunityFollowerForm,
273   ) -> Result<Self, Error> {
274     use crate::schema::community_follower::dsl::*;
275     insert_into(community_follower)
276       .values(community_follower_form)
277       .get_result::<Self>(conn)
278   }
279   fn unfollow(
280     conn: &PgConnection,
281     community_follower_form: &CommunityFollowerForm,
282   ) -> Result<usize, Error> {
283     use crate::schema::community_follower::dsl::*;
284     diesel::delete(
285       community_follower
286         .filter(community_id.eq(&community_follower_form.community_id))
287         .filter(user_id.eq(&community_follower_form.user_id)),
288     )
289     .execute(conn)
290   }
291 }
292
293 #[cfg(test)]
294 mod tests {
295   use crate::{community::*, tests::establish_unpooled_connection, user::*, ListingType, SortType};
296
297   #[test]
298   fn test_crud() {
299     let conn = establish_unpooled_connection();
300
301     let new_user = UserForm {
302       name: "bobbee".into(),
303       preferred_username: None,
304       password_encrypted: "nope".into(),
305       email: None,
306       matrix_user_id: None,
307       avatar: None,
308       admin: false,
309       banned: false,
310       updated: None,
311       show_nsfw: false,
312       theme: "darkly".into(),
313       default_sort_type: SortType::Hot as i16,
314       default_listing_type: ListingType::Subscribed as i16,
315       lang: "browser".into(),
316       show_avatars: true,
317       send_notifications_to_email: false,
318       actor_id: "changeme_8266238".into(),
319       bio: None,
320       local: true,
321       private_key: None,
322       public_key: None,
323       last_refreshed_at: None,
324     };
325
326     let inserted_user = User_::create(&conn, &new_user).unwrap();
327
328     let new_community = CommunityForm {
329       name: "TIL".into(),
330       creator_id: inserted_user.id,
331       title: "nada".to_owned(),
332       description: None,
333       category_id: 1,
334       nsfw: false,
335       removed: None,
336       deleted: None,
337       updated: None,
338       actor_id: "changeme_7625376".into(),
339       local: true,
340       private_key: None,
341       public_key: None,
342       last_refreshed_at: None,
343       published: None,
344     };
345
346     let inserted_community = Community::create(&conn, &new_community).unwrap();
347
348     let expected_community = Community {
349       id: inserted_community.id,
350       creator_id: inserted_user.id,
351       name: "TIL".into(),
352       title: "nada".to_owned(),
353       description: None,
354       category_id: 1,
355       nsfw: false,
356       removed: false,
357       deleted: false,
358       published: inserted_community.published,
359       updated: None,
360       actor_id: inserted_community.actor_id.to_owned(),
361       local: true,
362       private_key: None,
363       public_key: None,
364       last_refreshed_at: inserted_community.published,
365     };
366
367     let community_follower_form = CommunityFollowerForm {
368       community_id: inserted_community.id,
369       user_id: inserted_user.id,
370     };
371
372     let inserted_community_follower =
373       CommunityFollower::follow(&conn, &community_follower_form).unwrap();
374
375     let expected_community_follower = CommunityFollower {
376       id: inserted_community_follower.id,
377       community_id: inserted_community.id,
378       user_id: inserted_user.id,
379       published: inserted_community_follower.published,
380     };
381
382     let community_user_form = CommunityModeratorForm {
383       community_id: inserted_community.id,
384       user_id: inserted_user.id,
385     };
386
387     let inserted_community_user = CommunityModerator::join(&conn, &community_user_form).unwrap();
388
389     let expected_community_user = CommunityModerator {
390       id: inserted_community_user.id,
391       community_id: inserted_community.id,
392       user_id: inserted_user.id,
393       published: inserted_community_user.published,
394     };
395
396     let community_user_ban_form = CommunityUserBanForm {
397       community_id: inserted_community.id,
398       user_id: inserted_user.id,
399     };
400
401     let inserted_community_user_ban =
402       CommunityUserBan::ban(&conn, &community_user_ban_form).unwrap();
403
404     let expected_community_user_ban = CommunityUserBan {
405       id: inserted_community_user_ban.id,
406       community_id: inserted_community.id,
407       user_id: inserted_user.id,
408       published: inserted_community_user_ban.published,
409     };
410
411     let read_community = Community::read(&conn, inserted_community.id).unwrap();
412     let updated_community =
413       Community::update(&conn, inserted_community.id, &new_community).unwrap();
414     let ignored_community = CommunityFollower::unfollow(&conn, &community_follower_form).unwrap();
415     let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
416     let unban = CommunityUserBan::unban(&conn, &community_user_ban_form).unwrap();
417     let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
418     User_::delete(&conn, inserted_user.id).unwrap();
419
420     assert_eq!(expected_community, read_community);
421     assert_eq!(expected_community, inserted_community);
422     assert_eq!(expected_community, updated_community);
423     assert_eq!(expected_community_follower, inserted_community_follower);
424     assert_eq!(expected_community_user, inserted_community_user);
425     assert_eq!(expected_community_user_ban, inserted_community_user_ban);
426     assert_eq!(1, ignored_community);
427     assert_eq!(1, left_community);
428     assert_eq!(1, unban);
429     // assert_eq!(2, loaded_count);
430     assert_eq!(1, num_deleted);
431   }
432 }