summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2016-04-18 18:53:32 +0200
committerRémy Coutable <remy@rymai.me>2016-06-14 13:07:26 +0200
commitd26f81239a33b80694783ee35f0da0e2ed082c9b (patch)
treef092e818d4b81805a16879b13407a335bbda0054 /spec
parent17c22156c5fa5663aae65178ed38cbeef9a80b7e (diff)
downloadgitlab-ce-d26f81239a33b80694783ee35f0da0e2ed082c9b.tar.gz
Add request access for groups
Signed-off-by: Rémy Coutable <remy@rymai.me>
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb198
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb249
-rw-r--r--spec/features/groups/members/owner_manages_access_requests_spec.rb52
-rw-r--r--spec/features/groups/members/user_requests_access_spec.rb54
-rw-r--r--spec/features/projects/members/master_manages_access_requests_spec.rb51
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb54
-rw-r--r--spec/helpers/members_helper_spec.rb139
-rw-r--r--spec/helpers/projects_helper_spec.rb29
-rw-r--r--spec/mailers/notify_spec.rb100
-rw-r--r--spec/models/concerns/access_requestable_spec.rb41
-rw-r--r--spec/models/group_spec.rb59
-rw-r--r--spec/models/member_spec.rb89
-rw-r--r--spec/models/members/group_member_spec.rb22
-rw-r--r--spec/models/members/project_member_spec.rb22
-rw-r--r--spec/models/project_spec.rb11
-rw-r--r--spec/models/project_team_spec.rb150
16 files changed, 1230 insertions, 90 deletions
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index a5986598715..aea809f890b 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -4,17 +4,211 @@ describe Groups::GroupMembersController do
let(:user) { create(:user) }
let(:group) { create(:group) }
- context "index" do
+ describe '#index' do
before do
group.add_owner(user)
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
it 'renders index with group members' do
- get :index, group_id: group.path
+ get :index, group_id: group
expect(response.status).to eq(200)
expect(response).to render_template(:index)
end
end
+
+ describe '#destroy' do
+ let(:group) { create(:group, :public) }
+
+ context 'when member is not found' do
+ it 'returns 403' do
+ delete :destroy, group_id: group,
+ id: 42
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'when member is found' do
+ let(:user) { create(:user) }
+ let(:group_user) { create(:user) }
+ let(:member) do
+ group.add_developer(group_user)
+ group.group_members.find_by(user_id: group_user.id)
+ end
+
+ context 'when user does not have enough rights' do
+ before do
+ group.add_developer(user)
+ sign_in(user)
+ end
+
+ it 'returns 403' do
+ delete :destroy, group_id: group,
+ id: member
+
+ expect(response.status).to eq(403)
+ expect(group.users).to include group_user
+ end
+ end
+
+ context 'when user has enough rights' do
+ before do
+ group.add_owner(user)
+ sign_in(user)
+ end
+
+ it '[HTML] removes user from members' do
+ delete :destroy, group_id: group,
+ id: member
+
+ expect(response).to set_flash.to 'User was successfully removed from group.'
+ expect(response).to redirect_to(group_group_members_path(group))
+ expect(group.users).not_to include group_user
+ end
+
+ it '[JS] removes user from members' do
+ xhr :delete, :destroy, group_id: group,
+ id: member
+
+ expect(response).to be_success
+ expect(group.users).not_to include group_user
+ end
+ end
+ end
+ end
+
+ describe '#leave' do
+ let(:group) { create(:group, :public) }
+ let(:user) { create(:user) }
+
+ context 'when member is not found' do
+ before { sign_in(user) }
+
+ it 'returns 403' do
+ delete :leave, group_id: group
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'when member is found' do
+ context 'and is not an owner' do
+ before do
+ group.add_developer(user)
+ sign_in(user)
+ end
+
+ it 'removes user from members' do
+ delete :leave, group_id: group
+
+ expect(response).to set_flash.to "You left #{group.name} group."
+ expect(response).to redirect_to(dashboard_groups_path)
+ expect(group.users).not_to include user
+ end
+ end
+
+ context 'and is an owner' do
+ before do
+ group.add_owner(user)
+ sign_in(user)
+ end
+
+ it 'cannot removes himself from the group' do
+ delete :leave, group_id: group
+
+ expect(response).to redirect_to(dashboard_groups_path)
+ expect(response).to set_flash[:alert].to "You can not leave #{group.name} group because you're the last owner. Transfer or delete the group."
+ expect(group.users).to include user
+ end
+ end
+
+ context 'and is a requester' do
+ before do
+ group.request_access(user)
+ sign_in(user)
+ end
+
+ it 'removes user from members' do
+ delete :leave, group_id: group
+
+ expect(response).to set_flash.to 'You withdrawn your access request to the group.'
+ expect(response).to redirect_to(dashboard_groups_path)
+ expect(group.group_members.request).to be_empty
+ expect(group.users).not_to include user
+ end
+ end
+ end
+ end
+
+ describe '#request_access' do
+ let(:group) { create(:group, :public) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'creates a new GroupMember that is not a team member' do
+ post :request_access, group_id: group
+
+ expect(response).to set_flash.to 'Your request for access has been queued for review.'
+ expect(response).to redirect_to(group_path(group))
+ expect(group.group_members.request.find_by(created_by_id: user.id).created_by).to eq user
+ expect(group.users).not_to include user
+ end
+ end
+
+ describe '#approve' do
+ let(:group) { create(:group, :public) }
+
+ context 'when member is not found' do
+ it 'returns 403' do
+ post :approve, group_id: group,
+ id: 42
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'when member is found' do
+ let(:user) { create(:user) }
+ let(:group_requester) { create(:user) }
+ let(:member) do
+ group.request_access(group_requester)
+ group.group_members.request.find_by(created_by_id: group_requester.id)
+ end
+
+ context 'when user does not have enough rights' do
+ before do
+ group.add_developer(user)
+ sign_in(user)
+ end
+
+ it 'returns 403' do
+ post :approve, group_id: group,
+ id: member
+
+ expect(response.status).to eq(403)
+ expect(group.users).not_to include group_requester
+ end
+ end
+
+ context 'when user has enough rights' do
+ before do
+ group.add_owner(user)
+ sign_in(user)
+ end
+
+ it 'adds user to members' do
+ post :approve, group_id: group,
+ id: member
+
+ expect(response).to redirect_to(group_group_members_path(group))
+ expect(group.users).to include group_requester
+ end
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 750fbecdd07..2ea09f43f26 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -1,22 +1,22 @@
require('spec_helper')
describe Projects::ProjectMembersController do
- let(:project) { create(:project) }
- let(:another_project) { create(:project, :private) }
- let(:user) { create(:user) }
- let(:member) { create(:user) }
-
- before do
- project.team << [user, :master]
- another_project.team << [member, :guest]
- sign_in(user)
- end
-
describe '#apply_import' do
+ let(:project) { create(:project) }
+ let(:another_project) { create(:project, :private) }
+ let(:user) { create(:user) }
+ let(:member) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ another_project.team << [member, :guest]
+ sign_in(user)
+ end
+
shared_context 'import applied' do
before do
- post(:apply_import, namespace_id: project.namespace.to_param,
- project_id: project.to_param,
+ post(:apply_import, namespace_id: project.namespace,
+ project_id: project,
source_project_id: another_project.id)
end
end
@@ -48,18 +48,231 @@ describe Projects::ProjectMembersController do
end
describe '#index' do
- let(:project) { create(:project, :private) }
-
context 'when user is member' do
- let(:member) { create(:user) }
-
before do
+ project = create(:project, :private)
+ member = create(:user)
project.team << [member, :guest]
sign_in(member)
- get :index, namespace_id: project.namespace.to_param, project_id: project.to_param
+
+ get :index, namespace_id: project.namespace, project_id: project
end
it { expect(response.status).to eq(200) }
end
end
+
+ describe '#destroy' do
+ let(:project) { create(:project, :public) }
+
+ context 'when member is not found' do
+ it 'returns 404' do
+ delete :destroy, namespace_id: project.namespace,
+ project_id: project,
+ id: 42
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when member is found' do
+ let(:user) { create(:user) }
+ let(:team_user) { create(:user) }
+ let(:member) do
+ project.team << [team_user, :developer]
+ project.project_members.find_by(user_id: team_user.id)
+ end
+
+ context 'when user does not have enough rights' do
+ before do
+ project.team << [user, :developer]
+ sign_in(user)
+ end
+
+ it 'returns 404' do
+ delete :destroy, namespace_id: project.namespace,
+ project_id: project,
+ id: member
+
+ expect(response.status).to eq(404)
+ expect(project.users).to include team_user
+ end
+ end
+
+ context 'when user has enough rights' do
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ it '[HTML] removes user from members' do
+ delete :destroy, namespace_id: project.namespace,
+ project_id: project,
+ id: member
+
+ expect(response).to redirect_to(
+ namespace_project_project_members_path(project.namespace, project)
+ )
+ expect(project.users).not_to include team_user
+ end
+
+ it '[JS] removes user from members' do
+ xhr :delete, :destroy, namespace_id: project.namespace,
+ project_id: project,
+ id: member
+
+ expect(response).to be_success
+ expect(project.users).not_to include team_user
+ end
+ end
+ end
+ end
+
+ describe '#leave' do
+ let(:project) { create(:project, :public) }
+ let(:user) { create(:user) }
+
+ context 'when member is not found' do
+ before { sign_in(user) }
+
+ it 'returns 403' do
+ delete :leave, namespace_id: project.namespace,
+ project_id: project
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'when member is found' do
+ context 'and is not an owner' do
+ before do
+ project.team << [user, :developer]
+ sign_in(user)
+ end
+
+ it 'removes user from members' do
+ delete :leave, namespace_id: project.namespace,
+ project_id: project
+
+ expect(response).to set_flash.to 'You left the project.'
+ expect(response).to redirect_to(dashboard_projects_path)
+ expect(project.users).not_to include user
+ end
+ end
+
+ context 'and is an owner' do
+ before do
+ project.update(namespace_id: user.namespace_id)
+ project.team << [user, :master, user]
+ sign_in(user)
+ end
+
+ it 'cannot removes himself from the project' do
+ delete :leave, namespace_id: project.namespace,
+ project_id: project
+
+ expect(response).to redirect_to(
+ namespace_project_project_members_path(project.namespace, project)
+ )
+ expect(response).to set_flash[:alert].to 'You can not leave your own project. Transfer or delete the project.'
+ expect(project.users).to include user
+ end
+ end
+
+ context 'and is a requester' do
+ before do
+ project.request_access(user)
+ sign_in(user)
+ end
+
+ it 'removes user from members' do
+ delete :leave, namespace_id: project.namespace,
+ project_id: project
+
+ expect(response).to set_flash.to 'You withdrawn your access request to the project.'
+ expect(response).to redirect_to(dashboard_projects_path)
+ expect(project.project_members.request).to be_empty
+ expect(project.users).not_to include user
+ end
+ end
+ end
+ end
+
+ describe '#request_access' do
+ let(:project) { create(:project, :public) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'creates a new ProjectMember that is not a team member' do
+ post :request_access, namespace_id: project.namespace,
+ project_id: project
+
+ expect(response).to set_flash.to 'Your request for access has been queued for review.'
+ expect(response).to redirect_to(
+ namespace_project_path(project.namespace, project)
+ )
+ expect(project.project_members.request.find_by(created_by_id: user.id).created_by).to eq user
+ expect(project.users).not_to include user
+ end
+ end
+
+ describe '#approve' do
+ let(:project) { create(:project, :public) }
+
+ context 'when member is not found' do
+ it 'returns 404' do
+ post :approve, namespace_id: project.namespace,
+ project_id: project,
+ id: 42
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when member is found' do
+ let(:user) { create(:user) }
+ let(:team_requester) { create(:user) }
+ let(:member) do
+ project.request_access(team_requester)
+ project.project_members.request.find_by(created_by_id: team_requester.id)
+ end
+
+ context 'when user does not have enough rights' do
+ before do
+ project.team << [user, :developer]
+ sign_in(user)
+ end
+
+ it 'returns 404' do
+ post :approve, namespace_id: project.namespace,
+ project_id: project,
+ id: member
+
+ expect(response.status).to eq(404)
+ expect(project.users).not_to include team_requester
+ end
+ end
+
+ context 'when user has enough rights' do
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ it 'adds user to members' do
+ post :approve, namespace_id: project.namespace,
+ project_id: project,
+ id: member
+
+ expect(response).to redirect_to(
+ namespace_project_project_members_path(project.namespace, project)
+ )
+ expect(project.users).to include team_requester
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb
new file mode 100644
index 00000000000..d5b5e0e35ea
--- /dev/null
+++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+feature 'Groups > Members > Owner manages access requests', feature: true do
+ let(:user) { create(:user) }
+ let(:owner) { create(:user) }
+ let(:group) { create(:group, :public) }
+
+ background do
+ group.request_access(user)
+ group.add_owner(owner)
+ login_as(owner)
+ end
+
+ scenario 'owner can see access requests' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+ end
+
+ scenario 'master can grant access' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+
+ perform_enqueued_jobs do
+ click_on 'Grant access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Access to #{group.name} group was granted/
+ end
+
+ scenario 'master can deny access' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+
+ perform_enqueued_jobs do
+ click_on 'Deny access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Access to #{group.name} group was denied/
+ end
+
+
+ def expect_visible_access_request(group, user)
+ expect(group.access_requested?(user)).to be_truthy
+ expect(page).to have_content "#{group.name} access requests (1)"
+ expect(page).to have_content user.name
+ end
+end
diff --git a/spec/features/groups/members/user_requests_access_spec.rb b/spec/features/groups/members/user_requests_access_spec.rb
new file mode 100644
index 00000000000..9b8492807fa
--- /dev/null
+++ b/spec/features/groups/members/user_requests_access_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+feature 'Groups > Members > User requests access', feature: true do
+ let(:user) { create(:user) }
+ let(:owner) { create(:user) }
+ let(:group) { create(:group, :public) }
+
+ background do
+ group.add_owner(owner)
+ login_as(user)
+ end
+
+ scenario 'user can request access to a group' do
+ visit group_path(group)
+
+ perform_enqueued_jobs do
+ click_link 'Request Access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [owner.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Request to join #{group.name} group/
+
+ expect(group.access_requested?(user)).to be_truthy
+ expect(page).to have_content 'Your request for access has been queued for review.'
+ expect(page).to have_content 'Withdraw Request'
+ end
+
+ scenario 'user is not listed in the group members page' do
+ visit group_path(group)
+
+ click_link 'Request Access'
+
+ expect(group.access_requested?(user)).to be_truthy
+
+ click_link 'Members'
+
+ visit group_group_members_path(group)
+ page.within('.content') do
+ expect(page).not_to have_content(user.name)
+ end
+ end
+
+ scenario 'user can withdraw its request for access' do
+ visit group_path(group)
+ click_link 'Request Access'
+
+ expect(group.access_requested?(user)).to be_truthy
+
+ click_link 'Withdraw Request'
+
+ expect(group.access_requested?(user)).to be_falsey
+ expect(page).to have_content 'You withdrawn your access request to the group.'
+ end
+end
diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb
new file mode 100644
index 00000000000..1b5490ba97f
--- /dev/null
+++ b/spec/features/projects/members/master_manages_access_requests_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+feature 'Projects > Members > Master manages access requests', feature: true do
+ let(:user) { create(:user) }
+ let(:master) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ background do
+ project.request_access(user)
+ project.team << [master, :master]
+ login_as(master)
+ end
+
+ scenario 'master can see access requests' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+ end
+
+ scenario 'master can grant access' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+
+ perform_enqueued_jobs do
+ click_on 'Grant access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Access to #{project.name_with_namespace} project was granted/
+ end
+
+ scenario 'master can deny access' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+
+ perform_enqueued_jobs do
+ click_on 'Deny access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Access to #{project.name_with_namespace} project was denied/
+ end
+
+ def expect_visible_access_request(project, user)
+ expect(project.access_requested?(user)).to be_truthy
+ expect(page).to have_content "#{project.name} access requests (1)"
+ expect(page).to have_content user.name
+ end
+end
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
new file mode 100644
index 00000000000..58a7ec1880d
--- /dev/null
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+feature 'Projects > Members > User requests access', feature: true do
+ let(:user) { create(:user) }
+ let(:master) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ background do
+ project.team << [master, :master]
+ login_as(user)
+ end
+
+ scenario 'user can request access to a project' do
+ visit namespace_project_path(project.namespace, project)
+
+ perform_enqueued_jobs do
+ click_link 'Request Access'
+ end
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [master.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match /Request to join #{project.name_with_namespace} project/
+
+ expect(project.access_requested?(user)).to be_truthy
+ expect(page).to have_content 'Your request for access has been queued for review.'
+ expect(page).to have_content 'Withdraw Request'
+ end
+
+ scenario 'user is not listed in the project members page' do
+ visit namespace_project_path(project.namespace, project)
+
+ click_link 'Request Access'
+
+ expect(project.access_requested?(user)).to be_truthy
+
+ click_link 'Members'
+
+ visit namespace_project_project_members_path(project.namespace, project)
+ page.within('.content') do
+ expect(page).not_to have_content(user.name)
+ end
+ end
+
+ scenario 'user can withdraw its request for access' do
+ visit namespace_project_path(project.namespace, project)
+ click_link 'Request Access'
+
+ expect(project.access_requested?(user)).to be_truthy
+
+ click_link 'Withdraw Request'
+
+ expect(project.access_requested?(user)).to be_falsey
+ expect(page).to have_content 'You withdrawn your access request to the project.'
+ end
+end
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
new file mode 100644
index 00000000000..f1782146241
--- /dev/null
+++ b/spec/helpers/members_helper_spec.rb
@@ -0,0 +1,139 @@
+require 'spec_helper'
+
+describe MembersHelper do
+ describe '#member_class' do
+ let(:project_member) { build(:project_member) }
+ let(:group_member) { build(:group_member) }
+
+ it { expect(member_class(project_member)).to eq ProjectMember }
+ it { expect(member_class(group_member)).to eq GroupMember }
+ end
+
+ describe '#members_association' do
+ let(:project) { build_stubbed(:project) }
+ let(:group) { build_stubbed(:group) }
+
+ it { expect(members_association(project)).to eq :project_members }
+ it { expect(members_association(group)).to eq :group_members }
+ end
+
+ describe '#action_member_permission' do
+ let(:project_member) { build(:project_member) }
+ let(:group_member) { build(:group_member) }
+
+ it { expect(action_member_permission(:admin, project_member)).to eq :admin_project_member }
+ it { expect(action_member_permission(:admin, group_member)).to eq :admin_group_member }
+ end
+
+ describe '#can_see_entity_roles?' do
+ let(:project) { create(:project) }
+ let(:group) { create(:group) }
+ let(:user) { build(:user) }
+ let(:admin) { build(:user, :admin) }
+ let(:project_member) { create(:project_member, project: project) }
+ let(:group_member) { create(:group_member, group: group) }
+
+ it { expect(can_see_entity_roles?(nil, project)).to be_falsy }
+ it { expect(can_see_entity_roles?(nil, group)).to be_falsy }
+ it { expect(can_see_entity_roles?(admin, project)).to be_truthy }
+ it { expect(can_see_entity_roles?(admin, group)).to be_truthy }
+ it { expect(can_see_entity_roles?(project_member.user, project)).to be_truthy }
+ it { expect(can_see_entity_roles?(group_member.user, group)).to be_truthy }
+ end
+
+ describe '#member_path' do
+ let(:project_member) { create(:project_member) }
+ let(:group_member) { create(:group_member) }
+
+ it { expect(member_path(project_member)).to eq namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(member_path(group_member)).to eq group_group_member_path(group_member.source, group_member) }
+ it { expect { member_path(double(:member, source: 'foo')) }.to raise_error ArgumentError, 'Unknown object class' }
+ end
+
+ describe '#resend_invite_member_path' do
+ let(:project_member) { create(:project_member) }
+ let(:group_member) { create(:group_member) }
+
+ it { expect(resend_invite_member_path(project_member)).to eq resend_invite_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(resend_invite_member_path(group_member)).to eq resend_invite_group_group_member_path(group_member.source, group_member) }
+ it { expect { resend_invite_member_path(double(:member, source: 'foo')) }.to raise_error ArgumentError, 'Unknown object class' }
+ end
+
+ describe '#request_access_path' do
+ let(:project) { build_stubbed(:project) }
+ let(:group) { build_stubbed(:group) }
+
+ it { expect(request_access_path(project)).to eq request_access_namespace_project_project_members_path(project.namespace, project) }
+ it { expect(request_access_path(group)).to eq request_access_group_group_members_path(group) }
+ it { expect { request_access_path(double(:member, source: 'foo')) }.to raise_error ArgumentError, 'Unknown object class' }
+ end
+
+ describe '#approve_request_member_path' do
+ let(:project_member) { create(:project_member) }
+ let(:group_member) { create(:group_member) }
+
+ it { expect(approve_request_member_path(project_member)).to eq approve_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(approve_request_member_path(group_member)).to eq approve_group_group_member_path(group_member.source, group_member) }
+ it { expect { approve_request_member_path(double(:member, source: 'foo')) }.to raise_error ArgumentError, 'Unknown object class' }
+ end
+
+ describe '#leave_path' do
+ let(:project) { build_stubbed(:project) }
+ let(:group) { build_stubbed(:group) }
+
+ it { expect(leave_path(project)).to eq leave_namespace_project_project_members_path(project.namespace, project) }
+ it { expect(leave_path(group)).to eq leave_group_group_members_path(group) }
+ it { expect { leave_path(double(:member, source: 'foo')) }.to raise_error ArgumentError, 'Unknown object class' }
+ end
+
+ describe '#withdraw_request_message' do
+ let(:project) { build_stubbed(:project) }
+ let(:group) { build_stubbed(:group) }
+
+ it { expect(withdraw_request_message(project)).to eq "Are you sure you want to withdraw your access request for the \"#{project.name_with_namespace}\" project?" }
+ it { expect(withdraw_request_message(group)).to eq "Are you sure you want to withdraw your access request for the \"#{group.name}\" group?" }
+ end
+
+ describe '#remove_member_message' do
+ let(:requester) { build(:user) }
+ let(:project) { create(:project) }
+ let(:project_member) { build(:project_member, project: project) }
+ let(:project_member_invite) { build(:project_member, project: project).tap { |m| m.generate_invite_token! } }
+ let(:project_member_request) { project.request_access(requester) }
+ let(:group) { create(:group) }
+ let(:group_member) { build(:group_member, group: group) }
+ let(:group_member_invite) { build(:group_member, group: group).tap { |m| m.generate_invite_token! } }
+ let(:group_member_request) { group.request_access(requester) }
+
+ it { expect(remove_member_message(project_member)).to eq "You are going to remove #{project_member.user.name} from the #{project.name_with_namespace} project. Are you sure?" }
+ it { expect(remove_member_message(project_member_invite)).to eq "You are going to revoke the invitation for #{project_member_invite.invite_email} to join the #{project.name_with_namespace} project. Are you sure?" }
+ it { expect(remove_member_message(project_member_request)).to eq "You are going to deny #{requester.name}'s request to join the #{project.name_with_namespace} project. Are you sure?" }
+ it { expect(remove_member_message(group_member)).to eq "You are going to remove #{group_member.user.name} from the #{group.name} group. Are you sure?" }
+ it { expect(remove_member_message(group_member_invite)).to eq "You are going to revoke the invitation for #{group_member_invite.invite_email} to join the #{group.name} group. Are you sure?" }
+ it { expect(remove_member_message(group_member_request)).to eq "You are going to deny #{requester.name}'s request to join the #{group.name} group. Are you sure?" }
+ end
+
+ describe '#remove_member_title' do
+ let(:requester) { build(:user) }
+ let(:project) { create(:project) }
+ let(:project_member) { build(:project_member, project: project) }
+ let(:project_member_request) { project.request_access(requester) }
+ let(:group) { create(:group) }
+ let(:group_member) { build(:group_member, group: group) }
+ let(:group_member_request) { group.request_access(requester) }
+
+ it { expect(remove_member_title(project_member)).to eq 'Remove user' }
+ it { expect(remove_member_title(project_member_request)).to eq 'Deny access request' }
+ it { expect(remove_member_title(group_member)).to eq 'Remove user' }
+ it { expect(remove_member_title(group_member_request)).to eq 'Deny access request' }
+ end
+
+ describe '#leave_confirmation_message' do
+ let(:project) { build_stubbed(:project) }
+ let(:group) { build_stubbed(:group) }
+ let(:user) { build_stubbed(:user) }
+
+ it { expect(leave_confirmation_message(project)).to eq "Are you sure you want to leave \"#{project.name_with_namespace}\" project?" }
+ it { expect(leave_confirmation_message(group)).to eq "Are you sure you want to leave \"#{group.name}\" group?" }
+ end
+end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index ac5af8740dc..fa81c28849e 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -1,6 +1,25 @@
require 'spec_helper'
describe ProjectsHelper do
+ describe '#max_access_level' do
+ let(:master) { create(:user) }
+ let(:owner) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { build_stubbed(:empty_project, namespace: group) }
+
+ before do
+ group.add_master(master)
+ group.add_owner(owner)
+ group.add_reporter(reporter)
+ end
+
+ it { expect(max_access_level(project, master)).to eq 'Master' }
+ it { expect(max_access_level(project, owner)).to eq 'Owner' }
+ it { expect(max_access_level(project, reporter)).to eq 'Reporter' }
+ it { expect(max_access_level(project, build_stubbed(:user))).to be_nil }
+ end
+
describe "#project_status_css_class" do
it "returns appropriate class" do
expect(project_status_css_class("started")).to eq("active")
@@ -45,16 +64,6 @@ describe ProjectsHelper do
end
end
- describe 'user_max_access_in_project' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
- before do
- project.team.add_user(user, Gitlab::Access::MASTER)
- end
-
- it { expect(helper.user_max_access_in_project(user.id, project)).to eq('Master') }
- end
-
describe "readme_cache_key" do
let(:project) { create(:project) }
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 818825b1477..2d86038030e 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -400,6 +400,54 @@ describe Notify do
end
end
+ describe 'project access requested' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:project_member) do
+ project.request_access(user)
+ project.project_members.find_by(created_by_id: user.id)
+ end
+ subject { Notify.project_access_requested_email(project_member.id) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like "a user cannot unsubscribe through footer link"
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Request to join #{project.name_with_namespace} project/
+ end
+
+ it 'contains name of project' do
+ is_expected.to have_body_text /#{project.name}/
+ end
+
+ it 'contains new user role' do
+ is_expected.to have_body_text /#{project_member.human_access}/
+ end
+ end
+
+ describe 'project access denied' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:project_member) do
+ project.request_access(user)
+ project.project_members.find_by(created_by_id: user.id)
+ end
+ subject { Notify.project_access_denied_email(project.id, user.id) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like "a user cannot unsubscribe through footer link"
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Access to #{project.name_with_namespace} project was denied/
+ end
+
+ it 'contains name of project' do
+ is_expected.to have_body_text /#{project.name}/
+ end
+ end
+
describe 'project access changed' do
let(:project) { create(:project) }
let(:user) { create(:user) }
@@ -411,7 +459,7 @@ describe Notify do
it_behaves_like "a user cannot unsubscribe through footer link"
it 'has the correct subject' do
- is_expected.to have_subject /Access to project was granted/
+ is_expected.to have_subject /Access to #{project.name_with_namespace} project was granted/
end
it 'contains name of project' do
@@ -535,6 +583,54 @@ describe Notify do
end
end
+ describe 'group access requested' do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+ let(:group_member) do
+ group.request_access(user)
+ group.group_members.find_by(created_by_id: user.id)
+ end
+ subject { Notify.group_access_requested_email(group_member.id) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like "a user cannot unsubscribe through footer link"
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Request to join #{group.name} group/
+ end
+
+ it 'contains name of group' do
+ is_expected.to have_body_text /#{group.name}/
+ end
+
+ it 'contains new user role' do
+ is_expected.to have_body_text /#{group_member.human_access}/
+ end
+ end
+
+ describe 'group access denied' do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+ let(:group_member) do
+ group.request_access(user)
+ group.group_members.find_by(created_by_id: user.id)
+ end
+ subject { Notify.group_access_denied_email(group.id, user.id) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like "a user cannot unsubscribe through footer link"
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Access to #{group.name} group was denied/
+ end
+
+ it 'contains name of group' do
+ is_expected.to have_body_text /#{group.name}/
+ end
+ end
+
describe 'group access changed' do
let(:group) { create(:group) }
let(:user) { create(:user) }
@@ -547,7 +643,7 @@ describe Notify do
it_behaves_like "a user cannot unsubscribe through footer link"
it 'has the correct subject' do
- is_expected.to have_subject /Access to group was granted/
+ is_expected.to have_subject /Access to #{group.name} group was granted/
end
it 'contains name of project' do
diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb
new file mode 100644
index 00000000000..2dfed1eb4c4
--- /dev/null
+++ b/spec/models/concerns/access_requestable_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe AccessRequestable do
+ describe 'Group' do
+ describe '#request_access' do
+ let(:group) { create(:group, :public) }
+ let(:user) { create(:user) }
+
+ it { expect(group.request_access(user)).to be_a(GroupMember) }
+ it { expect(group.request_access(user).user).to be_nil }
+ it { expect(group.request_access(user).created_by).to eq(user) }
+ end
+
+ describe '#access_requested?' do
+ let(:group) { create(:group, :public) }
+ let(:user) { create(:user) }
+
+ before { group.request_access(user) }
+
+ it { expect(group.access_requested?(user)).to be_truthy }
+ end
+ end
+
+ describe 'Project' do
+ describe '#request_access' do
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+
+ it { expect(project.request_access(user)).to be_a(ProjectMember) }
+ end
+
+ describe '#access_requested?' do
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+
+ before { project.request_access(user) }
+
+ it { expect(project.access_requested?(user)).to be_truthy }
+ end
+ end
+end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 6fa16be7f04..52f9d57bc0a 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -5,7 +5,22 @@ describe Group, models: true do
describe 'associations' do
it { is_expected.to have_many :projects }
- it { is_expected.to have_many :group_members }
+ it { is_expected.to have_many(:group_members).dependent(:destroy) }
+ it { is_expected.to have_many(:users).through(:group_members) }
+ it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
+ it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
+ it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
+
+ describe '#group_members' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+
+ before { group.request_access(user) }
+
+ it 'does not includes membership requests' do
+ expect(user.group_members).to be_empty
+ end
+ end
end
describe 'modules' do
@@ -131,4 +146,46 @@ describe Group, models: true do
expect(described_class.search(group.path.upcase)).to eq([group])
end
end
+
+ describe '#has_owner?' do
+ before { @members = setup_group_members(group) }
+
+ it { expect(group.has_owner?(@members[:owner])).to be_truthy }
+ it { expect(group.has_owner?(@members[:master])).to be_falsey }
+ it { expect(group.has_owner?(@members[:developer])).to be_falsey }
+ it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
+ it { expect(group.has_owner?(@members[:guest])).to be_falsey }
+ it { expect(group.has_owner?(@members[:requester])).to be_falsey }
+ end
+
+ describe '#has_master?' do
+ before { @members = setup_group_members(group) }
+
+ it { expect(group.has_master?(@members[:owner])).to be_falsey }
+ it { expect(group.has_master?(@members[:master])).to be_truthy }
+ it { expect(group.has_master?(@members[:developer])).to be_falsey }
+ it { expect(group.has_master?(@members[:reporter])).to be_falsey }
+ it { expect(group.has_master?(@members[:guest])).to be_falsey }
+ it { expect(group.has_master?(@members[:requester])).to be_falsey }
+ end
+
+ def setup_group_members(group)
+ members = {
+ owner: create(:user),
+ master: create(:user),
+ developer: create(:user),
+ reporter: create(:user),
+ guest: create(:user),
+ requester: create(:user)
+ }
+
+ group.add_user(members[:owner], GroupMember::OWNER)
+ group.add_user(members[:master], GroupMember::MASTER)
+ group.add_user(members[:developer], GroupMember::DEVELOPER)
+ group.add_user(members[:reporter], GroupMember::REPORTER)
+ group.add_user(members[:guest], GroupMember::GUEST)
+ group.request_access(members[:requester])
+
+ members
+ end
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 6e51730eecd..a3d525d8d56 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -55,6 +55,47 @@ describe Member, models: true do
end
end
+ describe 'Scopes' do
+ before do
+ project = create(:project)
+ @invited_member = build(:project_member, user: nil).tap { |m| m.generate_invite_token! }
+ @accepted_invite_member = build(:project_member, user: nil).tap { |m| m.generate_invite_token! && m.accept_invite!(build(:user)) }
+
+ requested_user = create(:user).tap { |u| project.request_access(u) }
+ @requested_member = project.project_members.find_by(created_by_id: requested_user.id)
+ accepted_request_user = create(:user).tap { |u| project.request_access(u) }
+ @accepted_request_member = project.project_members.find_by(created_by_id: accepted_request_user.id).tap { |m| m.accept_request }
+ end
+
+ describe '#invite' do
+ it { expect(described_class.invite).to include @invited_member }
+ it { expect(described_class.invite).not_to include @accepted_invite_member }
+ it { expect(described_class.invite).not_to include @requested_member }
+ it { expect(described_class.invite).not_to include @accepted_request_member }
+ end
+
+ describe '#request' do
+ it { expect(described_class.request).not_to include @invited_member }
+ it { expect(described_class.request).not_to include @accepted_invite_member }
+ it { expect(described_class.request).to include @requested_member }
+ it { expect(described_class.request).not_to include @accepted_request_member }
+ end
+
+ describe '#non_request' do
+ it { expect(described_class.non_request).to include @invited_member }
+ it { expect(described_class.non_request).to include @accepted_invite_member }
+ it { expect(described_class.non_request).not_to include @requested_member }
+ it { expect(described_class.non_request).to include @accepted_request_member }
+ end
+
+ describe '#non_pending' do
+ it { expect(described_class.non_pending).not_to include @invited_member }
+ it { expect(described_class.non_pending).to include @accepted_invite_member }
+ it { expect(described_class.non_pending).not_to include @requested_member }
+ it { expect(described_class.non_pending).to include @accepted_request_member }
+ end
+ end
+
describe "Delegate methods" do
it { is_expected.to respond_to(:user_name) }
it { is_expected.to respond_to(:user_email) }
@@ -97,6 +138,54 @@ describe Member, models: true do
end
end
+ describe '#accept_request' do
+ let(:user) { create(:user) }
+ let(:member) { create(:project_member, requested_at: Time.now.utc, user: nil, created_by: user) }
+
+ it 'returns true' do
+ expect(member.accept_request).to be_truthy
+ end
+
+ it 'sets the user' do
+ member.accept_request
+
+ expect(member.user).to eq(user)
+ end
+
+ it 'clears requested_at' do
+ member.accept_request
+
+ expect(member.requested_at).to be_nil
+ end
+
+ it 'calls #after_accept_request' do
+ expect(member).to receive(:after_accept_request)
+
+ member.accept_request
+ end
+ end
+
+ describe '#decline_request' do
+ let(:user) { create(:user) }
+ let(:member) { create(:project_member, requested_at: Time.now.utc, user: nil, created_by: user) }
+
+ it 'returns true' do
+ expect(member.decline_request).to be_truthy
+ end
+
+ it 'destroys the member' do
+ member.decline_request
+
+ expect(member).to be_destroyed
+ end
+
+ it 'calls #after_decline_request' do
+ expect(member).to receive(:after_decline_request)
+
+ member.decline_request
+ end
+ end
+
describe "#accept_invite!" do
let!(:member) { create(:project_member, invite_email: "user@example.com", user: nil) }
let(:user) { create(:user) }
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 5424c9b9cba..c3070d4cb78 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
describe GroupMember, models: true do
- context 'notification' do
+ describe 'notifications' do
describe "#after_create" do
it "should send email to user" do
membership = build(:group_member)
@@ -50,5 +50,25 @@ describe GroupMember, models: true do
@group_member.update_attribute(:access_level, GroupMember::OWNER)
end
end
+
+ describe 'after accept_request' do
+ let(:member) { create(:group_member, user: nil, created_by: build_stubbed(:user), requested_at: Time.now) }
+
+ it "calls #accept_group_access_request" do
+ expect_any_instance_of(NotificationService).to receive(:new_group_member)
+
+ member.accept_request
+ end
+ end
+
+ describe 'after decline_request' do
+ let(:member) { create(:group_member, user: nil, created_by: build_stubbed(:user), requested_at: Time.now) }
+
+ it "calls #decline_group_access_request" do
+ expect_any_instance_of(NotificationService).to receive(:decline_group_access_request)
+
+ member.decline_request
+ end
+ end
end
end
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 9f13874b532..99b3c77c6cd 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -135,4 +135,26 @@ describe ProjectMember, models: true do
it { expect(@project_1.users).to be_empty }
it { expect(@project_2.users).to be_empty }
end
+
+ describe 'notifications' do
+ describe 'after accept_request' do
+ let(:member) { create(:project_member, user: nil, created_by: build_stubbed(:user), requested_at: Time.now) }
+
+ it 'calls #accept_project_access_request' do
+ expect_any_instance_of(NotificationService).to receive(:new_project_member)
+
+ member.accept_request
+ end
+ end
+
+ describe 'after decline_request' do
+ let(:member) { create(:project_member, user: nil, created_by: build_stubbed(:user), requested_at: Time.now) }
+
+ it 'calls #decline_project_access_request' do
+ expect_any_instance_of(NotificationService).to receive(:decline_project_access_request)
+
+ member.decline_request
+ end
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index de8815f5a38..d5a4b73affd 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -29,6 +29,17 @@ describe Project, models: true do
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:todos).dependent(:destroy) }
+
+ describe '#project_members' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ before { project.request_access(user) }
+
+ it 'does not includes membership requests' do
+ expect(user.project_members).to be_empty
+ end
+ end
end
describe 'modules' do
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 8bebd6a9447..36b1f439955 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -73,69 +73,107 @@ describe ProjectTeam, models: true do
end
end
- describe :max_invited_level do
- let(:group) { create(:group) }
- let(:project) { create(:empty_project) }
-
- before do
- project.project_group_links.create(
- group: group,
- group_access: Gitlab::Access::DEVELOPER
- )
-
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
+ describe '#find_member' do
+ context 'personal project' do
+ let(:project) { create(:empty_project) }
+ let(:requester) { create(:user) }
+
+ before do
+ project.team << [master, :master]
+ project.team << [reporter, :reporter]
+ project.team << [guest, :guest]
+ project.request_access(requester)
+ end
+
+ it { expect(project.team.find_member(master.id)).to be_a(ProjectMember) }
+ it { expect(project.team.find_member(reporter.id)).to be_a(ProjectMember) }
+ it { expect(project.team.find_member(guest.id)).to be_a(ProjectMember) }
+ it { expect(project.team.find_member(nonmember.id)).to be_nil }
+ it { expect(project.team.find_member(requester.id)).to be_nil }
end
- it { expect(project.team.max_invited_level(master.id)).to eq(Gitlab::Access::DEVELOPER) }
- it { expect(project.team.max_invited_level(reporter.id)).to eq(Gitlab::Access::REPORTER) }
- it { expect(project.team.max_invited_level(nonmember.id)).to be_nil }
- end
-
- describe :max_member_access do
- let(:group) { create(:group) }
- let(:project) { create(:empty_project) }
-
- before do
- project.project_group_links.create(
- group: group,
- group_access: Gitlab::Access::DEVELOPER
- )
-
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
- end
-
- it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) }
- it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
- it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
-
- it "does not have an access" do
- project.namespace.update(share_with_group_lock: true)
- expect(project.team.max_member_access(master.id)).to be_nil
- expect(project.team.max_member_access(reporter.id)).to be_nil
+ context 'group project' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, group: group) }
+ let(:requester) { create(:user) }
+
+ before do
+ group.add_master(master)
+ group.add_reporter(reporter)
+ group.add_guest(guest)
+ group.request_access(requester)
+ end
+
+ it { expect(project.team.find_member(master.id)).to be_a(GroupMember) }
+ it { expect(project.team.find_member(reporter.id)).to be_a(GroupMember) }
+ it { expect(project.team.find_member(guest.id)).to be_a(GroupMember) }
+ it { expect(project.team.find_member(nonmember.id)).to be_nil }
+ it { expect(project.team.find_member(requester.id)).to be_nil }
end
end
- describe "#human_max_access" do
- it 'returns Master role' do
- user = create(:user)
- group = create(:group)
- group.add_master(user)
-
- project = build_stubbed(:empty_project, namespace: group)
-
- expect(project.team.human_max_access(user.id)).to eq 'Master'
+ describe '#max_member_access' do
+ let(:requester) { create(:user) }
+
+ context 'personal project' do
+ let(:project) { create(:empty_project) }
+
+ context 'when project is not shared with group' do
+ before do
+ project.team << [master, :master]
+ project.team << [reporter, :reporter]
+ project.team << [guest, :guest]
+ project.request_access(requester)
+ end
+
+ it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) }
+ it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
+ it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) }
+ it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
+ it { expect(project.team.max_member_access(requester.id)).to be_nil }
+ end
+
+ context 'when project is shared with group' do
+ before do
+ group = create(:group)
+ project.project_group_links.create(
+ group: group,
+ group_access: Gitlab::Access::DEVELOPER)
+
+ group.add_master(master)
+ group.add_reporter(reporter)
+ end
+
+ it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) }
+ it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
+ it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
+ it { expect(project.team.max_member_access(requester.id)).to be_nil }
+
+ context 'but share_with_group_lock is true' do
+ before { project.namespace.update(share_with_group_lock: true) }
+
+ it { expect(project.team.max_member_access(master.id)).to be_nil }
+ it { expect(project.team.max_member_access(reporter.id)).to be_nil }
+ end
+ end
end
- it 'returns Owner role' do
- user = create(:user)
- group = create(:group)
- group.add_owner(user)
-
- project = build_stubbed(:empty_project, namespace: group)
-
- expect(project.team.human_max_access(user.id)).to eq 'Owner'
+ context 'group project' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, group: group) }
+
+ before do
+ group.add_master(master)
+ group.add_reporter(reporter)
+ group.add_guest(guest)
+ group.request_access(requester)
+ end
+
+ it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) }
+ it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
+ it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) }
+ it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
+ it { expect(project.team.max_member_access(requester.id)).to be_nil }
end
end
end