FEATURE: set notification levels when added to a group (#10378)

FEATURE: set notification levels when added to a group (#10378)

  • FEATURE: set notification levels when added to a group

This feature allows admins and group owners to define default category and tag tracking levels that will be applied to user preferences automatically at the time when users are added to the group. Users are free to change those preferences afterwards. When removed from a group, the user’s notification preferences aren’t changed.

diff --git a/app/assets/javascripts/discourse/app/controllers/group-manage-categories.js b/app/assets/javascripts/discourse/app/controllers/group-manage-categories.js
new file mode 100644
index 0000000..629679c
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/controllers/group-manage-categories.js
@@ -0,0 +1,14 @@
+import discourseComputed from "discourse-common/utils/decorators";
+import Controller from "@ember/controller";
+
+export default Controller.extend({
+  @discourseComputed(
+    "model.watchingCategories.[]",
+    "model.watchingFirstPostCategories.[]",
+    "model.trackingCategories.[]",
+    "model.mutedCategories.[]"
+  )
+  selectedCategories(watching, watchingFirst, tracking, muted) {
+    return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
+  }
+});
diff --git a/app/assets/javascripts/discourse/app/controllers/group-manage-tags.js b/app/assets/javascripts/discourse/app/controllers/group-manage-tags.js
new file mode 100644
index 0000000..151365c
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/controllers/group-manage-tags.js
@@ -0,0 +1,14 @@
+import discourseComputed from "discourse-common/utils/decorators";
+import Controller from "@ember/controller";
+
+export default Controller.extend({
+  @discourseComputed(
+    "model.watching_tags.[]",
+    "model.watching_first_post_tags.[]",
+    "model.tracking_tags.[]",
+    "model.muted_tags.[]"
+  )
+  selectedTags(watching, watchingFirst, tracking, muted) {
+    return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
+  }
+});
diff --git a/app/assets/javascripts/discourse/app/controllers/group-manage.js b/app/assets/javascripts/discourse/app/controllers/group-manage.js
index b4fab89..455c7a9 100644
--- a/app/assets/javascripts/discourse/app/controllers/group-manage.js
+++ b/app/assets/javascripts/discourse/app/controllers/group-manage.js
@@ -13,6 +13,14 @@ export default Controller.extend({
         route: "group.manage.interaction",
         title: "groups.manage.interaction.title"
       },
+      {
+        route: "group.manage.categories",
+        title: "groups.manage.categories.title"
+      },
+      {
+        route: "group.manage.tags",
+        title: "groups.manage.tags.title"
+      },
 
       { route: "group.manage.logs", title: "groups.manage.logs.title" }
     ];
diff --git a/app/assets/javascripts/discourse/app/models/group.js b/app/assets/javascripts/discourse/app/models/group.js
index 889272f..883aedc 100644
--- a/app/assets/javascripts/discourse/app/models/group.js
+++ b/app/assets/javascripts/discourse/app/models/group.js
@@ -176,6 +176,35 @@ const Group = RestModel.extend({
     }
   },
 
+  @observes("watching_category_ids")
+  _updateWatchingCategories() {
+    this.set(
+      "watchingCategories",
+      Category.findByIds(this.watching_category_ids)
+    );
+  },
+
+  @observes("tracking_category_ids")
+  _updateTrackingCategories() {
+    this.set(
+      "trackingCategories",
+      Category.findByIds(this.tracking_category_ids)
+    );
+  },
+
+  @observes("watching_first_post_category_ids")
+  _updateWatchingFirstPostCategories() {
+    this.set(
+      "watchingFirstPostCategories",
+      Category.findByIds(this.watching_first_post_category_ids)
+    );
+  },
+
+  @observes("muted_category_ids")
+  _updateMutedCategories() {
+    this.set("mutedCategories", Category.findByIds(this.muted_category_ids));
+  },
+
   asJSON() {
     const attrs = {
       name: this.name,
@@ -211,6 +240,26 @@ const Group = RestModel.extend({
       publish_read_state: this.publish_read_state
     };
 
+    ["muted", "watching", "tracking", "watching_first_post"].forEach(s => {
+      let prop =
+        s === "watching_first_post"
+          ? "watchingFirstPostCategories"
+          : s + "Categories";
+
+      let categories = this.get(prop);
+
+      if (categories) {
+        attrs[s + "_category_ids"] =
+          categories.length > 0 ? categories.map(c => c.get("id")) : [-1];
+      }
+
+      let tags = this.get(s + "_tags");
+
+      if (tags) {
+        attrs[s + "_tags"] = tags.length > 0 ? tags : [""];
+      }
+    });
+
     if (this.flair_type === "icon") {
       attrs["flair_icon"] = this.flair_icon;
     } else if (this.flair_type === "image") {
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 23aa5e2..1e9df27 100644
--- a/app/assets/javascripts/discourse/app/routes/app-route-map.js
+++ b/app/assets/javascripts/discourse/app/routes/app-route-map.js
@@ -94,6 +94,8 @@ export default function() {
       this.route("interaction");
       this.route("email");
       this.route("members");
+      this.route("categories");
+      this.route("tags");
       this.route("logs");
     });
 
diff --git a/app/assets/javascripts/discourse/app/routes/group-manage-categories.js b/app/assets/javascripts/discourse/app/routes/group-manage-categories.js
new file mode 100644
index 0000000..7a03095
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/routes/group-manage-categories.js
@@ -0,0 +1,10 @@
+import I18n from "I18n";
+import DiscourseRoute from "discourse/routes/discourse";
+
+export default DiscourseRoute.extend({
+  showFooter: true,
+
+  titleToken() {
+    return I18n.t("groups.manage.categories.title");
+  }
+});
diff --git a/app/assets/javascripts/discourse/app/routes/group-manage-tags.js b/app/assets/javascripts/discourse/app/routes/group-manage-tags.js
new file mode 100644
index 0000000..a05c258
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/routes/group-manage-tags.js
@@ -0,0 +1,10 @@
+import I18n from "I18n";
+import DiscourseRoute from "discourse/routes/discourse";
+
+export default DiscourseRoute.extend({
+  showFooter: true,
+
+  titleToken() {
+    return I18n.t("groups.manage.tags.title");
+  }
+});
diff --git a/app/assets/javascripts/discourse/app/templates/group/manage/categories.hbs b/app/assets/javascripts/discourse/app/templates/group/manage/categories.hbs
new file mode 100644
index 0000000..c130ce5
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/templates/group/manage/categories.hbs
@@ -0,0 +1,64 @@
+<form class="groups-form form-vertical groups-notifications-form">
+  <div class="control-group">
+    <label class="control-label">{{i18n "groups.manage.categories.long_title"}}</label>
+    <div>{{i18n "groups.manage.categories.description"}}</div>
+  </div>
+
+  <div class="control-group">
+    <label>{{d-icon "d-watching"}} {{i18n "user.watched_categories"}}</label>
+
+    {{category-selector
+      categories=model.watchingCategories
+      blacklist=selectedCategories
+      onChange=(action (mut model.watchingCategories))
+    }}
+
+    <div class="control-instructions">
+      {{i18n "groups.manage.categories.watched_categories_instructions"}}
+    </div>
+  </div>
+
+  <div class="control-group">
+    <label>{{d-icon "d-tracking"}} {{i18n "user.tracked_categories"}}</label>
+
+    {{category-selector
+      categories=model.trackingCategories
+      blacklist=selectedCategories
+      onChange=(action (mut model.trackingCategories))
+    }}
+
+    <div class="control-instructions">
+      {{i18n "groups.manage.categories.tracked_categories_instructions"}}
+    </div>
+  </div>
+
+  <div class="control-group">
+    <label>{{d-icon "d-watching-first"}} {{i18n "user.watched_first_post_categories"}}</label>
+
+    {{category-selector
+      categories=model.watchingFirstPostCategories
+      blacklist=selectedCategories
+      onChange=(action (mut model.watchingFirstPostCategories))
+    }}
+
+    <div class="control-instructions">
+      {{i18n "groups.manage.categories.watching_first_post_categories_instructions"}}
+    </div>
+  </div>
+
+  <div class="control-group">
+    <label>{{d-icon "d-muted"}} {{i18n "user.muted_categories"}}</label>
+
+    {{category-selector
+      categories=model.mutedCategories
+      blacklist=selectedCategories

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

GitHub sha: 1ca81fbb

This commit appears in #10378 which was approved by eviltrout. It was merged by nlalonde.