FEATURE: Invite emails to groups from add member modal (#10308)

FEATURE: Invite emails to groups from add member modal (#10308)

diff --git a/app/assets/javascripts/discourse/app/controllers/group-add-members.js b/app/assets/javascripts/discourse/app/controllers/group-add-members.js
index 0637ac7..283a975 100644
--- a/app/assets/javascripts/discourse/app/controllers/group-add-members.js
+++ b/app/assets/javascripts/discourse/app/controllers/group-add-members.js
@@ -4,42 +4,101 @@ import Controller from "@ember/controller";
 import { extractError } from "discourse/lib/ajax-error";
 import ModalFunctionality from "discourse/mixins/modal-functionality";
 import { action } from "@ember/object";
+import { emailValid } from "discourse/lib/utilities";
+import I18n from "I18n";
 
 export default Controller.extend(ModalFunctionality, {
   loading: false,
   setAsOwner: false,
+  notifyUsers: false,
+  usernamesAndEmails: null,
+  usernames: null,
+  emails: null,
 
-  @discourseComputed("model.usernames", "loading")
-  disableAddButton(usernames, loading) {
-    return loading || !usernames || !(usernames.length > 0);
+  onShow() {
+    this.setProperties({
+      usernamesAndEmails: "",
+      usernames: [],
+      emails: [],
+      setAsOwner: false,
+      notifyUsers: false
+    });
+  },
+
+  @discourseComputed("usernamesAndEmails", "loading")
+  disableAddButton(usernamesAndEmails, loading) {
+    return loading || !usernamesAndEmails || !(usernamesAndEmails.length > 0);
+  },
+
+  @discourseComputed("usernamesAndEmails")
+  emailsPresent() {
+    this._splitEmailsAndUsernames();
+    return this.emails.length;
+  },
+
+  @discourseComputed("usernamesAndEmails")
+  notifyUsersDisabled() {
+    this._splitEmailsAndUsernames();
+    return this.usernames.length === 0 && this.emails.length > 0;
+  },
+
+  @discourseComputed("model.name", "model.full_name")
+  title(name, fullName) {
+    return I18n.t("groups.add_members.title", { group_name: fullName || name });
   },
 
   @action
   addMembers() {
     this.set("loading", true);
 
-    const usernames = this.model.usernames;
-    if (isEmpty(usernames)) {
-      return;
+    if (this.emailsPresent) {
+      this.set("setAsOwner", false);
     }
-    let promise;
 
-    if (this.setAsOwner) {
-      promise = this.model.addOwners(usernames, true);
-    } else {
-      promise = this.model.addMembers(usernames, true);
+    if (this.notifyUsersDisabled) {
+      this.set("notifyUsers", false);
     }
 
+    if (isEmpty(this.usernamesAndEmails)) {
+      return;
+    }
+
+    const promise = this.setAsOwner
+      ? this.model.addOwners(this.usernames, true, this.notifyUsers)
+      : this.model.addMembers(
+          this.usernames,
+          true,
+          this.notifyUsers,
+          this.emails
+        );
+
     promise
       .then(() => {
+        let queryParams = {};
+
+        if (this.usernames) {
+          queryParams.filter = this.usernames;
+        }
+
         this.transitionToRoute("group.members", this.get("model.name"), {
-          queryParams: { filter: usernames }
+          queryParams
         });
 
-        this.model.set("usernames", null);
         this.send("closeModal");
       })
       .catch(error => this.flash(extractError(error), "error"))
       .finally(() => this.set("loading", false));
+  },
+
+  _splitEmailsAndUsernames() {
+    let emails = [];
+    let usernames = [];
+
+    this.usernamesAndEmails.split(",").forEach(u => {
+      emailValid(u) ? emails.push(u) : usernames.push(u);
+    });
+
+    this.set("emails", emails.join(","));
+    this.set("usernames", usernames.join(","));
   }
 });
diff --git a/app/assets/javascripts/discourse/app/controllers/group-bulk-add.js b/app/assets/javascripts/discourse/app/controllers/group-bulk-add.js
deleted file mode 100644
index cf4f869..0000000
--- a/app/assets/javascripts/discourse/app/controllers/group-bulk-add.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import discourseComputed from "discourse-common/utils/decorators";
-import { isEmpty } from "@ember/utils";
-import Controller from "@ember/controller";
-import { extractError } from "discourse/lib/ajax-error";
-import ModalFunctionality from "discourse/mixins/modal-functionality";
-import { ajax } from "discourse/lib/ajax";
-
-export default Controller.extend(ModalFunctionality, {
-  loading: false,
-
-  @discourseComputed("input", "loading", "result")
-  disableAddButton(input, loading, result) {
-    return loading || isEmpty(input) || input.length <= 0 || result;
-  },
-
-  actions: {
-    cancel() {
-      this.set("result", null);
-    },
-
-    add() {
-      this.setProperties({
-        loading: true,
-        result: null
-      });
-
-      const users = this.input
-        .split("\n")
-        .uniq()
-        .reject(x => x.length === 0);
-
-      ajax("/admin/groups/bulk", {
-        data: { users, group_id: this.get("model.id") },
-        type: "PUT"
-      })
-        .then(result => {
-          this.set("result", result);
-
-          if (result.users_not_added) {
-            this.set("result.invalidUsers", result.users_not_added.join(", "));
-          }
-        })
-        .catch(error => {
-          this.flash(extractError(error), "error");
-        })
-        .finally(() => {
-          this.set("loading", false);
-        });
-    }
-  }
-});
diff --git a/app/assets/javascripts/discourse/app/models/group.js b/app/assets/javascripts/discourse/app/models/group.js
index af514bd..889272f 100644
--- a/app/assets/javascripts/discourse/app/models/group.js
+++ b/app/assets/javascripts/discourse/app/models/group.js
@@ -113,10 +113,10 @@ const Group = RestModel.extend({
     }).then(() => this.findMembers(params, true));
   },
 
-  addMembers(usernames, filter) {
+  addMembers(usernames, filter, notifyUsers, emails = []) {
     return ajax(`/groups/${this.id}/members.json`, {
       type: "PUT",
-      data: { usernames }
+      data: { usernames, emails, notify_users: notifyUsers }
     }).then(response => {
       if (filter) {
         this._filterMembers(response);
@@ -126,10 +126,10 @@ const Group = RestModel.extend({
     });
   },
 
-  addOwners(usernames, filter) {
+  addOwners(usernames, filter, notifyUsers) {
     return ajax(`/admin/groups/${this.id}/owners.json`, {
       type: "PUT",
-      data: { group: { usernames } }
+      data: { group: { usernames, notify_users: notifyUsers } }
     }).then(response => {
       if (filter) {
         this._filterMembers(response);
diff --git a/app/assets/javascripts/discourse/app/routes/group-index.js b/app/assets/javascripts/discourse/app/routes/group-index.js
index cdd8310..a67229c 100644
--- a/app/assets/javascripts/discourse/app/routes/group-index.js
+++ b/app/assets/javascripts/discourse/app/routes/group-index.js
@@ -29,11 +29,6 @@ export default DiscourseRoute.extend({
   },
 
   @action
-  showBulkAddModal() {
-    showModal("group-bulk-add", { model: this.modelFor("group") });
-  },
-
-  @action
   didTransition() {
     this.controllerFor("group-index").set("filterInput", this._params.filter);
     return true;
diff --git a/app/assets/javascripts/discourse/app/templates/group-index.hbs b/app/assets/javascripts/discourse/app/templates/group-index.hbs
index 07d46d3..c21bc1b 100644
--- a/app/assets/javascripts/discourse/app/templates/group-index.hbs
+++ b/app/assets/javascripts/discourse/app/templates/group-index.hbs
@@ -13,14 +13,8 @@
       {{#if canManageGroup}}
         {{d-button icon="plus"
         action=(route-action "showAddMembersModal")
-        label="groups.add_members.title"
+        label="groups.manage.add_members"
         class="group-members-add"}}
-        {{#if currentUser.admin}}
-          {{d-button icon="plus"
-          action=(route-action "showBulkAddModal")
-          label="admin.groups.bulk_add.title"
-          class="group-bulk-add"}}
-        {{/if}}
       {{/if}}
     </div>
   </div>
diff --git a/app/assets/javascripts/discourse/app/templates/mobile/group-index.hbs b/app/assets/javascripts/discourse/app/templates/mobile/group-index.hbs
index 7ec5779..0df396b 100644

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

GitHub sha: b76731d7

1 Like

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