mirror of
https://github.com/discourse/discourse.git
synced 2025-02-10 21:34:50 +00:00
Currently, when a suspended user belongs to a group PM (private message with more than two people in it) and a staff member sends a message to this group PM, then the suspended user will receive an email. This happens because a suspended user can only receive emails from staff members. But in this case, this can be seen as a bug as the expected behavior would be instead to not send any email to the suspended user. A staff member can participate in active discussions like any other member and so their messages in this context shouldn’t be treated differently than the ones from regular users. This patch addresses this issue by checking if a suspended user receives a message from a group PM or not. If that’s the case then an email won’t be sent no matter if the post originated from a staff member or not.
935 lines
30 KiB
Ruby
935 lines
30 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe Jobs::UserEmail do
|
|
before { SiteSetting.email_time_window_mins = 10 }
|
|
|
|
fab!(:user) { Fabricate(:user, last_seen_at: 11.minutes.ago) }
|
|
fab!(:staged) { Fabricate(:user, staged: true, last_seen_at: 11.minutes.ago) }
|
|
fab!(:suspended) do
|
|
Fabricate(
|
|
:user,
|
|
last_seen_at: 10.minutes.ago,
|
|
suspended_at: 5.minutes.ago,
|
|
suspended_till: 7.days.from_now,
|
|
)
|
|
end
|
|
fab!(:anonymous) { Fabricate(:anonymous, last_seen_at: 11.minutes.ago) }
|
|
|
|
it "raises an error when there is no user" do
|
|
expect { Jobs::UserEmail.new.execute(type: :digest) }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "raises an error when there is no type" do
|
|
expect { Jobs::UserEmail.new.execute(user_id: user.id) }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "raises an error when the type doesn't exist" do
|
|
expect { Jobs::UserEmail.new.execute(type: :no_method, user_id: user.id) }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
context "when digest can be generated" do
|
|
fab!(:user) { Fabricate(:user, last_seen_at: 8.days.ago, last_emailed_at: 8.days.ago) }
|
|
fab!(:popular_topic) { Fabricate(:topic, user: Fabricate(:admin), created_at: 1.hour.ago) }
|
|
|
|
it "doesn't call the mailer when the user is missing" do
|
|
Jobs::UserEmail.new.execute(type: :digest, user_id: User.last.id + 10_000)
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't call the mailer when the user is staged" do
|
|
staged.update!(last_seen_at: 8.days.ago, last_emailed_at: 8.days.ago)
|
|
Jobs::UserEmail.new.execute(type: :digest, user_id: staged.id)
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
context "when not emailed recently" do
|
|
before do
|
|
freeze_time
|
|
user.update!(last_emailed_at: 8.days.ago)
|
|
end
|
|
|
|
it "calls the mailer when the user exists" do
|
|
Jobs::UserEmail.new.execute(type: :digest, user_id: user.id)
|
|
expect(ActionMailer::Base.deliveries).to_not be_empty
|
|
expect(user.user_stat.reload.digest_attempted_at).to eq_time(Time.zone.now)
|
|
end
|
|
end
|
|
|
|
context "when recently emailed" do
|
|
before do
|
|
freeze_time
|
|
user.update!(last_emailed_at: 2.hours.ago)
|
|
user.user_option.update!(digest_after_minutes: 1.day.to_i / 60)
|
|
end
|
|
|
|
it "skips sending digest email" do
|
|
Jobs::UserEmail.new.execute(type: :digest, user_id: user.id)
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
expect(user.user_stat.reload.digest_attempted_at).to eq_time(Time.zone.now)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with bounce score" do
|
|
it "always sends critical emails when bounce score threshold has been reached" do
|
|
email_token = Fabricate(:email_token)
|
|
user.user_stat.update(bounce_score: SiteSetting.bounce_score_threshold + 1)
|
|
|
|
Jobs::CriticalUserEmail.new.execute(
|
|
type: "signup",
|
|
user_id: user.id,
|
|
email_token: email_token.token,
|
|
)
|
|
|
|
email_log = EmailLog.where(user_id: user.id).last
|
|
expect(email_log.email_type).to eq("signup")
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
end
|
|
|
|
context "with to_address" do
|
|
it "overwrites a to_address when present" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :confirm_new_email,
|
|
user_id: user.id,
|
|
to_address: "jake@adventuretime.ooo",
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly("jake@adventuretime.ooo")
|
|
end
|
|
end
|
|
|
|
context "with disable_emails setting" do
|
|
it "sends when no" do
|
|
SiteSetting.disable_emails = "no"
|
|
Jobs::UserEmail.new.execute(type: :confirm_new_email, user_id: user.id)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
it "does not send an email when yes" do
|
|
SiteSetting.disable_emails = "yes"
|
|
Jobs::UserEmail.new.execute(type: :confirm_new_email, user_id: user.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
|
|
context "when recently seen" do
|
|
fab!(:post) { Fabricate(:post, user: user) }
|
|
fab!(:notification) do
|
|
Fabricate(
|
|
:notification,
|
|
user: user,
|
|
topic: post.topic,
|
|
post_number: post.post_number,
|
|
data: { original_post_id: post.id }.to_json,
|
|
)
|
|
end
|
|
before { user.update_column(:last_seen_at, 9.minutes.ago) }
|
|
|
|
it "doesn't send an email to a user that's been recently seen" do
|
|
Jobs::UserEmail.new.execute(type: :user_replied, user_id: user.id, post_id: post.id)
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "does send an email to a user that's been recently seen but has email_level set to always" do
|
|
user.user_option.update(email_level: UserOption.email_level_types[:always])
|
|
PostTiming.create!(
|
|
topic_id: post.topic_id,
|
|
post_number: post.post_number,
|
|
user_id: user.id,
|
|
msecs: 100,
|
|
)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_replied,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
it "doesn't send an email even if email_level is set to always if `force_respect_seen_recently` arg is true" do
|
|
user.user_option.update(email_level: UserOption.email_level_types[:always])
|
|
PostTiming.create!(
|
|
topic_id: post.topic_id,
|
|
post_number: post.post_number,
|
|
user_id: user.id,
|
|
msecs: 100,
|
|
)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_replied,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
force_respect_seen_recently: true,
|
|
)
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "sends an email with no gsub substitution bugs" do
|
|
upload = Fabricate(:upload)
|
|
|
|
post.update!(raw: <<~RAW)
|
|
This is a test post
|
|
|
|
With a \\0 \\1 \\2 in it
|
|
RAW
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
email = ActionMailer::Base.deliveries.first
|
|
|
|
expect(email.to).to contain_exactly(user.email)
|
|
|
|
html_part = email.parts.find { |x| x.content_type.include? "html" }
|
|
expect(html_part.body.to_s).to_not include("%{email_content}")
|
|
expect(html_part.body.to_s).to include('\0')
|
|
end
|
|
|
|
it "sends an email by default for a PM to a user that's been recently seen" do
|
|
upload = Fabricate(:upload)
|
|
|
|
post.update!(raw: <<~RAW)
|
|
This is a test post
|
|
|
|
<a class="attachment" href="#{upload.url}">test</a>
|
|
<img src="#{upload.url}"/>
|
|
RAW
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
email = ActionMailer::Base.deliveries.first
|
|
|
|
expect(email.to).to contain_exactly(user.email)
|
|
|
|
expect(email.parts[0].body.to_s).to include(<<~MD)
|
|
This is a test post
|
|
|
|
[test|attachment](#{Discourse.base_url}#{upload.url})
|
|
![](#{Discourse.base_url}#{upload.url})
|
|
MD
|
|
end
|
|
|
|
it "sends a PM email to a user that's been recently seen and has email_messages_level set to always" do
|
|
user.user_option.update(email_messages_level: UserOption.email_level_types[:always])
|
|
user.user_option.update(email_level: UserOption.email_level_types[:never])
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
it "doesn't send a PM email to a user that's been recently seen and has email_messages_level set to never" do
|
|
user.user_option.update(email_messages_level: UserOption.email_level_types[:never])
|
|
user.user_option.update(email_level: UserOption.email_level_types[:always])
|
|
Jobs::UserEmail.new.execute(type: :user_private_message, user_id: user.id, post_id: post.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send a regular post email to a user that's been recently seen and has email_level set to never" do
|
|
user.user_option.update(email_messages_level: UserOption.email_level_types[:always])
|
|
user.user_option.update(email_level: UserOption.email_level_types[:never])
|
|
Jobs::UserEmail.new.execute(type: :user_replied, user_id: user.id, post_id: post.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
|
|
context "with email_log" do
|
|
fab!(:post) { Fabricate(:post, created_at: 30.seconds.ago) }
|
|
|
|
before { SiteSetting.editing_grace_period = 0 }
|
|
|
|
it "creates an email log when the mail is sent (via Email::Sender)" do
|
|
freeze_time
|
|
|
|
last_emailed_at = 7.days.ago
|
|
user.update!(last_emailed_at: last_emailed_at)
|
|
Topic.last.update(created_at: 1.minute.ago)
|
|
|
|
expect do Jobs::UserEmail.new.execute(type: :digest, user_id: user.id) end.to change {
|
|
EmailLog.count
|
|
}.by(1)
|
|
|
|
email_log = EmailLog.last
|
|
|
|
expect(email_log.user).to eq(user)
|
|
expect(email_log.post).to eq(nil)
|
|
# last_emailed_at should have changed
|
|
expect(email_log.user.last_emailed_at).to_not eq_time(last_emailed_at)
|
|
end
|
|
|
|
it "creates a skipped email log when the mail is skipped" do
|
|
freeze_time
|
|
|
|
last_emailed_at = 7.days.ago
|
|
user.update!(last_emailed_at: last_emailed_at, suspended_till: 1.year.from_now)
|
|
|
|
expect do Jobs::UserEmail.new.execute(type: :digest, user_id: user.id) end.to change {
|
|
SkippedEmailLog.count
|
|
}.by(1)
|
|
|
|
expect(
|
|
SkippedEmailLog.exists?(
|
|
email_type: "digest",
|
|
user: user,
|
|
post: nil,
|
|
to_address: user.email,
|
|
reason_type: SkippedEmailLog.reason_types[:user_email_user_suspended_not_pm],
|
|
),
|
|
).to eq(true)
|
|
|
|
# last_emailed_at doesn't change
|
|
expect(user.last_emailed_at).to eq_time(last_emailed_at)
|
|
end
|
|
|
|
it "creates a skipped email log when the user isn't allowed to see the post" do
|
|
user.user_option.update(email_level: UserOption.email_level_types[:always])
|
|
post.topic.convert_to_private_message(Discourse.system_user)
|
|
|
|
expect do
|
|
Jobs::UserEmail.new.execute(type: :user_posted, user_id: user.id, post_id: post.id)
|
|
end.to change { SkippedEmailLog.count }.by(1)
|
|
|
|
expect(
|
|
SkippedEmailLog.exists?(
|
|
email_type: "user_posted",
|
|
user: user,
|
|
post: post,
|
|
to_address: user.email,
|
|
reason_type: SkippedEmailLog.reason_types[:user_email_access_denied],
|
|
),
|
|
).to eq(true)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
|
|
context "with args" do
|
|
it "passes a token as an argument when a token is present" do
|
|
Jobs::UserEmail.new.execute(type: :forgot_password, user_id: user.id, email_token: "asdfasdf")
|
|
|
|
mail = ActionMailer::Base.deliveries.first
|
|
|
|
expect(mail.to).to contain_exactly(user.email)
|
|
expect(mail.body).to include("asdfasdf")
|
|
end
|
|
|
|
context "with confirm_new_email" do
|
|
let(:email_token) { Fabricate(:email_token, user: user) }
|
|
before do
|
|
EmailChangeRequest.create!(
|
|
user: user,
|
|
requested_by: requested_by,
|
|
new_email_token: email_token,
|
|
new_email: "testnew@test.com",
|
|
change_state: EmailChangeRequest.states[:authorizing_new],
|
|
)
|
|
end
|
|
|
|
context "when the change was requested by admin" do
|
|
let(:requested_by) { Fabricate(:admin) }
|
|
it "passes along true for the requested_by_admin param which changes the wording in the email" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :confirm_new_email,
|
|
user_id: user.id,
|
|
email_token: email_token.token,
|
|
)
|
|
mail = ActionMailer::Base.deliveries.first
|
|
expect(mail.body).to include("This email change was requested by a site admin.")
|
|
end
|
|
end
|
|
|
|
context "when the change was requested by the user" do
|
|
let(:requested_by) { user }
|
|
it "passes along false for the requested_by_admin param which changes the wording in the email" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :confirm_new_email,
|
|
user_id: user.id,
|
|
email_token: email_token.token,
|
|
)
|
|
mail = ActionMailer::Base.deliveries.first
|
|
expect(mail.body).not_to include("This email change was requested by a site admin.")
|
|
end
|
|
end
|
|
|
|
context "when requested_by record is not present" do
|
|
let(:requested_by) { nil }
|
|
it "passes along false for the requested_by_admin param which changes the wording in the email" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :confirm_new_email,
|
|
user_id: user.id,
|
|
email_token: email_token.token,
|
|
)
|
|
mail = ActionMailer::Base.deliveries.first
|
|
expect(mail.body).not_to include("This email change was requested by a site admin.")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with post" do
|
|
fab!(:post) { Fabricate(:post, user: user) }
|
|
|
|
it "doesn't send the email if you've seen the post" do
|
|
PostTiming.record_timing(
|
|
topic_id: post.topic_id,
|
|
user_id: user.id,
|
|
post_number: post.post_number,
|
|
msecs: 6666,
|
|
)
|
|
Jobs::UserEmail.new.execute(type: :user_private_message, user_id: user.id, post_id: post.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send the email if the user deleted the post" do
|
|
post.update_column(:user_deleted, true)
|
|
Jobs::UserEmail.new.execute(type: :user_private_message, user_id: user.id, post_id: post.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send the email if user of the post has been deleted" do
|
|
post.update!(user_id: nil)
|
|
Jobs::UserEmail.new.execute(type: :user_replied, user_id: user.id, post_id: post.id)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
context "when user is suspended" do
|
|
context "when topic is a private message" do
|
|
subject(:send_email) do
|
|
described_class.new.execute(
|
|
type: :user_private_message,
|
|
user_id: suspended.id,
|
|
post_id: post.id,
|
|
notification_id: pm_notification.id,
|
|
)
|
|
end
|
|
|
|
let(:pm_notification) do
|
|
Fabricate(
|
|
:notification,
|
|
user: suspended,
|
|
topic: post.topic,
|
|
post_number: post.post_number,
|
|
data: { original_post_id: post.id }.to_json,
|
|
)
|
|
end
|
|
fab!(:moderator) { Fabricate(:moderator) }
|
|
fab!(:regular_user) { Fabricate(:user) }
|
|
|
|
context "when this is not a group PM" do
|
|
let(:post) { Fabricate(:private_message_post, user: user, recipient: suspended) }
|
|
|
|
context "when post is from a staff user" do
|
|
let(:user) { moderator }
|
|
|
|
it "does send an email" do
|
|
send_email
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(suspended.email)
|
|
end
|
|
end
|
|
|
|
context "when post is from a regular user" do
|
|
let(:user) { regular_user }
|
|
|
|
it "doesn't send email" do
|
|
send_email
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when this is a group PM" do
|
|
fab!(:group) { Fabricate(:group) }
|
|
fab!(:users) { Fabricate.times(2, :user) }
|
|
|
|
let(:post) { Fabricate(:group_private_message_post, user: user, recipients: group) }
|
|
|
|
before { group.users << [suspended, *users] }
|
|
|
|
context "when post is from a staff user" do
|
|
let(:user) { moderator }
|
|
|
|
it "does not send an email" do
|
|
send_email
|
|
expect(ActionMailer::Base.deliveries).to be_empty
|
|
end
|
|
end
|
|
|
|
context "when post is from a regular user" do
|
|
let(:user) { regular_user }
|
|
|
|
it "does not send an email" do
|
|
send_email
|
|
expect(ActionMailer::Base.deliveries).to be_empty
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
it "doesn't send PM from system user" do
|
|
pm_from_system = SystemMessage.create(suspended, :unsilenced)
|
|
|
|
system_pm_notification =
|
|
Fabricate(
|
|
:notification,
|
|
user: suspended,
|
|
topic: pm_from_system.topic,
|
|
post_number: pm_from_system.post_number,
|
|
data: { original_post_id: pm_from_system.id }.to_json,
|
|
)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: suspended.id,
|
|
post_id: pm_from_system.id,
|
|
notification_id: system_pm_notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
|
|
context "when user is anonymous" do
|
|
before { SiteSetting.allow_anonymous_posting = true }
|
|
|
|
it "doesn't send email for a pm from a regular user" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: anonymous.id,
|
|
post_id: post.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send email for a pm from a staff user" do
|
|
pm_from_staff = Fabricate(:post, user: Fabricate(:moderator))
|
|
pm_from_staff.topic.topic_allowed_users.create!(user_id: anonymous.id)
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: anonymous.id,
|
|
post_id: pm_from_staff.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with notification" do
|
|
fab!(:post) { Fabricate(:post, user: user) }
|
|
fab!(:notification) do
|
|
Fabricate(
|
|
:notification,
|
|
user: user,
|
|
topic: post.topic,
|
|
post_number: post.post_number,
|
|
data: { original_post_id: post.id }.to_json,
|
|
)
|
|
end
|
|
|
|
it "doesn't send the email if the notification has been seen" do
|
|
notification.update_column(:read, true)
|
|
message, err =
|
|
Jobs::UserEmail.new.message_for_email(
|
|
user,
|
|
post,
|
|
:user_mentioned,
|
|
notification,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(message).to eq(nil)
|
|
|
|
expect(
|
|
SkippedEmailLog.exists?(
|
|
email_type: "user_mentioned",
|
|
user: user,
|
|
post: post,
|
|
to_address: user.email,
|
|
reason_type: SkippedEmailLog.reason_types[:user_email_notification_already_read],
|
|
),
|
|
).to eq(true)
|
|
end
|
|
|
|
it "does send the email if the notification has been seen but user has email_level set to always" do
|
|
notification.update_column(:read, true)
|
|
user.user_option.update_column(:email_level, UserOption.email_level_types[:always])
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
it "does send the email if the user is using daily mailing list mode" do
|
|
user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 0)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
it "sends the mail if the user enabled mailing list mode, but mailing list mode is disabled globally" do
|
|
user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 1)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
|
|
context "when recently seen" do
|
|
it "doesn't send an email to a user that's been recently seen" do
|
|
user.update!(last_seen_at: 9.minutes.ago)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_replied,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "does send an email to a user that's been recently seen but has email_level set to always" do
|
|
user.update!(last_seen_at: 9.minutes.ago)
|
|
user.user_option.update!(email_level: UserOption.email_level_types[:always])
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_replied,
|
|
user_id: user.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to contain_exactly(user.email)
|
|
end
|
|
end
|
|
|
|
context "when max_emails_per_day_per_user limit is reached" do
|
|
before do
|
|
SiteSetting.max_emails_per_day_per_user = 2
|
|
2.times { Fabricate(:email_log, user: user, email_type: "blah", to_address: user.email) }
|
|
end
|
|
|
|
it "does not send notification if limit is reached" do
|
|
expect do
|
|
2.times do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
end
|
|
end.to change { SkippedEmailLog.count }.by(1)
|
|
|
|
expect(
|
|
SkippedEmailLog.exists?(
|
|
email_type: "user_mentioned",
|
|
user: user,
|
|
post: post,
|
|
to_address: user.email,
|
|
reason_type: SkippedEmailLog.reason_types[:exceeded_emails_limit],
|
|
),
|
|
).to eq(true)
|
|
|
|
freeze_time(Time.zone.now.tomorrow + 1.second)
|
|
|
|
expect do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
end.not_to change { SkippedEmailLog.count }
|
|
end
|
|
|
|
it "sends critical email" do
|
|
expect do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :forgot_password,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
)
|
|
end.to change { EmailLog.count }.by(1)
|
|
|
|
expect(EmailLog.exists?(email_type: "forgot_password", user: user)).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "erodes bounce score each time an email is sent" do
|
|
SiteSetting.bounce_score_erode_on_send = 0.2
|
|
|
|
user.user_stat.update(bounce_score: 2.7)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
|
|
user.user_stat.reload
|
|
expect(user.user_stat.bounce_score).to eq(2.5)
|
|
|
|
user.user_stat.update(bounce_score: 0)
|
|
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
|
|
user.user_stat.reload
|
|
expect(user.user_stat.bounce_score).to eq(0)
|
|
end
|
|
|
|
it "does not send notification if bounce threshold is reached" do
|
|
user.user_stat.update(bounce_score: SiteSetting.bounce_score_threshold)
|
|
|
|
expect do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
end.to change { SkippedEmailLog.count }.by(1)
|
|
|
|
expect(
|
|
SkippedEmailLog.exists?(
|
|
email_type: "user_mentioned",
|
|
user: user,
|
|
post: post,
|
|
to_address: user.email,
|
|
reason_type: SkippedEmailLog.reason_types[:exceeded_bounces_limit],
|
|
),
|
|
).to eq(true)
|
|
end
|
|
|
|
it "doesn't send the mail if the user is using individual mailing list mode" do
|
|
SiteSetting.disable_mailing_list_mode = false
|
|
|
|
user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 1)
|
|
# sometimes, we pass the notification_id
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
# other times, we only pass the type of notification
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
post_id: post.id,
|
|
)
|
|
# When post is nil
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
)
|
|
# When post does not have a topic
|
|
post = Fabricate(:post)
|
|
post.topic.destroy
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
post_id: post.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send the mail if the user is using individual mailing list mode with no echo" do
|
|
SiteSetting.disable_mailing_list_mode = false
|
|
|
|
user.user_option.update(mailing_list_mode: true, mailing_list_mode_frequency: 2)
|
|
# sometimes, we pass the notification_id
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
# other times, we only pass the type of notification
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
post_id: post.id,
|
|
)
|
|
# When post is nil
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
)
|
|
# When post does not have a topic
|
|
post = Fabricate(:post)
|
|
post.topic.destroy
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_type: "posted",
|
|
post_id: post.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send the email if the post has been user deleted" do
|
|
post.update_column(:user_deleted, true)
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_mentioned,
|
|
user_id: user.id,
|
|
notification_id: notification.id,
|
|
post_id: post.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
context "when user is suspended" do
|
|
it "doesn't send email for a pm from a regular user" do
|
|
msg, err =
|
|
Jobs::UserEmail.new.message_for_email(
|
|
suspended,
|
|
Fabricate.build(:post),
|
|
:user_private_message,
|
|
notification,
|
|
)
|
|
|
|
expect(msg).to eq(nil)
|
|
expect(err).not_to eq(nil)
|
|
end
|
|
|
|
context "with pm from staff" do
|
|
before do
|
|
@pm_from_staff = Fabricate(:post, user: Fabricate(:moderator))
|
|
@pm_from_staff.topic.topic_allowed_users.create!(user_id: suspended.id)
|
|
@pm_notification =
|
|
Fabricate(
|
|
:notification,
|
|
user: suspended,
|
|
topic: @pm_from_staff.topic,
|
|
post_number: @pm_from_staff.post_number,
|
|
data: { original_post_id: @pm_from_staff.id }.to_json,
|
|
)
|
|
end
|
|
|
|
let :sent_message do
|
|
Jobs::UserEmail.new.message_for_email(
|
|
suspended,
|
|
@pm_from_staff,
|
|
:user_private_message,
|
|
@pm_notification,
|
|
)
|
|
end
|
|
|
|
it "sends an email" do
|
|
msg, err = sent_message
|
|
expect(msg).not_to be(nil)
|
|
expect(err).to be(nil)
|
|
end
|
|
|
|
it "sends an email even if user was last seen recently" do
|
|
suspended.update_column(:last_seen_at, 1.minute.ago)
|
|
|
|
msg, err = sent_message
|
|
expect(msg).not_to be(nil)
|
|
expect(err).to be(nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when user is anonymous" do
|
|
before { SiteSetting.allow_anonymous_posting = true }
|
|
|
|
it "doesn't send email for a pm from a regular user" do
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: anonymous.id,
|
|
post_id: post.id,
|
|
notification_id: notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
|
|
it "doesn't send email for a pm from staff" do
|
|
pm_from_staff = Fabricate(:post, user: Fabricate(:moderator))
|
|
pm_from_staff.topic.topic_allowed_users.create!(user_id: anonymous.id)
|
|
pm_notification =
|
|
Fabricate(
|
|
:notification,
|
|
user: anonymous,
|
|
topic: pm_from_staff.topic,
|
|
post_number: pm_from_staff.post_number,
|
|
data: { original_post_id: pm_from_staff.id }.to_json,
|
|
)
|
|
Jobs::UserEmail.new.execute(
|
|
type: :user_private_message,
|
|
user_id: anonymous.id,
|
|
post_id: pm_from_staff.id,
|
|
notification_id: pm_notification.id,
|
|
)
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|