2014-09-14 10:54:10 -04:00
|
|
|
require 'spec_helper'
|
|
|
|
|
2015-12-09 04:50:51 -05:00
|
|
|
describe Member, models: true do
|
2014-09-14 10:54:10 -04:00
|
|
|
describe "Associations" do
|
2015-02-12 13:17:35 -05:00
|
|
|
it { is_expected.to belong_to(:user) }
|
2014-09-14 10:54:10 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "Validation" do
|
|
|
|
subject { Member.new(access_level: Member::GUEST) }
|
|
|
|
|
2015-02-12 13:17:35 -05:00
|
|
|
it { is_expected.to validate_presence_of(:user) }
|
|
|
|
it { is_expected.to validate_presence_of(:source) }
|
2016-06-23 11:14:31 -04:00
|
|
|
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.all_values) }
|
2015-04-10 09:09:37 -04:00
|
|
|
|
2016-02-09 09:51:06 -05:00
|
|
|
it_behaves_like 'an object with email-formated attributes', :invite_email do
|
|
|
|
subject { build(:project_member) }
|
|
|
|
end
|
|
|
|
|
2015-04-10 09:09:37 -04:00
|
|
|
context "when an invite email is provided" do
|
|
|
|
let(:member) { build(:project_member, invite_email: "user@example.com", user: nil) }
|
|
|
|
|
|
|
|
it "doesn't require a user" do
|
|
|
|
expect(member).to be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it "requires a valid invite email" do
|
|
|
|
member.invite_email = "nope"
|
|
|
|
|
|
|
|
expect(member).not_to be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it "requires a unique invite email scoped to this source" do
|
|
|
|
create(:project_member, source: member.source, invite_email: member.invite_email)
|
|
|
|
|
|
|
|
expect(member).not_to be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is valid otherwise" do
|
|
|
|
expect(member).to be_valid
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when an invite email is not provided" do
|
|
|
|
let(:member) { build(:project_member) }
|
|
|
|
|
|
|
|
it "requires a user" do
|
|
|
|
member.user = nil
|
|
|
|
|
|
|
|
expect(member).not_to be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is valid otherwise" do
|
|
|
|
expect(member).to be_valid
|
|
|
|
end
|
|
|
|
end
|
2014-09-14 10:54:10 -04:00
|
|
|
end
|
2014-09-14 12:32:51 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe 'Scopes & finders' do
|
2016-04-18 12:53:32 -04:00
|
|
|
before do
|
2016-09-05 11:37:26 -04:00
|
|
|
project = create(:empty_project)
|
2016-06-02 12:05:06 -04:00
|
|
|
group = create(:group)
|
|
|
|
@owner_user = create(:user).tap { |u| group.add_owner(u) }
|
|
|
|
@owner = group.members.find_by(user_id: @owner_user.id)
|
|
|
|
|
|
|
|
@master_user = create(:user).tap { |u| project.team << [u, :master] }
|
|
|
|
@master = project.members.find_by(user_id: @master_user.id)
|
|
|
|
|
2016-09-05 11:37:26 -04:00
|
|
|
@blocked_user = create(:user).tap do |u|
|
|
|
|
project.team << [u, :master]
|
|
|
|
project.team << [u, :developer]
|
|
|
|
|
|
|
|
u.block!
|
|
|
|
end
|
|
|
|
@blocked_master = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::MASTER)
|
|
|
|
@blocked_developer = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::DEVELOPER)
|
|
|
|
|
2016-08-02 14:37:22 -04:00
|
|
|
Member.add_user(
|
|
|
|
project.members,
|
|
|
|
'toto1@example.com',
|
|
|
|
Gitlab::Access::DEVELOPER,
|
|
|
|
current_user: @master_user
|
|
|
|
)
|
2016-06-02 12:05:06 -04:00
|
|
|
@invited_member = project.members.invite.find_by_invite_email('toto1@example.com')
|
|
|
|
|
2016-09-05 11:37:26 -04:00
|
|
|
accepted_invite_user = build(:user, state: :active)
|
2016-08-02 14:37:22 -04:00
|
|
|
Member.add_user(
|
|
|
|
project.members,
|
|
|
|
'toto2@example.com',
|
|
|
|
Gitlab::Access::DEVELOPER,
|
|
|
|
current_user: @master_user
|
|
|
|
)
|
2016-06-02 12:05:06 -04:00
|
|
|
@accepted_invite_member = project.members.invite.find_by_invite_email('toto2@example.com').tap { |u| u.accept_invite!(accepted_invite_user) }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
|
|
|
requested_user = create(:user).tap { |u| project.request_access(u) }
|
2016-06-27 10:20:57 -04:00
|
|
|
@requested_member = project.requesters.find_by(user_id: requested_user.id)
|
2016-06-02 12:05:06 -04:00
|
|
|
|
2016-04-18 12:53:32 -04:00
|
|
|
accepted_request_user = create(:user).tap { |u| project.request_access(u) }
|
2016-06-27 10:20:57 -04:00
|
|
|
@accepted_request_member = project.requesters.find_by(user_id: accepted_request_user.id).tap { |m| m.accept_request }
|
2016-04-18 12:53:32 -04:00
|
|
|
end
|
|
|
|
|
2016-07-26 20:20:19 -04:00
|
|
|
describe '.access_for_user_ids' do
|
|
|
|
it 'returns the right access levels' do
|
2016-09-05 11:37:26 -04:00
|
|
|
users = [@owner_user.id, @master_user.id, @blocked_user.id]
|
2016-07-26 20:20:19 -04:00
|
|
|
expected = {
|
|
|
|
@owner_user.id => Gitlab::Access::OWNER,
|
|
|
|
@master_user.id => Gitlab::Access::MASTER
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(described_class.access_for_user_ids(users)).to eq(expected)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '.invite' do
|
|
|
|
it { expect(described_class.invite).not_to include @master }
|
2016-04-18 12:53:32 -04:00
|
|
|
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
|
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '.non_invite' do
|
|
|
|
it { expect(described_class.non_invite).to include @master }
|
|
|
|
it { expect(described_class.non_invite).not_to include @invited_member }
|
|
|
|
it { expect(described_class.non_invite).to include @accepted_invite_member }
|
|
|
|
it { expect(described_class.non_invite).to include @requested_member }
|
|
|
|
it { expect(described_class.non_invite).to include @accepted_request_member }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.request' do
|
|
|
|
it { expect(described_class.request).not_to include @master }
|
2016-04-18 12:53:32 -04:00
|
|
|
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
|
|
|
|
|
2016-09-05 11:37:26 -04:00
|
|
|
describe '.developers' do
|
|
|
|
subject { described_class.developers.to_a }
|
|
|
|
|
|
|
|
it { is_expected.not_to include @owner }
|
|
|
|
it { is_expected.not_to include @master }
|
|
|
|
it { is_expected.to include @invited_member }
|
|
|
|
it { is_expected.to include @accepted_invite_member }
|
|
|
|
it { is_expected.not_to include @requested_member }
|
|
|
|
it { is_expected.to include @accepted_request_member }
|
|
|
|
it { is_expected.not_to include @blocked_master }
|
|
|
|
it { is_expected.not_to include @blocked_developer }
|
|
|
|
end
|
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '.owners_and_masters' do
|
|
|
|
it { expect(described_class.owners_and_masters).to include @owner }
|
|
|
|
it { expect(described_class.owners_and_masters).to include @master }
|
|
|
|
it { expect(described_class.owners_and_masters).not_to include @invited_member }
|
|
|
|
it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member }
|
|
|
|
it { expect(described_class.owners_and_masters).not_to include @requested_member }
|
|
|
|
it { expect(described_class.owners_and_masters).not_to include @accepted_request_member }
|
2016-09-05 11:37:26 -04:00
|
|
|
it { expect(described_class.owners_and_masters).not_to include @blocked_master }
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.has_access' do
|
|
|
|
subject { described_class.has_access.to_a }
|
|
|
|
|
|
|
|
it { is_expected.to include @owner }
|
|
|
|
it { is_expected.to include @master }
|
|
|
|
it { is_expected.to include @invited_member }
|
|
|
|
it { is_expected.to include @accepted_invite_member }
|
|
|
|
it { is_expected.not_to include @requested_member }
|
|
|
|
it { is_expected.to include @accepted_request_member }
|
|
|
|
it { is_expected.not_to include @blocked_master }
|
|
|
|
it { is_expected.not_to include @blocked_developer }
|
2016-06-02 12:05:06 -04:00
|
|
|
end
|
2016-04-18 12:53:32 -04:00
|
|
|
end
|
|
|
|
|
2014-09-14 12:32:51 -04:00
|
|
|
describe "Delegate methods" do
|
2015-02-12 13:17:35 -05:00
|
|
|
it { is_expected.to respond_to(:user_name) }
|
|
|
|
it { is_expected.to respond_to(:user_email) }
|
2014-09-14 12:32:51 -04:00
|
|
|
end
|
2015-04-10 09:09:37 -04:00
|
|
|
|
2015-04-14 06:33:27 -04:00
|
|
|
describe ".add_user" do
|
|
|
|
let!(:user) { create(:user) }
|
|
|
|
let(:project) { create(:project) }
|
|
|
|
|
|
|
|
context "when called with a user id" do
|
|
|
|
it "adds the user as a member" do
|
|
|
|
Member.add_user(project.project_members, user.id, ProjectMember::MASTER)
|
|
|
|
|
|
|
|
expect(project.users).to include(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when called with a user object" do
|
|
|
|
it "adds the user as a member" do
|
|
|
|
Member.add_user(project.project_members, user, ProjectMember::MASTER)
|
|
|
|
|
|
|
|
expect(project.users).to include(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when called with a known user email" do
|
|
|
|
it "adds the user as a member" do
|
|
|
|
Member.add_user(project.project_members, user.email, ProjectMember::MASTER)
|
|
|
|
|
|
|
|
expect(project.users).to include(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when called with an unknown user email" do
|
|
|
|
it "adds a member invite" do
|
|
|
|
Member.add_user(project.project_members, "user@example.com", ProjectMember::MASTER)
|
|
|
|
|
|
|
|
expect(project.project_members.invite.pluck(:invite_email)).to include("user@example.com")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-18 12:53:32 -04:00
|
|
|
describe '#accept_request' do
|
2016-06-02 12:05:06 -04:00
|
|
|
let(:member) { create(:project_member, requested_at: Time.now.utc) }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
it { expect(member.accept_request).to be_truthy }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '#invite?' do
|
|
|
|
subject { create(:project_member, invite_email: "user@example.com", user: nil) }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
it { is_expected.to be_invite }
|
|
|
|
end
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '#request?' do
|
|
|
|
subject { create(:project_member, requested_at: Time.now.utc) }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
it { is_expected.to be_request }
|
|
|
|
end
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
describe '#pending?' do
|
|
|
|
let(:invited_member) { create(:project_member, invite_email: "user@example.com", user: nil) }
|
|
|
|
let(:requester) { create(:project_member, requested_at: Time.now.utc) }
|
2016-04-18 12:53:32 -04:00
|
|
|
|
2016-06-02 12:05:06 -04:00
|
|
|
it { expect(invited_member).to be_invite }
|
|
|
|
it { expect(requester).to be_pending }
|
2016-04-18 12:53:32 -04:00
|
|
|
end
|
|
|
|
|
2015-04-10 09:09:37 -04:00
|
|
|
describe "#accept_invite!" do
|
|
|
|
let!(:member) { create(:project_member, invite_email: "user@example.com", user: nil) }
|
|
|
|
let(:user) { create(:user) }
|
|
|
|
|
|
|
|
it "resets the invite token" do
|
|
|
|
member.accept_invite!(user)
|
|
|
|
|
|
|
|
expect(member.invite_token).to be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "sets the invite accepted timestamp" do
|
|
|
|
member.accept_invite!(user)
|
|
|
|
|
|
|
|
expect(member.invite_accepted_at).not_to be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "sets the user" do
|
|
|
|
member.accept_invite!(user)
|
|
|
|
|
|
|
|
expect(member.user).to eq(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "calls #after_accept_invite" do
|
|
|
|
expect(member).to receive(:after_accept_invite)
|
|
|
|
|
|
|
|
member.accept_invite!(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-04-10 10:37:02 -04:00
|
|
|
describe "#decline_invite!" do
|
|
|
|
let!(:member) { create(:project_member, invite_email: "user@example.com", user: nil) }
|
|
|
|
|
|
|
|
it "destroys the member" do
|
|
|
|
member.decline_invite!
|
|
|
|
|
|
|
|
expect(member).to be_destroyed
|
|
|
|
end
|
|
|
|
|
|
|
|
it "calls #after_decline_invite" do
|
|
|
|
expect(member).to receive(:after_decline_invite)
|
|
|
|
|
|
|
|
member.decline_invite!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-04-10 09:09:37 -04:00
|
|
|
describe "#generate_invite_token" do
|
|
|
|
let!(:member) { create(:project_member, invite_email: "user@example.com", user: nil) }
|
2016-02-09 09:51:06 -05:00
|
|
|
|
2015-04-10 09:09:37 -04:00
|
|
|
it "sets the invite token" do
|
|
|
|
expect { member.generate_invite_token }.to change { member.invite_token}
|
|
|
|
end
|
|
|
|
end
|
2014-09-14 10:54:10 -04:00
|
|
|
end
|