]> Untitled Git - lemmy.git/blobdiff - crates/db_schema/src/impls/community.rs
implement language tags for site/community in db and api (#2434)
[lemmy.git] / crates / db_schema / src / impls / community.rs
index 43b7db3e29621a17a601a12e115c7a3d1d55ad0b..966761b2d8f3c0611bb98630502f7e76ae3b2f2e 100644 (file)
@@ -1,19 +1,22 @@
 use crate::{
-  functions::lower,
-  naive_now,
   newtypes::{CommunityId, DbUrl, PersonId},
-  source::community::{
-    Community,
-    CommunityFollower,
-    CommunityFollowerForm,
-    CommunityForm,
-    CommunityModerator,
-    CommunityModeratorForm,
-    CommunityPersonBan,
-    CommunityPersonBanForm,
-    CommunitySafe,
+  source::{
+    actor_language::{CommunityLanguage, SiteLanguage},
+    community::{
+      Community,
+      CommunityFollower,
+      CommunityFollowerForm,
+      CommunityForm,
+      CommunityModerator,
+      CommunityModeratorForm,
+      CommunityPersonBan,
+      CommunityPersonBanForm,
+      CommunitySafe,
+    },
   },
   traits::{ApubActor, Bannable, Crud, DeleteableOrRemoveable, Followable, Joinable},
+  utils::{functions::lower, naive_now},
+  SubscribedType,
 };
 use diesel::{
   dsl::*,
@@ -24,7 +27,6 @@ use diesel::{
   RunQueryDsl,
   TextExpressionMethods,
 };
-use url::Url;
 
 mod safe_type {
   use crate::{schema::community::*, source::community::Community, traits::ToSafe};
@@ -44,6 +46,7 @@ mod safe_type {
     icon,
     banner,
     hidden,
+    posting_restricted_to_mods,
   );
 
   impl ToSafe for Community {
@@ -64,6 +67,7 @@ mod safe_type {
         icon,
         banner,
         hidden,
+        posting_restricted_to_mods,
       )
     }
   }
@@ -72,25 +76,36 @@ mod safe_type {
 impl Crud for Community {
   type Form = CommunityForm;
   type IdType = CommunityId;
-  fn read(conn: &PgConnection, community_id: CommunityId) -> Result<Self, Error> {
+  fn read(conn: &mut PgConnection, community_id: CommunityId) -> Result<Self, Error> {
     use crate::schema::community::dsl::*;
     community.find(community_id).first::<Self>(conn)
   }
 
-  fn delete(conn: &PgConnection, community_id: CommunityId) -> Result<usize, Error> {
+  fn delete(conn: &mut PgConnection, community_id: CommunityId) -> Result<usize, Error> {
     use crate::schema::community::dsl::*;
     diesel::delete(community.find(community_id)).execute(conn)
   }
 
-  fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
+  fn create(conn: &mut PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
     use crate::schema::community::dsl::*;
-    insert_into(community)
+    let community_ = insert_into(community)
       .values(new_community)
-      .get_result::<Self>(conn)
+      .get_result::<Self>(conn)?;
+
+    let site_languages = SiteLanguage::read_local(conn);
+    if let Ok(langs) = site_languages {
+      // if site exists, init user with site languages
+      CommunityLanguage::update(conn, langs, community_.id)?;
+    } else {
+      // otherwise, init with all languages (this only happens during tests)
+      CommunityLanguage::update(conn, vec![], community_.id)?;
+    }
+
+    Ok(community_)
   }
 
   fn update(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_id: CommunityId,
     new_community: &CommunityForm,
   ) -> Result<Self, Error> {
@@ -103,7 +118,7 @@ impl Crud for Community {
 
 impl Community {
   pub fn update_deleted(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_id: CommunityId,
     new_deleted: bool,
   ) -> Result<Community, Error> {
@@ -114,7 +129,7 @@ impl Community {
   }
 
   pub fn update_removed(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_id: CommunityId,
     new_removed: bool,
   ) -> Result<Community, Error> {
@@ -124,12 +139,15 @@ impl Community {
       .get_result::<Self>(conn)
   }
 
-  pub fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<DbUrl>, Error> {
+  pub fn distinct_federated_communities(conn: &mut PgConnection) -> Result<Vec<DbUrl>, Error> {
     use crate::schema::community::dsl::*;
     community.select(actor_id).distinct().load::<DbUrl>(conn)
   }
 
-  pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result<Community, Error> {
+  pub fn upsert(
+    conn: &mut PgConnection,
+    community_form: &CommunityForm,
+  ) -> Result<Community, Error> {
     use crate::schema::community::dsl::*;
     insert_into(community)
       .values(community_form)
@@ -138,12 +156,25 @@ impl Community {
       .set(community_form)
       .get_result::<Self>(conn)
   }
+
+  pub fn remove_avatar_and_banner(
+    conn: &mut PgConnection,
+    community_id: CommunityId,
+  ) -> Result<Self, Error> {
+    use crate::schema::community::dsl::*;
+    diesel::update(community.find(community_id))
+      .set((
+        icon.eq::<Option<String>>(None),
+        banner.eq::<Option<String>>(None),
+      ))
+      .get_result::<Self>(conn)
+  }
 }
 
 impl Joinable for CommunityModerator {
   type Form = CommunityModeratorForm;
   fn join(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_moderator_form: &CommunityModeratorForm,
   ) -> Result<Self, Error> {
     use crate::schema::community_moderator::dsl::*;
@@ -153,7 +184,7 @@ impl Joinable for CommunityModerator {
   }
 
   fn leave(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_moderator_form: &CommunityModeratorForm,
   ) -> Result<usize, Error> {
     use crate::schema::community_moderator::dsl::*;
@@ -188,7 +219,7 @@ impl DeleteableOrRemoveable for Community {
 
 impl CommunityModerator {
   pub fn delete_for_community(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     for_community_id: CommunityId,
   ) -> Result<usize, Error> {
     use crate::schema::community_moderator::dsl::*;
@@ -196,7 +227,7 @@ impl CommunityModerator {
   }
 
   pub fn get_person_moderated_communities(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     for_person_id: PersonId,
   ) -> Result<Vec<CommunityId>, Error> {
     use crate::schema::community_moderator::dsl::*;
@@ -210,7 +241,7 @@ impl CommunityModerator {
 impl Bannable for CommunityPersonBan {
   type Form = CommunityPersonBanForm;
   fn ban(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_person_ban_form: &CommunityPersonBanForm,
   ) -> Result<Self, Error> {
     use crate::schema::community_person_ban::dsl::*;
@@ -223,7 +254,7 @@ impl Bannable for CommunityPersonBan {
   }
 
   fn unban(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_person_ban_form: &CommunityPersonBanForm,
   ) -> Result<usize, Error> {
     use crate::schema::community_person_ban::dsl::*;
@@ -236,10 +267,26 @@ impl Bannable for CommunityPersonBan {
   }
 }
 
+impl CommunityFollower {
+  pub fn to_subscribed_type(follower: &Option<Self>) -> SubscribedType {
+    match follower {
+      Some(f) => {
+        if f.pending.unwrap_or(false) {
+          SubscribedType::Pending
+        } else {
+          SubscribedType::Subscribed
+        }
+      }
+      // If the row doesn't exist, the person isn't a follower.
+      None => SubscribedType::NotSubscribed,
+    }
+  }
+}
+
 impl Followable for CommunityFollower {
   type Form = CommunityFollowerForm;
   fn follow(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_follower_form: &CommunityFollowerForm,
   ) -> Result<Self, Error> {
     use crate::schema::community_follower::dsl::*;
@@ -251,7 +298,7 @@ impl Followable for CommunityFollower {
       .get_result::<Self>(conn)
   }
   fn follow_accepted(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_id_: CommunityId,
     person_id_: PersonId,
   ) -> Result<Self, Error>
@@ -264,11 +311,11 @@ impl Followable for CommunityFollower {
         .filter(community_id.eq(community_id_))
         .filter(person_id.eq(person_id_)),
     )
-    .set(pending.eq(true))
+    .set(pending.eq(false))
     .get_result::<Self>(conn)
   }
   fn unfollow(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_follower_form: &CommunityFollowerForm,
   ) -> Result<usize, Error> {
     use crate::schema::community_follower::dsl::*;
@@ -281,7 +328,10 @@ impl Followable for CommunityFollower {
   }
   // TODO: this function name only makes sense if you call it with a remote community. for a local
   //       community, it will also return true if only remote followers exist
-  fn has_local_followers(conn: &PgConnection, community_id_: CommunityId) -> Result<bool, Error> {
+  fn has_local_followers(
+    conn: &mut PgConnection,
+    community_id_: CommunityId,
+  ) -> Result<bool, Error> {
     use crate::schema::community_follower::dsl::*;
     diesel::select(exists(
       community_follower.filter(community_id.eq(community_id_)),
@@ -291,9 +341,8 @@ impl Followable for CommunityFollower {
 }
 
 impl ApubActor for Community {
-  fn read_from_apub_id(conn: &PgConnection, object_id: Url) -> Result<Option<Self>, Error> {
+  fn read_from_apub_id(conn: &mut PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error> {
     use crate::schema::community::dsl::*;
-    let object_id: DbUrl = object_id.into();
     Ok(
       community
         .filter(actor_id.eq(object_id))
@@ -303,16 +352,24 @@ impl ApubActor for Community {
     )
   }
 
-  fn read_from_name(conn: &PgConnection, community_name: &str) -> Result<Community, Error> {
+  fn read_from_name(
+    conn: &mut PgConnection,
+    community_name: &str,
+    include_deleted: bool,
+  ) -> Result<Community, Error> {
     use crate::schema::community::dsl::*;
-    community
+    let mut q = community
+      .into_boxed()
       .filter(local.eq(true))
-      .filter(lower(name).eq(lower(community_name)))
-      .first::<Self>(conn)
+      .filter(lower(name).eq(lower(community_name)));
+    if !include_deleted {
+      q = q.filter(deleted.eq(false)).filter(removed.eq(false));
+    }
+    q.first::<Self>(conn)
   }
 
   fn read_from_name_and_domain(
-    conn: &PgConnection,
+    conn: &mut PgConnection,
     community_name: &str,
     protocol_domain: &str,
   ) -> Result<Community, Error> {
@@ -327,32 +384,33 @@ impl ApubActor for Community {
 #[cfg(test)]
 mod tests {
   use crate::{
-    establish_unpooled_connection,
     source::{community::*, person::*},
     traits::{Bannable, Crud, Followable, Joinable},
+    utils::establish_unpooled_connection,
   };
   use serial_test::serial;
 
   #[test]
   #[serial]
   fn test_crud() {
-    let conn = establish_unpooled_connection();
+    let conn = &mut establish_unpooled_connection();
 
     let new_person = PersonForm {
       name: "bobbee".into(),
+      public_key: Some("pubkey".to_string()),
       ..PersonForm::default()
     };
 
-    let inserted_person = Person::create(&conn, &new_person).unwrap();
+    let inserted_person = Person::create(conn, &new_person).unwrap();
 
     let new_community = CommunityForm {
       name: "TIL".into(),
       title: "nada".to_owned(),
-      public_key: "nada".to_owned(),
+      public_key: Some("pubkey".to_string()),
       ..CommunityForm::default()
     };
 
-    let inserted_community = Community::create(&conn, &new_community).unwrap();
+    let inserted_community = Community::create(conn, &new_community).unwrap();
 
     let expected_community = Community {
       id: inserted_community.id,
@@ -367,7 +425,7 @@ mod tests {
       actor_id: inserted_community.actor_id.to_owned(),
       local: true,
       private_key: None,
-      public_key: "nada".to_owned(),
+      public_key: "pubkey".to_owned(),
       last_refreshed_at: inserted_community.published,
       icon: None,
       banner: None,
@@ -375,6 +433,7 @@ mod tests {
       inbox_url: inserted_community.inbox_url.to_owned(),
       shared_inbox_url: None,
       hidden: false,
+      posting_restricted_to_mods: false,
     };
 
     let community_follower_form = CommunityFollowerForm {
@@ -384,7 +443,7 @@ mod tests {
     };
 
     let inserted_community_follower =
-      CommunityFollower::follow(&conn, &community_follower_form).unwrap();
+      CommunityFollower::follow(conn, &community_follower_form).unwrap();
 
     let expected_community_follower = CommunityFollower {
       id: inserted_community_follower.id,
@@ -400,7 +459,7 @@ mod tests {
     };
 
     let inserted_community_moderator =
-      CommunityModerator::join(&conn, &community_moderator_form).unwrap();
+      CommunityModerator::join(conn, &community_moderator_form).unwrap();
 
     let expected_community_moderator = CommunityModerator {
       id: inserted_community_moderator.id,
@@ -416,7 +475,7 @@ mod tests {
     };
 
     let inserted_community_person_ban =
-      CommunityPersonBan::ban(&conn, &community_person_ban_form).unwrap();
+      CommunityPersonBan::ban(conn, &community_person_ban_form).unwrap();
 
     let expected_community_person_ban = CommunityPersonBan {
       id: inserted_community_person_ban.id,
@@ -426,14 +485,13 @@ mod tests {
       expires: None,
     };
 
-    let read_community = Community::read(&conn, inserted_community.id).unwrap();
-    let updated_community =
-      Community::update(&conn, inserted_community.id, &new_community).unwrap();
-    let ignored_community = CommunityFollower::unfollow(&conn, &community_follower_form).unwrap();
-    let left_community = CommunityModerator::leave(&conn, &community_moderator_form).unwrap();
-    let unban = CommunityPersonBan::unban(&conn, &community_person_ban_form).unwrap();
-    let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
-    Person::delete(&conn, inserted_person.id).unwrap();
+    let read_community = Community::read(conn, inserted_community.id).unwrap();
+    let updated_community = Community::update(conn, inserted_community.id, &new_community).unwrap();
+    let ignored_community = CommunityFollower::unfollow(conn, &community_follower_form).unwrap();
+    let left_community = CommunityModerator::leave(conn, &community_moderator_form).unwrap();
+    let unban = CommunityPersonBan::unban(conn, &community_person_ban_form).unwrap();
+    let num_deleted = Community::delete(conn, inserted_community.id).unwrap();
+    Person::delete(conn, inserted_person.id).unwrap();
 
     assert_eq!(expected_community, read_community);
     assert_eq!(expected_community, inserted_community);