Skip to content
Snippets Groups Projects
Commit 1c88d92b authored by Rémy Coutable's avatar Rémy Coutable
Browse files

Improve Member services


Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent e82f629b
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -11,7 +11,7 @@ describe Members::CreateService do
 
it 'adds user to members' do
params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST }
result = described_class.new(project, user, params).execute
result = described_class.new(user, params).execute(project)
 
expect(result[:status]).to eq(:success)
expect(project.users).to include project_user
Loading
Loading
@@ -19,7 +19,7 @@ describe Members::CreateService do
 
it 'adds no user to members' do
params = { user_ids: '', access_level: Gitlab::Access::GUEST }
result = described_class.new(project, user, params).execute
result = described_class.new(user, params).execute(project)
 
expect(result[:status]).to eq(:error)
expect(result[:message]).to be_present
Loading
Loading
@@ -30,7 +30,7 @@ describe Members::CreateService do
user_ids = 1.upto(101).to_a.join(',')
params = { user_ids: user_ids, access_level: Gitlab::Access::GUEST }
 
result = described_class.new(project, user, params).execute
result = described_class.new(user, params).execute(project)
 
expect(result[:status]).to eq(:error)
expect(result[:message]).to be_present
Loading
Loading
Loading
Loading
@@ -3,113 +3,200 @@ require 'spec_helper'
describe Members::DestroyService do
let(:current_user) { create(:user) }
let(:member_user) { create(:user) }
let(:project) { create(:project, :public) }
let(:group) { create(:group, :public) }
let(:group_project) { create(:project, :public, group: group) }
let(:opts) { {} }
 
shared_examples 'a service raising ActiveRecord::RecordNotFound' do
it 'raises ActiveRecord::RecordNotFound' do
expect { described_class.new(source, current_user).execute(member) }.to raise_error(ActiveRecord::RecordNotFound)
expect { described_class.new(current_user).execute(member) }.to raise_error(ActiveRecord::RecordNotFound)
end
end
 
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
it 'raises Gitlab::Access::AccessDeniedError' do
expect { described_class.new(source, current_user).execute(member) }.to raise_error(Gitlab::Access::AccessDeniedError)
expect { described_class.new(current_user).execute(member) }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
 
def number_of_assigned_issuables(user)
Issue.assigned_to(user).count + MergeRequest.assigned_to(user).count
end
shared_examples 'a service destroying a member' do
it 'destroys the member' do
expect { described_class.new(source, current_user).execute(member) }.to change { source.members.count }.by(-1)
expect { described_class.new(current_user).execute(member, opts) }.to change { member.source.members_and_requesters.count }.by(-1)
end
it 'unassigns issues and merge requests' do
if member.invite?
expect { described_class.new(current_user).execute(member, opts) }
.not_to change { number_of_assigned_issuables(member_user) }
else
create :issue, assignees: [member_user]
issue = create :issue, project: group_project, assignees: [member_user]
merge_request = create :merge_request, target_project: group_project, source_project: group_project, assignee: member_user
expect { described_class.new(current_user).execute(member, opts) }
.to change { number_of_assigned_issuables(member_user) }.from(3).to(1)
expect(issue.reload.assignee_ids).to be_empty
expect(merge_request.reload.assignee_id).to be_nil
end
end
it 'destroys member notification_settings' do
if member_user.notification_settings.any?
expect { described_class.new(current_user).execute(member, opts) }
.to change { member_user.notification_settings.count }.by(-1)
else
expect { described_class.new(current_user).execute(member, opts) }
.not_to change { member_user.notification_settings.count }
end
end
end
 
shared_examples 'a service destroying an access requester' do
it 'destroys the access requester' do
expect { described_class.new(source, current_user).execute(access_requester) }.to change { source.requesters.count }.by(-1)
end
it_behaves_like 'a service destroying a member'
 
it 'calls Member#after_decline_request' do
expect_any_instance_of(NotificationService).to receive(:decline_access_request).with(access_requester)
expect_any_instance_of(NotificationService).to receive(:decline_access_request).with(member)
 
described_class.new(source, current_user).execute(access_requester)
described_class.new(current_user).execute(member)
end
 
context 'when current user is the member' do
it 'does not call Member#after_decline_request' do
expect_any_instance_of(NotificationService).not_to receive(:decline_access_request).with(access_requester)
expect_any_instance_of(NotificationService).not_to receive(:decline_access_request).with(member)
 
described_class.new(source, member_user).execute(access_requester)
described_class.new(member_user).execute(member)
end
end
end
 
context 'with a member' do
before do
project.add_developer(member_user)
group_project.add_developer(member_user)
group.add_developer(member_user)
end
let(:member) { source.members.find_by(user_id: member_user.id) }
 
context 'when current user cannot destroy the given member' do
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { project }
let(:member) { group_project.members.find_by(user_id: member_user.id) }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { group_project.members.find_by(user_id: member_user.id) }
end
 
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { group }
let(:member) { group.members.find_by(user_id: member_user.id) }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { group.members.find_by(user_id: member_user.id) }
end
end
 
context 'when current user can destroy the given member' do
before do
project.add_master(current_user)
group_project.add_master(current_user)
group.add_owner(current_user)
end
 
it_behaves_like 'a service destroying a member' do
let(:source) { project }
let(:member) { group_project.members.find_by(user_id: member_user.id) }
end
 
it_behaves_like 'a service destroying a member' do
let(:source) { group }
let(:member) { group.members.find_by(user_id: member_user.id) }
end
end
end
 
context 'with an access requester' do
before do
project.update_attributes(request_access_enabled: true)
group_project.update_attributes(request_access_enabled: true)
group.update_attributes(request_access_enabled: true)
project.request_access(member_user)
group_project.request_access(member_user)
group.request_access(member_user)
end
let(:access_requester) { source.requesters.find_by(user_id: member_user.id) }
 
context 'when current user cannot destroy the given access requester' do
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { project }
let(:member) { access_requester }
let(:member) { group_project.requesters.find_by(user_id: member_user.id) }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { group_project.requesters.find_by(user_id: member_user.id) }
end
 
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { group }
let(:member) { access_requester }
let(:member) { group.requesters.find_by(user_id: member_user.id) }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { group.requesters.find_by(user_id: member_user.id) }
end
end
 
context 'when current user can destroy the given access requester' do
before do
project.add_master(current_user)
group_project.add_master(current_user)
group.add_owner(current_user)
end
 
it_behaves_like 'a service destroying an access requester' do
let(:source) { project }
let(:member) { group_project.requesters.find_by(user_id: member_user.id) }
end
 
it_behaves_like 'a service destroying an access requester' do
let(:source) { group }
let(:member) { group.requesters.find_by(user_id: member_user.id) }
end
end
end
context 'with an invited user' do
let(:project_invited_member) { create(:project_member, :invited, project: group_project) }
let(:group_invited_member) { create(:group_member, :invited, group: group) }
context 'when current user cannot destroy the given invited user' do
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:member) { project_invited_member }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { project_invited_member }
end
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:member) { group_invited_member }
end
it_behaves_like 'a service destroying a member' do
let(:opts) { { skip_authorization: true } }
let(:member) { group_invited_member }
end
end
context 'when current user can destroy the given invited user' do
before do
group_project.add_master(current_user)
group.add_owner(current_user)
end
# Regression spec for issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/32504
it_behaves_like 'a service destroying a member' do
let(:member) { project_invited_member }
end
it_behaves_like 'a service destroying a member' do
let(:member) { group_invited_member }
end
end
end
Loading
Loading
Loading
Loading
@@ -5,17 +5,17 @@ describe Members::RequestAccessService do
 
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
it 'raises Gitlab::Access::AccessDeniedError' do
expect { described_class.new(source, user).execute }.to raise_error(Gitlab::Access::AccessDeniedError)
expect { described_class.new(user).execute(source) }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
 
shared_examples 'a service creating a access request' do
it 'succeeds' do
expect { described_class.new(source, user).execute }.to change { source.requesters.count }.by(1)
expect { described_class.new(user).execute(source) }.to change { source.requesters.count }.by(1)
end
 
it 'returns a <Source>Member' do
member = described_class.new(source, user).execute
member = described_class.new(user).execute(source)
 
expect(member).to be_a "#{source.class}Member".constantize
expect(member.requested_at).to be_present
Loading
Loading
Loading
Loading
@@ -13,14 +13,14 @@ describe Members::UpdateService do
 
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
it 'raises Gitlab::Access::AccessDeniedError' do
expect { described_class.new(source, current_user, params).execute(member, permission: permission) }
expect { described_class.new(current_user, params).execute(member, permission: permission) }
.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
 
shared_examples 'a service updating a member' do
it 'updates the member' do
updated_member = described_class.new(source, current_user, params).execute(member, permission: permission)
updated_member = described_class.new(current_user, params).execute(member, permission: permission)
 
expect(updated_member).to be_valid
expect(updated_member.access_level).to eq(Gitlab::Access::MASTER)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment