2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2015-10-11 17:41:23 +08:00
|
|
|
require 'rails_helper'
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
describe Invite do
|
|
|
|
|
2014-12-31 22:55:03 +08:00
|
|
|
it { is_expected.to validate_presence_of :invited_by_id }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2015-01-20 02:50:01 +08:00
|
|
|
it { is_expected.to rate_limit }
|
|
|
|
|
2013-06-25 22:15:41 +08:00
|
|
|
let(:iceking) { 'iceking@adventuretime.ooo' }
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context 'user validators' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:coding_horror) { Fabricate(:coding_horror) }
|
|
|
|
fab!(:user) { Fabricate(:user) }
|
2013-02-06 03:16:51 +08:00
|
|
|
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
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).not_to be_valid
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not allow a user to invite themselves" do
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite.email_already_exists).to eq(true)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-10-09 22:44:15 +08:00
|
|
|
context 'email validators' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:coding_horror) { Fabricate(:coding_horror) }
|
2019-02-07 01:08:06 +08:00
|
|
|
|
|
|
|
it "should not allow an invite with unformatted email address" do
|
2020-06-03 10:13:25 +08:00
|
|
|
invite = Fabricate.build(:invite, email: "John Doe <john.doe@example.com>")
|
|
|
|
expect(invite.valid?).to eq(false)
|
|
|
|
expect(invite.errors.details[:email].first[:error]).to eq(I18n.t("user.email.invalid"))
|
2019-02-07 01:08:06 +08:00
|
|
|
end
|
2014-10-09 22:44:15 +08:00
|
|
|
|
2020-07-27 08:23:54 +08:00
|
|
|
it "should not allow an invite with blocklisted email" do
|
2019-02-07 01:08:06 +08:00
|
|
|
invite = Invite.create(email: "test@mailinator.com", invited_by: coding_horror)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).not_to be_valid
|
2014-10-09 22:44:15 +08:00
|
|
|
end
|
|
|
|
|
2020-07-27 08:23:54 +08:00
|
|
|
it "should allow an invite with non-blocklisted email" do
|
2014-10-09 22:44:15 +08:00
|
|
|
invite = Fabricate(:invite, email: "test@mail.com", invited_by: coding_horror)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).to be_valid
|
2014-10-09 22:44:15 +08:00
|
|
|
end
|
|
|
|
|
2020-06-03 10:13:25 +08:00
|
|
|
it "should not allow an invalid email address" do
|
|
|
|
invite = Fabricate.build(:invite, email: 'asjdso')
|
|
|
|
expect(invite.valid?).to eq(false)
|
|
|
|
expect(invite.errors.details[:email].first[:error]).to eq(I18n.t("user.email.invalid"))
|
|
|
|
end
|
2014-10-09 22:44:15 +08:00
|
|
|
end
|
|
|
|
|
2021-02-17 17:31:20 +08:00
|
|
|
context "DiscourseConnect validation" do
|
|
|
|
it "prevents creating an email invite when DiscourseConnect is enabled" do
|
|
|
|
SiteSetting.discourse_connect_url = "https://www.example.com/sso"
|
|
|
|
SiteSetting.enable_discourse_connect = true
|
2021-02-04 02:01:23 +08:00
|
|
|
|
|
|
|
invite = Fabricate.build(:invite, email: "test@mail.com")
|
|
|
|
expect(invite).not_to be_valid
|
2021-02-08 18:04:33 +08:00
|
|
|
expect(invite.errors.details[:email].first[:error]).to eq(I18n.t("invite.disabled_errors.discourse_connect_enabled"))
|
2021-02-04 02:01:23 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context '#create' do
|
|
|
|
context 'saved' do
|
|
|
|
subject { Fabricate(:invite) }
|
2014-10-29 23:06:50 +08:00
|
|
|
|
|
|
|
it "works" do
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(subject.invite_key).to be_present
|
|
|
|
expect(subject.email_already_exists).to eq(false)
|
2014-10-29 23:06:50 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
it 'should store a lower case version of the email' do
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(subject.email).to eq(iceking)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'to a topic' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:topic) { Fabricate(:topic) }
|
2013-02-06 03:16:51 +08:00
|
|
|
let(:inviter) { topic.user }
|
2013-02-26 00:42:20 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context 'email' do
|
|
|
|
it 'enqueues a job to email the invite' do
|
2018-12-05 23:43:07 +08:00
|
|
|
expect do
|
|
|
|
Invite.invite_by_email(iceking, inviter, topic)
|
|
|
|
end.to change { Jobs::InviteEmail.jobs.size }
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-19 13:59:12 +08:00
|
|
|
context 'links' do
|
|
|
|
it 'does not enqueue a job to email the invite' do
|
|
|
|
expect do
|
2020-06-09 23:19:32 +08:00
|
|
|
Invite.generate_single_use_invite_link(iceking, inviter, topic)
|
2019-07-19 13:59:12 +08:00
|
|
|
end.not_to change { Jobs::InviteEmail.jobs.size }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context 'destroyed' do
|
|
|
|
it "can invite the same user after their invite was destroyed" do
|
2018-12-05 23:43:07 +08:00
|
|
|
Invite.invite_by_email(iceking, inviter, topic).destroy!
|
|
|
|
invite = Invite.invite_by_email(iceking, inviter, topic)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).to be_present
|
2013-02-26 00:42:20 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'after created' do
|
2018-12-05 23:43:07 +08:00
|
|
|
let(:invite) { Invite.invite_by_email(iceking, inviter, topic) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
it 'belongs to the topic' do
|
2018-12-05 23:43:07 +08:00
|
|
|
expect(topic.invites).to eq([invite])
|
|
|
|
expect(invite.topics).to eq([topic])
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when added by another user' do
|
2019-05-10 18:59:31 +08:00
|
|
|
fab!(:coding_horror) { Fabricate(:coding_horror) }
|
2018-12-05 23:43:07 +08:00
|
|
|
|
|
|
|
let(:new_invite) do
|
|
|
|
Invite.invite_by_email(iceking, coding_horror, topic)
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
it 'returns a different invite' do
|
2018-12-05 23:43:07 +08:00
|
|
|
expect(new_invite).not_to eq(invite)
|
|
|
|
expect(new_invite.invite_key).not_to eq(invite.invite_key)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(new_invite.topics).to eq([topic])
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when adding a duplicate' do
|
|
|
|
it 'returns the original invite' do
|
2018-12-05 23:43:07 +08:00
|
|
|
%w{
|
|
|
|
iceking@adventuretime.ooo
|
|
|
|
iceking@ADVENTURETIME.ooo
|
|
|
|
ICEKING@adventuretime.ooo
|
|
|
|
}.each do |email|
|
|
|
|
expect(Invite.invite_by_email(
|
|
|
|
email, inviter, topic
|
|
|
|
)).to eq(invite)
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2014-01-22 04:13:55 +08:00
|
|
|
|
2017-04-11 22:05:35 +08:00
|
|
|
it 'updates timestamp of existing invite' do
|
2020-03-11 05:13:17 +08:00
|
|
|
freeze_time
|
2018-12-05 23:43:07 +08:00
|
|
|
invite.update!(created_at: 10.days.ago)
|
|
|
|
|
|
|
|
resend_invite = Invite.invite_by_email(
|
|
|
|
'iceking@adventuretime.ooo', inviter, topic
|
|
|
|
)
|
|
|
|
|
2020-03-11 05:13:17 +08:00
|
|
|
expect(resend_invite.created_at).to eq_time(Time.zone.now)
|
2017-04-11 22:05:35 +08:00
|
|
|
end
|
|
|
|
|
2014-01-22 04:13:55 +08:00
|
|
|
it 'returns a new invite if the other has expired' do
|
2017-04-11 22:05:35 +08:00
|
|
|
SiteSetting.invite_expiry_days = 1
|
2020-06-09 23:19:32 +08:00
|
|
|
invite.update!(expires_at: 2.days.ago)
|
2018-12-05 23:43:07 +08:00
|
|
|
|
|
|
|
new_invite = Invite.invite_by_email(
|
|
|
|
'iceking@adventuretime.ooo', inviter, topic
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(new_invite).not_to eq(invite)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(new_invite).not_to be_expired
|
2014-01-22 04:13:55 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when adding to another topic' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:another_topic) { Fabricate(:topic, user: topic.user) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
it 'should be the same invite' do
|
2018-12-05 23:43:07 +08:00
|
|
|
new_invite = Invite.invite_by_email(iceking, inviter, another_topic)
|
|
|
|
expect(new_invite).to eq(invite)
|
|
|
|
expect(another_topic.invites).to eq([invite])
|
|
|
|
expect(invite.topics).to match_array([topic, another_topic])
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2013-02-26 00:42:20 +08:00
|
|
|
end
|
2018-12-11 06:24:02 +08:00
|
|
|
|
2019-12-17 23:13:49 +08:00
|
|
|
it 'resets expiry of a resent invite' do
|
|
|
|
SiteSetting.invite_expiry_days = 2
|
2020-10-26 18:26:43 +08:00
|
|
|
invite.update!(invalidated_at: 10.days.ago, expires_at: 10.days.ago)
|
2019-12-17 23:13:49 +08:00
|
|
|
expect(invite).to be_expired
|
|
|
|
|
|
|
|
invite.resend_invite
|
2020-10-26 18:26:43 +08:00
|
|
|
expect(invite.invalidated_at).to be_nil
|
2019-12-17 23:13:49 +08:00
|
|
|
expect(invite).not_to be_expired
|
|
|
|
end
|
|
|
|
|
2019-07-19 13:59:12 +08:00
|
|
|
it 'correctly marks invite emailed_status for email invites' do
|
|
|
|
expect(invite.emailed_status).to eq(Invite.emailed_status_types[:sending])
|
2018-12-11 06:24:02 +08:00
|
|
|
|
|
|
|
Invite.invite_by_email(iceking, inviter, topic)
|
2019-07-19 13:59:12 +08:00
|
|
|
expect(invite.reload.emailed_status).to eq(Invite.emailed_status_types[:sending])
|
2018-12-11 06:24:02 +08:00
|
|
|
end
|
|
|
|
|
2019-07-19 13:59:12 +08:00
|
|
|
it 'does not mark emailed_status as sending after generating invite link' do
|
|
|
|
expect(invite.emailed_status).to eq(Invite.emailed_status_types[:sending])
|
2018-12-11 06:24:02 +08:00
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
Invite.generate_single_use_invite_link(iceking, inviter, topic)
|
2019-07-19 13:59:12 +08:00
|
|
|
expect(invite.reload.emailed_status).to eq(Invite.emailed_status_types[:not_required])
|
2018-12-11 06:24:02 +08:00
|
|
|
|
|
|
|
Invite.invite_by_email(iceking, inviter, topic)
|
2019-07-19 13:59:12 +08:00
|
|
|
expect(invite.reload.emailed_status).to eq(Invite.emailed_status_types[:not_required])
|
2018-12-11 06:24:02 +08:00
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
Invite.generate_single_use_invite_link(iceking, inviter, topic)
|
2019-07-19 13:59:12 +08:00
|
|
|
expect(invite.reload.emailed_status).to eq(Invite.emailed_status_types[:not_required])
|
2018-12-11 06:24:02 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
2020-06-09 23:19:32 +08:00
|
|
|
|
|
|
|
context 'invite links' do
|
|
|
|
let(:inviter) { Fabricate(:user) }
|
|
|
|
|
2021-01-20 16:50:02 +08:00
|
|
|
it 'with single use can exist' do
|
|
|
|
Invite.generate_multiple_use_invite_link(invited_by: inviter, max_redemptions_allowed: 1)
|
|
|
|
invite_link = Invite.last
|
|
|
|
expect(invite_link.is_invite_link?).to eq(true)
|
|
|
|
end
|
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
it "has sane defaults" do
|
|
|
|
Invite.generate_multiple_use_invite_link(invited_by: inviter)
|
|
|
|
invite_link = Invite.last
|
|
|
|
expect(invite_link.max_redemptions_allowed).to eq(5)
|
|
|
|
expect(invite_link.expires_at.to_date).to eq(1.month.from_now.to_date)
|
|
|
|
expect(invite_link.emailed_status).to eq(Invite.emailed_status_types[:not_required])
|
|
|
|
expect(invite_link.is_invite_link?).to eq(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'checks for max_redemptions_allowed range' do
|
|
|
|
SiteSetting.invite_link_max_redemptions_limit = 1000
|
|
|
|
expect do
|
|
|
|
Invite.generate_multiple_use_invite_link(invited_by: inviter, max_redemptions_allowed: 1001)
|
|
|
|
end.to raise_error(ActiveRecord::RecordInvalid)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not enqueue a job to email the invite' do
|
|
|
|
expect do
|
|
|
|
Invite.generate_multiple_use_invite_link(invited_by: inviter)
|
|
|
|
end.not_to change { Jobs::InviteEmail.jobs.size }
|
|
|
|
end
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'an existing user' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:topic) { Fabricate(:topic, category_id: nil, archetype: 'private_message') }
|
|
|
|
fab!(:coding_horror) { Fabricate(:coding_horror) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-09-11 15:39:20 +08:00
|
|
|
it "works" do
|
2018-12-05 23:43:07 +08:00
|
|
|
expect do
|
|
|
|
Invite.invite_by_email(coding_horror.email, topic.user, topic)
|
|
|
|
end.to raise_error(Invite::UserExists)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-19 22:29:15 +08:00
|
|
|
context 'a staged user' do
|
|
|
|
it 'creates an invite for a staged user' do
|
|
|
|
Fabricate(:staged, email: 'staged@account.com')
|
|
|
|
invite = Invite.invite_by_email('staged@account.com', Fabricate(:coding_horror))
|
|
|
|
|
|
|
|
expect(invite).to be_valid
|
|
|
|
expect(invite.email).to eq('staged@account.com')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context '.redeem' do
|
|
|
|
|
2019-05-10 18:59:31 +08:00
|
|
|
fab!(:invite) { Fabricate(:invite) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
it 'creates a notification for the invitee' do
|
2014-12-31 22:55:03 +08:00
|
|
|
expect { invite.redeem }.to change(Notification, :count)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'wont redeem an expired invite' do
|
2019-05-13 15:42:13 +08:00
|
|
|
SiteSetting.invite_expiry_days = 10
|
2020-06-09 23:19:32 +08:00
|
|
|
invite.update_column(:expires_at, 20.days.ago)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite.redeem).to be_blank
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'wont redeem a deleted invite' do
|
|
|
|
invite.destroy
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite.redeem).to be_blank
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-01-22 05:53:46 +08:00
|
|
|
it "won't redeem an invalidated invite" do
|
|
|
|
invite.invalidated_at = 1.day.ago
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite.redeem).to be_blank
|
2014-01-22 05:53:46 +08:00
|
|
|
end
|
|
|
|
|
2015-03-26 00:55:18 +08:00
|
|
|
context "deletes duplicate invites" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:another_user) { Fabricate(:user) }
|
2015-03-26 00:55:18 +08:00
|
|
|
|
2019-05-17 05:55:36 +08:00
|
|
|
it 'delete duplicate invite' do
|
2015-03-26 00:55:18 +08:00
|
|
|
another_invite = Fabricate(:invite, email: invite.email, invited_by: another_user)
|
|
|
|
invite.redeem
|
|
|
|
duplicate_invite = Invite.find_by(id: another_invite.id)
|
|
|
|
expect(duplicate_invite).to be_nil
|
|
|
|
end
|
|
|
|
|
2015-03-26 01:59:37 +08:00
|
|
|
it 'does not delete already redeemed invite' do
|
2020-06-09 23:19:32 +08:00
|
|
|
redeemed_invite = Fabricate(:invite, email: invite.email, invited_by: another_user)
|
|
|
|
Fabricate(:invited_user, invite: invite, user: Fabricate(:user))
|
2015-03-26 01:59:37 +08:00
|
|
|
invite.redeem
|
|
|
|
used_invite = Invite.find_by(id: redeemed_invite.id)
|
|
|
|
expect(used_invite).not_to be_nil
|
|
|
|
end
|
2015-03-26 00:55:18 +08:00
|
|
|
end
|
|
|
|
|
2016-09-21 01:12:00 +08:00
|
|
|
context "as a moderator" do
|
|
|
|
it "will give the user a moderator flag" do
|
|
|
|
invite.invited_by = Fabricate(:admin)
|
|
|
|
invite.moderator = true
|
|
|
|
invite.save
|
|
|
|
|
|
|
|
user = invite.redeem
|
|
|
|
expect(user).to be_moderator
|
|
|
|
end
|
|
|
|
|
|
|
|
it "will not give the user a moderator flag if the inviter is not staff" do
|
|
|
|
invite.moderator = true
|
|
|
|
invite.save
|
|
|
|
|
|
|
|
user = invite.redeem
|
|
|
|
expect(user).not_to be_moderator
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-05-08 14:45:49 +08:00
|
|
|
context "when inviting to groups" do
|
|
|
|
it "add the user to the correct groups" do
|
|
|
|
group = Fabricate(:group)
|
2020-06-15 17:13:56 +08:00
|
|
|
group.add_owner(invite.invited_by)
|
2014-05-08 14:45:49 +08:00
|
|
|
invite.invited_groups.build(group_id: group.id)
|
|
|
|
invite.save
|
|
|
|
|
|
|
|
user = invite.redeem
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(user.groups.count).to eq(1)
|
2014-05-08 14:45:49 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "invite trust levels" do
|
2013-02-06 03:16:51 +08:00
|
|
|
it "returns the trust level in default_invitee_trust_level" do
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.default_invitee_trust_level = TrustLevel[3]
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite.redeem.trust_level).to eq(TrustLevel[3])
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-07-11 09:21:39 +08:00
|
|
|
context 'inviting when must_approve_users? is enabled' do
|
2014-01-18 00:11:42 +08:00
|
|
|
it 'correctly activates accounts' do
|
2017-03-05 21:55:21 +08:00
|
|
|
invite.invited_by = Fabricate(:admin)
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.must_approve_users = true
|
2013-07-11 09:21:39 +08:00
|
|
|
user = invite.redeem
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(user.approved?).to eq(true)
|
2013-07-11 09:21:39 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
context 'simple invite' do
|
|
|
|
let!(:user) { invite.redeem }
|
|
|
|
|
2013-07-11 09:21:39 +08:00
|
|
|
it 'works correctly' do
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(user.is_a?(User)).to eq(true)
|
|
|
|
expect(user.send_welcome_message).to eq(true)
|
|
|
|
expect(user.trust_level).to eq(SiteSetting.default_invitee_trust_level)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'after redeeming' do
|
|
|
|
before do
|
|
|
|
invite.reload
|
|
|
|
end
|
|
|
|
|
2013-07-11 09:21:39 +08:00
|
|
|
it 'works correctly' do
|
|
|
|
# has set the user_id attribute
|
2020-06-09 23:19:32 +08:00
|
|
|
expect(invite.invited_users.first.user).to eq(user)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-07-11 09:21:39 +08:00
|
|
|
# returns true for redeemed
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).to be_redeemed
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'again' do
|
2018-05-08 22:42:58 +08:00
|
|
|
it 'will not redeem twice' do
|
|
|
|
expect(invite.redeem).to be_blank
|
2014-07-02 00:52:52 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'invited to topics' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:tl2_user) { Fabricate(:user, trust_level: 2) }
|
|
|
|
fab!(:topic) { Fabricate(:private_message_topic, user: tl2_user) }
|
2018-02-26 12:46:15 +08:00
|
|
|
|
|
|
|
let!(:invite) do
|
2014-05-09 09:45:18 +08:00
|
|
|
topic.invite(topic.user, 'jake@adventuretime.ooo')
|
2018-02-26 12:46:15 +08:00
|
|
|
Invite.find_by(invited_by_id: topic.user)
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
context 'redeem topic invite' do
|
|
|
|
it 'adds the user to the topic_users' do
|
2014-05-09 09:45:18 +08:00
|
|
|
user = invite.redeem
|
|
|
|
topic.reload
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(topic.allowed_users.include?(user)).to eq(true)
|
|
|
|
expect(Guardian.new(user).can_see?(topic)).to eq(true)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'invited by another user to the same topic' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:another_tl2_user) { Fabricate(:user, trust_level: 2) }
|
2017-02-03 01:38:25 +08:00
|
|
|
let!(:another_invite) { topic.invite(another_tl2_user, 'jake@adventuretime.ooo') }
|
2013-02-06 03:16:51 +08:00
|
|
|
let!(:user) { invite.redeem }
|
|
|
|
|
|
|
|
it 'adds the user to the topic_users' do
|
2014-05-09 09:45:18 +08:00
|
|
|
topic.reload
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(topic.allowed_users.include?(user)).to eq(true)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'invited by another user to a different topic' do
|
|
|
|
let!(:user) { invite.redeem }
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:another_tl2_user) { Fabricate(:user, trust_level: 2) }
|
|
|
|
fab!(:another_topic) { Fabricate(:topic, user: another_tl2_user) }
|
2014-05-09 09:45:18 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
it 'adds the user to the topic_users of the first topic' do
|
2017-02-03 01:38:25 +08:00
|
|
|
expect(another_topic.invite(another_tl2_user, user.username)).to be_truthy # invited via username
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(topic.allowed_users.include?(user)).to eq(true)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
2013-02-26 00:42:20 +08:00
|
|
|
end
|
2020-06-09 23:19:32 +08:00
|
|
|
|
|
|
|
context 'invite_link' do
|
|
|
|
fab!(:invite_link) { Fabricate(:invite, email: nil, max_redemptions_allowed: 5, expires_at: 1.month.from_now, emailed_status: Invite.emailed_status_types[:not_required]) }
|
|
|
|
|
|
|
|
it 'works correctly' do
|
|
|
|
user = invite_link.redeem_invite_link(email: 'foo@example.com')
|
|
|
|
expect(user.is_a?(User)).to eq(true)
|
|
|
|
expect(user.send_welcome_message).to eq(true)
|
|
|
|
expect(user.trust_level).to eq(SiteSetting.default_invitee_trust_level)
|
|
|
|
expect(user.active).to eq(false)
|
|
|
|
invite_link.reload
|
|
|
|
expect(invite_link.redemption_count).to eq(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns error if user with that email already exists' do
|
|
|
|
user = Fabricate(:user)
|
|
|
|
expect do
|
|
|
|
invite_link.redeem_invite_link(email: user.email)
|
|
|
|
end.to raise_error(Invite::UserExists)
|
|
|
|
end
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
describe '.find_all_pending_invites_from' do
|
2013-11-09 03:11:41 +08:00
|
|
|
context 'with user that has invited' do
|
|
|
|
it 'returns invites' do
|
|
|
|
inviter = Fabricate(:user)
|
|
|
|
invite = Fabricate(:invite, invited_by: inviter)
|
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
invites = Invite.find_all_pending_invites_from(inviter)
|
2013-11-09 03:11:41 +08:00
|
|
|
|
|
|
|
expect(invites).to include invite
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with user that has not invited' do
|
|
|
|
it 'does not return invites' do
|
|
|
|
user = Fabricate(:user)
|
2014-05-08 14:45:49 +08:00
|
|
|
Fabricate(:invite)
|
2013-11-09 03:11:41 +08:00
|
|
|
|
2020-06-09 23:19:32 +08:00
|
|
|
invites = Invite.find_all_pending_invites_from(user)
|
2013-11-09 03:11:41 +08:00
|
|
|
|
|
|
|
expect(invites).to be_empty
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-07-11 20:09:12 +08:00
|
|
|
describe '.find_pending_invites_from' do
|
|
|
|
it 'returns pending invites only' do
|
|
|
|
inviter = Fabricate(:user)
|
2020-06-09 23:19:32 +08:00
|
|
|
redeemed_invite = Fabricate(
|
2015-07-11 20:09:12 +08:00
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
email: 'redeemed@example.com'
|
|
|
|
)
|
2020-06-09 23:19:32 +08:00
|
|
|
Fabricate(:invited_user, invite: redeemed_invite, user: Fabricate(:user))
|
2015-07-11 20:09:12 +08:00
|
|
|
|
|
|
|
pending_invite = Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
email: 'pending@example.com'
|
|
|
|
)
|
|
|
|
|
|
|
|
invites = Invite.find_pending_invites_from(inviter)
|
|
|
|
|
2017-08-31 12:06:56 +08:00
|
|
|
expect(invites.length).to eq(1)
|
2015-07-11 20:09:12 +08:00
|
|
|
expect(invites.first).to eq pending_invite
|
2017-11-14 18:38:54 +08:00
|
|
|
|
|
|
|
expect(Invite.find_pending_invites_count(inviter)).to eq(1)
|
2015-07-11 20:09:12 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-11-09 03:11:41 +08:00
|
|
|
describe '.find_redeemed_invites_from' do
|
|
|
|
it 'returns redeemed invites only' do
|
|
|
|
inviter = Fabricate(:user)
|
2014-05-08 14:45:49 +08:00
|
|
|
Fabricate(
|
2013-11-09 03:11:41 +08:00
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
email: 'pending@example.com'
|
|
|
|
)
|
2014-05-08 14:45:49 +08:00
|
|
|
|
2013-11-09 03:11:41 +08:00
|
|
|
redeemed_invite = Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
email: 'redeemed@example.com'
|
|
|
|
)
|
2020-06-09 23:19:32 +08:00
|
|
|
Fabricate(:invited_user, invite: redeemed_invite, user: Fabricate(:user))
|
2013-11-09 03:11:41 +08:00
|
|
|
|
|
|
|
invites = Invite.find_redeemed_invites_from(inviter)
|
|
|
|
|
2017-08-31 12:06:56 +08:00
|
|
|
expect(invites.length).to eq(1)
|
2020-06-09 23:19:32 +08:00
|
|
|
expect(invites.first).to eq redeemed_invite.invited_users.first
|
2017-11-14 18:38:54 +08:00
|
|
|
|
|
|
|
expect(Invite.find_redeemed_invites_count(inviter)).to eq(1)
|
2013-11-09 03:11:41 +08:00
|
|
|
end
|
2020-06-09 23:19:32 +08:00
|
|
|
|
|
|
|
it 'returns redeemed invites for invite links' do
|
|
|
|
inviter = Fabricate(:user)
|
|
|
|
invite_link = Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
max_redemptions_allowed: 50
|
|
|
|
)
|
|
|
|
Fabricate(:invited_user, invite: invite_link, user: Fabricate(:user))
|
|
|
|
Fabricate(:invited_user, invite: invite_link, user: Fabricate(:user))
|
|
|
|
Fabricate(:invited_user, invite: invite_link, user: Fabricate(:user))
|
|
|
|
|
|
|
|
invites = Invite.find_redeemed_invites_from(inviter)
|
|
|
|
expect(invites.length).to eq(3)
|
|
|
|
expect(Invite.find_redeemed_invites_count(inviter)).to eq(3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.find_links_invites_from' do
|
|
|
|
it 'returns invite links only' do
|
|
|
|
inviter = Fabricate(:user)
|
|
|
|
Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
email: 'pending@example.com'
|
|
|
|
)
|
|
|
|
|
|
|
|
invite_link_1 = Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
max_redemptions_allowed: 5
|
|
|
|
)
|
|
|
|
|
|
|
|
invite_link_2 = Fabricate(
|
|
|
|
:invite,
|
|
|
|
invited_by: inviter,
|
|
|
|
max_redemptions_allowed: 50
|
|
|
|
)
|
|
|
|
|
|
|
|
invites = Invite.find_links_invites_from(inviter)
|
|
|
|
|
|
|
|
expect(invites.length).to eq(2)
|
|
|
|
expect(invites.first).to eq(invite_link_2)
|
|
|
|
expect(invites.first.max_redemptions_allowed).to eq(50)
|
|
|
|
|
|
|
|
expect(Invite.find_links_invites_count(inviter)).to eq(2)
|
|
|
|
end
|
2013-11-09 03:11:41 +08:00
|
|
|
end
|
2014-01-22 05:53:46 +08:00
|
|
|
|
|
|
|
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
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(subject).to eq(nil)
|
2014-01-22 05:53:46 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'sets the matching invite to be invalid' do
|
2020-06-09 23:19:32 +08:00
|
|
|
invite = Fabricate(:invite, invited_by: Fabricate(:user), email: email)
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(subject).to eq(invite)
|
|
|
|
expect(subject.link_valid?).to eq(false)
|
|
|
|
expect(subject).to be_valid
|
2014-01-22 05:53:46 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'sets the matching invite to be invalid without being case-sensitive' do
|
2020-06-09 23:19:32 +08:00
|
|
|
invite = Fabricate(:invite, invited_by: Fabricate(:user), email: 'invite.me2@Example.COM')
|
2014-01-22 05:53:46 +08:00
|
|
|
result = described_class.invalidate_for_email('invite.me2@EXAMPLE.com')
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(result).to eq(invite)
|
|
|
|
expect(result.link_valid?).to eq(false)
|
|
|
|
expect(result).to be_valid
|
2014-01-22 05:53:46 +08:00
|
|
|
end
|
|
|
|
end
|
2014-07-05 03:53:41 +08:00
|
|
|
|
|
|
|
describe '.redeem_from_email' do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:inviter) { Fabricate(:user) }
|
2020-06-09 23:19:32 +08:00
|
|
|
fab!(:invite) { Fabricate(:invite, invited_by: inviter, email: 'test@example.com') }
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:user) { Fabricate(:user, email: invite.email) }
|
2014-07-05 03:53:41 +08:00
|
|
|
|
|
|
|
it 'redeems the invite from email' do
|
2016-09-21 01:12:00 +08:00
|
|
|
Invite.redeem_from_email(user.email)
|
2014-07-05 03:53:41 +08:00
|
|
|
invite.reload
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).to be_redeemed
|
2014-07-05 03:53:41 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not redeem the invite if email does not match' do
|
2016-09-21 01:12:00 +08:00
|
|
|
Invite.redeem_from_email('test24@example.com')
|
2014-07-05 03:53:41 +08:00
|
|
|
invite.reload
|
2014-12-31 22:55:03 +08:00
|
|
|
expect(invite).not_to be_redeemed
|
2014-07-05 03:53:41 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-07-08 18:19:46 +08:00
|
|
|
describe '.resend_all_invites_from' do
|
|
|
|
it 'resends all non-redeemed invites by a user' do
|
|
|
|
SiteSetting.invite_expiry_days = 30
|
|
|
|
user = Fabricate(:user)
|
|
|
|
new_invite = Fabricate(:invite, invited_by: user)
|
|
|
|
expired_invite = Fabricate(:invite, invited_by: user)
|
|
|
|
expired_invite.update!(expires_at: 2.days.ago)
|
|
|
|
redeemed_invite = Fabricate(:invite, invited_by: user)
|
|
|
|
Fabricate(:invited_user, invite: redeemed_invite, user: Fabricate(:user))
|
|
|
|
redeemed_invite.update!(expires_at: 5.days.ago)
|
|
|
|
|
|
|
|
Invite.resend_all_invites_from(user.id)
|
|
|
|
new_invite.reload
|
|
|
|
expired_invite.reload
|
|
|
|
redeemed_invite.reload
|
|
|
|
|
|
|
|
expect(new_invite.expires_at.to_date).to eq(30.days.from_now.to_date)
|
|
|
|
expect(expired_invite.expires_at.to_date).to eq(30.days.from_now.to_date)
|
|
|
|
expect(redeemed_invite.expires_at.to_date).to eq(5.days.ago.to_date)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-07 17:49:46 +08:00
|
|
|
describe '.rescind_all_expired_invites_from' do
|
|
|
|
it 'removes all expired invites sent by a user' do
|
|
|
|
SiteSetting.invite_expiry_days = 1
|
2017-06-29 22:32:07 +08:00
|
|
|
user = Fabricate(:user)
|
|
|
|
invite_1 = Fabricate(:invite, invited_by: user)
|
|
|
|
invite_2 = Fabricate(:invite, invited_by: user)
|
2019-03-07 17:49:46 +08:00
|
|
|
expired_invite = Fabricate(:invite, invited_by: user)
|
2020-06-09 23:19:32 +08:00
|
|
|
expired_invite.update!(expires_at: 2.days.ago)
|
2019-03-07 17:49:46 +08:00
|
|
|
Invite.rescind_all_expired_invites_from(user)
|
2017-06-29 22:32:07 +08:00
|
|
|
invite_1.reload
|
|
|
|
invite_2.reload
|
2019-03-07 17:49:46 +08:00
|
|
|
expired_invite.reload
|
|
|
|
expect(invite_1.deleted_at).to eq(nil)
|
|
|
|
expect(invite_2.deleted_at).to eq(nil)
|
|
|
|
expect(expired_invite.deleted_at).to be_present
|
2017-06-29 22:32:07 +08:00
|
|
|
end
|
|
|
|
end
|
2019-07-19 13:59:12 +08:00
|
|
|
|
|
|
|
describe '#emailed_status_types' do
|
|
|
|
context "verify enum sequence" do
|
|
|
|
before do
|
|
|
|
@emailed_status_types = Invite.emailed_status_types
|
|
|
|
end
|
|
|
|
|
|
|
|
it "'not_required' should be at 0 position" do
|
|
|
|
expect(@emailed_status_types[:not_required]).to eq(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "'sent' should be at 4th position" do
|
|
|
|
expect(@emailed_status_types[:sent]).to eq(4)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|