3 schema::{community, community_follower, community_moderator, community_user_ban},
10 use diesel::{dsl::*, result::Error, *};
13 #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
14 #[table_name = "community"]
15 pub struct Community {
19 pub description: Option<String>,
23 pub published: chrono::NaiveDateTime,
24 pub updated: Option<chrono::NaiveDateTime>,
29 pub private_key: Option<String>,
30 pub public_key: Option<String>,
31 pub last_refreshed_at: chrono::NaiveDateTime,
32 pub icon: Option<String>,
33 pub banner: Option<String>,
36 /// A safe representation of community, without the sensitive info
37 #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
38 #[table_name = "community"]
39 pub struct CommunitySafe {
43 pub description: Option<String>,
47 pub published: chrono::NaiveDateTime,
48 pub updated: Option<chrono::NaiveDateTime>,
53 pub icon: Option<String>,
54 pub banner: Option<String>,
58 use crate::{schema::community::columns::*, source::community::Community, ToSafe};
77 impl ToSafe for Community {
78 type SafeColumns = Columns;
79 fn safe_columns_tuple() -> Self::SafeColumns {
101 #[derive(Insertable, AsChangeset, Debug)]
102 #[table_name = "community"]
103 pub struct CommunityForm {
106 pub description: Option<String>,
107 pub category_id: i32,
109 pub removed: Option<bool>,
110 pub published: Option<chrono::NaiveDateTime>,
111 pub updated: Option<chrono::NaiveDateTime>,
112 pub deleted: Option<bool>,
114 pub actor_id: Option<String>,
116 pub private_key: Option<String>,
117 pub public_key: Option<String>,
118 pub last_refreshed_at: Option<chrono::NaiveDateTime>,
119 pub icon: Option<Option<String>>,
120 pub banner: Option<Option<String>>,
123 impl Crud<CommunityForm> for Community {
124 fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> {
125 use crate::schema::community::dsl::*;
126 community.find(community_id).first::<Self>(conn)
129 fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> {
130 use crate::schema::community::dsl::*;
131 diesel::delete(community.find(community_id)).execute(conn)
134 fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
135 use crate::schema::community::dsl::*;
136 insert_into(community)
137 .values(new_community)
138 .get_result::<Self>(conn)
144 new_community: &CommunityForm,
145 ) -> Result<Self, Error> {
146 use crate::schema::community::dsl::*;
147 diesel::update(community.find(community_id))
149 .get_result::<Self>(conn)
153 impl ApubObject<CommunityForm> for Community {
154 fn read_from_apub_id(conn: &PgConnection, for_actor_id: &str) -> Result<Self, Error> {
155 use crate::schema::community::dsl::*;
157 .filter(actor_id.eq(for_actor_id))
161 fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
162 use crate::schema::community::dsl::*;
163 insert_into(community)
164 .values(community_form)
165 .on_conflict(actor_id)
168 .get_result::<Self>(conn)
173 pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result<Self, Error> {
174 use crate::schema::community::dsl::*;
176 .filter(local.eq(true))
177 .filter(name.eq(community_name))
181 pub fn update_deleted(
185 ) -> Result<Self, Error> {
186 use crate::schema::community::dsl::*;
187 diesel::update(community.find(community_id))
188 .set((deleted.eq(new_deleted), updated.eq(naive_now())))
189 .get_result::<Self>(conn)
192 pub fn update_removed(
196 ) -> Result<Self, Error> {
197 use crate::schema::community::dsl::*;
198 diesel::update(community.find(community_id))
199 .set((removed.eq(new_removed), updated.eq(naive_now())))
200 .get_result::<Self>(conn)
203 pub fn update_removed_for_creator(
207 ) -> Result<Vec<Self>, Error> {
208 use crate::schema::community::dsl::*;
209 diesel::update(community.filter(creator_id.eq(for_creator_id)))
210 .set((removed.eq(new_removed), updated.eq(naive_now())))
211 .get_results::<Self>(conn)
214 pub fn update_creator(
218 ) -> Result<Self, Error> {
219 use crate::schema::community::dsl::*;
220 diesel::update(community.find(community_id))
221 .set((creator_id.eq(new_creator_id), updated.eq(naive_now())))
222 .get_result::<Self>(conn)
225 fn community_mods_and_admins(conn: &PgConnection, community_id: i32) -> Result<Vec<i32>, Error> {
226 use crate::views::{community_moderator_view::CommunityModeratorView, user_view::UserViewSafe};
227 let mut mods_and_admins: Vec<i32> = Vec::new();
228 mods_and_admins.append(
229 &mut CommunityModeratorView::for_community(conn, community_id)
230 .map(|v| v.into_iter().map(|m| m.moderator.id).collect())?,
233 .append(&mut UserViewSafe::admins(conn).map(|v| v.into_iter().map(|a| a.user.id).collect())?);
237 pub fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error> {
238 use crate::schema::community::dsl::*;
239 community.select(actor_id).distinct().load::<String>(conn)
242 pub fn is_mod_or_admin(conn: &PgConnection, user_id: i32, community_id: i32) -> bool {
243 Self::community_mods_and_admins(conn, community_id)
249 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
250 #[belongs_to(Community)]
251 #[table_name = "community_moderator"]
252 pub struct CommunityModerator {
254 pub community_id: i32,
256 pub published: chrono::NaiveDateTime,
259 #[derive(Insertable, AsChangeset, Clone)]
260 #[table_name = "community_moderator"]
261 pub struct CommunityModeratorForm {
262 pub community_id: i32,
266 impl Joinable<CommunityModeratorForm> for CommunityModerator {
269 community_user_form: &CommunityModeratorForm,
270 ) -> Result<Self, Error> {
271 use crate::schema::community_moderator::dsl::*;
272 insert_into(community_moderator)
273 .values(community_user_form)
274 .get_result::<Self>(conn)
279 community_user_form: &CommunityModeratorForm,
280 ) -> Result<usize, Error> {
281 use crate::schema::community_moderator::dsl::*;
284 .filter(community_id.eq(community_user_form.community_id))
285 .filter(user_id.eq(community_user_form.user_id)),
291 impl CommunityModerator {
292 pub fn delete_for_community(conn: &PgConnection, for_community_id: i32) -> Result<usize, Error> {
293 use crate::schema::community_moderator::dsl::*;
294 diesel::delete(community_moderator.filter(community_id.eq(for_community_id))).execute(conn)
297 pub fn get_user_moderated_communities(
300 ) -> Result<Vec<i32>, Error> {
301 use crate::schema::community_moderator::dsl::*;
303 .filter(user_id.eq(for_user_id))
304 .select(community_id)
309 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
310 #[belongs_to(Community)]
311 #[table_name = "community_user_ban"]
312 pub struct CommunityUserBan {
314 pub community_id: i32,
316 pub published: chrono::NaiveDateTime,
319 #[derive(Insertable, AsChangeset, Clone)]
320 #[table_name = "community_user_ban"]
321 pub struct CommunityUserBanForm {
322 pub community_id: i32,
326 impl Bannable<CommunityUserBanForm> for CommunityUserBan {
329 community_user_ban_form: &CommunityUserBanForm,
330 ) -> Result<Self, Error> {
331 use crate::schema::community_user_ban::dsl::*;
332 insert_into(community_user_ban)
333 .values(community_user_ban_form)
334 .get_result::<Self>(conn)
339 community_user_ban_form: &CommunityUserBanForm,
340 ) -> Result<usize, Error> {
341 use crate::schema::community_user_ban::dsl::*;
344 .filter(community_id.eq(community_user_ban_form.community_id))
345 .filter(user_id.eq(community_user_ban_form.user_id)),
351 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
352 #[belongs_to(Community)]
353 #[table_name = "community_follower"]
354 pub struct CommunityFollower {
356 pub community_id: i32,
358 pub published: chrono::NaiveDateTime,
359 pub pending: Option<bool>,
362 #[derive(Insertable, AsChangeset, Clone)]
363 #[table_name = "community_follower"]
364 pub struct CommunityFollowerForm {
365 pub community_id: i32,
370 impl Followable<CommunityFollowerForm> for CommunityFollower {
373 community_follower_form: &CommunityFollowerForm,
374 ) -> Result<Self, Error> {
375 use crate::schema::community_follower::dsl::*;
376 insert_into(community_follower)
377 .values(community_follower_form)
378 .on_conflict((community_id, user_id))
380 .set(community_follower_form)
381 .get_result::<Self>(conn)
383 fn follow_accepted(conn: &PgConnection, community_id_: i32, user_id_: i32) -> Result<Self, Error>
387 use crate::schema::community_follower::dsl::*;
390 .filter(community_id.eq(community_id_))
391 .filter(user_id.eq(user_id_)),
393 .set(pending.eq(true))
394 .get_result::<Self>(conn)
398 community_follower_form: &CommunityFollowerForm,
399 ) -> Result<usize, Error> {
400 use crate::schema::community_follower::dsl::*;
403 .filter(community_id.eq(&community_follower_form.community_id))
404 .filter(user_id.eq(&community_follower_form.user_id)),
408 // TODO: this function name only makes sense if you call it with a remote community. for a local
409 // community, it will also return true if only remote followers exist
410 fn has_local_followers(conn: &PgConnection, community_id_: i32) -> Result<bool, Error> {
411 use crate::schema::community_follower::dsl::*;
412 diesel::select(exists(
413 community_follower.filter(community_id.eq(community_id_)),
422 source::{community::*, user::*},
423 tests::establish_unpooled_connection,
430 let conn = establish_unpooled_connection();
432 let new_user = UserForm {
433 name: "bobbee".into(),
434 preferred_username: None,
435 password_encrypted: "nope".into(),
437 matrix_user_id: None,
445 theme: "browser".into(),
446 default_sort_type: SortType::Hot as i16,
447 default_listing_type: ListingType::Subscribed as i16,
448 lang: "browser".into(),
450 send_notifications_to_email: false,
456 last_refreshed_at: None,
459 let inserted_user = User_::create(&conn, &new_user).unwrap();
461 let new_community = CommunityForm {
463 creator_id: inserted_user.id,
464 title: "nada".to_owned(),
475 last_refreshed_at: None,
481 let inserted_community = Community::create(&conn, &new_community).unwrap();
483 let expected_community = Community {
484 id: inserted_community.id,
485 creator_id: inserted_user.id,
487 title: "nada".to_owned(),
493 published: inserted_community.published,
495 actor_id: inserted_community.actor_id.to_owned(),
499 last_refreshed_at: inserted_community.published,
504 let community_follower_form = CommunityFollowerForm {
505 community_id: inserted_community.id,
506 user_id: inserted_user.id,
510 let inserted_community_follower =
511 CommunityFollower::follow(&conn, &community_follower_form).unwrap();
513 let expected_community_follower = CommunityFollower {
514 id: inserted_community_follower.id,
515 community_id: inserted_community.id,
516 user_id: inserted_user.id,
517 pending: Some(false),
518 published: inserted_community_follower.published,
521 let community_user_form = CommunityModeratorForm {
522 community_id: inserted_community.id,
523 user_id: inserted_user.id,
526 let inserted_community_user = CommunityModerator::join(&conn, &community_user_form).unwrap();
528 let expected_community_user = CommunityModerator {
529 id: inserted_community_user.id,
530 community_id: inserted_community.id,
531 user_id: inserted_user.id,
532 published: inserted_community_user.published,
535 let community_user_ban_form = CommunityUserBanForm {
536 community_id: inserted_community.id,
537 user_id: inserted_user.id,
540 let inserted_community_user_ban =
541 CommunityUserBan::ban(&conn, &community_user_ban_form).unwrap();
543 let expected_community_user_ban = CommunityUserBan {
544 id: inserted_community_user_ban.id,
545 community_id: inserted_community.id,
546 user_id: inserted_user.id,
547 published: inserted_community_user_ban.published,
550 let read_community = Community::read(&conn, inserted_community.id).unwrap();
551 let updated_community =
552 Community::update(&conn, inserted_community.id, &new_community).unwrap();
553 let ignored_community = CommunityFollower::unfollow(&conn, &community_follower_form).unwrap();
554 let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
555 let unban = CommunityUserBan::unban(&conn, &community_user_ban_form).unwrap();
556 let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
557 User_::delete(&conn, inserted_user.id).unwrap();
559 assert_eq!(expected_community, read_community);
560 assert_eq!(expected_community, inserted_community);
561 assert_eq!(expected_community, updated_community);
562 assert_eq!(expected_community_follower, inserted_community_follower);
563 assert_eq!(expected_community_user, inserted_community_user);
564 assert_eq!(expected_community_user_ban, inserted_community_user_ban);
565 assert_eq!(1, ignored_community);
566 assert_eq!(1, left_community);
567 assert_eq!(1, unban);
568 // assert_eq!(2, loaded_count);
569 assert_eq!(1, num_deleted);