Support multi-group user search

Support multi-group user search

diff --git a/app/assets/javascripts/discourse/components/user-selector.js.es6 b/app/assets/javascripts/discourse/components/user-selector.js.es6
index ebc11d4..2cc9544 100644
--- a/app/assets/javascripts/discourse/components/user-selector.js.es6
+++ b/app/assets/javascripts/discourse/components/user-selector.js.es6
@@ -72,7 +72,7 @@ export default TextField.extend({
             allowedUsers,
             includeMentionableGroups,
             includeMessageableGroups,
-            group: userSelectorComponent.group,
+            groupMembersOf: userSelectorComponent.groupMembersOf,
             allowEmails
           });
         },
diff --git a/app/assets/javascripts/discourse/lib/user-search.js.es6 b/app/assets/javascripts/discourse/lib/user-search.js.es6
index fc2e29a..753460f 100644
--- a/app/assets/javascripts/discourse/lib/user-search.js.es6
+++ b/app/assets/javascripts/discourse/lib/user-search.js.es6
@@ -16,7 +16,7 @@ function performSearch(
   includeMentionableGroups,
   includeMessageableGroups,
   allowedUsers,
-  group,
+  groupMembersOf,
   resultsFn
 ) {
   var cached = cache[term];
@@ -40,7 +40,7 @@ function performSearch(
       include_groups: includeGroups,
       include_mentionable_groups: includeMentionableGroups,
       include_messageable_groups: includeMessageableGroups,
-      group: group,
+      groups: groupMembersOf,
       topic_allowed_users: allowedUsers
     }
   });
@@ -140,7 +140,7 @@ export default function userSearch(options) {
     includeMessageableGroups = options.includeMessageableGroups,
     allowedUsers = options.allowedUsers,
     topicId = options.topicId,
-    group = options.group;
+    groupMembersOf = options.groupMembersOf;
 
   if (oldSearch) {
     oldSearch.abort();
@@ -172,7 +172,7 @@ export default function userSearch(options) {
       includeMentionableGroups,
       includeMessageableGroups,
       allowedUsers,
-      group,
+      groupMembersOf,
       function(r) {
         clearTimeout(clearPromise);
         resolve(organizeResults(r, options));
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 6693ab6..5a63496 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -843,15 +843,17 @@ class UsersController < ApplicationController
     topic_id = topic_id.to_i if topic_id
     topic_allowed_users = params[:topic_allowed_users] || false
 
-    if params[:group].present?
-      @group = Group.find_by(name: params[:group])
+    group_names = params[:groups] || []
+    group_names << params[:group] if params[:group]
+    if group_names.present?
+      @groups = Group.where(name: group_names)
     end
 
     results = UserSearch.new(term,
                              topic_id: topic_id,
                              topic_allowed_users: topic_allowed_users,
                              searching_user: current_user,
-                             group: @group
+                             groups: @groups
                             ).search
 
     user_fields = [:username, :upload_avatar_template]
diff --git a/app/models/user_search.rb b/app/models/user_search.rb
index 088c91b..469c4dc 100644
--- a/app/models/user_search.rb
+++ b/app/models/user_search.rb
@@ -13,18 +13,18 @@ class UserSearch
     @searching_user = opts[:searching_user]
     @include_staged_users = opts[:include_staged_users] || false
     @limit = opts[:limit] || 20
-    @group = opts[:group]
+    @groups = opts[:groups]
     @guardian = Guardian.new(@searching_user)
-    @guardian.ensure_can_see_group!(@group) if @group
+    @groups.each { |group| @guardian.ensure_can_see_group!(group) } if @groups
   end
 
   def scoped_users
     users = User.where(active: true)
     users = users.where(staged: false) unless @include_staged_users
 
-    if @group
+    if @groups
       users = users.joins("INNER JOIN group_users ON group_users.user_id = users.id")
-        .where("group_users.group_id = ?", @group.id)
+        .where("group_users.group_id IN (?)", @groups.map(&:id))
     end
 
     unless @searching_user && @searching_user.staff?
diff --git a/spec/models/user_search_spec.rb b/spec/models/user_search_spec.rb
index 3973a78..6d1ae9f 100644
--- a/spec/models/user_search_spec.rb
+++ b/spec/models/user_search_spec.rb
@@ -51,10 +51,22 @@ describe UserSearch do
     _samantha = Fabricate(:user, username: 'samantha')
     group.add(sam)
 
-    results = search_for("sam", group: group)
+    results = search_for("sam", groups: [group])
     expect(results.count).to eq(1)
   end
 
+  it 'allows filtering by multiple groups' do
+    group_1 = Fabricate(:group)
+    sam = Fabricate(:user, username: 'sam')
+    group_2 = Fabricate(:group)
+    samantha = Fabricate(:user, username: 'samantha')
+    group_1.add(sam)
+    group_2.add(samantha)
+
+    results = search_for("sam", groups: [group_1, group_2])
+    expect(results.count).to eq(2)
+  end
+
   # this is a seriously expensive integration test,
   # re-creating this entire test db is too expensive reuse
   it "operates correctly" do
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 30f8b24..6fb0402 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -3021,6 +3021,54 @@ describe UsersController do
           expect(JSON.parse(response.body)).not_to have_key(:groups)
         end
       end
+
+      describe 'when searching by group name' do
+        fab!(:exclusive_group) { Fabricate(:group) }
+
+        it 'return results if the user is a group member' do
+          exclusive_group.add(user)
+
+          get "/u/search/users.json", params: {
+            group: exclusive_group.name,
+            term: user.username
+          }
+
+          expect(users_found).to contain_exactly(user.username)
+        end
+
+        it 'does not return results if the user is not a group member' do
+          get "/u/search/users.json", params: {
+            group: exclusive_group.name,
+            term: user.username
+          }
+
+          expect(users_found).to be_empty
+        end
+
+        it 'returns results if the user is member of one of the groups' do
+          exclusive_group.add(user)
+
+          get "/u/search/users.json", params: {
+            groups: [exclusive_group.name],
+            term: user.username
+          }
+
+          expect(users_found).to contain_exactly(user.username)
+        end
+
+        it 'does not return results if the user is not a member of the groups' do
+          get "/u/search/users.json", params: {
+            groups: [exclusive_group.name],
+            term: user.username
+          }
+
+          expect(users_found).to be_empty
+        end
+
+        def users_found
+          JSON.parse(response.body)['users'].map { |u| u['username'] }
+        end
+      end
     end
   end

GitHub sha: e7ee556e

1 Like