FEATURE: Add "Group owners" to posting options for groups

FEATURE: Add “Group owners” to posting options for groups

Context: https://meta.discourse.org/t/121589

This new setting option lets group owners message/mention large groups without granting that privilege to all members.

diff --git a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6
index 3b792fd..f475697 100644
--- a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6
+++ b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6
@@ -40,6 +40,7 @@ export default Ember.Component.extend({
       { name: I18n.t("groups.alias_levels.only_admins"), value: 1 },
       { name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 },
       { name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 },
+      { name: I18n.t("groups.alias_levels.owners_mods_and_admins"), value: 4 },
       { name: I18n.t("groups.alias_levels.everyone"), value: 99 }
     ];
   },
diff --git a/app/models/group.rb b/app/models/group.rb
index 19cad44..9251524 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -83,6 +83,7 @@ class Group < ActiveRecord::Base
     only_admins: 1,
     mods_and_admins: 2,
     members_mods_and_admins: 3,
+    owners_mods_and_admins: 4,
     everyone: 99
   }
 
@@ -164,6 +165,9 @@ class Group < ActiveRecord::Base
           (
             messageable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in (
             SELECT group_id FROM group_users WHERE user_id = :user_id)
+          ) OR (
+            messageable_level = #{ALIAS_LEVELS[:owners_mods_and_admins]} AND id in (
+            SELECT group_id FROM group_users WHERE user_id = :user_id AND owner IS TRUE)
           )", levels: alias_levels(user), user_id: user && user.id)
   }
 
@@ -174,7 +178,11 @@ class Group < ActiveRecord::Base
       mentionable_level = #{ALIAS_LEVELS[:members_mods_and_admins]}
       AND id in (
         SELECT group_id FROM group_users WHERE user_id = :user_id)
-      )
+    ) OR (
+      mentionable_level = #{ALIAS_LEVELS[:owners_mods_and_admins]}
+      AND id in (
+        SELECT group_id FROM group_users WHERE user_id = :user_id AND owner IS TRUE)
+    )
     SQL
   end
 
@@ -185,11 +193,13 @@ class Group < ActiveRecord::Base
       levels = [ALIAS_LEVELS[:everyone],
                 ALIAS_LEVELS[:only_admins],
                 ALIAS_LEVELS[:mods_and_admins],
-                ALIAS_LEVELS[:members_mods_and_admins]]
+                ALIAS_LEVELS[:members_mods_and_admins],
+                ALIAS_LEVELS[:owners_mods_and_admins]]
     elsif user && user.moderator?
       levels = [ALIAS_LEVELS[:everyone],
                 ALIAS_LEVELS[:mods_and_admins],
-                ALIAS_LEVELS[:members_mods_and_admins]]
+                ALIAS_LEVELS[:members_mods_and_admins],
+                ALIAS_LEVELS[:owners_mods_and_admins]]
     end
 
     levels
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b7d2452..aad6399 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -661,6 +661,7 @@ en:
         only_admins: "Only admins"
         mods_and_admins: "Only moderators and Admins"
         members_mods_and_admins: "Only group members, moderators and admins"
+        owners_mods_and_admins: "Only group owners, moderators and admins"
         everyone: "Everyone"
       notifications:
         watching:
diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb
index adab91e..aab726c 100644
--- a/spec/components/guardian_spec.rb
+++ b/spec/components/guardian_spec.rb
@@ -346,6 +346,25 @@ describe Guardian do
       end
     end
 
+    it "respects the group members messageable_level" do
+      group.update!(messageable_level: Group::ALIAS_LEVELS[:members_mods_and_admins])
+      expect(Guardian.new(user).can_send_private_message?(group)).to eq(false)
+
+      group.add(user)
+      expect(Guardian.new(user).can_send_private_message?(group)).to eq(true)
+    end
+
+    it "respects the group owners messageable_level" do
+      group.update!(messageable_level: Group::ALIAS_LEVELS[:owners_mods_and_admins])
+      expect(Guardian.new(user).can_send_private_message?(group)).to eq(false)
+
+      group.add(user)
+      expect(Guardian.new(user).can_send_private_message?(group)).to eq(false)
+
+      group.add_owner(user)
+      expect(Guardian.new(user).can_send_private_message?(group)).to eq(true)
+    end
+
     context 'target user has private message disabled' do
       before do
         another_user.user_option.update!(allow_private_messages: false)
diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb
index 5293060..77ce568 100644
--- a/spec/models/post_spec.rb
+++ b/spec/models/post_spec.rb
@@ -1020,6 +1020,23 @@ describe Post do
           )
         end
       end
+
+      describe 'when group owner can mention a group' do
+        before do
+          group.update!(mentionable_level: Group::ALIAS_LEVELS[:owners_mods_and_admins])
+          group.add_owner(post.user)
+        end
+
+        it 'should create the mention' do
+          post.update!(raw: "hello @#{group.name}")
+          post.trigger_post_process
+          post.reload
+
+          expect(post.cooked).to eq(
+            %Q|<p>hello <a class="mention-group" href="/groups/#{group.name}">@#{group.name}</a></p>|
+          )
+        end
+      end
     end
   end
 
diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb
index 9e3c4bb..d8e38e7 100644
--- a/spec/services/post_alerter_spec.rb
+++ b/spec/services/post_alerter_spec.rb
@@ -286,6 +286,14 @@ describe PostAlerter do
       }.to change(evil_trout.notifications, :count).by(0)
 
       expect(GroupMention.count).to eq(3)
+
+      group.update_columns(mentionable_level: Group::ALIAS_LEVELS[:owners_mods_and_admins])
+      group.add_owner(user)
+      expect {
+        create_post_with_alerts(raw: "Hello @group the owner can mention you", user: user)
+      }.to change(evil_trout.notifications, :count).by(1)
+
+      expect(GroupMention.count).to eq(4)
     end
 
     it "triggers :before_create_notifications_for_users" do

GitHub sha: 7b051789