summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Van Landuyt <bob@vanlanduyt.co>2017-11-09 15:59:11 +0100
committerBob Van Landuyt <bob@vanlanduyt.co>2017-11-14 16:57:41 +0100
commit022d8420ec0713909ff379e1e8d36c4e46bde3a3 (patch)
treeb2cdf284c023430410239a2d41806e010615c0fa
parentfb7abd87daa8930682b05870361fe9dd112f050f (diff)
downloadgitlab-ce-022d8420ec0713909ff379e1e8d36c4e46bde3a3.tar.gz
Include child projects a user can manage in namespace dropdowns
These dropdown options are used for creating and transfering projects.
-rw-r--r--app/helpers/namespaces_helper.rb2
-rw-r--r--app/models/user.rb11
-rw-r--r--changelogs/unreleased/bvl-subgroup-in-dropdowns.yml5
-rw-r--r--spec/features/projects/project_settings_spec.rb6
-rw-r--r--spec/features/projects/user_creates_project_spec.rb31
-rw-r--r--spec/features/projects/user_transfers_a_project_spec.rb49
-rw-r--r--spec/helpers/namespaces_helper_spec.rb25
-rw-r--r--spec/models/user_spec.rb38
8 files changed, 157 insertions, 10 deletions
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index d7df9bb06d2..fa749098d76 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -4,7 +4,7 @@ module NamespacesHelper
end
def namespaces_options(selected = :current_user, display_path: false, extra_group: nil)
- groups = current_user.owned_groups + current_user.masters_groups
+ groups = current_user.manageable_groups.includes(:route)
users = [current_user.namespace]
unless extra_group.nil? || extra_group.is_a?(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