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::{community::Community, schema::community::columns::*, 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 .get_result::<Self>(conn)
380 fn follow_accepted(conn: &PgConnection, community_id_: i32, user_id_: i32) -> Result<Self, Error>
384 use crate::schema::community_follower::dsl::*;
387 .filter(community_id.eq(community_id_))
388 .filter(user_id.eq(user_id_)),
390 .set(pending.eq(true))
391 .get_result::<Self>(conn)
395 community_follower_form: &CommunityFollowerForm,
396 ) -> Result<usize, Error> {
397 use crate::schema::community_follower::dsl::*;
400 .filter(community_id.eq(&community_follower_form.community_id))
401 .filter(user_id.eq(&community_follower_form.user_id)),
405 // TODO: this function name only makes sense if you call it with a remote community. for a local
406 // community, it will also return true if only remote followers exist
407 fn has_local_followers(conn: &PgConnection, community_id_: i32) -> Result<bool, Error> {
408 use crate::schema::community_follower::dsl::*;
409 diesel::select(exists(
410 community_follower.filter(community_id.eq(community_id_)),
418 use crate::{community::*, tests::establish_unpooled_connection, user::*, ListingType, SortType};
422 let conn = establish_unpooled_connection();
424 let new_user = UserForm {
425 name: "bobbee".into(),
426 preferred_username: None,
427 password_encrypted: "nope".into(),
429 matrix_user_id: None,
437 theme: "browser".into(),
438 default_sort_type: SortType::Hot as i16,
439 default_listing_type: ListingType::Subscribed as i16,
440 lang: "browser".into(),
442 send_notifications_to_email: false,
448 last_refreshed_at: None,
451 let inserted_user = User_::create(&conn, &new_user).unwrap();
453 let new_community = CommunityForm {
455 creator_id: inserted_user.id,
456 title: "nada".to_owned(),
467 last_refreshed_at: None,
473 let inserted_community = Community::create(&conn, &new_community).unwrap();
475 let expected_community = Community {
476 id: inserted_community.id,
477 creator_id: inserted_user.id,
479 title: "nada".to_owned(),
485 published: inserted_community.published,
487 actor_id: inserted_community.actor_id.to_owned(),
491 last_refreshed_at: inserted_community.published,
496 let community_follower_form = CommunityFollowerForm {
497 community_id: inserted_community.id,
498 user_id: inserted_user.id,
502 let inserted_community_follower =
503 CommunityFollower::follow(&conn, &community_follower_form).unwrap();
505 let expected_community_follower = CommunityFollower {
506 id: inserted_community_follower.id,
507 community_id: inserted_community.id,
508 user_id: inserted_user.id,
509 pending: Some(false),
510 published: inserted_community_follower.published,
513 let community_user_form = CommunityModeratorForm {
514 community_id: inserted_community.id,
515 user_id: inserted_user.id,
518 let inserted_community_user = CommunityModerator::join(&conn, &community_user_form).unwrap();
520 let expected_community_user = CommunityModerator {
521 id: inserted_community_user.id,
522 community_id: inserted_community.id,
523 user_id: inserted_user.id,
524 published: inserted_community_user.published,
527 let community_user_ban_form = CommunityUserBanForm {
528 community_id: inserted_community.id,
529 user_id: inserted_user.id,
532 let inserted_community_user_ban =
533 CommunityUserBan::ban(&conn, &community_user_ban_form).unwrap();
535 let expected_community_user_ban = CommunityUserBan {
536 id: inserted_community_user_ban.id,
537 community_id: inserted_community.id,
538 user_id: inserted_user.id,
539 published: inserted_community_user_ban.published,
542 let read_community = Community::read(&conn, inserted_community.id).unwrap();
543 let updated_community =
544 Community::update(&conn, inserted_community.id, &new_community).unwrap();
545 let ignored_community = CommunityFollower::unfollow(&conn, &community_follower_form).unwrap();
546 let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
547 let unban = CommunityUserBan::unban(&conn, &community_user_ban_form).unwrap();
548 let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
549 User_::delete(&conn, inserted_user.id).unwrap();
551 assert_eq!(expected_community, read_community);
552 assert_eq!(expected_community, inserted_community);
553 assert_eq!(expected_community, updated_community);
554 assert_eq!(expected_community_follower, inserted_community_follower);
555 assert_eq!(expected_community_user, inserted_community_user);
556 assert_eq!(expected_community_user_ban, inserted_community_user_ban);
557 assert_eq!(1, ignored_community);
558 assert_eq!(1, left_community);
559 assert_eq!(1, unban);
560 // assert_eq!(2, loaded_count);
561 assert_eq!(1, num_deleted);