2020-11-05 00:09:16 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2021-03-31 18:09:19 +00:00
|
|
|
RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_shared_state, :sidekiq_inline do
|
2021-05-21 12:10:27 +00:00
|
|
|
let_it_be(:project, reload: true) { create(:project) }
|
2021-03-04 15:11:19 +00:00
|
|
|
let_it_be(:user) { project.owner }
|
|
|
|
let_it_be(:project_user) { create(:user) }
|
2021-03-31 18:09:19 +00:00
|
|
|
let_it_be(:namespace) { project.namespace }
|
2021-03-04 15:11:19 +00:00
|
|
|
let(:params) { {} }
|
2021-06-10 03:10:01 +00:00
|
|
|
let(:base_params) { { access_level: Gitlab::Access::GUEST, source: project, invite_source: '_invite_source_' } }
|
2021-03-04 15:11:19 +00:00
|
|
|
|
2021-03-31 18:09:19 +00:00
|
|
|
subject(:result) { described_class.new(user, base_params.merge(params) ).execute }
|
2021-03-04 15:11:19 +00:00
|
|
|
|
2021-03-31 18:09:19 +00:00
|
|
|
context 'when there is a valid member invited' do
|
2021-03-04 15:11:19 +00:00
|
|
|
let(:params) { { email: 'email@example.org' } }
|
|
|
|
|
|
|
|
it 'successfully creates a member' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
end
|
2021-03-31 18:09:19 +00:00
|
|
|
|
|
|
|
it_behaves_like 'records an onboarding progress action', :user_added
|
|
|
|
end
|
|
|
|
|
2021-05-21 12:10:27 +00:00
|
|
|
context 'when email belongs to an existing user as a secondary email' do
|
|
|
|
let(:secondary_email) { create(:email, email: 'secondary@example.com', user: project_user) }
|
|
|
|
let(:params) { { email: secondary_email.email } }
|
|
|
|
|
|
|
|
it 'adds an existing user to members', :aggregate_failures do
|
|
|
|
expect_to_create_members(count: 1)
|
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
expect(project.users).to include project_user
|
|
|
|
expect(project.members.last).not_to be_invite
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-03-31 18:09:19 +00:00
|
|
|
context 'when email is not a valid email' do
|
|
|
|
let(:params) { { email: '_bogus_' } }
|
|
|
|
|
|
|
|
it 'returns an error' do
|
|
|
|
expect_not_to_create_members
|
|
|
|
expect(result[:message]['_bogus_']).to eq("Invite email is invalid")
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'does not record an onboarding progress action'
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when emails are passed as an array' do
|
|
|
|
let(:params) { { email: %w[email@example.org email2@example.org] } }
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'successfully creates members' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 2)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when emails are passed as an empty string' do
|
|
|
|
let(:params) { { email: '' } }
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'returns an error' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_not_to_create_members
|
2021-04-07 21:09:01 +00:00
|
|
|
expect(result[:message]).to eq('Emails cannot be blank')
|
2021-03-04 15:11:19 +00:00
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when email param is not included' do
|
|
|
|
it 'returns an error' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_not_to_create_members
|
2021-04-07 21:09:01 +00:00
|
|
|
expect(result[:message]).to eq('Emails cannot be blank')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when email is not a valid email format' do
|
|
|
|
let(:params) { { email: '_bogus_' } }
|
|
|
|
|
|
|
|
it 'returns an error' do
|
|
|
|
expect { result }.not_to change(ProjectMember, :count)
|
|
|
|
expect(result[:status]).to eq(:error)
|
|
|
|
expect(result[:message][params[:email]]).to eq("Invite email is invalid")
|
2021-03-04 15:11:19 +00:00
|
|
|
end
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when duplicate email addresses are passed' do
|
|
|
|
let(:params) { { email: 'email@example.org,email@example.org' } }
|
|
|
|
|
|
|
|
it 'only creates one member per unique address' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when observing email limits' do
|
|
|
|
let_it_be(:emails) { Array(1..101).map { |n| "email#{n}@example.com" } }
|
|
|
|
|
|
|
|
context 'when over the allowed default limit of emails' do
|
|
|
|
let(:params) { { email: emails } }
|
|
|
|
|
|
|
|
it 'limits the number of emails to 100' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_not_to_create_members
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:message]).to eq('Too many users specified (limit is 100)')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when over the allowed custom limit of emails' do
|
|
|
|
let(:params) { { email: 'email@example.org,email2@example.org', limit: 1 } }
|
|
|
|
|
|
|
|
it 'limits the number of emails to the limit supplied' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_not_to_create_members
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:message]).to eq('Too many users specified (limit is 1)')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when limit allowed is disabled via limit param' do
|
|
|
|
let(:params) { { email: emails, limit: -1 } }
|
|
|
|
|
|
|
|
it 'does not limit number of emails' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 101)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when email belongs to an existing user' do
|
|
|
|
let(:params) { { email: project_user.email } }
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'adds an existing user to members' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
expect(project.users).to include project_user
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when access level is not valid' do
|
|
|
|
let(:params) { { email: project_user.email, access_level: -1 } }
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'returns an error' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_not_to_create_members
|
2021-04-07 21:09:01 +00:00
|
|
|
expect(result[:message][project_user.email])
|
|
|
|
.to eq("Access level is not included in the list")
|
2021-03-04 15:11:19 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when invite already exists for an included email' do
|
|
|
|
let!(:invited_member) { create(:project_member, :invited, project: project) }
|
|
|
|
let(:params) { { email: "#{invited_member.invite_email},#{project_user.email}" } }
|
2020-11-05 00:09:16 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'adds new email and returns an error for the already invited email' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:error)
|
2021-04-07 21:09:01 +00:00
|
|
|
expect(result[:message][invited_member.invite_email])
|
|
|
|
.to eq("Invite email has already been taken")
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(project.users).to include project_user
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|
2020-12-08 09:09:41 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when access request already exists for an included email' do
|
|
|
|
let!(:requested_member) { create(:project_member, :access_request, project: project) }
|
|
|
|
let(:params) { { email: "#{requested_member.user.email},#{project_user.email}" } }
|
|
|
|
|
|
|
|
it 'adds new email and returns an error for the already invited email' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:error)
|
|
|
|
expect(result[:message][requested_member.user.email])
|
2021-04-07 21:09:01 +00:00
|
|
|
.to eq("User already exists in source")
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(project.users).to include project_user
|
|
|
|
end
|
|
|
|
end
|
2020-12-08 09:09:41 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
context 'when email is already a member on the project' do
|
|
|
|
let!(:existing_member) { create(:project_member, :guest, project: project) }
|
|
|
|
let(:params) { { email: "#{existing_member.user.email},#{project_user.email}" } }
|
2020-12-08 09:09:41 +00:00
|
|
|
|
2021-03-04 15:11:19 +00:00
|
|
|
it 'adds new email and returns an error for the already invited email' do
|
2021-03-31 18:09:19 +00:00
|
|
|
expect_to_create_members(count: 1)
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(result[:status]).to eq(:error)
|
2021-04-07 21:09:01 +00:00
|
|
|
expect(result[:message][existing_member.user.email])
|
|
|
|
.to eq("User already exists in source")
|
2021-03-04 15:11:19 +00:00
|
|
|
expect(project.users).to include project_user
|
|
|
|
end
|
2020-12-08 09:09:41 +00:00
|
|
|
end
|
2021-03-31 18:09:19 +00:00
|
|
|
|
|
|
|
def expect_to_create_members(count:)
|
|
|
|
expect { result }.to change(ProjectMember, :count).by(count)
|
|
|
|
end
|
|
|
|
|
|
|
|
def expect_not_to_create_members
|
|
|
|
expect { result }.not_to change(ProjectMember, :count)
|
|
|
|
expect(result[:status]).to eq(:error)
|
|
|
|
end
|
2020-11-05 00:09:16 +00:00
|
|
|
end
|