From 70261ff11c93dcad30b0f4b3b61c4289d0ae1bb3 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 14 Aug 2018 15:43:46 +0200 Subject: add users search results to global search --- app/services/search/global_service.rb | 2 +- app/views/search/_category.html.haml | 5 +++++ app/views/search/results/_user.html.haml | 8 ++++++++ lib/gitlab/search_results.rb | 14 ++++++++++++++ spec/features/global_search_spec.rb | 18 ++++++++++++++++++ spec/lib/gitlab/search_results_spec.rb | 12 ++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 app/views/search/results/_user.html.haml diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index d6af26d949d..b19e9f57450 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -23,7 +23,7 @@ module Search def allowed_scopes strong_memoize(:allowed_scopes) do - %w[issues merge_requests milestones] + %w[issues merge_requests milestones users] end end diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index aaf9b973cda..65c1a30716b 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -78,3 +78,8 @@ = _("Milestones") %span.badge.badge-pill = limited_count(@search_results.limited_milestones_count) + %li{ class: active_when(@scope == 'users') } + = link_to search_filter_path(scope: 'users') do + Users + %span.badge.badge-pill + = limited_count(@search_results.limited_users_count) diff --git a/app/views/search/results/_user.html.haml b/app/views/search/results/_user.html.haml new file mode 100644 index 00000000000..fd454950ef0 --- /dev/null +++ b/app/views/search/results/_user.html.haml @@ -0,0 +1,8 @@ +%ul.content-list + %li + .avatar-cell.d-none.d-sm-block + = user_avatar(user: user, user_name: user.name, css_class: 'd-none d-sm-inline avatar s40') + .user-info + = link_to user_path(user), class: 'd-none d-sm-inline' do + .item-title= user.name + .cgray= user.to_reference diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 491148ec1a6..28946ceacf6 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -32,6 +32,8 @@ module Gitlab merge_requests.page(page).per(per_page) when 'milestones' milestones.page(page).per(per_page) + when 'users' + users.page(page).per(per_page) else Kaminari.paginate_array([]).page(page).per(per_page) end @@ -71,6 +73,12 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord + # rubocop:disable CodeReuse/ActiveRecord + def limited_users_count + @limited_users_count ||= users.limit(count_limit).count + end + # rubocop:enable CodeReuse/ActiveRecord + def single_commit_result? false end @@ -129,6 +137,12 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord + def users + return [] unless Ability.allowed?(current_user, :read_users_list) + + UsersFinder.new(current_user, search: query).execute + end + def default_scope 'projects' end diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index d7692181453..9ecf2cab3b5 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -25,4 +25,22 @@ describe 'Global search' do expect(page).to have_selector('.gl-pagination .next') end end + + describe 'users search' do + it 'shows the found user under the Users tab' do + create(:user, username: 'gob_bluth', name: 'Gob Bluth') + + visit dashboard_projects_path + + fill_in 'search', with: 'gob' + click_button 'Go' + + expect(page).to have_content('Users 1') + + click_on('Users 1') + + expect(page).to have_content('Gob Bluth') + expect(page).to have_content('@gob_bluth') + end + end end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index 87288baedb0..3d14eebc2c1 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -121,6 +121,18 @@ describe Gitlab::SearchResults do results.objects('issues') end end + + describe '#users' do + it 'returns an empty array when the current_user is not allowed to read users list' do + expect(results.objects('users')).to be_empty + end + + it 'calls the UsersFinder' do + expect(UsersFinder).to receive(:new).with(user, search: 'foo').and_call_original + + results.objects('users') + end + end end it 'does not list issues on private projects' do -- cgit v1.2.1 From 22f44b50d8ece6cdb2d83cb8e2b1c5b51f01d70d Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 13:53:23 +0200 Subject: add users search results to project scoped search --- app/services/search/project_service.rb | 2 +- app/views/search/_category.html.haml | 6 +++ lib/gitlab/project_search_results.rb | 6 +++ spec/features/global_search_spec.rb | 18 -------- .../search/user_searches_for_users_spec.rb | 53 ++++++++++++++++++++++ spec/lib/gitlab/project_search_results_spec.rb | 16 +++++++ 6 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 spec/features/search/user_searches_for_users_spec.rb diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb index f223c8be103..0d82c5cd5b2 100644 --- a/app/services/search/project_service.rb +++ b/app/services/search/project_service.rb @@ -16,7 +16,7 @@ module Search end def scope - @scope ||= %w[notes issues merge_requests milestones wiki_blobs commits].delete(params[:scope]) { 'blobs' } + @scope ||= %w[notes issues merge_requests milestones wiki_blobs commits users].delete(params[:scope]) { 'blobs' } end end end diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index 65c1a30716b..79923aeeebf 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -45,6 +45,12 @@ = _("Commits") %span.badge.badge-pill = @search_results.commits_count + - if can?(current_user, :read_users_list) + %li{ class: active_when(@scope == 'users') } + = link_to search_filter_path(scope: 'users') do + Users + %span.badge.badge-pill + = limited_count(@search_results.limited_users_count) - elsif @show_snippets %li{ class: active_when(@scope == 'snippet_blobs') } diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index a68f8801c2a..0957d1b6149 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -22,11 +22,17 @@ module Gitlab paginated_blobs(wiki_blobs, page) when 'commits' Kaminari.paginate_array(commits).page(page).per(per_page) + when 'users' + users.page(page).per(per_page) else super(scope, page, false) end end + def users + super.where(id: @project.users) + end + def blobs_count @blobs_count ||= blobs.count end diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index 9ecf2cab3b5..d7692181453 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -25,22 +25,4 @@ describe 'Global search' do expect(page).to have_selector('.gl-pagination .next') end end - - describe 'users search' do - it 'shows the found user under the Users tab' do - create(:user, username: 'gob_bluth', name: 'Gob Bluth') - - visit dashboard_projects_path - - fill_in 'search', with: 'gob' - click_button 'Go' - - expect(page).to have_content('Users 1') - - click_on('Users 1') - - expect(page).to have_content('Gob Bluth') - expect(page).to have_content('@gob_bluth') - end - end end diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb new file mode 100644 index 00000000000..ba4b66c78cb --- /dev/null +++ b/spec/features/search/user_searches_for_users_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe 'User searches for users' do + context 'when on the dashboard' do + it 'finds the user' do + create(:user, username: 'gob_bluth', name: 'Gob Bluth') + + sign_in(create(:user)) + + visit dashboard_projects_path + + fill_in 'search', with: 'gob' + click_button 'Go' + + expect(page).to have_content('Users 1') + + click_on('Users 1') + + expect(page).to have_content('Gob Bluth') + expect(page).to have_content('@gob_bluth') + end + end + + context 'when on the project page' do + it 'finds the user belonging to the project' do + project = create(:project) + + user1 = create(:user, username: 'gob_bluth', name: 'Gob Bluth') + create(:project_member, :developer, user: user1, project: project) + + user2 = create(:user, username: 'michael_bluth', name: 'Michael Bluth') + create(:project_member, :developer, user: user2, project: project) + + create(:user, username: 'gob_2018', name: 'George Oscar Bluth') + + sign_in(user1) + + visit projects_path(project) + + fill_in 'search', with: 'gob' + click_button 'Go' + + expect(page).to have_content('Gob Bluth') + expect(page).to have_content('@gob_bluth') + + expect(page).not_to have_content('Michael Bluth') + expect(page).not_to have_content('@michael_bluth') + + expect(page).not_to have_content('George Oscar Bluth') + expect(page).not_to have_content('@gob_2018') + end + end +end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 6831274d37c..a5495184448 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -412,4 +412,20 @@ describe Gitlab::ProjectSearchResults do end end end + + describe 'user search' do + let(:project) { create(:project) } + + it 'returns the users belonging to the project matching the search query' do + user1 = create(:user, username: 'gob_bluth') + create(:project_member, :developer, user: user1, project: project) + + user2 = create(:user, username: 'michael_bluth') + create(:project_member, :developer, user: user2, project: project) + + create(:user, username: 'gob_2018') + + expect(described_class.new(user, project, 'gob').objects('users')).to eq [user1] + end + end end -- cgit v1.2.1 From 65df88c4907195ea789bd5b35ddde1305b7c199a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 13:56:24 +0200 Subject: move ability check from service class to view --- app/views/search/_category.html.haml | 11 ++++++----- lib/gitlab/search_results.rb | 2 -- spec/lib/gitlab/search_results_spec.rb | 4 ---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index 79923aeeebf..e9fdf3dbbc1 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -84,8 +84,9 @@ = _("Milestones") %span.badge.badge-pill = limited_count(@search_results.limited_milestones_count) - %li{ class: active_when(@scope == 'users') } - = link_to search_filter_path(scope: 'users') do - Users - %span.badge.badge-pill - = limited_count(@search_results.limited_users_count) + - if can?(current_user, :read_users_list) + %li{ class: active_when(@scope == 'users') } + = link_to search_filter_path(scope: 'users') do + Users + %span.badge.badge-pill + = limited_count(@search_results.limited_users_count) diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 28946ceacf6..dd8854a89d4 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -138,8 +138,6 @@ module Gitlab # rubocop: enable CodeReuse/ActiveRecord def users - return [] unless Ability.allowed?(current_user, :read_users_list) - UsersFinder.new(current_user, search: query).execute end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index 3d14eebc2c1..1a42fd36de0 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -123,10 +123,6 @@ describe Gitlab::SearchResults do end describe '#users' do - it 'returns an empty array when the current_user is not allowed to read users list' do - expect(results.objects('users')).to be_empty - end - it 'calls the UsersFinder' do expect(UsersFinder).to receive(:new).with(user, search: 'foo').and_call_original -- cgit v1.2.1 From a52d1dbb0f7a32964ee86977cec5236cce027a93 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 14:03:55 +0200 Subject: dry up the use of the user search tab --- app/views/search/_category.html.haml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index e9fdf3dbbc1..19d7d13512d 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -1,3 +1,11 @@ +- users = capture_haml do + - if can?(current_user, :read_users_list) + %li{ class: active_when(@scope == 'users') } + = link_to search_filter_path(scope: 'users') do + Users + %span.badge.badge-pill + = limited_count(@search_results.limited_users_count) + .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller .fade-left= icon('angle-left') .fade-right= icon('angle-right') @@ -45,12 +53,7 @@ = _("Commits") %span.badge.badge-pill = @search_results.commits_count - - if can?(current_user, :read_users_list) - %li{ class: active_when(@scope == 'users') } - = link_to search_filter_path(scope: 'users') do - Users - %span.badge.badge-pill - = limited_count(@search_results.limited_users_count) + = users - elsif @show_snippets %li{ class: active_when(@scope == 'snippet_blobs') } @@ -84,9 +87,4 @@ = _("Milestones") %span.badge.badge-pill = limited_count(@search_results.limited_milestones_count) - - if can?(current_user, :read_users_list) - %li{ class: active_when(@scope == 'users') } - = link_to search_filter_path(scope: 'users') do - Users - %span.badge.badge-pill - = limited_count(@search_results.limited_users_count) + = users -- cgit v1.2.1 From a8818bab76fe89bb8ab5960c614e2b734bd2c496 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 15:25:17 +0200 Subject: add users search results to group scoped search --- app/services/search/group_service.rb | 6 +++++ lib/gitlab/group_search_results.rb | 17 ++++++++++++ .../search/user_searches_for_users_spec.rb | 30 +++++++++++++++++++++ spec/lib/gitlab/group_search_results_spec.rb | 31 ++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 lib/gitlab/group_search_results.rb create mode 100644 spec/lib/gitlab/group_search_results_spec.rb diff --git a/app/services/search/group_service.rb b/app/services/search/group_service.rb index 34803d005e3..6f3b5f00b86 100644 --- a/app/services/search/group_service.rb +++ b/app/services/search/group_service.rb @@ -11,6 +11,12 @@ module Search @group = group end + def execute + Gitlab::GroupSearchResults.new( + current_user, projects, group, params[:search], default_project_filter: default_project_filter + ) + end + def projects return Project.none unless group return @projects if defined? @projects diff --git a/lib/gitlab/group_search_results.rb b/lib/gitlab/group_search_results.rb new file mode 100644 index 00000000000..0654d5e25b4 --- /dev/null +++ b/lib/gitlab/group_search_results.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Gitlab + class GroupSearchResults < SearchResults + def initialize(current_user, limit_projects, group, query, default_project_filter: false, per_page: 20) + super(current_user, limit_projects, query, default_project_filter: default_project_filter, per_page: per_page) + + @group = group + end + + # rubocop:disable CodeReuse/ActiveRecord + def users + super.where(id: @group.users_with_descendants) + end + # rubocop:enable CodeReuse/ActiveRecord + end +end diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb index ba4b66c78cb..3725143291d 100644 --- a/spec/features/search/user_searches_for_users_spec.rb +++ b/spec/features/search/user_searches_for_users_spec.rb @@ -50,4 +50,34 @@ describe 'User searches for users' do expect(page).not_to have_content('@gob_2018') end end + + context 'when on the group page' do + it 'finds the user belonging to the group' do + group = create(:group) + + user1 = create(:user, username: 'gob_bluth', name: 'Gob Bluth') + create(:group_member, :developer, user: user1, group: group) + + user2 = create(:user, username: 'michael_bluth', name: 'Michael Bluth') + create(:group_member, :developer, user: user2, group: group) + + create(:user, username: 'gob_2018', name: 'George Oscar Bluth') + + sign_in(user1) + + visit group_path(group) + + fill_in 'search', with: 'gob' + click_button 'Go' + + expect(page).to have_content('Gob Bluth') + expect(page).to have_content('@gob_bluth') + + expect(page).not_to have_content('Michael Bluth') + expect(page).not_to have_content('@michael_bluth') + + expect(page).not_to have_content('George Oscar Bluth') + expect(page).not_to have_content('@gob_2018') + end + end end diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb new file mode 100644 index 00000000000..22ea3ebb9a4 --- /dev/null +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe Gitlab::GroupSearchResults do + let(:user) { create(:user) } + + describe 'user search' do + let(:group) { create(:group) } + + it 'returns the users belonging to the group matching the search query' do + user1 = create(:user, username: 'gob_bluth') + create(:group_member, :developer, user: user1, group: group) + + user2 = create(:user, username: 'michael_bluth') + create(:group_member, :developer, user: user2, group: group) + + create(:user, username: 'gob_2018') + + expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [user1] + end + + it 'returns the user belonging to the subgroup matching the search query', :nested_groups do + user1 = create(:user, username: 'gob_bluth') + subgroup = create(:group, parent: group) + create(:group_member, :developer, user: user1, group: subgroup) + + create(:user, username: 'gob_2018') + + expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [user1] + end + end +end -- cgit v1.2.1 From 40962ac4aa5a900af14c045a812144a22f512991 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 15:40:56 +0200 Subject: add changelog --- changelogs/unreleased/feature-users-search-results.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/feature-users-search-results.yml diff --git a/changelogs/unreleased/feature-users-search-results.yml b/changelogs/unreleased/feature-users-search-results.yml new file mode 100644 index 00000000000..151d08bce12 --- /dev/null +++ b/changelogs/unreleased/feature-users-search-results.yml @@ -0,0 +1,5 @@ +--- +title: Add users search results to global search +merge_request: 21197 +author: Alexis Reigel +type: added -- cgit v1.2.1 From 5a45b54fd96a49ca83dcf9e2d06c1bdcdacaa59e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 15 Aug 2018 21:18:45 +0200 Subject: search results: show user's status emoji --- app/controllers/search_controller.rb | 5 +++++ app/views/search/results/_user.html.haml | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 1b22907c10f..a7b789f848a 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -29,6 +29,7 @@ class SearchController < ApplicationController @search_objects = search_service.search_objects render_commits if @scope == 'commits' + eager_load_user_status if @scope == 'users' check_single_commit_result end @@ -54,6 +55,10 @@ class SearchController < ApplicationController @search_objects = prepare_commits_for_rendering(@search_objects) end + def eager_load_user_status + @search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord + end + def check_single_commit_result if @search_results.single_commit_result? only_commit = @search_results.objects('commits').first diff --git a/app/views/search/results/_user.html.haml b/app/views/search/results/_user.html.haml index fd454950ef0..8060a1577e4 100644 --- a/app/views/search/results/_user.html.haml +++ b/app/views/search/results/_user.html.haml @@ -4,5 +4,7 @@ = user_avatar(user: user, user_name: user.name, css_class: 'd-none d-sm-inline avatar s40') .user-info = link_to user_path(user), class: 'd-none d-sm-inline' do - .item-title= user.name + .item-title + = user.name + = user_status(user) .cgray= user.to_reference -- cgit v1.2.1 From 0592233a1add02c02a706ae1aa2f66661155146a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 17 Sep 2018 14:54:32 +0200 Subject: add users search to search api --- doc/api/search.md | 69 +++++++++++++++++++++++++++++++++++++-- lib/api/helpers/search_helpers.rb | 6 ++-- lib/api/search.rb | 3 +- spec/requests/api/search_spec.rb | 43 ++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 7 deletions(-) diff --git a/doc/api/search.md b/doc/api/search.md index aa601648b2c..169b6730bdd 100644 --- a/doc/api/search.md +++ b/doc/api/search.md @@ -17,7 +17,7 @@ GET /search | `scope` | string | yes | The scope to search in | | `search` | string | yes | The search query | -Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, snippet_blobs. +Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, snippet_blobs, users. The response depends on the requested scope. @@ -281,6 +281,27 @@ Example response: ] ``` +### Scope: users + +```bash +curl --request GET --header "PRIVATE-TOKEN: " https://gitlab.example.com/api/v4/search?scope=users&search=doe +``` + +Example response: + +```json +[ + { + "id": 1, + "name": "John Doe1", + "username": "user1", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", + "web_url": "http://localhost/user1" + } +] +``` + ## Group Search API Search within the specified group. @@ -297,7 +318,7 @@ GET /groups/:id/search | `scope` | string | yes | The scope to search in | | `search` | string | yes | The search query | -Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones. +Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, users. The response depends on the requested scope. @@ -499,6 +520,27 @@ Example response: ] ``` +### Scope: users + +```bash +curl --request GET --header "PRIVATE-TOKEN: " https://gitlab.example.com/api/v4/groups/3/search?scope=users&search=doe +``` + +Example response: + +```json +[ + { + "id": 1, + "name": "John Doe1", + "username": "user1", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", + "web_url": "http://localhost/user1" + } +] +``` + ## Project Search API Search within the specified project. @@ -515,7 +557,7 @@ GET /projects/:id/search | `scope` | string | yes | The scope to search in | | `search` | string | yes | The search query | -Search the expression within the specified scope. Currently these scopes are supported: issues, merge_requests, milestones, notes, wiki_blobs, commits, blobs. +Search the expression within the specified scope. Currently these scopes are supported: issues, merge_requests, milestones, notes, wiki_blobs, commits, blobs, users. The response depends on the requested scope. @@ -828,4 +870,25 @@ Example response: ] ``` +### Scope: users + +```bash +curl --request GET --header "PRIVATE-TOKEN: " https://gitlab.example.com/api/v4/projects/6/search?scope=users&search=doe +``` + +Example response: + +```json +[ + { + "id": 1, + "name": "John Doe1", + "username": "user1", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", + "web_url": "http://localhost/user1" + } +] +``` + [ce-41763]: https://gitlab.com/gitlab-org/gitlab-ce/issues/41763 diff --git a/lib/api/helpers/search_helpers.rb b/lib/api/helpers/search_helpers.rb index 47fb5a36327..0e052e0e273 100644 --- a/lib/api/helpers/search_helpers.rb +++ b/lib/api/helpers/search_helpers.rb @@ -5,17 +5,17 @@ module API module SearchHelpers def self.global_search_scopes # This is a separate method so that EE can redefine it. - %w(projects issues merge_requests milestones snippet_titles snippet_blobs) + %w(projects issues merge_requests milestones snippet_titles snippet_blobs users) end def self.group_search_scopes # This is a separate method so that EE can redefine it. - %w(projects issues merge_requests milestones) + %w(projects issues merge_requests milestones users) end def self.project_search_scopes # This is a separate method so that EE can redefine it. - %w(issues merge_requests milestones notes wiki_blobs commits blobs) + %w(issues merge_requests milestones notes wiki_blobs commits blobs users) end end end diff --git a/lib/api/search.rb b/lib/api/search.rb index f65e810bf90..431c45a386a 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -17,7 +17,8 @@ module API blobs: Entities::Blob, wiki_blobs: Entities::Blob, snippet_titles: Entities::Snippet, - snippet_blobs: Entities::Snippet + snippet_blobs: Entities::Snippet, + users: Entities::UserBasic }.freeze def search(additional_params = {}) diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb index c48ca832c85..0f539fb6c60 100644 --- a/spec/requests/api/search_spec.rb +++ b/spec/requests/api/search_spec.rb @@ -77,6 +77,16 @@ describe API::Search do it_behaves_like 'response is correct', schema: 'public_api/v4/milestones' end + context 'for users scope' do + before do + create(:user, name: 'billy') + + get api('/search', user), scope: 'users', search: 'billy' + end + + it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + end + context 'for snippet_titles scope' do before do create(:snippet, :public, title: 'awesome snippet', content: 'snippet content') @@ -192,6 +202,28 @@ describe API::Search do it_behaves_like 'response is correct', schema: 'public_api/v4/milestones' end + + context 'for user scope' do + before do + user = create(:user, name: 'billy') + create(:group_member, :developer, user: user, group: group) + + get api("/groups/#{group.id}/search", user), scope: 'users', search: 'billy' + end + + it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + end + + context 'for users scope with group path as id' do + before do + user1 = create(:user, name: 'billy') + create(:group_member, :developer, user: user1, group: group) + + get api("/groups/#{CGI.escape(group.full_path)}/search", user), scope: 'users', search: 'billy' + end + + it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + end end end @@ -269,6 +301,17 @@ describe API::Search do it_behaves_like 'response is correct', schema: 'public_api/v4/milestones' end + context 'for users scope' do + before do + user1 = create(:user, name: 'billy') + create(:project_member, :developer, user: user1, project: project) + + get api("/projects/#{project.id}/search", user), scope: 'users', search: 'billy' + end + + it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + end + context 'for notes scope' do before do create(:note_on_merge_request, project: project, note: 'awesome note') -- cgit v1.2.1 From d7a3e54be4af3206681b3e81c746e3f7c31f52e5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 17 Sep 2018 17:37:20 +0200 Subject: only users from groups the current user has access --- lib/gitlab/group_search_results.rb | 9 ++++++++- spec/lib/gitlab/group_search_results_spec.rb | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/group_search_results.rb b/lib/gitlab/group_search_results.rb index 0654d5e25b4..8223135dc07 100644 --- a/lib/gitlab/group_search_results.rb +++ b/lib/gitlab/group_search_results.rb @@ -10,7 +10,14 @@ module Gitlab # rubocop:disable CodeReuse/ActiveRecord def users - super.where(id: @group.users_with_descendants) + # 1: get all groups the current user has access to + groups = GroupsFinder.new(current_user).execute.joins(:users) + + # 2: get all users the current user has access to (-> `SearchResults#users`) + users = super + + # 3: filter for users that belong to the previously selected groups + users.where(id: groups.select('members.user_id')) end # rubocop:enable CodeReuse/ActiveRecord end diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb index 22ea3ebb9a4..a9f94038524 100644 --- a/spec/lib/gitlab/group_search_results_spec.rb +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -27,5 +27,15 @@ describe Gitlab::GroupSearchResults do expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [user1] end + + it 'does not return the user belonging to the private subgroup', :nested_groups do + user1 = create(:user, username: 'gob_bluth') + subgroup = create(:group, :private, parent: group) + create(:group_member, :developer, user: user1, group: subgroup) + + create(:user, username: 'gob_2018') + + expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [] + end end end -- cgit v1.2.1 From 241f38b01d6ba3fdbed0a1f8b74b354441d79fb2 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Dec 2018 13:25:52 +0100 Subject: project's user search includes group members too --- lib/gitlab/project_search_results.rb | 2 +- spec/lib/gitlab/project_search_results_spec.rb | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 0957d1b6149..58f06b6708c 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -30,7 +30,7 @@ module Gitlab end def users - super.where(id: @project.users) + super.where(id: @project.team.members) # rubocop:disable CodeReuse/ActiveRecord end def blobs_count diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index a5495184448..4a41d5cf51e 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -414,9 +414,9 @@ describe Gitlab::ProjectSearchResults do end describe 'user search' do - let(:project) { create(:project) } + it 'returns the user belonging to the project matching the search query' do + project = create(:project) - it 'returns the users belonging to the project matching the search query' do user1 = create(:user, username: 'gob_bluth') create(:project_member, :developer, user: user1, project: project) @@ -425,7 +425,23 @@ describe Gitlab::ProjectSearchResults do create(:user, username: 'gob_2018') - expect(described_class.new(user, project, 'gob').objects('users')).to eq [user1] + result = described_class.new(user, project, 'gob').objects('users') + + expect(result).to eq [user1] + end + + it 'returns the user belonging to the group matching the search query' do + group = create(:group) + project = create(:project, namespace: group) + + user1 = create(:user, username: 'gob_bluth') + create(:group_member, :developer, user: user1, group: group) + + create(:user, username: 'gob_2018') + + result = described_class.new(user, project, 'gob').objects('users') + + expect(result).to eq [user1] end end end -- cgit v1.2.1 From 3b01d23af0a17e269bbd39eab0d54b55d9b84b3e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Dec 2018 14:05:49 +0100 Subject: spec for group's user search incl. parent group --- spec/lib/gitlab/group_search_results_spec.rb | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb index a9f94038524..02245ca88dc 100644 --- a/spec/lib/gitlab/group_search_results_spec.rb +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -15,7 +15,9 @@ describe Gitlab::GroupSearchResults do create(:user, username: 'gob_2018') - expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [user1] + result = described_class.new(user, anything, group, 'gob').objects('users') + + expect(result).to eq [user1] end it 'returns the user belonging to the subgroup matching the search query', :nested_groups do @@ -25,7 +27,21 @@ describe Gitlab::GroupSearchResults do create(:user, username: 'gob_2018') - expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [user1] + result = described_class.new(user, anything, group, 'gob').objects('users') + + expect(result).to eq [user1] + end + + it 'returns the user belonging to the parent group matching the search query', :nested_groups do + user1 = create(:user, username: 'gob_bluth') + parent_group = create(:group, children: [group]) + create(:group_member, :developer, user: user1, group: parent_group) + + create(:user, username: 'gob_2018') + + result = described_class.new(user, anything, group, 'gob').objects('users') + + expect(result).to eq [user1] end it 'does not return the user belonging to the private subgroup', :nested_groups do @@ -35,7 +51,9 @@ describe Gitlab::GroupSearchResults do create(:user, username: 'gob_2018') - expect(described_class.new(user, anything, group, 'gob').objects('users')).to eq [] + result = described_class.new(user, anything, group, 'gob').objects('users') + + expect(result).to eq [] end end end -- cgit v1.2.1 From db0cf709703f0cc344351d2a8fd28d7d51046296 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 17 Dec 2018 14:30:49 +0100 Subject: restrict user result set by the scoped group --- lib/gitlab/group_search_results.rb | 12 +++++++++--- spec/lib/gitlab/group_search_results_spec.rb | 10 ++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/group_search_results.rb b/lib/gitlab/group_search_results.rb index 8223135dc07..7255293b194 100644 --- a/lib/gitlab/group_search_results.rb +++ b/lib/gitlab/group_search_results.rb @@ -13,11 +13,17 @@ module Gitlab # 1: get all groups the current user has access to groups = GroupsFinder.new(current_user).execute.joins(:users) - # 2: get all users the current user has access to (-> `SearchResults#users`) + # 2: Get the group's whole hierarchy + group_users = @group.direct_and_indirect_users + + # 3: get all users the current user has access to (-> + # `SearchResults#users`), which also applies the query. users = super - # 3: filter for users that belong to the previously selected groups - users.where(id: groups.select('members.user_id')) + # 4: filter for users that belong to the previously selected groups + users + .where(id: group_users.select('id')) + .where(id: groups.select('members.user_id')) end # rubocop:enable CodeReuse/ActiveRecord end diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb index 02245ca88dc..2734fcef0a0 100644 --- a/spec/lib/gitlab/group_search_results_spec.rb +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -55,5 +55,15 @@ describe Gitlab::GroupSearchResults do expect(result).to eq [] end + + it 'does not return the user belonging to an unrelated group' do + user = create(:user, username: 'gob_bluth') + unrelated_group = create(:group) + create(:group_member, :developer, user: user, group: unrelated_group) + + result = described_class.new(user, anything, group, 'gob').objects('users') + + expect(result).to eq [] + end end end -- cgit v1.2.1 From b4437cfaecfcd0f48079a2027920e828ea1c7e48 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 18 Dec 2018 09:35:54 +0100 Subject: use project_search_tabs? for user search check --- app/helpers/projects_helper.rb | 3 ++- app/helpers/search_helper.rb | 8 ++++++++ app/views/search/_category.html.haml | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 2ac8ddc5244..5496aa4908c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -364,7 +364,8 @@ module ProjectsHelper blobs: :download_code, commits: :download_code, merge_requests: :read_merge_request, - notes: [:read_merge_request, :download_code, :read_issue, :read_project_snippet] + notes: [:read_merge_request, :download_code, :read_issue, :read_project_snippet], + members: :read_project_member ) end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 0ee76a51f7d..97fcb200c67 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -201,4 +201,12 @@ module SearchHelper def limited_count(count, limit = 1000) count > limit ? "#{limit}+" : count end + + def search_tabs?(tab) + if @project + project_search_tabs?(:members) + else + can?(current_user, :read_users_list) + end + end end diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index 19d7d13512d..df408e5fb60 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -1,5 +1,5 @@ - users = capture_haml do - - if can?(current_user, :read_users_list) + - if search_tabs?(:members) %li{ class: active_when(@scope == 'users') } = link_to search_filter_path(scope: 'users') do Users -- cgit v1.2.1 From 4c684a8d5c5432a720577486451830f085994fd3 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 18 Dec 2018 13:51:26 +0100 Subject: check ability for user search results --- lib/gitlab/search_results.rb | 2 ++ spec/lib/gitlab/search_results_spec.rb | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index dd8854a89d4..301d5e326d9 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -138,6 +138,8 @@ module Gitlab # rubocop: enable CodeReuse/ActiveRecord def users + return User.none unless Ability.allowed?(current_user, :read_users_list) + UsersFinder.new(current_user, search: query).execute end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index 1a42fd36de0..4b57eecff93 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -123,6 +123,14 @@ describe Gitlab::SearchResults do end describe '#users' do + it 'does not call the UsersFinder when the current_user is not allowed to read users list' do + allow(Ability).to receive(:allowed?).and_return(false) + + expect(UsersFinder).not_to receive(:new).with(user, search: 'foo').and_call_original + + results.objects('users') + end + it 'calls the UsersFinder' do expect(UsersFinder).to receive(:new).with(user, search: 'foo').and_call_original -- cgit v1.2.1 From c36d98501b86e12d03d9a66d3ada9688531f6cd8 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 19 Dec 2018 14:49:46 +0100 Subject: extract helper for search scope api param --- lib/api/search.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/api/search.rb b/lib/api/search.rb index 431c45a386a..01eaf2f142a 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -52,6 +52,15 @@ module API # Defining this method here as a noop allows us to easily extend it in # EE, without having to modify this file directly. end + + params :scope do |options| + values = SCOPE_ENTITY.stringify_keys.slice(*options[:values]).keys + + requires :scope, + type: String, + desc: 'The scope of the search', + values: values + end end resource :search do @@ -60,10 +69,7 @@ module API end params do requires :search, type: String, desc: 'The expression it should be searched for' - requires :scope, - type: String, - desc: 'The scope of the search', - values: Helpers::SearchHelpers.global_search_scopes + use :scope, values: Helpers::SearchHelpers.global_search_scopes use :pagination end get do @@ -80,10 +86,7 @@ module API params do requires :id, type: String, desc: 'The ID of a group' requires :search, type: String, desc: 'The expression it should be searched for' - requires :scope, - type: String, - desc: 'The scope of the search', - values: Helpers::SearchHelpers.group_search_scopes + use :scope, values: Helpers::SearchHelpers.group_search_scopes use :pagination end get ':id/(-/)search' do @@ -100,10 +103,7 @@ module API params do requires :id, type: String, desc: 'The ID of a project' requires :search, type: String, desc: 'The expression it should be searched for' - requires :scope, - type: String, - desc: 'The scope of the search', - values: Helpers::SearchHelpers.project_search_scopes + use :scope, Helpers::SearchHelpers.project_search_scopes use :pagination end get ':id/(-/)search' do -- cgit v1.2.1 From 55629a2e4d0237760e1e252f9dbe658f39045156 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 19 Dec 2018 15:24:46 +0100 Subject: add feature flag for users search --- app/controllers/search_controller.rb | 2 ++ app/helpers/search_helper.rb | 2 ++ app/services/search/global_service.rb | 3 ++- app/services/search/project_service.rb | 7 ++++++- lib/api/search.rb | 9 ++++++++- 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index a7b789f848a..90d4bc674d9 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -56,6 +56,8 @@ class SearchController < ApplicationController end def eager_load_user_status + return if Feature.disabled?(:users_search, default_enabled: true) + @search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 97fcb200c67..8110377850b 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -203,6 +203,8 @@ module SearchHelper end def search_tabs?(tab) + return false if Feature.disabled?(:users_search, default_enabled: true) + if @project project_search_tabs?(:members) else diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index b19e9f57450..f711839e389 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -23,7 +23,8 @@ module Search def allowed_scopes strong_memoize(:allowed_scopes) do - %w[issues merge_requests milestones users] + allowed_scopes = %w[issues merge_requests milestones] + allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true) end end diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb index 0d82c5cd5b2..32d5cd7ddb2 100644 --- a/app/services/search/project_service.rb +++ b/app/services/search/project_service.rb @@ -16,7 +16,12 @@ module Search end def scope - @scope ||= %w[notes issues merge_requests milestones wiki_blobs commits users].delete(params[:scope]) { 'blobs' } + @scope ||= begin + allowed_scopes = %w[notes issues merge_requests milestones wiki_blobs commits] + allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true) + + allowed_scopes.delete(params[:scope]) { 'blobs' } + end end end end diff --git a/lib/api/search.rb b/lib/api/search.rb index 01eaf2f142a..d271923dbd6 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -54,7 +54,14 @@ module API end params :scope do |options| - values = SCOPE_ENTITY.stringify_keys.slice(*options[:values]).keys + scope_entities = + if Feature.enabled?(:users_search, default_enabled: true) + SCOPE_ENTITY + else + SCOPE_ENTITY.reject { |key, value| key == :users } + end + + values = scope_entities.stringify_keys.slice(*options[:values]).keys requires :scope, type: String, -- cgit v1.2.1 From 6385c7229cd61eb46b75bcd7441782954a46f1b7 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 10 Jan 2019 19:10:45 +0100 Subject: move users method to public section this is for EE to be able to call this (elastic search) --- lib/gitlab/search_results.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 301d5e326d9..8988b9ad7be 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -87,6 +87,12 @@ module Gitlab 1001 end + def users + return User.none unless Ability.allowed?(current_user, :read_users_list) + + UsersFinder.new(current_user, search: query).execute + end + private def projects @@ -137,12 +143,6 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord - def users - return User.none unless Ability.allowed?(current_user, :read_users_list) - - UsersFinder.new(current_user, search: query).execute - end - def default_scope 'projects' end -- cgit v1.2.1 From b0981097c302dd04df23ec557b4dcce5c952f2bf Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 17 Jan 2019 19:27:20 +0100 Subject: return 400 on users search and feature is disabled as the params block is evaluated when loading the class and the db connection is not available yet we can't use the feature toggle inside that block. --- lib/api/search.rb | 19 ++++++++++------- locale/gitlab.pot | 3 +++ spec/requests/api/search_spec.rb | 46 +++++++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/lib/api/search.rb b/lib/api/search.rb index d271923dbd6..30e68c5aac1 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -53,15 +53,14 @@ module API # EE, without having to modify this file directly. end - params :scope do |options| - scope_entities = - if Feature.enabled?(:users_search, default_enabled: true) - SCOPE_ENTITY - else - SCOPE_ENTITY.reject { |key, value| key == :users } - end + def check_users_search_allowed! + if Feature.disabled?(:users_search, default_enabled: true) && params[:scope].to_sym == :users + render_api_error!({ error: _("Scope not supported with disabled 'users_search' feature!") }, 400) + end + end - values = scope_entities.stringify_keys.slice(*options[:values]).keys + params :scope do |options| + values = SCOPE_ENTITY.stringify_keys.slice(*options[:values]).keys requires :scope, type: String, @@ -81,6 +80,7 @@ module API end get do verify_search_scope! + check_users_search_allowed! present search, with: entity end @@ -98,6 +98,7 @@ module API end get ':id/(-/)search' do verify_search_scope! + check_users_search_allowed! present search(group_id: user_group.id), with: entity end @@ -114,6 +115,8 @@ module API use :pagination end get ':id/(-/)search' do + check_users_search_allowed! + present search(project_id: user_project.id), with: entity end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5b192f4ccbc..5cc4942d150 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -6632,6 +6632,9 @@ msgstr "" msgid "Scope" msgstr "" +msgid "Scope not supported with disabled 'users_search' feature!" +msgstr "" + msgid "Scroll down to Google Code Project Hosting and enable the switch on the right." msgstr "" diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb index 0f539fb6c60..49672591b3b 100644 --- a/spec/requests/api/search_spec.rb +++ b/spec/requests/api/search_spec.rb @@ -81,10 +81,22 @@ describe API::Search do before do create(:user, name: 'billy') - get api('/search', user), scope: 'users', search: 'billy' + get api('/search', user), params: { scope: 'users', search: 'billy' } end it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + + context 'when users search feature is disabled' do + before do + allow(Feature).to receive(:disabled?).with(:users_search, default_enabled: true).and_return(true) + + get api('/search', user), params: { scope: 'users', search: 'billy' } + end + + it 'returns 400 error' do + expect(response).to have_gitlab_http_status(400) + end + end end context 'for snippet_titles scope' do @@ -203,15 +215,27 @@ describe API::Search do it_behaves_like 'response is correct', schema: 'public_api/v4/milestones' end - context 'for user scope' do + context 'for users scope' do before do user = create(:user, name: 'billy') create(:group_member, :developer, user: user, group: group) - get api("/groups/#{group.id}/search", user), scope: 'users', search: 'billy' + get api("/groups/#{group.id}/search", user), params: { scope: 'users', search: 'billy' } end it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + + context 'when users search feature is disabled' do + before do + allow(Feature).to receive(:disabled?).with(:users_search, default_enabled: true).and_return(true) + + get api("/groups/#{group.id}/search", user), params: { scope: 'users', search: 'billy' } + end + + it 'returns 400 error' do + expect(response).to have_gitlab_http_status(400) + end + end end context 'for users scope with group path as id' do @@ -219,7 +243,7 @@ describe API::Search do user1 = create(:user, name: 'billy') create(:group_member, :developer, user: user1, group: group) - get api("/groups/#{CGI.escape(group.full_path)}/search", user), scope: 'users', search: 'billy' + get api("/groups/#{CGI.escape(group.full_path)}/search", user), params: { scope: 'users', search: 'billy' } end it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' @@ -306,10 +330,22 @@ describe API::Search do user1 = create(:user, name: 'billy') create(:project_member, :developer, user: user1, project: project) - get api("/projects/#{project.id}/search", user), scope: 'users', search: 'billy' + get api("/projects/#{project.id}/search", user), params: { scope: 'users', search: 'billy' } end it_behaves_like 'response is correct', schema: 'public_api/v4/user/basics' + + context 'when users search feature is disabled' do + before do + allow(Feature).to receive(:disabled?).with(:users_search, default_enabled: true).and_return(true) + + get api("/projects/#{project.id}/search", user), params: { scope: 'users', search: 'billy' } + end + + it 'returns 400 error' do + expect(response).to have_gitlab_http_status(400) + end + end end context 'for notes scope' do -- cgit v1.2.1 From fcf90d051ba2c0e57b3df65711d4ed6b846cfb8e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 6 Feb 2019 20:55:58 +0100 Subject: un-dry the search api scope due to the usage in EE this attempt to more DRYness is not worth it. --- lib/api/search.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/api/search.rb b/lib/api/search.rb index 30e68c5aac1..de3ed3d4540 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -58,15 +58,6 @@ module API render_api_error!({ error: _("Scope not supported with disabled 'users_search' feature!") }, 400) end end - - params :scope do |options| - values = SCOPE_ENTITY.stringify_keys.slice(*options[:values]).keys - - requires :scope, - type: String, - desc: 'The scope of the search', - values: values - end end resource :search do @@ -75,7 +66,10 @@ module API end params do requires :search, type: String, desc: 'The expression it should be searched for' - use :scope, values: Helpers::SearchHelpers.global_search_scopes + requires :scope, + type: String, + desc: 'The scope of the search', + values: Helpers::SearchHelpers.global_search_scopes use :pagination end get do @@ -93,7 +87,10 @@ module API params do requires :id, type: String, desc: 'The ID of a group' requires :search, type: String, desc: 'The expression it should be searched for' - use :scope, values: Helpers::SearchHelpers.group_search_scopes + requires :scope, + type: String, + desc: 'The scope of the search', + values: Helpers::SearchHelpers.group_search_scopes use :pagination end get ':id/(-/)search' do @@ -111,7 +108,10 @@ module API params do requires :id, type: String, desc: 'The ID of a project' requires :search, type: String, desc: 'The expression it should be searched for' - use :scope, Helpers::SearchHelpers.project_search_scopes + requires :scope, + type: String, + desc: 'The scope of the search', + values: Helpers::SearchHelpers.project_search_scopes use :pagination end get ':id/(-/)search' do -- cgit v1.2.1 From 27ac48c394780df923eeb94f3a7f47f6a5f4c649 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 15 Mar 2019 07:50:36 +0000 Subject: Apply suggestion to lib/api/search.rb --- lib/api/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/search.rb b/lib/api/search.rb index de3ed3d4540..60095300ea1 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -54,7 +54,7 @@ module API end def check_users_search_allowed! - if Feature.disabled?(:users_search, default_enabled: true) && params[:scope].to_sym == :users + if params[:scope].to_sym == :users && Feature.disabled?(:users_search, default_enabled: true) render_api_error!({ error: _("Scope not supported with disabled 'users_search' feature!") }, 400) end end -- cgit v1.2.1