discourse/spec/models/invite_spec.rb

437 lines
13 KiB
Ruby

require 'spec_helper'
describe Invite do
it { should validate_presence_of :invited_by_id }
let(:iceking) { 'iceking@adventuretime.ooo' }
context 'user validators' do
let(:coding_horror) { Fabricate(:coding_horror) }
let(:user) { Fabricate(:user) }
let(:invite) { Invite.create(email: user.email, invited_by: coding_horror) }
it "should not allow an invite with the same email as an existing user" do
invite.should_not be_valid
end
it "should not allow a user to invite themselves" do
invite.email_already_exists.should == true
end
end
context 'email validators' do
let(:coding_horror) { Fabricate(:coding_horror) }
let(:invite) { Invite.create(email: "test@mailinator.com", invited_by: coding_horror) }
it "should not allow an invite with blacklisted email" do
invite.should_not be_valid
end
it "should allow an invite with non-blacklisted email" do
invite = Fabricate(:invite, email: "test@mail.com", invited_by: coding_horror)
invite.should be_valid
end
end
context '#create' do
context 'saved' do
subject { Fabricate(:invite) }
it "works" do
subject.invite_key.should be_present
subject.email_already_exists.should == false
end
it 'should store a lower case version of the email' do
subject.email.should == iceking
end
end
context 'to a topic' do
let!(:topic) { Fabricate(:topic) }
let(:inviter) { topic.user }
context 'email' do
it 'enqueues a job to email the invite' do
Jobs.expects(:enqueue).with(:invite_email, has_key(:invite_id))
topic.invite_by_email(inviter, iceking)
end
end
context 'destroyed' do
it "can invite the same user after their invite was destroyed" do
invite = topic.invite_by_email(inviter, iceking)
invite.destroy
invite = topic.invite_by_email(inviter, iceking)
invite.should be_present
end
end
context 'after created' do
before do
@invite = topic.invite_by_email(inviter, iceking)
end
it 'belongs to the topic' do
topic.invites.should == [@invite]
@invite.topics.should == [topic]
end
context 'when added by another user' do
let(:coding_horror) { Fabricate(:coding_horror) }
let(:new_invite) { topic.invite_by_email(coding_horror, iceking) }
it 'returns a different invite' do
new_invite.should_not == @invite
new_invite.invite_key.should_not == @invite.invite_key
new_invite.topics.should == [topic]
end
end
context 'when adding a duplicate' do
it 'returns the original invite' do
topic.invite_by_email(inviter, 'iceking@adventuretime.ooo').should == @invite
topic.invite_by_email(inviter, 'iceking@ADVENTURETIME.ooo').should == @invite
topic.invite_by_email(inviter, 'ICEKING@adventuretime.ooo').should == @invite
end
it 'returns a new invite if the other has expired' do
SiteSetting.stubs(:invite_expiry_days).returns(1)
@invite.created_at = 2.days.ago
@invite.save
new_invite = topic.invite_by_email(inviter, 'iceking@adventuretime.ooo')
new_invite.should_not == @invite
new_invite.should_not be_expired
end
end
context 'when adding to another topic' do
let!(:another_topic) { Fabricate(:topic, user: topic.user) }
it 'should be the same invite' do
@new_invite = another_topic.invite_by_email(inviter, iceking)
@new_invite.should == @invite
another_topic.invites.should == [@invite]
@invite.topics.should =~ [topic, another_topic]
end
end
end
end
end
context 'an existing user' do
let(:topic) { Fabricate(:topic, category_id: nil, archetype: 'private_message') }
let(:coding_horror) { Fabricate(:coding_horror) }
let!(:invite) { topic.invite_by_email(topic.user, coding_horror.email) }
it "works" do
# doesn't create an invite
invite.should be_blank
# gives the user permission to access the topic
topic.allowed_users.include?(coding_horror).should == true
end
end
context '.redeem' do
let(:invite) { Fabricate(:invite) }
it 'creates a notification for the invitee' do
lambda { invite.redeem }.should change(Notification, :count)
end
it 'wont redeem an expired invite' do
SiteSetting.expects(:invite_expiry_days).returns(10)
invite.update_column(:created_at, 20.days.ago)
invite.redeem.should be_blank
end
it 'wont redeem a deleted invite' do
invite.destroy
invite.redeem.should be_blank
end
it "won't redeem an invalidated invite" do
invite.invalidated_at = 1.day.ago
invite.redeem.should be_blank
end
context 'enqueues a job to email "set password" instructions' do
it 'does not enqueue an email if sso is enabled' do
SiteSetting.stubs(:enable_sso).returns(true)
Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never
invite.redeem
end
it 'does not enqueue an email if local login is disabled' do
SiteSetting.stubs(:enable_local_logins).returns(false)
Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never
invite.redeem
end
it 'does not enqueue an email if the user has already set password' do
user = Fabricate(:user, email: invite.email, password_hash: "7af7805c9ee3697ed1a83d5e3cb5a3a431d140933a87fdcdc5a42aeef9337f81")
Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never
invite.redeem
end
it 'enqueues an email if all conditions are satisfied' do
Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username))
invite.redeem
end
end
context "when inviting to groups" do
it "add the user to the correct groups" do
group = Fabricate(:group)
invite.invited_groups.build(group_id: group.id)
invite.save
user = invite.redeem
user.groups.count.should == 1
end
end
context "invite trust levels" do
it "returns the trust level in default_invitee_trust_level" do
SiteSetting.stubs(:default_invitee_trust_level).returns(TrustLevel[3])
invite.redeem.trust_level.should == TrustLevel[3]
end
end
context 'inviting when must_approve_users? is enabled' do
it 'correctly activates accounts' do
SiteSetting.stubs(:must_approve_users).returns(true)
user = invite.redeem
user.approved?.should == true
end
end
context 'simple invite' do
let!(:user) { invite.redeem }
it 'works correctly' do
user.is_a?(User).should == true
user.send_welcome_message.should == true
user.trust_level.should == SiteSetting.default_invitee_trust_level
end
context 'after redeeming' do
before do
invite.reload
end
it 'works correctly' do
# has set the user_id attribute
invite.user.should == user
# returns true for redeemed
invite.should be_redeemed
end
context 'again' do
context "without a passthrough" do
before do
SiteSetting.invite_passthrough_hours = 0
end
it 'will not redeem twice' do
invite.redeem.should be_blank
end
end
context "with a passthrough" do
before do
SiteSetting.invite_passthrough_hours = 1
end
it 'will not redeem twice' do
invite.redeem.should be_present
invite.redeem.send_welcome_message.should == false
end
end
end
end
end
context 'invited to topics' do
let!(:topic) { Fabricate(:private_message_topic) }
let!(:invite) {
topic.invite(topic.user, 'jake@adventuretime.ooo')
}
context 'redeem topic invite' do
it 'adds the user to the topic_users' do
user = invite.redeem
topic.reload
topic.allowed_users.include?(user).should == true
Guardian.new(user).can_see?(topic).should == true
end
end
context 'invited by another user to the same topic' do
let(:coding_horror) { User.find_by(username: "CodingHorror") }
let!(:another_invite) { topic.invite(coding_horror, 'jake@adventuretime.ooo') }
let!(:user) { invite.redeem }
it 'adds the user to the topic_users' do
topic.reload
topic.allowed_users.include?(user).should == true
end
end
context 'invited by another user to a different topic' do
let!(:another_invite) { another_topic.invite(coding_horror, 'jake@adventuretime.ooo') }
let!(:user) { invite.redeem }
let(:coding_horror) { User.find_by(username: "CodingHorror") }
let(:another_topic) { Fabricate(:topic, category_id: nil, archetype: "private_message", user: coding_horror) }
it 'adds the user to the topic_users of the first topic' do
topic.allowed_users.include?(user).should == true
another_topic.allowed_users.include?(user).should == true
another_invite.reload
another_invite.should_not be_redeemed
end
context 'if they redeem the other invite afterwards' do
it 'returns the same user' do
result = another_invite.redeem
result.should == user
another_invite.reload
another_invite.should be_redeemed
end
end
end
end
end
describe '.find_all_invites_from' do
context 'with user that has invited' do
it 'returns invites' do
inviter = Fabricate(:user)
invite = Fabricate(:invite, invited_by: inviter)
invites = Invite.find_all_invites_from(inviter)
expect(invites).to include invite
end
end
context 'with user that has not invited' do
it 'does not return invites' do
user = Fabricate(:user)
Fabricate(:invite)
invites = Invite.find_all_invites_from(user)
expect(invites).to be_empty
end
end
end
describe '.find_redeemed_invites_from' do
it 'returns redeemed invites only' do
inviter = Fabricate(:user)
Fabricate(
:invite,
invited_by: inviter,
user_id: nil,
email: 'pending@example.com'
)
redeemed_invite = Fabricate(
:invite,
invited_by: inviter,
user_id: 123,
email: 'redeemed@example.com'
)
invites = Invite.find_redeemed_invites_from(inviter)
expect(invites).to have(1).items
expect(invites.first).to eq redeemed_invite
end
end
describe '.invalidate_for_email' do
let(:email) { 'invite.me@example.com' }
subject { described_class.invalidate_for_email(email) }
it 'returns nil if there is no invite for the given email' do
subject.should == nil
end
it 'sets the matching invite to be invalid' do
invite = Fabricate(:invite, invited_by: Fabricate(:user), user_id: nil, email: email)
subject.should == invite
subject.link_valid?.should == false
subject.should be_valid
end
it 'sets the matching invite to be invalid without being case-sensitive' do
invite = Fabricate(:invite, invited_by: Fabricate(:user), user_id: nil, email: 'invite.me2@Example.COM')
result = described_class.invalidate_for_email('invite.me2@EXAMPLE.com')
result.should == invite
result.link_valid?.should == false
result.should be_valid
end
end
describe '.redeem_from_email' do
let(:inviter) { Fabricate(:user) }
let(:invite) { Fabricate(:invite, invited_by: inviter, email: 'test@example.com', user_id: nil) }
let(:user) { Fabricate(:user, email: invite.email) }
it 'redeems the invite from email' do
result = Invite.redeem_from_email(user.email)
invite.reload
invite.should be_redeemed
end
it 'does not redeem the invite if email does not match' do
result = Invite.redeem_from_email('test24@example.com')
invite.reload
invite.should_not be_redeemed
end
end
describe '.redeem_from_token' do
let(:inviter) { Fabricate(:user) }
let(:invite) { Fabricate(:invite, invited_by: inviter, email: 'test@example.com', user_id: nil) }
let(:user) { Fabricate(:user, email: invite.email) }
it 'redeems the invite from token' do
result = Invite.redeem_from_token(invite.invite_key, user.email)
invite.reload
invite.should be_redeemed
end
it 'does not redeem the invite if token does not match' do
result = Invite.redeem_from_token("bae0071f995bb4b6f756e80b383778b5", user.email)
invite.reload
invite.should_not be_redeemed
end
end
end