]> Untitled Git - lemmy.git/blobdiff - crates/db_schema/src/impls/community.rs
Cache & Optimize Woodpecker CI (#3450)
[lemmy.git] / crates / db_schema / src / impls / community.rs
index f341b5ed9eb21dfdd7151836fa543212c88f9a79..258e4150442b9473de31a10583381408209f6662 100644 (file)
@@ -1,8 +1,8 @@
 use crate::{
   newtypes::{CommunityId, DbUrl, PersonId},
-  schema::community::dsl::{actor_id, community, deleted, local, name, removed},
+  schema::{community, instance},
   source::{
-    actor_language::{CommunityLanguage, SiteLanguage},
+    actor_language::CommunityLanguage,
     community::{
       Community,
       CommunityFollower,
@@ -12,118 +12,54 @@ use crate::{
       CommunityModeratorForm,
       CommunityPersonBan,
       CommunityPersonBanForm,
-      CommunitySafe,
       CommunityUpdateForm,
     },
   },
-  traits::{ApubActor, Bannable, Crud, DeleteableOrRemoveable, Followable, Joinable},
+  traits::{ApubActor, Bannable, Crud, Followable, Joinable},
   utils::{functions::lower, get_conn, DbPool},
   SubscribedType,
 };
-use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl, TextExpressionMethods};
+use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
 use diesel_async::RunQueryDsl;
 
-mod safe_type {
-  use crate::{
-    schema::community::{
-      actor_id,
-      banner,
-      deleted,
-      description,
-      hidden,
-      icon,
-      id,
-      instance_id,
-      local,
-      name,
-      nsfw,
-      posting_restricted_to_mods,
-      published,
-      removed,
-      title,
-      updated,
-    },
-    source::community::Community,
-    traits::ToSafe,
-  };
-
-  type Columns = (
-    id,
-    name,
-    title,
-    description,
-    removed,
-    published,
-    updated,
-    deleted,
-    nsfw,
-    actor_id,
-    local,
-    icon,
-    banner,
-    hidden,
-    posting_restricted_to_mods,
-    instance_id,
-  );
-
-  impl ToSafe for Community {
-    type SafeColumns = Columns;
-    fn safe_columns_tuple() -> Self::SafeColumns {
-      (
-        id,
-        name,
-        title,
-        description,
-        removed,
-        published,
-        updated,
-        deleted,
-        nsfw,
-        actor_id,
-        local,
-        icon,
-        banner,
-        hidden,
-        posting_restricted_to_mods,
-        instance_id,
-      )
-    }
-  }
-}
-
 #[async_trait]
 impl Crud for Community {
   type InsertForm = CommunityInsertForm;
   type UpdateForm = CommunityUpdateForm;
   type IdType = CommunityId;
-  async fn read(pool: &DbPool, community_id: CommunityId) -> Result<Self, Error> {
+  async fn read(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
-    community.find(community_id).first::<Self>(conn).await
+    community::table
+      .find(community_id)
+      .first::<Self>(conn)
+      .await
   }
 
-  async fn delete(pool: &DbPool, community_id: CommunityId) -> Result<usize, Error> {
+  async fn delete(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result<usize, Error> {
     let conn = &mut get_conn(pool).await?;
-    diesel::delete(community.find(community_id))
+    diesel::delete(community::table.find(community_id))
       .execute(conn)
       .await
   }
 
-  async fn create(pool: &DbPool, form: &Self::InsertForm) -> Result<Self, Error> {
+  async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
+    let is_new_community = match &form.actor_id {
+      Some(id) => Community::read_from_apub_id(pool, id).await?.is_none(),
+      None => true,
+    };
     let conn = &mut get_conn(pool).await?;
-    let community_ = insert_into(community)
+
+    // Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible
+    let community_ = insert_into(community::table)
       .values(form)
-      .on_conflict(actor_id)
+      .on_conflict(community::actor_id)
       .do_update()
       .set(form)
       .get_result::<Self>(conn)
       .await?;
 
-    let site_languages = SiteLanguage::read_local(pool).await;
-    if let Ok(langs) = site_languages {
-      // if site exists, init user with site languages
-      CommunityLanguage::update(pool, langs, community_.id).await?;
-    } else {
-      // otherwise, init with all languages (this only happens during tests)
+    // Initialize languages for new community
+    if is_new_community {
       CommunityLanguage::update(pool, vec![], community_.id).await?;
     }
 
@@ -131,12 +67,12 @@ impl Crud for Community {
   }
 
   async fn update(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_id: CommunityId,
     form: &Self::UpdateForm,
   ) -> Result<Self, Error> {
     let conn = &mut get_conn(pool).await?;
-    diesel::update(community.find(community_id))
+    diesel::update(community::table.find(community_id))
       .set(form)
       .get_result::<Self>(conn)
       .await
@@ -147,7 +83,7 @@ impl Crud for Community {
 impl Joinable for CommunityModerator {
   type Form = CommunityModeratorForm;
   async fn join(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_moderator_form: &CommunityModeratorForm,
   ) -> Result<Self, Error> {
     use crate::schema::community_moderator::dsl::community_moderator;
@@ -159,7 +95,7 @@ impl Joinable for CommunityModerator {
   }
 
   async fn leave(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_moderator_form: &CommunityModeratorForm,
   ) -> Result<usize, Error> {
     use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
@@ -174,26 +110,6 @@ impl Joinable for CommunityModerator {
   }
 }
 
-impl DeleteableOrRemoveable for CommunitySafe {
-  fn blank_out_deleted_or_removed_info(mut self) -> Self {
-    self.title = String::new();
-    self.description = None;
-    self.icon = None;
-    self.banner = None;
-    self
-  }
-}
-
-impl DeleteableOrRemoveable for Community {
-  fn blank_out_deleted_or_removed_info(mut self) -> Self {
-    self.title = String::new();
-    self.description = None;
-    self.icon = None;
-    self.banner = None;
-    self
-  }
-}
-
 pub enum CollectionType {
   Moderators,
   Featured,
@@ -202,20 +118,20 @@ pub enum CollectionType {
 impl Community {
   /// Get the community which has a given moderators or featured url, also return the collection type
   pub async fn get_by_collection_url(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     url: &DbUrl,
   ) -> Result<(Community, CollectionType), Error> {
     use crate::schema::community::dsl::{featured_url, moderators_url};
     use CollectionType::*;
     let conn = &mut get_conn(pool).await?;
-    let res = community
+    let res = community::table
       .filter(moderators_url.eq(url))
       .first::<Self>(conn)
       .await;
     if let Ok(c) = res {
       return Ok((c, Moderators));
     }
-    let res = community
+    let res = community::table
       .filter(featured_url.eq(url))
       .first::<Self>(conn)
       .await;
@@ -228,7 +144,7 @@ impl Community {
 
 impl CommunityModerator {
   pub async fn delete_for_community(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     for_community_id: CommunityId,
   ) -> Result<usize, Error> {
     use crate::schema::community_moderator::dsl::{community_id, community_moderator};
@@ -239,8 +155,19 @@ impl CommunityModerator {
       .await
   }
 
+  pub async fn leave_all_communities(
+    pool: &mut DbPool<'_>,
+    for_person_id: PersonId,
+  ) -> Result<usize, Error> {
+    use crate::schema::community_moderator::dsl::{community_moderator, person_id};
+    let conn = &mut get_conn(pool).await?;
+    diesel::delete(community_moderator.filter(person_id.eq(for_person_id)))
+      .execute(conn)
+      .await
+  }
+
   pub async fn get_person_moderated_communities(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     for_person_id: PersonId,
   ) -> Result<Vec<CommunityId>, Error> {
     use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
@@ -257,7 +184,7 @@ impl CommunityModerator {
 impl Bannable for CommunityPersonBan {
   type Form = CommunityPersonBanForm;
   async fn ban(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_person_ban_form: &CommunityPersonBanForm,
   ) -> Result<Self, Error> {
     use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
@@ -272,7 +199,7 @@ impl Bannable for CommunityPersonBan {
   }
 
   async fn unban(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_person_ban_form: &CommunityPersonBanForm,
   ) -> Result<usize, Error> {
     use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
@@ -306,7 +233,7 @@ impl CommunityFollower {
 #[async_trait]
 impl Followable for CommunityFollower {
   type Form = CommunityFollowerForm;
-  async fn follow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<Self, Error> {
+  async fn follow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<Self, Error> {
     use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
     let conn = &mut get_conn(pool).await?;
     insert_into(community_follower)
@@ -318,7 +245,7 @@ impl Followable for CommunityFollower {
       .await
   }
   async fn follow_accepted(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_id_: CommunityId,
     person_id_: PersonId,
   ) -> Result<Self, Error> {
@@ -338,7 +265,7 @@ impl Followable for CommunityFollower {
     .get_result::<Self>(conn)
     .await
   }
-  async fn unfollow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<usize, Error> {
+  async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
     use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
     let conn = &mut get_conn(pool).await?;
     diesel::delete(
@@ -353,11 +280,14 @@ impl Followable for CommunityFollower {
 
 #[async_trait]
 impl ApubActor for Community {
-  async fn read_from_apub_id(pool: &DbPool, object_id: &DbUrl) -> Result<Option<Self>, Error> {
+  async fn read_from_apub_id(
+    pool: &mut DbPool<'_>,
+    object_id: &DbUrl,
+  ) -> Result<Option<Self>, Error> {
     let conn = &mut get_conn(pool).await?;
     Ok(
-      community
-        .filter(actor_id.eq(object_id))
+      community::table
+        .filter(community::actor_id.eq(object_id))
         .first::<Community>(conn)
         .await
         .ok()
@@ -366,30 +296,34 @@ impl ApubActor for Community {
   }
 
   async fn read_from_name(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_name: &str,
     include_deleted: bool,
   ) -> Result<Community, Error> {
     let conn = &mut get_conn(pool).await?;
-    let mut q = community
+    let mut q = community::table
       .into_boxed()
-      .filter(local.eq(true))
-      .filter(lower(name).eq(lower(community_name)));
+      .filter(community::local.eq(true))
+      .filter(lower(community::name).eq(community_name.to_lowercase()));
     if !include_deleted {
-      q = q.filter(deleted.eq(false)).filter(removed.eq(false));
+      q = q
+        .filter(community::deleted.eq(false))
+        .filter(community::removed.eq(false));
     }
     q.first::<Self>(conn).await
   }
 
   async fn read_from_name_and_domain(
-    pool: &DbPool,
+    pool: &mut DbPool<'_>,
     community_name: &str,
-    protocol_domain: &str,
+    for_domain: &str,
   ) -> Result<Community, Error> {
     let conn = &mut get_conn(pool).await?;
-    community
-      .filter(lower(name).eq(lower(community_name)))
-      .filter(actor_id.like(format!("{protocol_domain}%")))
+    community::table
+      .inner_join(instance::table)
+      .filter(lower(community::name).eq(community_name.to_lowercase()))
+      .filter(instance::domain.eq(for_domain))
+      .select(community::all_columns)
       .first::<Self>(conn)
       .await
   }
@@ -397,6 +331,9 @@ impl ApubActor for Community {
 
 #[cfg(test)]
 mod tests {
+  #![allow(clippy::unwrap_used)]
+  #![allow(clippy::indexing_slicing)]
+
   use crate::{
     source::{
       community::{
@@ -422,6 +359,7 @@ mod tests {
   #[serial]
   async fn test_crud() {
     let pool = &build_db_pool_for_tests().await;
+    let pool = &mut pool.into();
 
     let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
       .await