diff options
author | Sean McGivern <sean@mcgivern.me.uk> | 2017-11-14 17:54:24 +0000 |
---|---|---|
committer | Sean McGivern <sean@mcgivern.me.uk> | 2017-11-14 17:54:24 +0000 |
commit | f3454b2e776203b331cc25226f2943c82a28d4c8 (patch) | |
tree | d40b9031fdcdd6f50a8d4ae91211394d9b0a0e92 | |
parent | 96764f2649aed61be92129c02a5425f36c561394 (diff) | |
parent | 889c25ebde36275340fff1973b21cb94e2ae40e5 (diff) | |
download | gitlab-ce-f3454b2e776203b331cc25226f2943c82a28d4c8.tar.gz |
Merge branch 'bvl-subgroup-in-dropdowns' into 'master'
Include child projects a user can manage in namespace dropdowns
Closes #39987
See merge request gitlab-org/gitlab-ce!15294
-rw-r--r-- | app/helpers/namespaces_helper.rb | 7 | ||||
-rw-r--r-- | app/models/user.rb | 11 | ||||
-rw-r--r-- | changelogs/unreleased/bvl-subgroup-in-dropdowns.yml | 5 | ||||
-rw-r--r-- | spec/features/projects/project_settings_spec.rb | 6 | ||||
-rw-r--r-- | spec/features/projects/user_creates_project_spec.rb | 31 | ||||
-rw-r--r-- | spec/features/projects/user_transfers_a_project_spec.rb | 49 | ||||
-rw-r--r-- | spec/helpers/namespaces_helper_spec.rb | 25 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 38 |
8 files changed, 161 insertions, 11 deletions
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index d7df9bb06d2..b78d3072186 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -4,8 +4,11 @@ module NamespacesHelper end def namespaces_options(selected = :current_user, display_path: false, extra_group: nil) - groups = current_user.owned_groups + current_user.masters_groups - users = [current_user.namespace] + groups = current_user.manageable_groups + .joins(:route) + .includes(:route) + .order('routes.path') + users = [current_user.namespace] unless extra_group.nil? || extra_group.is_a?(Group) extra_group = Group.find(extra_group) if Namespace.find(extra_group).kind == 'group' diff --git a/app/models/user.rb b/app/models/user.rb index f436efd604f..ea10e2854d6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -921,7 +921,16 @@ class User < ActiveRecord::Base end def manageable_namespaces - @manageable_namespaces ||= [namespace] + owned_groups + masters_groups + @manageable_namespaces ||= [namespace] + manageable_groups + end + + def manageable_groups + union = Gitlab::SQL::Union.new([owned_groups.select(:id), + masters_groups.select(:id)]) + arel_union = Arel::Nodes::SqlLiteral.new(union.to_sql) + owned_and_master_groups = Group.where(Group.arel_table[:id].in(arel_union)) + + Gitlab::GroupHierarchy.new(owned_and_master_groups).base_and_descendants end def namespaces diff --git a/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml b/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml new file mode 100644 index 00000000000..1114d429dec --- /dev/null +++ b/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml @@ -0,0 +1,5 @@ +--- +title: Make sure a user can add projects to subgroups they have access to +merge_request: 15294 +author: +type: fixed diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 15a5cd9990b..a3ea778d401 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -144,7 +144,10 @@ describe 'Edit Project Settings' do specify 'the project is accessible via the new path' do transfer_project(project, group) new_path = namespace_project_path(group, project) + visit new_path + wait_for_requests + expect(current_path).to eq(new_path) expect(find('.breadcrumbs')).to have_content(project.name) end @@ -153,7 +156,10 @@ describe 'Edit Project Settings' do old_path = project_path(project) transfer_project(project, group) new_path = namespace_project_path(group, project) + visit old_path + wait_for_requests + expect(current_path).to eq(new_path) expect(find('.breadcrumbs')).to have_content(project.name) end diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb index 4a152572502..f95469ad070 100644 --- a/spec/features/projects/user_creates_project_spec.rb +++ b/spec/features/projects/user_creates_project_spec.rb @@ -6,10 +6,11 @@ feature 'User creates a project', :js do before do sign_in(user) create(:personal_key, user: user) - visit(new_project_path) end it 'creates a new project' do + visit(new_project_path) + fill_in(:project_path, with: 'Empty') page.within('#content-body') do @@ -24,4 +25,32 @@ feature 'User creates a project', :js do expect(page).to have_content('git remote') expect(page).to have_content(project.url_to_repo) end + + context 'in a subgroup they do not own', :nested_groups do + let(:parent) { create(:group) } + let!(:subgroup) { create(:group, parent: parent) } + + before do + parent.add_owner(user) + end + + it 'creates a new project' do + visit(new_project_path) + + fill_in :project_path, with: 'a-subgroup-project' + + page.find('.js-select-namespace').click + page.find("div[role='option']", text: subgroup.full_path).click + + page.within('#content-body') do + click_button('Create project') + end + + expect(page).to have_content("Project 'a-subgroup-project' was successfully created") + + project = Project.last + + expect(project.namespace).to eq(subgroup) + end + end end diff --git a/spec/features/projects/user_transfers_a_project_spec.rb b/spec/features/projects/user_transfers_a_project_spec.rb new file mode 100644 index 00000000000..78f72b644ff --- /dev/null +++ b/spec/features/projects/user_transfers_a_project_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +feature 'User transfers a project', :js do + let(:user) { create(:user) } + let(:project) { create(:project, :repository, namespace: user.namespace) } + + before do + sign_in user + end + + def transfer_project(project, group) + visit edit_project_path(project) + + page.within('.js-project-transfer-form') do + page.find('.select2-container').click + end + + page.find("div[role='option']", text: group.full_name).click + + click_button('Transfer project') + + fill_in 'confirm_name_input', with: project.name + + click_button 'Confirm' + + wait_for_requests + end + + it 'allows transferring a project to a subgroup of a namespace' do + group = create(:group) + group.add_owner(user) + + transfer_project(project, group) + + expect(project.reload.namespace).to eq(group) + end + + context 'when nested groups are available', :nested_groups do + it 'allows transferring a project to a subgroup' do + parent = create(:group) + parent.add_owner(user) + subgroup = create(:group, parent: parent) + + transfer_project(project, subgroup) + + expect(project.reload.namespace).to eq(subgroup) + end + end +end diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index 8365b3f5538..460d3b6a7e4 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -29,5 +29,30 @@ describe NamespacesHelper do expect(options).not_to include(admin_group.name) expect(options).to include(user_group.name) end + + context 'when nested groups are available', :nested_groups do + it 'includes groups nested in groups the user can administer' do + allow(helper).to receive(:current_user).and_return(user) + child_group = create(:group, :private, parent: user_group) + + options = helper.namespaces_options + + expect(options).to include(child_group.name) + end + + it 'orders the groups correctly' do + allow(helper).to receive(:current_user).and_return(user) + child_group = create(:group, :private, parent: user_group) + other_child = create(:group, :private, parent: user_group) + sub_child = create(:group, :private, parent: child_group) + + expect(helper).to receive(:options_for_group) + .with([user_group, child_group, sub_child, other_child], anything) + .and_call_original + allow(helper).to receive(:options_for_group).and_call_original + + helper.namespaces_options + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 65dccf9638d..88732962071 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -642,16 +642,40 @@ describe User do end describe 'groups' do + let(:user) { create(:user) } + let(:group) { create(:group) } + before do - @user = create :user - @group = create :group - @group.add_owner(@user) + group.add_owner(user) end - it { expect(@user.several_namespaces?).to be_truthy } - it { expect(@user.authorized_groups).to eq([@group]) } - it { expect(@user.owned_groups).to eq([@group]) } - it { expect(@user.namespaces).to match_array([@user.namespace, @group]) } + it { expect(user.several_namespaces?).to be_truthy } + it { expect(user.authorized_groups).to eq([group]) } + it { expect(user.owned_groups).to eq([group]) } + it { expect(user.namespaces).to contain_exactly(user.namespace, group) } + it { expect(user.manageable_namespaces).to contain_exactly(user.namespace, group) } + + context 'with child groups', :nested_groups do + let!(:subgroup) { create(:group, parent: group) } + + describe '#manageable_namespaces' do + it 'includes all the namespaces the user can manage' do + expect(user.manageable_namespaces).to contain_exactly(user.namespace, group, subgroup) + end + end + + describe '#manageable_groups' do + it 'includes all the namespaces the user can manage' do + expect(user.manageable_groups).to contain_exactly(group, subgroup) + end + + it 'does not include duplicates if a membership was added for the subgroup' do + subgroup.add_owner(user) + + expect(user.manageable_groups).to contain_exactly(group, subgroup) + end + end + end end describe 'group multiple owners' do |