diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-04-01 00:27:34 +0100 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-04-01 00:27:34 +0100 |
commit | 8d3ed6e49e1577e4198b7d5e60fd2e70cb3a446d (patch) | |
tree | 3d77ec54a8e97a75aee650a2ef4e464065af9c5d | |
parent | d0260cb7f20ba23672d773e5fc011f9c2cf81aaa (diff) | |
parent | b54acba8b732688c59fe2f38510c469dc86ee499 (diff) | |
download | gitlab-ce-30264-fix-vue-pagination.tar.gz |
Merge branch 'master' into 30264-fix-vue-pagination30264-fix-vue-pagination
* master:
Prevent users from disconnecting gitlab account from CAS
30276 Move issue, mr, todos next to profile dropdown in top nav
Refactor SearchController#show
Updating documentation to include a missing step in the update procedure
Fix link to Jira service documentation
Remove unnecessary ORDER BY clause from `forked_to_project_id` subquery
Fixed a gap underneath the scrolling inner page links
Add download attribute to download links
27 files changed, 531 insertions, 109 deletions
diff --git a/app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js b/app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js index 3555040d60f..f18e2dfadaf 100644 --- a/app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js +++ b/app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js @@ -21,6 +21,7 @@ export default { <li v-for="artifact in artifacts"> <a rel="nofollow" + download :href="artifact.path"> <i class="fa fa-download" aria-hidden="true"></i> <span>Download {{artifact.name}} artifacts</span> diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 0e09638a8cc..e6d808717f3 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -146,6 +146,10 @@ display: block; } + &.scrolling-tabs { + float: left; + } + li a { padding: 16px 15px 11px; } @@ -480,6 +484,10 @@ .inner-page-scroll-tabs { position: relative; + .nav-links { + padding-bottom: 1px; + } + .fade-right { @include fade(left, $white-light); right: 0; diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 69959fe3687..7d1aa8d1ce0 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -1,11 +1,22 @@ class Profiles::AccountsController < Profiles::ApplicationController + include AuthHelper + def show @user = current_user end def unlink provider = params[:provider] - current_user.identities.find_by(provider: provider).destroy unless provider.to_s == 'saml' + identity = current_user.identities.find_by(provider: provider) + + return render_404 unless identity + + if unlink_allowed?(provider) + identity.destroy + else + flash[:alert] = "You are not allowed to unlink your primary login account" + end + redirect_to profile_account_path end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 612d69cf557..4a579601785 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -6,45 +6,19 @@ class SearchController < ApplicationController layout 'search' def show - if params[:project_id].present? - @project = Project.find_by(id: params[:project_id]) - @project = nil unless can?(current_user, :download_code, @project) - end + search_service = SearchService.new(current_user, params) - if params[:group_id].present? - @group = Group.find_by(id: params[:group_id]) - @group = nil unless can?(current_user, :read_group, @group) - end + @project = search_service.project + @group = search_service.group return if params[:search].blank? @search_term = params[:search] - @scope = params[:scope] - @show_snippets = params[:snippets].eql? 'true' - - @search_results = - if @project - unless %w(blobs notes issues merge_requests milestones wiki_blobs - commits).include?(@scope) - @scope = 'blobs' - end - - Search::ProjectService.new(@project, current_user, params).execute - elsif @show_snippets - unless %w(snippet_blobs snippet_titles).include?(@scope) - @scope = 'snippet_blobs' - end - - Search::SnippetService.new(current_user, params).execute - else - unless %w(projects issues merge_requests milestones).include?(@scope) - @scope = 'projects' - end - Search::GlobalService.new(current_user, params).execute - end - - @search_objects = @search_results.objects(@scope, params[:page]) + @scope = search_service.scope + @show_snippets = search_service.show_snippets? + @search_results = search_service.search_results + @search_objects = search_service.search_objects check_single_commit_result end diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 1ee6c1d3afa..101fe579da2 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -76,5 +76,9 @@ module AuthHelper (current_user.otp_grace_period_started_at + current_application_settings.two_factor_grace_period.hours) < Time.current end + def unlink_allowed?(provider) + %w(saml cas3).exclude?(provider.to_s) + end + extend self end diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index eef403dba92..3b90fd1c2c7 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -62,7 +62,7 @@ class JiraService < IssueTrackerService def help "You need to configure JIRA before enabling this service. For more details read the - [JIRA service documentation](#{help_page_url('project_services/jira')})." + [JIRA service documentation](#{help_page_url('user/project/integrations/jira')})." end def title diff --git a/app/models/user.rb b/app/models/user.rb index cbd741f96ed..95a766f2ede 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -635,8 +635,10 @@ class User < ActiveRecord::Base end def fork_of(project) - links = ForkedProjectLink.where(forked_from_project_id: project, forked_to_project_id: personal_projects) - + links = ForkedProjectLink.where( + forked_from_project_id: project, + forked_to_project_id: personal_projects.unscope(:order) + ) if links.any? links.first.forked_to_project else diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index 781cd13b44b..a3c655493a5 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -16,5 +16,9 @@ module Search Gitlab::SearchResults.new(current_user, projects, params[:search]) end + + def scope + @scope ||= %w[issues merge_requests milestones].delete(params[:scope]) { 'projects' } + end end end diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb index 4b500914cfb..9a22abae635 100644 --- a/app/services/search/project_service.rb +++ b/app/services/search/project_service.rb @@ -12,5 +12,9 @@ module Search params[:search], params[:repository_ref]) end + + def scope + @scope ||= %w[notes issues merge_requests milestones wiki_blobs commits].delete(params[:scope]) { 'blobs' } + end end end diff --git a/app/services/search/snippet_service.rb b/app/services/search/snippet_service.rb index 0b3e713e220..4f161beea4d 100644 --- a/app/services/search/snippet_service.rb +++ b/app/services/search/snippet_service.rb @@ -11,5 +11,9 @@ module Search Gitlab::SnippetSearchResults.new(snippets, params[:search]) end + + def scope + @scope ||= %w[snippet_titles].delete(params[:scope]) { 'snippet_blobs' } + end end end diff --git a/app/services/search_service.rb b/app/services/search_service.rb new file mode 100644 index 00000000000..8d46a8dab3e --- /dev/null +++ b/app/services/search_service.rb @@ -0,0 +1,63 @@ +class SearchService + include Gitlab::Allowable + + def initialize(current_user, params = {}) + @current_user = current_user + @params = params.dup + end + + def project + return @project if defined?(@project) + + @project = + if params[:project_id].present? + the_project = Project.find_by(id: params[:project_id]) + can?(current_user, :download_code, the_project) ? the_project : nil + else + nil + end + end + + def group + return @group if defined?(@group) + + @group = + if params[:group_id].present? + the_group = Group.find_by(id: params[:group_id]) + can?(current_user, :read_group, the_group) ? the_group : nil + else + nil + end + end + + def show_snippets? + return @show_snippets if defined?(@show_snippets) + + @show_snippets = params[:snippets] == 'true' + end + + delegate :scope, to: :search_service + + def search_results + @search_results ||= search_service.execute + end + + def search_objects + @search_objects ||= search_results.objects(scope, params[:page]) + end + + private + + def search_service + @search_service ||= + if project + Search::ProjectService.new(project, current_user, params) + elsif show_snippets? + Search::SnippetService.new(current_user, params) + else + Search::GlobalService.new(current_user, params) + end + end + + attr_reader :current_user, :params +end diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 43abd44d89f..23abf6897d4 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -35,6 +35,15 @@ %li = link_to admin_root_path, title: 'Admin Area', aria: { label: "Admin Area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('wrench fw') + - if current_user.can_create_project? + %li + = link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = icon('plus fw') + - if Gitlab::Sherlock.enabled? + %li + = link_to sherlock_transactions_path, title: 'Sherlock Transactions', + data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = icon('tachometer fw') %li = link_to assigned_issues_dashboard_path, title: 'Issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('hashtag fw') @@ -50,15 +59,6 @@ = icon('check-circle fw') %span.badge.todos-count = todos_count_format(todos_pending_count) - - if current_user.can_create_project? - %li - = link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do - = icon('plus fw') - - if Gitlab::Sherlock.enabled? - %li - = link_to sherlock_transactions_path, title: 'Sherlock Transactions', - data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do - = icon('tachometer fw') %li.header-user.dropdown = link_to current_user, class: "header-user-dropdown-toggle", data: { toggle: "dropdown" } do = image_tag avatar_icon(current_user, 26), width: 26, height: 26, class: "header-user-avatar" diff --git a/app/views/notify/project_was_exported_email.html.haml b/app/views/notify/project_was_exported_email.html.haml index b28fea35ad5..76440926a2b 100644 --- a/app/views/notify/project_was_exported_email.html.haml +++ b/app/views/notify/project_was_exported_email.html.haml @@ -2,7 +2,7 @@ Project #{@project.name} was exported successfully. %p The project export can be downloaded from: - = link_to download_export_namespace_project_url(@project.namespace, @project) do + = link_to download_export_namespace_project_url(@project.namespace, @project), rel: 'nofollow', download: '', do = @project.name_with_namespace + " export" %p The download link will expire in 24 hours. diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 8a994f6d600..5ce2220c907 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -75,12 +75,12 @@ .provider-btn-image = provider_image_tag(provider) - if auth_active?(provider) - - if provider.to_s == 'saml' - %a.provider-btn - Active - - else + - if unlink_allowed?(provider) = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'provider-btn' do Disconnect + - else + %a.provider-btn + Active - else = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn not-active' do Connect diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml index edf55d59f28..de8c173f26f 100644 --- a/app/views/projects/artifacts/browse.html.haml +++ b/app/views/projects/artifacts/browse.html.haml @@ -3,7 +3,7 @@ .top-block.row-content-block.clearfix .pull-right = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), - class: 'btn btn-default download' do + rel: 'nofollow', download: '', class: 'btn btn-default download' do = icon('download') Download artifacts archive diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml index b597c7f7a12..6f45d5b0689 100644 --- a/app/views/projects/builds/_sidebar.html.haml +++ b/app/views/projects/builds/_sidebar.html.haml @@ -33,7 +33,7 @@ = link_to keep_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default', method: :post do Keep - = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-default' do + = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), rel: 'nofollow', download: '', class: 'btn btn-sm btn-default' do Download - if @build.artifacts_metadata? diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 09286a1b3c6..aeed293a724 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -94,7 +94,7 @@ %td .pull-right - if can?(current_user, :read_build, build) && build.artifacts? - = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do + = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), rel: 'nofollow', download: '', title: 'Download artifacts', class: 'btn btn-build' do = icon('download') - if can?(current_user, :update_build, build) - if build.active? diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 82e0d0025ec..b78de092a60 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -163,7 +163,7 @@ - if @project.export_project_path = link_to 'Download export', download_export_namespace_project_path(@project.namespace, @project), - method: :get, class: "btn btn-default" + rel: 'nofollow', download: '', method: :get, class: "btn btn-default" = link_to 'Generate new export', generate_new_export_namespace_project_path(@project.namespace, @project), method: :post, class: "btn btn-default" - else diff --git a/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml b/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml new file mode 100644 index 00000000000..17e38ba6243 --- /dev/null +++ b/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml @@ -0,0 +1,4 @@ +--- +title: Prevent users from disconnecting GitLab account from CAS +merge_request: 10282 +author: diff --git a/changelogs/unreleased/29929-jira-doc.yml b/changelogs/unreleased/29929-jira-doc.yml new file mode 100644 index 00000000000..f79dcd84634 --- /dev/null +++ b/changelogs/unreleased/29929-jira-doc.yml @@ -0,0 +1,4 @@ +--- +title: Fix link to Jira service documentation +merge_request: +author: diff --git a/changelogs/unreleased/30276-move-top-badges.yml b/changelogs/unreleased/30276-move-top-badges.yml new file mode 100644 index 00000000000..68a8ab359fd --- /dev/null +++ b/changelogs/unreleased/30276-move-top-badges.yml @@ -0,0 +1,4 @@ +--- +title: Move issue, mr, todos next to profile dropdown in top nav +merge_request: +author: diff --git a/changelogs/unreleased/forked-subquery-order.yml b/changelogs/unreleased/forked-subquery-order.yml new file mode 100644 index 00000000000..06fb8236783 --- /dev/null +++ b/changelogs/unreleased/forked-subquery-order.yml @@ -0,0 +1,4 @@ +--- +title: Remove unnecessary ORDER BY clause from `forked_to_project_id` subquery +merge_request: +author: mhasbini diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md index f28896c2227..4b3c5bf6d64 100644 --- a/doc/update/8.2-to-8.3.md +++ b/doc/update/8.2-to-8.3.md @@ -120,6 +120,14 @@ There are new configuration options available for [`gitlab.yml`][yaml]. View the git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gitlab.yml.example ``` +#### GitLab default file + +The value of the `gitlab_workhorse_options` variable should be updated within the default gitlab file (`/etc/default/gitlab`) according to the following diff: + +```sh +git diff origin/8-2-stable:lib/support/init.d/gitlab.default.example origin/8-3-stable:lib/support/init.d/gitlab.default.example +``` + #### Nginx configuration GitLab 8.3 introduces major changes in the NGINX configuration. diff --git a/spec/controllers/profiles/accounts_controller_spec.rb b/spec/controllers/profiles/accounts_controller_spec.rb index 18148acde3e..2f9d18e3a0e 100644 --- a/spec/controllers/profiles/accounts_controller_spec.rb +++ b/spec/controllers/profiles/accounts_controller_spec.rb @@ -1,25 +1,47 @@ require 'spec_helper' describe Profiles::AccountsController do - let(:user) { create(:omniauth_user, provider: 'saml') } + describe 'DELETE unlink' do + let(:user) { create(:omniauth_user) } - before do - sign_in(user) - end + before do + sign_in(user) + end - it 'does not allow to unlink SAML connected account' do - identity = user.identities.last - delete :unlink, provider: 'saml' - updated_user = User.find(user.id) + it 'renders 404 if someone tries to unlink a non existent provider' do + delete :unlink, provider: 'github' - expect(response).to have_http_status(302) - expect(updated_user.identities.size).to eq(1) - expect(updated_user.identities).to include(identity) - end + expect(response).to have_http_status(404) + end + + [:saml, :cas3].each do |provider| + describe "#{provider} provider" do + let(:user) { create(:omniauth_user, provider: provider.to_s) } + + it "does not allow to unlink connected account" do + identity = user.identities.last + + delete :unlink, provider: provider.to_s + + expect(response).to have_http_status(302) + expect(user.reload.identities).to include(identity) + end + end + end + + [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0].each do |provider| + describe "#{provider} provider" do + let(:user) { create(:omniauth_user, provider: provider.to_s) } + + it 'allows to unlink connected account' do + identity = user.identities.last - it 'does allow to delete other linked accounts' do - user.identities.create(provider: 'twitter', extern_uid: 'twitter_123') + delete :unlink, provider: provider.to_s - expect { delete :unlink, provider: 'twitter' }.to change(Identity.all, :size).by(-1) + expect(response).to have_http_status(302) + expect(user.reload.identities).not_to include(identity) + end + end + end end end diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index cd3281d6f51..a0e1265efff 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -62,4 +62,18 @@ describe AuthHelper do end end end + + describe 'unlink_allowed?' do + [:saml, :cas3].each do |provider| + it "returns true if the provider is #{provider}" do + expect(helper.unlink_allowed?(provider)).to be false + end + end + + [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0].each do |provider| + it "returns false if the provider is #{provider}" do + expect(helper.unlink_allowed?(provider)).to be true + end + end + end end diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb new file mode 100644 index 00000000000..2531607acad --- /dev/null +++ b/spec/services/search/global_service_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Search::GlobalService, services: true do + let(:user) { create(:user) } + let(:internal_user) { create(:user) } + + let!(:found_project) { create(:empty_project, :private, name: 'searchable_project') } + let!(:unfound_project) { create(:empty_project, :private, name: 'unfound_project') } + let!(:internal_project) { create(:empty_project, :internal, name: 'searchable_internal_project') } + let!(:public_project) { create(:empty_project, :public, name: 'searchable_public_project') } + + before do + found_project.add_master(user) + end + + describe '#execute' do + context 'unauthenticated' do + it 'returns public projects only' do + results = Search::GlobalService.new(nil, search: "searchable").execute + + expect(results.objects('projects')).to match_array [public_project] + end + end + + context 'authenticated' do + it 'returns public, internal and private projects' do + results = Search::GlobalService.new(user, search: "searchable").execute + + expect(results.objects('projects')).to match_array [public_project, found_project, internal_project] + end + + it 'returns only public & internal projects' do + results = Search::GlobalService.new(internal_user, search: "searchable").execute + + expect(results.objects('projects')).to match_array [internal_project, public_project] + end + + it 'namespace name is searchable' do + results = Search::GlobalService.new(user, search: found_project.namespace.path).execute + + expect(results.objects('projects')).to match_array [found_project] + end + + context 'nested group' do + let!(:nested_group) { create(:group, :nested) } + let!(:project) { create(:empty_project, namespace: nested_group) } + + before do + project.add_master(user) + end + + it 'returns result from nested group' do + results = Search::GlobalService.new(user, search: project.path).execute + + expect(results.objects('projects')).to match_array [project] + end + + it 'returns result from descendants when search inside group' do + results = Search::GlobalService.new(user, search: project.path, group_id: nested_group.parent).execute + + expect(results.objects('projects')).to match_array [project] + end + end + end + end +end diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 6ef5fa008aa..2112f1cf9ea 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -1,65 +1,286 @@ require 'spec_helper' -describe 'Search::GlobalService', services: true do +describe SearchService, services: true do let(:user) { create(:user) } - let(:public_user) { create(:user) } - let(:internal_user) { create(:user) } - let!(:found_project) { create(:empty_project, :private, name: 'searchable_project') } - let!(:unfound_project) { create(:empty_project, :private, name: 'unfound_project') } - let!(:internal_project) { create(:empty_project, :internal, name: 'searchable_internal_project') } - let!(:public_project) { create(:empty_project, :public, name: 'searchable_public_project') } + let(:accessible_group) { create(:group, :private) } + let(:inaccessible_group) { create(:group, :private) } + let!(:group_member) { create(:group_member, group: accessible_group, user: user) } + + let!(:accessible_project) { create(:empty_project, :private, name: 'accessible_project') } + let!(:inaccessible_project) { create(:empty_project, :private, name: 'inaccessible_project') } + let(:note) { create(:note_on_issue, project: accessible_project) } + + let(:snippet) { create(:snippet, author: user) } + let(:group_project) { create(:empty_project, group: accessible_group, name: 'group_project') } + let(:public_project) { create(:empty_project, :public, name: 'public_project') } before do - found_project.team << [user, :master] + accessible_project.add_master(user) + end + + describe '#project' do + context 'when the project is accessible' do + it 'returns the project' do + project = SearchService.new(user, project_id: accessible_project.id).project + + expect(project).to eq accessible_project + end + end + + context 'when the project is not accessible' do + it 'returns nil' do + project = SearchService.new(user, project_id: inaccessible_project.id).project + + expect(project).to be_nil + end + end + + context 'when there is no project_id' do + it 'returns nil' do + project = SearchService.new(user).project + + expect(project).to be_nil + end + end end - describe '#execute' do - context 'unauthenticated' do - it 'returns public projects only' do - context = Search::GlobalService.new(nil, search: "searchable") - results = context.execute - expect(results.objects('projects')).to match_array [public_project] + describe '#group' do + context 'when the group is accessible' do + it 'returns the group' do + group = SearchService.new(user, group_id: accessible_group.id).group + + expect(group).to eq accessible_group end end - context 'authenticated' do - it 'returns public, internal and private projects' do - context = Search::GlobalService.new(user, search: "searchable") - results = context.execute - expect(results.objects('projects')).to match_array [public_project, found_project, internal_project] + context 'when the group is not accessible' do + it 'returns nil' do + group = SearchService.new(user, group_id: inaccessible_group.id).group + + expect(group).to be_nil end + end + + context 'when there is no group_id' do + it 'returns nil' do + group = SearchService.new(user).group - it 'returns only public & internal projects' do - context = Search::GlobalService.new(internal_user, search: "searchable") - results = context.execute - expect(results.objects('projects')).to match_array [internal_project, public_project] + expect(group).to be_nil end + end + end + + describe '#show_snippets?' do + context 'when :snippets is \'true\'' do + it 'returns true' do + show_snippets = SearchService.new(user, snippets: 'true').show_snippets? - it 'namespace name is searchable' do - context = Search::GlobalService.new(user, search: found_project.namespace.path) - results = context.execute - expect(results.objects('projects')).to match_array [found_project] + expect(show_snippets).to be_truthy end + end - context 'nested group' do - let!(:nested_group) { create(:group, :nested) } - let!(:project) { create(:empty_project, namespace: nested_group) } + context 'when :snippets is not \'true\'' do + it 'returns false' do + show_snippets = SearchService.new(user, snippets: 'tru').show_snippets? + + expect(show_snippets).to be_falsey + end + end - before { project.add_master(user) } + context 'when :snippets is missing' do + it 'returns false' do + show_snippets = SearchService.new(user).show_snippets? - it 'returns result from nested group' do - context = Search::GlobalService.new(user, search: project.path) - results = context.execute - expect(results.objects('projects')).to match_array [project] + expect(show_snippets).to be_falsey + end + end + end + + describe '#scope' do + context 'with accessible project_id' do + context 'and allowed scope' do + it 'returns the specified scope' do + scope = SearchService.new(user, project_id: accessible_project.id, scope: 'notes').scope + + expect(scope).to eq 'notes' end + end + + context 'and disallowed scope' do + it 'returns the default scope' do + scope = SearchService.new(user, project_id: accessible_project.id, scope: 'projects').scope - it 'returns result from descendants when search inside group' do - context = Search::GlobalService.new(user, search: project.path, group_id: nested_group.parent) - results = context.execute - expect(results.objects('projects')).to match_array [project] + expect(scope).to eq 'blobs' end end + + context 'and no scope' do + it 'returns the default scope' do + scope = SearchService.new(user, project_id: accessible_project.id).scope + + expect(scope).to eq 'blobs' + end + end + end + + context 'with \'true\' snippets' do + context 'and allowed scope' do + it 'returns the specified scope' do + scope = SearchService.new(user, snippets: 'true', scope: 'snippet_titles').scope + + expect(scope).to eq 'snippet_titles' + end + end + + context 'and disallowed scope' do + it 'returns the default scope' do + scope = SearchService.new(user, snippets: 'true', scope: 'projects').scope + + expect(scope).to eq 'snippet_blobs' + end + end + + context 'and no scope' do + it 'returns the default scope' do + scope = SearchService.new(user, snippets: 'true').scope + + expect(scope).to eq 'snippet_blobs' + end + end + end + + context 'with no project_id, no snippets' do + context 'and allowed scope' do + it 'returns the specified scope' do + scope = SearchService.new(user, scope: 'issues').scope + + expect(scope).to eq 'issues' + end + end + + context 'and disallowed scope' do + it 'returns the default scope' do + scope = SearchService.new(user, scope: 'blobs').scope + + expect(scope).to eq 'projects' + end + end + + context 'and no scope' do + it 'returns the default scope' do + scope = SearchService.new(user).scope + + expect(scope).to eq 'projects' + end + end + end + end + + describe '#search_results' do + context 'with accessible project_id' do + it 'returns an instance of Gitlab::ProjectSearchResults' do + search_results = SearchService.new( + user, + project_id: accessible_project.id, + scope: 'notes', + search: note.note).search_results + + expect(search_results).to be_a Gitlab::ProjectSearchResults + end + end + + context 'with accessible project_id and \'true\' snippets' do + it 'returns an instance of Gitlab::ProjectSearchResults' do + search_results = SearchService.new( + user, + project_id: accessible_project.id, + snippets: 'true', + scope: 'notes', + search: note.note).search_results + + expect(search_results).to be_a Gitlab::ProjectSearchResults + end + end + + context 'with \'true\' snippets' do + it 'returns an instance of Gitlab::SnippetSearchResults' do + search_results = SearchService.new( + user, + snippets: 'true', + search: snippet.content).search_results + + expect(search_results).to be_a Gitlab::SnippetSearchResults + end + end + + context 'with no project_id and no snippets' do + it 'returns an instance of Gitlab::SearchResults' do + search_results = SearchService.new( + user, + search: public_project.name).search_results + + expect(search_results).to be_a Gitlab::SearchResults + end + end + end + + describe '#search_objects' do + context 'with accessible project_id' do + it 'returns objects in the project' do + search_objects = SearchService.new( + user, + project_id: accessible_project.id, + scope: 'notes', + search: note.note).search_objects + + expect(search_objects.first).to eq note + end + end + + context 'with accessible project_id and \'true\' snippets' do + it 'returns objects in the project' do + search_objects = SearchService.new( + user, + project_id: accessible_project.id, + snippets: 'true', + scope: 'notes', + search: note.note).search_objects + + expect(search_objects.first).to eq note + end + end + + context 'with \'true\' snippets' do + it 'returns objects in snippets' do + search_objects = SearchService.new( + user, + snippets: 'true', + search: snippet.content).search_objects + + expect(search_objects.first).to eq snippet + end + end + + context 'with accessible group_id' do + it 'returns objects in the group' do + search_objects = SearchService.new( + user, + group_id: accessible_group.id, + search: group_project.name).search_objects + + expect(search_objects.first).to eq group_project + end + end + + context 'with no project_id, group_id or snippets' do + it 'returns objects in global' do + search_objects = SearchService.new( + user, + search: public_project.name).search_objects + + expect(search_objects.first).to eq public_project + end end end end |