From db1abff857278c621278e4a398095df5d3351e43 Mon Sep 17 00:00:00 2001
From: Nutomic <me@nutomic.com>
Date: Thu, 22 Apr 2021 23:42:58 +0000
Subject: [PATCH] Add option to limit community creation to admins only (fixes
 #1586) (#1587)

* Add option to limit community creation to admins only (fixes #1586)

* address review
---
 crates/api_common/src/site.rs                 |  2 ++
 crates/api_crud/src/community/create.rs       | 23 +++++++++++++------
 crates/api_crud/src/site/create.rs            |  1 +
 crates/api_crud/src/site/read.rs              |  1 +
 crates/api_crud/src/site/update.rs            |  1 +
 .../src/aggregates/site_aggregates.rs         |  1 +
 crates/db_schema/src/schema.rs                |  1 +
 crates/db_schema/src/source/site.rs           |  2 ++
 .../down.sql                                  |  1 +
 .../up.sql                                    |  1 +
 10 files changed, 27 insertions(+), 7 deletions(-)
 create mode 100644 migrations/2021-04-20-155001_limit-admins-create-community/down.sql
 create mode 100644 migrations/2021-04-20-155001_limit-admins-create-community/up.sql

diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs
index 397b5a72..ffee7ba8 100644
--- a/crates/api_common/src/site.rs
+++ b/crates/api_common/src/site.rs
@@ -71,6 +71,7 @@ pub struct CreateSite {
   pub enable_downvotes: bool,
   pub open_registration: bool,
   pub enable_nsfw: bool,
+  pub community_creation_admin_only: bool,
   pub auth: String,
 }
 
@@ -84,6 +85,7 @@ pub struct EditSite {
   pub enable_downvotes: bool,
   pub open_registration: bool,
   pub enable_nsfw: bool,
+  pub community_creation_admin_only: Option<bool>,
   pub auth: String,
 }
 
diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs
index d733966c..88f4415b 100644
--- a/crates/api_crud/src/community/create.rs
+++ b/crates/api_crud/src/community/create.rs
@@ -4,6 +4,7 @@ use lemmy_api_common::{
   blocking,
   community::{CommunityResponse, CreateCommunity},
   get_local_user_view_from_jwt,
+  is_admin,
 };
 use lemmy_apub::{
   generate_apub_endpoint,
@@ -13,13 +14,16 @@ use lemmy_apub::{
   EndpointType,
 };
 use lemmy_db_queries::{diesel_option_overwrite_to_url, ApubObject, Crud, Followable, Joinable};
-use lemmy_db_schema::source::community::{
-  Community,
-  CommunityFollower,
-  CommunityFollowerForm,
-  CommunityForm,
-  CommunityModerator,
-  CommunityModeratorForm,
+use lemmy_db_schema::source::{
+  community::{
+    Community,
+    CommunityFollower,
+    CommunityFollowerForm,
+    CommunityForm,
+    CommunityModerator,
+    CommunityModeratorForm,
+  },
+  site::Site,
 };
 use lemmy_db_views_actor::community_view::CommunityView;
 use lemmy_utils::{
@@ -43,6 +47,11 @@ impl PerformCrud for CreateCommunity {
     let data: &CreateCommunity = &self;
     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
 
+    let site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??;
+    if site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
+      return Err(ApiError::err("only_admins_can_create_communities").into());
+    }
+
     check_slurs(&data.name)?;
     check_slurs(&data.title)?;
     check_slurs_opt(&data.description)?;
diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs
index b9889bf1..dc6e649d 100644
--- a/crates/api_crud/src/site/create.rs
+++ b/crates/api_crud/src/site/create.rs
@@ -67,6 +67,7 @@ impl PerformCrud for CreateSite {
       open_registration: data.open_registration,
       enable_nsfw: data.enable_nsfw,
       updated: None,
+      community_creation_admin_only: Some(data.community_creation_admin_only),
     };
 
     let create_site = move |conn: &'_ _| Site::create(conn, &site_form);
diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs
index d3bf0d2d..e378b26b 100644
--- a/crates/api_crud/src/site/read.rs
+++ b/crates/api_crud/src/site/read.rs
@@ -51,6 +51,7 @@ impl PerformCrud for GetSite {
             open_registration: true,
             enable_nsfw: true,
             auth: login_response.jwt,
+            community_creation_admin_only: false,
           };
           create_site.perform(context, websocket_id).await?;
           info!("Site {} created", setup.site_name);
diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs
index e9c5828d..58f40849 100644
--- a/crates/api_crud/src/site/update.rs
+++ b/crates/api_crud/src/site/update.rs
@@ -65,6 +65,7 @@ impl PerformCrud for EditSite {
       enable_downvotes: data.enable_downvotes,
       open_registration: data.open_registration,
       enable_nsfw: data.enable_nsfw,
+      community_creation_admin_only: data.community_creation_admin_only,
     };
 
     let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
diff --git a/crates/db_queries/src/aggregates/site_aggregates.rs b/crates/db_queries/src/aggregates/site_aggregates.rs
index 995462e1..934a7305 100644
--- a/crates/db_queries/src/aggregates/site_aggregates.rs
+++ b/crates/db_queries/src/aggregates/site_aggregates.rs
@@ -58,6 +58,7 @@ mod tests {
       open_registration: true,
       enable_nsfw: true,
       updated: None,
+      community_creation_admin_only: Some(false),
     };
 
     Site::create(&conn, &site_form).unwrap();
diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs
index f92e43f7..a7008398 100644
--- a/crates/db_schema/src/schema.rs
+++ b/crates/db_schema/src/schema.rs
@@ -433,6 +433,7 @@ table! {
         icon -> Nullable<Varchar>,
         banner -> Nullable<Varchar>,
         description -> Nullable<Text>,
+        community_creation_admin_only -> Bool,
     }
 }
 
diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs
index 41042bc5..67bba993 100644
--- a/crates/db_schema/src/source/site.rs
+++ b/crates/db_schema/src/source/site.rs
@@ -16,6 +16,7 @@ pub struct Site {
   pub icon: Option<DbUrl>,
   pub banner: Option<DbUrl>,
   pub description: Option<String>,
+  pub community_creation_admin_only: bool,
 }
 
 #[derive(Insertable, AsChangeset)]
@@ -32,4 +33,5 @@ pub struct SiteForm {
   pub icon: Option<Option<DbUrl>>,
   pub banner: Option<Option<DbUrl>>,
   pub description: Option<Option<String>>,
+  pub community_creation_admin_only: Option<bool>,
 }
diff --git a/migrations/2021-04-20-155001_limit-admins-create-community/down.sql b/migrations/2021-04-20-155001_limit-admins-create-community/down.sql
new file mode 100644
index 00000000..a04036f4
--- /dev/null
+++ b/migrations/2021-04-20-155001_limit-admins-create-community/down.sql
@@ -0,0 +1 @@
+ALTER TABLE site DROP COLUMN community_creation_admin_only;
diff --git a/migrations/2021-04-20-155001_limit-admins-create-community/up.sql b/migrations/2021-04-20-155001_limit-admins-create-community/up.sql
new file mode 100644
index 00000000..f302f88a
--- /dev/null
+++ b/migrations/2021-04-20-155001_limit-admins-create-community/up.sql
@@ -0,0 +1 @@
+ALTER TABLE site ADD COLUMN community_creation_admin_only bool NOT NULL DEFAULT false;
-- 
2.44.1