2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe Jobs::BulkInvite do
|
2019-04-15 21:13:53 +08:00
|
|
|
describe "#execute" do
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:user)
|
|
|
|
fab!(:admin)
|
|
|
|
fab!(:east_coast_user)
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:group1) { Fabricate(:group, name: "group1") }
|
|
|
|
fab!(:group2) { Fabricate(:group, name: "group2") }
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:topic)
|
2019-10-30 14:08:47 +08:00
|
|
|
let(:staged_user) { Fabricate(:user, staged: true, active: false) }
|
2021-03-29 19:03:19 +08:00
|
|
|
let(:email) { "test@discourse.org" }
|
2022-10-04 23:41:06 +08:00
|
|
|
let(:invites) do
|
|
|
|
[
|
|
|
|
{ email: user.email },
|
|
|
|
{ email: staged_user.email },
|
|
|
|
{ email: "test2@discourse.org" },
|
|
|
|
{ email: "test@discourse.org", groups: "GROUP1;group2", topic_id: topic.id },
|
|
|
|
{ email: "invalid" },
|
|
|
|
]
|
2014-06-26 02:35:11 +08:00
|
|
|
end
|
|
|
|
|
2024-05-18 02:21:21 +08:00
|
|
|
def parse_skipped_and_failed_emails(input)
|
|
|
|
skipped_invites_emails = input[/Skipped Invites for Emails?:\s+``` text\n(.+?)\n```/m, 1]
|
|
|
|
failed_invites_emails = input[/Failed Invites for Emails?:\s+``` text\n(.+?)\n```/m, 1]
|
|
|
|
|
|
|
|
{ skipped_invites: skipped_invites_emails, failed_invites: failed_invites_emails }
|
|
|
|
end
|
|
|
|
|
2019-04-15 21:13:53 +08:00
|
|
|
it "raises an error when the invites array is missing" do
|
2019-06-04 22:49:46 +08:00
|
|
|
expect { Jobs::BulkInvite.new.execute(current_user_id: user.id) }.to raise_error(
|
2019-04-15 21:13:53 +08:00
|
|
|
Discourse::InvalidParameters,
|
|
|
|
/invites/,
|
|
|
|
)
|
2014-06-26 02:35:11 +08:00
|
|
|
end
|
|
|
|
|
2019-04-15 21:13:53 +08:00
|
|
|
it "raises an error when current_user_id is not valid" do
|
|
|
|
expect { Jobs::BulkInvite.new.execute(invites: invites) }.to raise_error(
|
2019-05-06 17:09:47 +08:00
|
|
|
Discourse::InvalidParameters,
|
|
|
|
/current_user_id/,
|
2019-04-15 21:13:53 +08:00
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
|
|
|
|
2019-04-15 21:13:53 +08:00
|
|
|
it "creates the right invites" do
|
|
|
|
described_class.new.execute(current_user_id: admin.id, invites: invites)
|
2014-06-26 23:16:53 +08:00
|
|
|
|
2019-10-30 14:08:47 +08:00
|
|
|
expect(Invite.exists?(email: staged_user.email)).to eq(true)
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(Invite.exists?(email: "test2@discourse.org")).to eq(true)
|
2019-04-15 21:13:53 +08:00
|
|
|
|
2019-10-30 14:08:47 +08:00
|
|
|
invite = Invite.last
|
|
|
|
expect(invite.email).to eq(email)
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(invite.invited_groups.pluck(:group_id)).to contain_exactly(group1.id, group2.id)
|
2019-04-15 21:13:53 +08:00
|
|
|
expect(invite.topic_invites.pluck(:topic_id)).to contain_exactly(topic.id)
|
2022-10-04 23:41:06 +08:00
|
|
|
|
|
|
|
post = Post.last
|
|
|
|
expect(post.raw).to include("3 invites")
|
|
|
|
expect(post.raw).to include("1 skipped")
|
|
|
|
expect(post.raw).to include("0 warning")
|
|
|
|
expect(post.raw).to include("1 error")
|
2014-06-26 02:35:11 +08:00
|
|
|
end
|
|
|
|
|
2023-08-19 00:33:40 +08:00
|
|
|
it "handles daylight savings time correctly" do
|
|
|
|
# EDT (-04:00) transitions to EST (-05:00) on the first Sunday in November.
|
|
|
|
# Freeze time to the last Day of October, so that the creation and expiration date will be in different time zones.
|
|
|
|
Time.use_zone("Eastern Time (US & Canada)") do
|
|
|
|
freeze_time DateTime.parse("2023-10-31 06:00:00 -0400")
|
|
|
|
described_class.new.execute(current_user_id: east_coast_user.id, invites: invites)
|
|
|
|
invite = Invite.first
|
|
|
|
expect(invite.expires_at.hour).to equal(6)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-15 21:13:53 +08:00
|
|
|
it "does not create invited groups for automatic groups" do
|
|
|
|
group2.update!(automatic: true)
|
|
|
|
|
|
|
|
described_class.new.execute(current_user_id: admin.id, invites: invites)
|
|
|
|
|
|
|
|
invite = Invite.last
|
|
|
|
expect(invite.email).to eq(email)
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(invite.invited_groups.pluck(:group_id)).to contain_exactly(group1.id)
|
2022-10-04 23:41:06 +08:00
|
|
|
|
|
|
|
post = Post.last
|
|
|
|
expect(post.raw).to include("1 warning")
|
2019-04-15 21:13:53 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "does not create invited groups record if the user can not manage the group" do
|
|
|
|
group1.add_owner(user)
|
|
|
|
|
|
|
|
described_class.new.execute(current_user_id: user.id, invites: invites)
|
|
|
|
|
|
|
|
invite = Invite.last
|
|
|
|
expect(invite.email).to eq(email)
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(invite.invited_groups.pluck(:group_id)).to contain_exactly(group1.id)
|
2019-04-15 21:13:53 +08:00
|
|
|
end
|
2019-04-15 21:26:03 +08:00
|
|
|
|
|
|
|
it "adds existing users to valid groups" do
|
2021-03-29 19:03:19 +08:00
|
|
|
existing_user = Fabricate(:user, email: "test@discourse.org")
|
2019-04-15 21:26:03 +08:00
|
|
|
|
|
|
|
group2.update!(automatic: true)
|
|
|
|
|
|
|
|
expect do
|
|
|
|
described_class.new.execute(current_user_id: admin.id, invites: invites)
|
2019-10-30 14:08:47 +08:00
|
|
|
end.to change { Invite.count }.by(2)
|
2019-04-15 21:26:03 +08:00
|
|
|
|
2019-10-30 14:08:47 +08:00
|
|
|
expect(Invite.exists?(email: staged_user.email)).to eq(true)
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(Invite.exists?(email: "test2@discourse.org")).to eq(true)
|
2019-04-15 21:26:03 +08:00
|
|
|
expect(existing_user.reload.groups).to eq([group1])
|
|
|
|
end
|
2014-06-26 02:35:11 +08:00
|
|
|
|
2021-05-21 09:43:47 +08:00
|
|
|
it "can create staged users and prepopulate user fields" do
|
2021-03-31 18:42:53 +08:00
|
|
|
user_field = Fabricate(:user_field, name: "Location")
|
2021-04-01 00:19:57 +08:00
|
|
|
user_field_color = Fabricate(:user_field, field_type: "dropdown", name: "Color")
|
|
|
|
user_field_color.user_field_options.create!(value: "Red")
|
|
|
|
user_field_color.user_field_options.create!(value: "Green")
|
|
|
|
user_field_color.user_field_options.create!(value: "Blue")
|
|
|
|
|
2021-03-29 19:03:19 +08:00
|
|
|
described_class.new.execute(
|
|
|
|
current_user_id: admin.id,
|
|
|
|
invites: [
|
|
|
|
{ email: "test@discourse.org" }, # new user without user fields
|
2021-04-01 00:19:57 +08:00
|
|
|
{ email: user.email, location: "value 1", color: "blue" }, # existing user with user fields
|
|
|
|
{ email: staged_user.email, location: "value 2", color: "redd" }, # existing staged user with user fields
|
2021-03-31 18:42:53 +08:00
|
|
|
{ email: "test2@discourse.org", location: "value 3" }, # new staged user with user fields
|
2021-03-29 19:03:19 +08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(Invite.count).to eq(3)
|
|
|
|
expect(User.where(staged: true).find_by_email("test@discourse.org")).to eq(nil)
|
|
|
|
expect(user.user_fields[user_field.id.to_s]).to eq("value 1")
|
2021-04-01 00:19:57 +08:00
|
|
|
expect(user.user_fields[user_field_color.id.to_s]).to eq("Blue")
|
2022-05-16 21:21:33 +08:00
|
|
|
expect(staged_user.user_fields[user_field.id.to_s]).to eq("value 2")
|
2021-04-01 00:19:57 +08:00
|
|
|
expect(staged_user.user_fields[user_field_color.id.to_s]).to eq(nil)
|
2021-03-29 19:03:19 +08:00
|
|
|
new_staged_user = User.where(staged: true).find_by_email("test2@discourse.org")
|
|
|
|
expect(new_staged_user.user_fields[user_field.id.to_s]).to eq("value 3")
|
|
|
|
end
|
|
|
|
|
2024-05-18 02:21:21 +08:00
|
|
|
it "includes any skipped and failed emails in the private message" do
|
|
|
|
described_class.new.execute(
|
|
|
|
current_user_id: admin.id,
|
|
|
|
invites: [{ email: "bad_email" }, { email: user.email }, { email: "test@discourse.org" }],
|
|
|
|
)
|
|
|
|
|
|
|
|
post = Post.last
|
|
|
|
result = parse_skipped_and_failed_emails(post.raw)
|
|
|
|
expect(result[:skipped_invites]).to eq(user.email)
|
|
|
|
expect(result[:failed_invites]).to eq("bad_email")
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "when there are more than 200 invites" do
|
2019-07-19 13:59:12 +08:00
|
|
|
let(:bulk_invites) { [] }
|
|
|
|
|
|
|
|
before { 202.times { |i| bulk_invites << { email: "test_#{i}@discourse.org" } } }
|
|
|
|
|
|
|
|
it "rate limits email sending" do
|
|
|
|
described_class.new.execute(current_user_id: admin.id, invites: bulk_invites)
|
|
|
|
|
|
|
|
invite = Invite.last
|
2021-03-29 19:03:19 +08:00
|
|
|
expect(invite.email).to eq("test_201@discourse.org")
|
2019-07-19 13:59:12 +08:00
|
|
|
expect(invite.emailed_status).to eq(Invite.emailed_status_types[:bulk_pending])
|
|
|
|
expect(Jobs::ProcessBulkInviteEmails.jobs.size).to eq(1)
|
|
|
|
end
|
|
|
|
end
|
2024-03-30 01:22:00 +08:00
|
|
|
|
|
|
|
it "does not send an invite email when skip_email_bulk_invites is true" do
|
|
|
|
SiteSetting.skip_email_bulk_invites = true
|
|
|
|
|
|
|
|
described_class.new.execute(current_user_id: admin.id, invites: invites)
|
|
|
|
|
|
|
|
invite = Invite.last
|
|
|
|
expect(invite.emailed_status).to eq(Invite.emailed_status_types[:not_required])
|
|
|
|
end
|
2019-07-19 13:59:12 +08:00
|
|
|
end
|
2014-06-26 02:35:11 +08:00
|
|
|
end
|