FEATURE: Group category permissions tab (#10388)

FEATURE: Group category permissions tab (#10388)

diff --git a/app/assets/javascripts/discourse/app/controllers/group-permissions.js b/app/assets/javascripts/discourse/app/controllers/group-permissions.js
new file mode 100644
index 0000000..7ae8f5a
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/controllers/group-permissions.js
@@ -0,0 +1,3 @@
+import Controller from "@ember/controller";
+
+export default Controller.extend();
diff --git a/app/assets/javascripts/discourse/app/controllers/group.js b/app/assets/javascripts/discourse/app/controllers/group.js
index 9b2f063..e4b62a0 100644
--- a/app/assets/javascripts/discourse/app/controllers/group.js
+++ b/app/assets/javascripts/discourse/app/controllers/group.js
@@ -79,6 +79,13 @@ export default Controller.extend({
       );
     }
 
+    defaultTabs.push(
+      Tab.create({
+        name: "permissions",
+        i18nKey: "permissions.title"
+      })
+    );
+
     return defaultTabs;
   },
 
diff --git a/app/assets/javascripts/discourse/app/models/permission-type.js b/app/assets/javascripts/discourse/app/models/permission-type.js
index 698c2db..305be2d 100644
--- a/app/assets/javascripts/discourse/app/models/permission-type.js
+++ b/app/assets/javascripts/discourse/app/models/permission-type.js
@@ -2,28 +2,24 @@ import I18n from "I18n";
 import discourseComputed from "discourse-common/utils/decorators";
 import EmberObject from "@ember/object";
 
+export function buildPermissionDescription(id) {
+  return I18n.t("permission_types." + PermissionType.DESCRIPTION_KEYS[id]);
+}
+
 const PermissionType = EmberObject.extend({
   @discourseComputed("id")
   description(id) {
-    var key = "";
-
-    switch (id) {
-      case 1:
-        key = "full";
-        break;
-      case 2:
-        key = "create_post";
-        break;
-      case 3:
-        key = "readonly";
-        break;
-    }
-    return I18n.t("permission_types." + key);
+    return buildPermissionDescription(id);
   }
 });
 
 PermissionType.FULL = 1;
 PermissionType.CREATE_POST = 2;
 PermissionType.READONLY = 3;
+PermissionType.DESCRIPTION_KEYS = {
+  1: "full",
+  2: "create_post",
+  3: "readonly"
+};
 
 export default PermissionType;
diff --git a/app/assets/javascripts/discourse/app/routes/app-route-map.js b/app/assets/javascripts/discourse/app/routes/app-route-map.js
index 1e9df27..bee1fd7 100644
--- a/app/assets/javascripts/discourse/app/routes/app-route-map.js
+++ b/app/assets/javascripts/discourse/app/routes/app-route-map.js
@@ -103,6 +103,8 @@ export default function() {
       this.route("inbox");
       this.route("archive");
     });
+
+    this.route("permissions");
   });
 
   // User routes
diff --git a/app/assets/javascripts/discourse/app/routes/group-permissions.js b/app/assets/javascripts/discourse/app/routes/group-permissions.js
new file mode 100644
index 0000000..141721f
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/routes/group-permissions.js
@@ -0,0 +1,34 @@
+import I18n from "I18n";
+import DiscourseRoute from "discourse/routes/discourse";
+import { ajax } from "discourse/lib/ajax";
+import { buildPermissionDescription } from "discourse/models/permission-type";
+
+export default DiscourseRoute.extend({
+  showFooter: true,
+
+  titleToken() {
+    return I18n.t("groups.permissions.title");
+  },
+
+  model() {
+    let group = this.modelFor("group");
+
+    return ajax(`/g/${group.name}/permissions`)
+      .then(permissions => {
+        permissions.forEach(permission => {
+          permission.description = buildPermissionDescription(
+            permission.permission_type
+          );
+        });
+        return { permissions };
+      })
+      .catch(() => {
+        this.transitionTo("group.members", group);
+      });
+  },
+
+  setupController(controller, model) {
+    this.controllerFor("group-permissions").setProperties({ model });
+    this.controllerFor("group").set("showing", "permissions");
+  }
+});
diff --git a/app/assets/javascripts/discourse/app/templates/group/permissions.hbs b/app/assets/javascripts/discourse/app/templates/group/permissions.hbs
new file mode 100644
index 0000000..f4f9d82
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/templates/group/permissions.hbs
@@ -0,0 +1,20 @@
+<section class="user-content">
+  {{#if model.permissions}}
+    <label class="group-category-permissions-desc">
+      {{i18n "groups.permissions.description"}}
+    </label>
+    <table class="group-category-permissions">
+      <tbody>
+        {{#each model.permissions as |permission|}}
+          <tr>
+            <td>{{category-link permission.category}}</td>
+            <td>{{permission.description}}</td>
+          </tr>
+        {{/each}}
+      </tbody>
+    </table>
+  {{else}}
+    {{i18n "groups.permissions.none"}}
+  {{/if}}
+</section>
+
diff --git a/app/assets/stylesheets/common/base/group.scss b/app/assets/stylesheets/common/base/group.scss
index d77e149..c53d771 100644
--- a/app/assets/stylesheets/common/base/group.scss
+++ b/app/assets/stylesheets/common/base/group.scss
@@ -189,3 +189,21 @@ table.group-members {
     }
   }
 }
+
+label.group-category-permissions-desc {
+  font-size: 1.15em;
+  margin-bottom: 1em;
+}
+
+table.group-category-permissions {
+  width: 100%;
+
+  tr {
+    line-height: 3em;
+    width: 100%;
+
+    .category-name {
+      font-size: 1.25em;
+    }
+  }
+}
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 47b1c16..53ca795 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -546,6 +546,12 @@ class GroupsController < ApplicationController
     render_serialized(groups, BasicGroupSerializer)
   end
 
+  def permissions
+    group = find_group(:id)
+    category_groups = group.category_groups.select { |category_group| guardian.can_see_category?(category_group.category) }
+    render_serialized(category_groups.sort_by { |category_group| category_group.category.name }, CategoryGroupSerializer)
+  end
+
   private
 
   def group_params(automatic: false)
diff --git a/app/serializers/category_group_serializer.rb b/app/serializers/category_group_serializer.rb
new file mode 100644
index 0000000..fc44982
--- /dev/null
+++ b/app/serializers/category_group_serializer.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class CategoryGroupSerializer < ApplicationSerializer
+  has_one :category, serializer: CategorySerializer, embed: :objects
+  has_one :group, serializer: BasicGroupSerializer, embed: :objects
+
+  attributes :permission_type
+end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 75d77f0..9a0a16a 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -682,6 +682,10 @@ en:
           details: "Details"
           from: "From"
           to: "To"
+      permissions:
+        title: "Permissions"
+        none: "There are no categories associated with this group."
+        description: "Members of this group can access these categories"
       public_admission: "Allow users to join the group freely (Requires publicly visible group)"
       public_exit: "Allow users to leave the group freely"
       empty:
diff --git a/config/routes.rb b/config/routes.rb
index c124e0b..50083ce 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -585,6 +585,7 @@ Discourse::Application.routes.draw do
             get path => 'groups#show'
           end
 
+          get "permissions" => "groups#permissions"
           put "members" => "groups#add_members"
           delete "members" => "groups#remove_member"
           post "request_membership" => "groups#request_membership"
diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb
index dc9a9e4..c19e0f2 100644
--- a/spec/requests/groups_controller_spec.rb
+++ b/spec/requests/groups_controller_spec.rb
@@ -1747,4 +1747,55 @@ describe GroupsController do
       expect(response.parsed_body["available"]).to eq(true)
     end
   end
+
+  describe "#permissions" do
+    before do

[... diff too long, it was truncated ...]

GitHub sha: b7a092bd

This commit appears in #10388 which was approved by eviltrout. It was merged by markvanlan.

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/show-group-permissions-transparently-on-category-and-topic-pages/15718/11