mirror of
https://github.com/discourse/discourse.git
synced 2024-12-25 05:33:43 +08:00
5f6b6e9818
In 958437e7dd
we ensured that the email summaries are properly sent based on 'digest_attempted_at' for people who barely/never visit the forum.
This fixed the "frequency" of the email summaries but introduced a bug where the digest would be sent even though there wasn't anything new since for some users.
The logic we use to compute the threshold date for the content to be included in the digest was
```ruby
@since = opts[:since] || user.last_seen_at || user.user_stat&.digest_attempted_at || 1.month.ago
```
It was working as expected for users who haven never been seen but for users who have connected at least once, we would use their "last_seen_at" date as the "threshold date" for the content to be sent in a summary 😬
This fix changes the logic to be the most recent date amongst the `last_seen_at`, `digest_attempted_at` and `1.month.ago` so it's correctly handling cases where
- user has never been seen nor emailed a summary
- user has been seen in a while but has recently been sent a summary
- user has been sent a summary recently but hasn't been seen in a while.
1575 lines
53 KiB
Ruby
1575 lines
53 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe UserNotifications do
|
|
let(:user) { Fabricate(:admin) }
|
|
|
|
describe "#get_context_posts" do
|
|
it "does not include hidden/deleted/user_deleted posts in context" do
|
|
post1 = create_post
|
|
_post2 = Fabricate(:post, topic: post1.topic, deleted_at: 1.day.ago)
|
|
_post3 = Fabricate(:post, topic: post1.topic, user_deleted: true)
|
|
_post4 = Fabricate(:post, topic: post1.topic, hidden: true)
|
|
_post5 = Fabricate(:post, topic: post1.topic, post_type: Post.types[:moderator_action])
|
|
_post6 = Fabricate(:post, topic: post1.topic, post_type: Post.types[:small_action])
|
|
_post7 = Fabricate(:post, topic: post1.topic, post_type: Post.types[:whisper])
|
|
last = Fabricate(:post, topic: post1.topic)
|
|
|
|
post1.user.user_option.email_previous_replies = UserOption.previous_replies_type[:always]
|
|
|
|
# default is only post #1
|
|
expect(UserNotifications.get_context_posts(last, nil, post1.user).count).to eq(1)
|
|
# staff members can also see the whisper
|
|
moderator = build(:moderator)
|
|
moderator.user_option = UserOption.new
|
|
moderator.user_option.email_previous_replies = UserOption.previous_replies_type[:always]
|
|
tu = TopicUser.new(topic: post1.topic, user: moderator)
|
|
expect(UserNotifications.get_context_posts(last, tu, tu.user).count).to eq(2)
|
|
end
|
|
|
|
it "allows users to control context" do
|
|
post1 = create_post
|
|
_post2 = Fabricate(:post, topic: post1.topic)
|
|
post3 = Fabricate(:post, topic: post1.topic)
|
|
|
|
user = Fabricate(:user)
|
|
TopicUser.change(user.id, post1.topic_id, last_emailed_post_number: 1)
|
|
topic_user = TopicUser.find_by(user_id: user.id, topic_id: post1.topic_id)
|
|
# to avoid reloads after update_columns
|
|
user = topic_user.user
|
|
user.user_option.update_columns(
|
|
email_previous_replies: UserOption.previous_replies_type[:unless_emailed],
|
|
)
|
|
|
|
expect(UserNotifications.get_context_posts(post3, topic_user, user).count).to eq(1)
|
|
|
|
user.user_option.update_columns(
|
|
email_previous_replies: UserOption.previous_replies_type[:never],
|
|
)
|
|
expect(UserNotifications.get_context_posts(post3, topic_user, user).count).to eq(0)
|
|
|
|
user.user_option.update_columns(
|
|
email_previous_replies: UserOption.previous_replies_type[:always],
|
|
)
|
|
expect(UserNotifications.get_context_posts(post3, topic_user, user).count).to eq(2)
|
|
|
|
SiteSetting.private_email = true
|
|
expect(UserNotifications.get_context_posts(post3, topic_user, user).count).to eq(0)
|
|
end
|
|
end
|
|
|
|
describe ".signup" do
|
|
subject(:email) { UserNotifications.signup(user) }
|
|
|
|
it "works" do
|
|
expect(email.to).to eq([user.email])
|
|
expect(email.subject).to be_present
|
|
expect(email.from).to eq([SiteSetting.notification_email])
|
|
expect(email.body).to be_present
|
|
end
|
|
end
|
|
|
|
describe ".forgot_password" do
|
|
subject(:email) { UserNotifications.forgot_password(user) }
|
|
|
|
it "works" do
|
|
expect(email.to).to eq([user.email])
|
|
expect(email.subject).to be_present
|
|
expect(email.from).to eq([SiteSetting.notification_email])
|
|
expect(email.body).to be_present
|
|
end
|
|
end
|
|
|
|
describe ".post_approved" do
|
|
fab!(:post)
|
|
|
|
it "works" do
|
|
subject =
|
|
UserNotifications.post_approved(user, { notification_data_hash: { post_url: post.url } })
|
|
|
|
expect(subject.to).to eq([user.email])
|
|
expect(subject.subject).to be_present
|
|
expect(subject.from).to eq([SiteSetting.notification_email])
|
|
expect(subject.body).to be_present
|
|
end
|
|
end
|
|
|
|
describe ".confirm_new_email" do
|
|
let(:opts) { { requested_by_admin: requested_by_admin, email_token: token } }
|
|
let(:token) { "test123" }
|
|
|
|
context "when requested by admin" do
|
|
let(:requested_by_admin) { true }
|
|
|
|
it "uses the requested by admin template" do
|
|
expect(UserNotifications.confirm_new_email(user, opts).body).to include(
|
|
"This email change was requested by a site admin.",
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when not requested by admin" do
|
|
let(:requested_by_admin) { false }
|
|
|
|
it "uses the normal template" do
|
|
expect(UserNotifications.confirm_new_email(user, opts).body).not_to include(
|
|
"This email change was requested by a site admin.",
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".email_login" do
|
|
subject(:email) { UserNotifications.email_login(user, email_token: email_token) }
|
|
|
|
let(:email_token) do
|
|
Fabricate(:email_token, user: user, scope: EmailToken.scopes[:email_login]).token
|
|
end
|
|
|
|
it "generates the right email" do
|
|
expect(email.to).to eq([user.email])
|
|
expect(email.from).to eq([SiteSetting.notification_email])
|
|
|
|
expect(email.subject).to eq(
|
|
I18n.t("user_notifications.email_login.subject_template", email_prefix: SiteSetting.title),
|
|
)
|
|
|
|
expect(email.body.to_s).to match(
|
|
I18n.t(
|
|
"user_notifications.email_login.text_body_template",
|
|
site_name: SiteSetting.title,
|
|
base_url: Discourse.base_url,
|
|
email_token: email_token,
|
|
),
|
|
)
|
|
end
|
|
end
|
|
|
|
describe ".digest" do
|
|
subject(:email) { UserNotifications.digest(user) }
|
|
|
|
after { Discourse.redis.keys("summary-new-users:*").each { |key| Discourse.redis.del(key) } }
|
|
|
|
context "without new topics" do
|
|
it "doesn't send the email" do
|
|
expect(email.to).to be_blank
|
|
end
|
|
end
|
|
|
|
context "with topics only from new users" do
|
|
let!(:new_today) do
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user, trust_level: TrustLevel[0], created_at: 10.minutes.ago),
|
|
title: "Hey everyone look at me",
|
|
)
|
|
end
|
|
let!(:new_yesterday) do
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user, trust_level: TrustLevel[0], created_at: 25.hours.ago),
|
|
created_at: 25.hours.ago,
|
|
title: "This topic is of interest to you",
|
|
)
|
|
end
|
|
|
|
it "returns topics from new users if they're more than 24 hours old" do
|
|
expect(email.to).to eq([user.email])
|
|
html = email.html_part.body.to_s
|
|
expect(html).to include(new_yesterday.title)
|
|
expect(html).to_not include(new_today.title)
|
|
end
|
|
end
|
|
|
|
context "with new topics" do
|
|
fab!(:coding_horror)
|
|
|
|
let!(:popular_topic) { Fabricate(:topic, user: coding_horror, created_at: 1.hour.ago) }
|
|
|
|
let!(:another_popular_topic) do
|
|
Fabricate(:topic, user: coding_horror, created_at: 1.hour.ago)
|
|
end
|
|
|
|
let!(:post) { Fabricate(:post, topic: popular_topic, post_number: 1) }
|
|
|
|
let!(:another_post) { Fabricate(:post, topic: another_popular_topic, post_number: 1) }
|
|
|
|
it "works" do
|
|
expect(email.to).to eq([user.email])
|
|
expect(email.subject).to be_present
|
|
expect(email.from).to eq([SiteSetting.notification_email])
|
|
expect(email.html_part.body.to_s).to be_present
|
|
expect(email.text_part.body.to_s).to be_present
|
|
expect(email.header["List-Unsubscribe"].to_s).to match(/\/email\/unsubscribe\/\h{64}/)
|
|
expect(email.header["X-Discourse-Topic-Ids"].to_s).to eq(
|
|
"#{another_popular_topic.id},#{popular_topic.id}",
|
|
)
|
|
expect(email.header["X-Discourse-Post-Ids"].to_s).to eq("#{another_post.id},#{post.id}")
|
|
expect(email.html_part.body.to_s).to include("New Users")
|
|
end
|
|
|
|
it "doesn't include new user count if digest_after_minutes is low" do
|
|
user.user_option.digest_after_minutes = 60
|
|
expect(email.html_part.body.to_s).to_not include("New Users")
|
|
end
|
|
|
|
it "works with min_date string" do
|
|
digest = UserNotifications.digest(user, since: 1.month.ago.to_date.to_s)
|
|
expect(digest.html_part.body.to_s).to be_present
|
|
expect(digest.text_part.body.to_s).to be_present
|
|
expect(digest.html_part.body.to_s).to include("New Users")
|
|
end
|
|
|
|
it "includes email_prefix in email subject instead of site title" do
|
|
SiteSetting.email_prefix = "Try Discourse"
|
|
SiteSetting.title = "Discourse Meta"
|
|
|
|
expect(email.subject).to match(/Try Discourse/)
|
|
expect(email.subject).not_to match(/Discourse Meta/)
|
|
end
|
|
|
|
it "includes unread likes received count within the since date" do
|
|
Fabricate(
|
|
:notification,
|
|
user: user,
|
|
notification_type: Notification.types[:liked],
|
|
created_at: 2.months.ago,
|
|
)
|
|
Fabricate(
|
|
:notification,
|
|
user: user,
|
|
notification_type: Notification.types[:liked],
|
|
read: true,
|
|
)
|
|
Fabricate(:notification, user: user, notification_type: Notification.types[:liked])
|
|
Fabricate(:notification, user: user, notification_type: Notification.types[:liked])
|
|
digest = UserNotifications.digest(user, since: 1.month.ago.to_date.to_s)
|
|
parsed_html = Nokogiri::HTML5.fragment(digest.html_part.body.to_s)
|
|
expect(parsed_html.css(".header-stat-count #likes_received_stat_count strong").text).to eq(
|
|
"2",
|
|
)
|
|
expect(
|
|
parsed_html.css(".header-stat-description #likes_received_stat_description strong").text,
|
|
).to eq("Likes Received")
|
|
end
|
|
|
|
it "excludes deleted topics and their posts" do
|
|
deleted =
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user),
|
|
title: "Delete this topic plz",
|
|
created_at: 1.hour.ago,
|
|
)
|
|
post =
|
|
Fabricate(
|
|
:post,
|
|
topic: deleted,
|
|
score: 100.0,
|
|
post_number: 2,
|
|
raw: "Your wish is my command",
|
|
created_at: 1.hour.ago,
|
|
)
|
|
deleted.trash!
|
|
html = email.html_part.body.to_s
|
|
expect(html).to_not include deleted.title
|
|
expect(html).to_not include post.raw
|
|
end
|
|
|
|
it "excludes shared drafts" do
|
|
cat = Fabricate(:category)
|
|
SiteSetting.shared_drafts_category = cat.id
|
|
topic =
|
|
Fabricate(:topic, title: "This is a draft", category_id: cat.id, created_at: 1.hour.ago)
|
|
post =
|
|
Fabricate(
|
|
:post,
|
|
topic: topic,
|
|
score: 100.0,
|
|
post_number: 2,
|
|
raw: "secret draft content",
|
|
created_at: 1.hour.ago,
|
|
)
|
|
html = email.html_part.body.to_s
|
|
expect(html).to_not include topic.title
|
|
expect(html).to_not include post.raw
|
|
end
|
|
|
|
it "excludes whispers and other post types that don't belong" do
|
|
t =
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user),
|
|
title: "Who likes the same stuff I like?",
|
|
created_at: 1.hour.ago,
|
|
)
|
|
whisper =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 2,
|
|
raw: "You like weird stuff",
|
|
post_type: Post.types[:whisper],
|
|
created_at: 1.hour.ago,
|
|
)
|
|
mod_action =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 3,
|
|
raw: "This topic unlisted",
|
|
post_type: Post.types[:moderator_action],
|
|
created_at: 1.hour.ago,
|
|
)
|
|
small_action =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 4,
|
|
raw: "A small action",
|
|
post_type: Post.types[:small_action],
|
|
created_at: 1.hour.ago,
|
|
)
|
|
html = email.html_part.body.to_s
|
|
expect(html).to_not include whisper.raw
|
|
expect(html).to_not include mod_action.raw
|
|
expect(html).to_not include small_action.raw
|
|
end
|
|
|
|
it "excludes deleted and hidden posts" do
|
|
t =
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user),
|
|
title: "Post objectionable stuff here",
|
|
created_at: 1.hour.ago,
|
|
)
|
|
deleted =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 2,
|
|
raw: "This post is uncalled for",
|
|
deleted_at: 5.minutes.ago,
|
|
created_at: 1.hour.ago,
|
|
)
|
|
hidden =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 3,
|
|
raw: "Try to find this post",
|
|
hidden: true,
|
|
hidden_at: 5.minutes.ago,
|
|
hidden_reason_id: Post.hidden_reasons[:flagged_by_tl3_user],
|
|
created_at: 1.hour.ago,
|
|
)
|
|
user_deleted =
|
|
Fabricate(
|
|
:post,
|
|
topic: t,
|
|
score: 100.0,
|
|
post_number: 4,
|
|
raw: "I regret this post",
|
|
user_deleted: true,
|
|
created_at: 1.hour.ago,
|
|
)
|
|
html = email.html_part.body.to_s
|
|
expect(html).to_not include deleted.raw
|
|
expect(html).to_not include hidden.raw
|
|
expect(html).to_not include user_deleted.raw
|
|
end
|
|
|
|
it "excludes posts that are newer than editing grace period" do
|
|
SiteSetting.editing_grace_period = 5.minutes
|
|
too_new =
|
|
Fabricate(
|
|
:topic,
|
|
user: Fabricate(:user),
|
|
title: "Oops I need to edit this",
|
|
created_at: 1.minute.ago,
|
|
)
|
|
_too_new_post =
|
|
Fabricate(
|
|
:post,
|
|
user: too_new.user,
|
|
topic: too_new,
|
|
score: 100.0,
|
|
post_number: 1,
|
|
created_at: 1.minute.ago,
|
|
)
|
|
html = email.html_part.body.to_s
|
|
expect(html).to_not include too_new.title
|
|
end
|
|
|
|
it "uses theme color" do
|
|
cs =
|
|
Fabricate(
|
|
:color_scheme,
|
|
name: "Fancy",
|
|
color_scheme_colors: [
|
|
Fabricate(:color_scheme_color, name: "header_primary", hex: "F0F0F0"),
|
|
Fabricate(:color_scheme_color, name: "header_background", hex: "1E1E1E"),
|
|
],
|
|
)
|
|
theme =
|
|
Fabricate(:theme, user_selectable: true, user: Fabricate(:admin), color_scheme_id: cs.id)
|
|
|
|
theme.set_default!
|
|
|
|
html = email.html_part.body.to_s
|
|
expect(html).to include "F0F0F0"
|
|
expect(html).to include "1E1E1E"
|
|
end
|
|
|
|
it "supports subfolder" do
|
|
set_subfolder "/forum"
|
|
html = email.html_part.body.to_s
|
|
text = email.text_part.body.to_s
|
|
expect(html).to be_present
|
|
expect(text).to be_present
|
|
expect(html).to_not include("/forum/forum")
|
|
expect(text).to_not include("/forum/forum")
|
|
expect(email.header["List-Unsubscribe"].to_s).to match(
|
|
/http:\/\/test.localhost\/forum\/email\/unsubscribe\/\h{64}/,
|
|
)
|
|
|
|
topic_url = "http://test.localhost/forum/t/#{popular_topic.slug}/#{popular_topic.id}"
|
|
expect(html).to include(topic_url)
|
|
expect(text).to include(topic_url)
|
|
end
|
|
|
|
it "applies lang/xml:lang html attributes" do
|
|
SiteSetting.default_locale = "pl_PL"
|
|
html = email.html_part.to_s
|
|
|
|
expect(html).to match(' lang="pl-PL"')
|
|
expect(html).to match(' xml:lang="pl-PL"')
|
|
end
|
|
|
|
it "uses digest_attempted_at when user hasn't been seen in a while" do
|
|
user.update!(last_seen_at: 7.days.ago)
|
|
user.user_stat.update!(digest_attempted_at: 30.minutes.ago)
|
|
expect(email.to).to be_nil
|
|
end
|
|
|
|
it "uses last_seen_at when user has been sent a digest in a while" do
|
|
user.update!(last_seen_at: 30.minutes.ago)
|
|
user.user_stat.update!(digest_attempted_at: 7.days.ago)
|
|
expect(email.to).to be_nil
|
|
end
|
|
|
|
it "caps at 1 month when user has never been seen or sent a digest" do
|
|
old_topic = Fabricate(:topic, created_at: 2.months.ago)
|
|
|
|
user.update!(last_seen_at: nil)
|
|
user.user_stat.update!(digest_attempted_at: nil)
|
|
expect(email.to).to contain_exactly(user.email)
|
|
|
|
html = email.html_part.body.to_s
|
|
expect(html).not_to include(old_topic.title)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".user_replied" do
|
|
let(:response_by_user) { Fabricate(:user, name: "John Doe") }
|
|
let(:category) { Fabricate(:category, name: "India") }
|
|
let(:tag1) { Fabricate(:tag, name: "Taggo", public_topic_count: 1) }
|
|
let(:tag2) { Fabricate(:tag, name: "Taggie", public_topic_count: 3) }
|
|
let(:tag3) { Fabricate(:tag, name: "Teggo", public_topic_count: 2) }
|
|
|
|
let(:hidden_tag) { Fabricate(:tag, name: "hidden") }
|
|
let!(:hidden_tag_group) do
|
|
Fabricate(:tag_group, permissions: { "staff" => 1 }, tag_names: [hidden_tag.name])
|
|
end
|
|
|
|
let(:topic) do
|
|
Fabricate(
|
|
:topic,
|
|
category: category,
|
|
tags: [tag1, tag2, tag3, hidden_tag],
|
|
title: "Super cool topic",
|
|
)
|
|
end
|
|
let(:post) { Fabricate(:post, topic: topic, raw: "This is My super duper cool topic") }
|
|
let(:response) { Fabricate(:basic_reply, topic: post.topic, user: response_by_user) }
|
|
let(:user) { Fabricate(:user) }
|
|
let(:notification) { Fabricate(:replied_notification, user: user, post: response) }
|
|
|
|
it "generates a correct email" do
|
|
SiteSetting.default_email_in_reply_to = true
|
|
|
|
# Fabricator is not fabricating this ...
|
|
SiteSetting.email_subject =
|
|
"[%{site_name}] %{optional_pm}%{optional_cat}%{optional_tags}%{topic_title}"
|
|
SiteSetting.enable_names = true
|
|
SiteSetting.display_name_on_posts = true
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
# from should include full user name
|
|
expect(mail[:from].display_names).to eql(["John Doe via Discourse"])
|
|
|
|
# subject should include category name
|
|
expect(mail.subject).to match(/India/)
|
|
|
|
# subject should include tag names
|
|
expect(mail.subject).to match(/Taggo/)
|
|
expect(mail.subject).to match(/Taggie/)
|
|
|
|
mail_html = mail.html_part.body.to_s
|
|
|
|
expect(mail_html.scan(/My super duper cool topic/).count).to eq(1)
|
|
expect(mail_html.scan(/In Reply To/).count).to eq(1)
|
|
|
|
# 2 "visit topic" link
|
|
expect(mail_html.scan(/Visit Topic/).count).to eq(2)
|
|
|
|
# 2 respond to links cause we have 1 context post
|
|
expect(mail_html.scan(/to respond/).count).to eq(2)
|
|
|
|
# 1 unsubscribe
|
|
expect(mail_html.scan(/To unsubscribe/).count).to eq(1)
|
|
|
|
# side effect, topic user is updated with post number
|
|
tu = TopicUser.get(post.topic_id, user)
|
|
expect(tu.last_emailed_post_number).to eq(response.post_number)
|
|
|
|
# no In Reply To if user opts out
|
|
user.user_option.email_in_reply_to = false
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.html_part.body.to_s.scan(/In Reply To/).count).to eq(0)
|
|
|
|
SiteSetting.enable_names = true
|
|
SiteSetting.display_name_on_posts = true
|
|
SiteSetting.prioritize_username_in_ux = false
|
|
|
|
response.user.username = "bobmarley"
|
|
response.user.name = "Bob Marley"
|
|
response.user.save
|
|
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
mail_html = mail.html_part.body.to_s
|
|
expect(mail_html.scan(/>Bob Marley/).count).to eq(1)
|
|
expect(mail_html.scan(/>bobmarley/).count).to eq(0)
|
|
|
|
expect(mail.subject.scan(/#{tag1.name}/).count).to eq(1)
|
|
expect(mail.subject.scan(/#{hidden_tag.name}/).count).to eq(0)
|
|
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
mail_html = mail.html_part.body.to_s
|
|
expect(mail_html.scan(/>Bob Marley/).count).to eq(0)
|
|
expect(mail_html.scan(/>bobmarley/).count).to eq(1)
|
|
end
|
|
|
|
describe "number of tags shown in subject line" do
|
|
describe "max_tags_per_email_subject siteSetting enabled" do
|
|
before { SiteSetting.enable_max_tags_per_email_subject = true }
|
|
|
|
it "should match max_tags_per_email_subject" do
|
|
SiteSetting.email_subject =
|
|
"[%{site_name}] %{optional_pm}%{optional_cat}%{optional_tags}%{topic_title}"
|
|
SiteSetting.max_tags_per_topic = 1
|
|
SiteSetting.max_tags_per_email_subject = 2
|
|
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.subject).to eq(
|
|
"[Discourse] [#{category.name}] #{tag2.name} #{tag3.name} #{topic.title}",
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "max_tags_per_email_subject siteSetting disabled" do
|
|
before { SiteSetting.enable_max_tags_per_email_subject = false }
|
|
|
|
it "should match max_tags_per_topic" do
|
|
SiteSetting.email_subject =
|
|
"[%{site_name}] %{optional_pm}%{optional_cat}%{optional_tags}%{topic_title}"
|
|
SiteSetting.max_tags_per_topic = 2
|
|
SiteSetting.max_tags_per_email_subject = 1
|
|
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.subject).to eq(
|
|
"[Discourse] [#{category.name}] #{tag2.name} #{tag3.name} #{topic.title}",
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
it "doesn't include details when private_email is enabled" do
|
|
SiteSetting.private_email = true
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.html_part.body.to_s).to_not include(response.raw)
|
|
expect(mail.html_part.body.to_s).to_not include(topic.url)
|
|
expect(mail.text_part.to_s).to_not include(response.raw)
|
|
expect(mail.text_part.to_s).to_not include(topic.url)
|
|
end
|
|
|
|
it "includes excerpt when post_excerpts_in_emails is enabled" do
|
|
paragraphs = [
|
|
"This is the first paragraph, but you should read more.",
|
|
"And here is its friend, the second paragraph.",
|
|
]
|
|
SiteSetting.post_excerpts_in_emails = true
|
|
SiteSetting.post_excerpt_maxlength = paragraphs.first.length
|
|
response.update!(raw: paragraphs.join("\n\n"))
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
mail_html = mail.html_part.body.to_s
|
|
expect(mail_html.scan(/#{paragraphs[0]}/).count).to eq(1)
|
|
expect(mail_html.scan(/#{paragraphs[1]}/).count).to eq(0)
|
|
end
|
|
end
|
|
|
|
describe ".user_posted" do
|
|
let(:response_by_user) { Fabricate(:user, name: "John Doe", username: "john") }
|
|
let(:topic) { Fabricate(:topic, title: "Super cool topic") }
|
|
let(:post) { Fabricate(:post, topic: topic) }
|
|
let(:response) { Fabricate(:post, topic: topic, user: response_by_user) }
|
|
let(:user) { Fabricate(:user) }
|
|
let(:notification) { Fabricate(:posted_notification, user: user, post: response) }
|
|
|
|
it "generates a correct email" do
|
|
SiteSetting.enable_names = false
|
|
mail =
|
|
UserNotifications.user_posted(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
# from should not include full user name if "show user full names" is disabled
|
|
expect(mail[:from].display_names).to_not eql(["John Doe"])
|
|
|
|
# from should include username if "show user full names" is disabled
|
|
expect(mail[:from].display_names).to eql(["john via Discourse"])
|
|
|
|
# subject should not include category name
|
|
expect(mail.subject).not_to match(/Uncategorized/)
|
|
|
|
# 1 respond to links as no context by default
|
|
expect(mail.html_part.body.to_s.scan(/to respond/).count).to eq(1)
|
|
|
|
# 1 unsubscribe link
|
|
expect(mail.html_part.body.to_s.scan(/To unsubscribe/).count).to eq(1)
|
|
|
|
# side effect, topic user is updated with post number
|
|
tu = TopicUser.get(post.topic_id, user)
|
|
expect(tu.last_emailed_post_number).to eq(response.post_number)
|
|
end
|
|
|
|
it "doesn't include details when private_email is enabled" do
|
|
SiteSetting.private_email = true
|
|
mail =
|
|
UserNotifications.user_posted(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.html_part.body.to_s).to_not include(response.raw)
|
|
expect(mail.text_part.to_s).to_not include(response.raw)
|
|
end
|
|
|
|
it "uses the original subject for staged users" do
|
|
incoming_email =
|
|
Fabricate(
|
|
:incoming_email,
|
|
subject: "Original Subject",
|
|
post: post,
|
|
topic: post.topic,
|
|
user: user,
|
|
)
|
|
|
|
mail =
|
|
UserNotifications.user_posted(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to match(/Super cool topic/)
|
|
|
|
user.update!(staged: true)
|
|
mail =
|
|
UserNotifications.user_posted(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to eq("Re: Original Subject")
|
|
|
|
another_post = Fabricate(:post, topic: topic)
|
|
incoming_email.update!(post_id: another_post.id)
|
|
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to match(/Super cool topic/)
|
|
end
|
|
end
|
|
|
|
describe ".user_private_message" do
|
|
let(:response_by_user) { Fabricate(:user, name: "", username: "john") }
|
|
let(:topic) { Fabricate(:private_message_topic, title: "Super cool topic") }
|
|
let(:post) { Fabricate(:post, topic: topic) }
|
|
let(:response) { Fabricate(:post, topic: topic, user: response_by_user) }
|
|
let(:user) { Fabricate(:user) }
|
|
let(:notification) { Fabricate(:private_message_notification, user: user, post: response) }
|
|
|
|
it "generates a correct email" do
|
|
SiteSetting.enable_names = true
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
# from should include username if full user name is not provided
|
|
expect(mail[:from].display_names).to eql(["john via Discourse"])
|
|
|
|
# subject should include "[PM]"
|
|
expect(mail.subject).to include("[PM] ")
|
|
|
|
# 1 "visit message" link
|
|
expect(mail.html_part.body.to_s.scan(/Visit Message/).count).to eq(1)
|
|
|
|
# 1 respond to link
|
|
expect(mail.html_part.body.to_s.scan(/to respond/).count).to eq(1)
|
|
|
|
# 1 unsubscribe link
|
|
expect(mail.html_part.body.to_s.scan(/To unsubscribe/).count).to eq(1)
|
|
|
|
# side effect, topic user is updated with post number
|
|
tu = TopicUser.get(topic.id, user)
|
|
expect(tu.last_emailed_post_number).to eq(response.post_number)
|
|
end
|
|
|
|
it "doesn't include details when private_email is enabled" do
|
|
SiteSetting.private_email = true
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.html_part.body.to_s).to_not include(response.raw)
|
|
expect(mail.html_part.body.to_s).to_not include(topic.url)
|
|
expect(mail.text_part.to_s).to_not include(response.raw)
|
|
expect(mail.text_part.to_s).to_not include(topic.url)
|
|
end
|
|
|
|
it "doesn't include group name in subject" do
|
|
group = Fabricate(:group)
|
|
topic.allowed_groups = [group]
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.subject).to include("[PM] ")
|
|
end
|
|
|
|
it "includes a list of participants (except for the destination user), groups first with member lists" do
|
|
group1 = Fabricate(:group, name: "group1")
|
|
group2 = Fabricate(:group, name: "group2")
|
|
|
|
user1 = Fabricate(:user, username: "one", groups: [group1, group2])
|
|
user2 = Fabricate(:user, username: "two", groups: [group1], staged: true)
|
|
|
|
topic.allowed_users = [user, user1, user2]
|
|
topic.allowed_groups = [group1, group2]
|
|
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
expect(mail.body).to include(
|
|
"[group1 (2)](http://test.localhost/g/group1), [group2 (1)](http://test.localhost/g/group2), [one](http://test.localhost/u/one), [two](http://test.localhost/u/two)",
|
|
)
|
|
end
|
|
|
|
context "when SiteSetting.group_name_in_subject is true" do
|
|
before { SiteSetting.group_in_subject = true }
|
|
|
|
let(:group) { Fabricate(:group, name: "my_group") }
|
|
let(:mail) do
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
end
|
|
|
|
shared_examples "includes first group name" do
|
|
it "includes first group name in subject" do
|
|
expect(mail.subject).to include("[my_group] ")
|
|
end
|
|
|
|
context "when first group has full name" do
|
|
it "includes full name in subject" do
|
|
group.full_name = "My Group"
|
|
group.save
|
|
expect(mail.subject).to include("[My Group] ")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with one group in pm" do
|
|
before { topic.allowed_groups = [group] }
|
|
|
|
include_examples "includes first group name"
|
|
end
|
|
|
|
context "with multiple groups in pm" do
|
|
let(:group2) { Fabricate(:group) }
|
|
|
|
before { topic.allowed_groups = [group, group2] }
|
|
|
|
include_examples "includes first group name"
|
|
end
|
|
|
|
context "with no groups in pm" do
|
|
it "includes %{optional_pm} in subject" do
|
|
expect(mail.subject).to include("[PM] ")
|
|
end
|
|
end
|
|
end
|
|
|
|
it "uses the original subject for staged users when topic was started via email" do
|
|
incoming_email =
|
|
Fabricate(
|
|
:incoming_email,
|
|
subject: "Original Subject",
|
|
post: post,
|
|
topic: topic,
|
|
user: user,
|
|
)
|
|
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to match(/Super cool topic/)
|
|
|
|
user.update!(staged: true)
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to eq("Re: Original Subject")
|
|
|
|
another_post = Fabricate(:post, topic: topic)
|
|
incoming_email.update!(post_id: another_post.id)
|
|
|
|
mail =
|
|
UserNotifications.user_private_message(
|
|
user,
|
|
post: response,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
expect(mail.subject).to match(/Super cool topic/)
|
|
end
|
|
end
|
|
|
|
it "adds a warning when mail limit is reached" do
|
|
SiteSetting.max_emails_per_day_per_user = 2
|
|
user = Fabricate(:user)
|
|
|
|
user.email_logs.create!(email_type: "blah", to_address: user.email, user_id: user.id)
|
|
|
|
post = Fabricate(:post)
|
|
reply = Fabricate(:post, topic_id: post.topic_id)
|
|
|
|
notification =
|
|
Fabricate(
|
|
:notification,
|
|
topic_id: post.topic_id,
|
|
post_number: reply.post_number,
|
|
user: post.user,
|
|
data: { original_username: "bob" }.to_json,
|
|
)
|
|
|
|
mail =
|
|
UserNotifications.user_replied(
|
|
user,
|
|
post: reply,
|
|
notification_type: notification.notification_type,
|
|
notification_data_hash: notification.data_hash,
|
|
)
|
|
|
|
# WARNING: you reached the limit of 100 email notifications per day. Further emails will be suppressed.
|
|
# Consider watching less topics or disabling mailing list mode.
|
|
expect(mail.html_part.body.to_s).to match(I18n.t("user_notifications.reached_limit", count: 2))
|
|
expect(mail.body.to_s).to match(I18n.t("user_notifications.reached_limit", count: 2))
|
|
end
|
|
|
|
def expects_build_with(condition)
|
|
UserNotifications.any_instance.expects(:build_email).with(user.email, condition)
|
|
mailer =
|
|
UserNotifications.public_send(
|
|
mail_type,
|
|
user,
|
|
notification_type: Notification.types[notification.notification_type],
|
|
notification_data_hash: notification.data_hash,
|
|
post: notification.post,
|
|
)
|
|
|
|
mailer.message
|
|
end
|
|
|
|
shared_examples "supports reply by email" do
|
|
context "with reply_by_email" do
|
|
it "should have allow_reply_by_email set when that feature is enabled" do
|
|
expects_build_with(has_entry(:allow_reply_by_email, true))
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples "no reply by email" do
|
|
context "with reply_by_email" do
|
|
it "doesn't support reply by email" do
|
|
expects_build_with(Not(has_entry(:allow_reply_by_email, true)))
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples "respect for private_email" do
|
|
context "with private_email" do
|
|
it "doesn't support reply by email" do
|
|
SiteSetting.private_email = true
|
|
|
|
mailer =
|
|
UserNotifications.public_send(
|
|
mail_type,
|
|
user,
|
|
notification_type: Notification.types[notification.notification_type],
|
|
notification_data_hash: notification.data_hash,
|
|
post: notification.post,
|
|
)
|
|
message = mailer.message
|
|
|
|
topic = notification.post.topic
|
|
expect(message.html_part.body.to_s).not_to include(topic.title)
|
|
expect(message.html_part.body.to_s).not_to include(topic.slug)
|
|
expect(message.text_part.body.to_s).not_to include(topic.title)
|
|
expect(message.text_part.body.to_s).not_to include(topic.slug)
|
|
end
|
|
end
|
|
end
|
|
|
|
# The parts of emails that are derived from templates are translated
|
|
shared_examples "sets user locale" do
|
|
context "with set locale for translating templates" do
|
|
it "sets the locale" do
|
|
expects_build_with(has_key(:locale))
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples "notification email building" do
|
|
let(:post) { Fabricate(:post, user: user) }
|
|
let(:mail_type) { "user_#{notification_type}" }
|
|
let(:mail_template) { "user_notifications.#{mail_type}" }
|
|
let(:username) { "walterwhite" }
|
|
let(:notification) do
|
|
Fabricate(
|
|
:notification,
|
|
user: user,
|
|
topic: post.topic,
|
|
notification_type: Notification.types[notification_type],
|
|
post_number: post.post_number,
|
|
data: { original_username: username }.to_json,
|
|
)
|
|
end
|
|
|
|
describe "email building" do
|
|
it "has a username" do
|
|
expects_build_with(has_entry(:username, username))
|
|
end
|
|
|
|
it "has a url" do
|
|
expects_build_with(has_key(:url))
|
|
end
|
|
|
|
it "has a template" do
|
|
expects_build_with(has_entry(:template, mail_template))
|
|
end
|
|
|
|
it "overrides the html part" do
|
|
expects_build_with(has_key(:html_override))
|
|
end
|
|
|
|
it "has a message" do
|
|
expects_build_with(has_key(:message))
|
|
end
|
|
|
|
it "has a context" do
|
|
expects_build_with(has_key(:context))
|
|
end
|
|
|
|
it "has an unsubscribe link" do
|
|
expects_build_with(has_key(:add_unsubscribe_link))
|
|
end
|
|
|
|
it "has an post_id" do
|
|
expects_build_with(has_key(:post_id))
|
|
end
|
|
|
|
it "has an topic_id" do
|
|
expects_build_with(has_key(:topic_id))
|
|
end
|
|
|
|
it "should have user name as from_alias" do
|
|
SiteSetting.enable_names = true
|
|
SiteSetting.display_name_on_posts = true
|
|
expects_build_with(has_entry(:from_alias, "#{user.name} via Discourse"))
|
|
end
|
|
|
|
it "should not have user name as from_alias if display_name_on_posts is disabled" do
|
|
SiteSetting.enable_names = false
|
|
SiteSetting.display_name_on_posts = false
|
|
expects_build_with(has_entry(:from_alias, "walterwhite via Discourse"))
|
|
end
|
|
|
|
it "should explain how to respond" do
|
|
expects_build_with(Not(has_entry(:include_respond_instructions, false)))
|
|
end
|
|
|
|
it "should not explain how to respond if the user is suspended" do
|
|
User.any_instance.stubs(:suspended?).returns(true)
|
|
expects_build_with(has_entry(:include_respond_instructions, false))
|
|
end
|
|
|
|
context "when customized" do
|
|
let(:custom_body) do
|
|
body = +<<~BODY
|
|
You are now officially notified.
|
|
%{header_instructions}
|
|
%{message} %{respond_instructions}
|
|
%{topic_title_url_encoded}
|
|
%{site_title_url_encoded}
|
|
BODY
|
|
|
|
body << "%{context}" if notification_type != :invited_to_topic
|
|
body
|
|
end
|
|
|
|
before do
|
|
TranslationOverride.upsert!(
|
|
SiteSetting.default_locale,
|
|
"#{mail_template}.text_body_template",
|
|
custom_body,
|
|
)
|
|
end
|
|
|
|
it "shouldn't use the default html_override" do
|
|
expects_build_with(Not(has_key(:html_override)))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "user mentioned email" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :mentioned }
|
|
include_examples "respect for private_email"
|
|
include_examples "supports reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "group mentioned email" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :group_mentioned }
|
|
let(:post) { Fabricate(:private_message_post) }
|
|
let(:user) { post.user }
|
|
let(:mail_type) { "group_mentioned" }
|
|
let(:mail_template) { "user_notifications.user_#{notification_type}_pm" }
|
|
|
|
include_examples "respect for private_email"
|
|
include_examples "supports reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "user replied" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :replied }
|
|
include_examples "respect for private_email"
|
|
include_examples "supports reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "user quoted" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :quoted }
|
|
include_examples "respect for private_email"
|
|
include_examples "supports reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "user posted" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :posted }
|
|
include_examples "respect for private_email"
|
|
include_examples "supports reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "user invited to a private message" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :invited_to_private_message }
|
|
let(:post) { Fabricate(:private_message_post) }
|
|
let(:user) { post.user }
|
|
let(:mail_template) { "user_notifications.user_#{notification_type}_pm" }
|
|
|
|
include_examples "respect for private_email"
|
|
include_examples "no reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "group invited to a private message" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :invited_to_private_message }
|
|
let(:post) { Fabricate(:private_message_post) }
|
|
let(:user) { post.user }
|
|
let(:group) { Fabricate(:group) }
|
|
let(:mail_template) { "user_notifications.user_#{notification_type}_pm_group" }
|
|
|
|
before do
|
|
notification.data_hash[:group_id] = group.id
|
|
notification.save!
|
|
end
|
|
|
|
it "should include the group name" do
|
|
expects_build_with(has_entry(:group_name, group.name))
|
|
end
|
|
|
|
include_examples "respect for private_email"
|
|
include_examples "no reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
describe "user invited to a topic" do
|
|
let(:notification_type) { :invited_to_topic }
|
|
|
|
include_examples "notification email building" do
|
|
include_examples "respect for private_email"
|
|
include_examples "no reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
|
|
context "when showing the right name in 'From' field" do
|
|
let(:inviter) { Fabricate(:user) }
|
|
let(:invitee) { Fabricate(:user) }
|
|
|
|
let(:notification) do
|
|
Fabricate(
|
|
:notification,
|
|
notification_type: Notification.types[:invited_to_topic],
|
|
user: invitee,
|
|
topic: post.topic,
|
|
post_number: post.post_number,
|
|
data: {
|
|
topic_title: post.topic.title,
|
|
display_username: inviter.username,
|
|
original_user_id: inviter.id,
|
|
original_username: inviter.username,
|
|
}.to_json,
|
|
)
|
|
end
|
|
|
|
let(:mailer) do
|
|
UserNotifications.public_send(
|
|
"user_invited_to_topic",
|
|
invitee,
|
|
notification_type: Notification.types[notification.notification_type],
|
|
notification_data_hash: notification.data_hash,
|
|
post: notification.post,
|
|
)
|
|
end
|
|
|
|
it "sends the email as the inviter" do
|
|
SiteSetting.enable_names = false
|
|
|
|
expect(mailer.message.to_s).to include(
|
|
"From: #{inviter.username} via #{SiteSetting.title} <#{SiteSetting.notification_email}>",
|
|
)
|
|
end
|
|
|
|
it "sends the email as the inviter" do
|
|
expect(mailer.message.to_s).to include(
|
|
"From: #{inviter.name} via #{SiteSetting.title} <#{SiteSetting.notification_email}>",
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "watching first post" do
|
|
include_examples "notification email building" do
|
|
let(:notification_type) { :invited_to_topic }
|
|
include_examples "respect for private_email"
|
|
include_examples "no reply by email"
|
|
include_examples "sets user locale"
|
|
end
|
|
end
|
|
|
|
# notification emails derived from templates are translated into the user's locale
|
|
shared_context "with notification derived from template" do
|
|
let(:user) { Fabricate(:user, locale: locale) }
|
|
let(:mail_type) { mail_type }
|
|
let(:notification) { Fabricate(:notification, user: user) }
|
|
end
|
|
|
|
describe "notifications from template" do
|
|
context "when user locale is allowed" do
|
|
before { SiteSetting.allow_user_locale = true }
|
|
|
|
%w[
|
|
signup
|
|
signup_after_approval
|
|
confirm_old_email
|
|
notify_old_email
|
|
confirm_new_email
|
|
forgot_password
|
|
admin_login
|
|
account_created
|
|
].each do |mail_type|
|
|
include_examples "with notification derived from template" do
|
|
let(:locale) { "fr" }
|
|
let(:mail_type) { mail_type }
|
|
it "sets the locale" do
|
|
expects_build_with(has_entry(:locale, "fr"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when user locale is not allowed" do
|
|
before { SiteSetting.allow_user_locale = false }
|
|
|
|
%w[
|
|
signup
|
|
signup_after_approval
|
|
notify_old_email
|
|
confirm_old_email
|
|
confirm_new_email
|
|
forgot_password
|
|
admin_login
|
|
account_created
|
|
].each do |mail_type|
|
|
include_examples "with notification derived from template" do
|
|
let(:locale) { "fr" }
|
|
let(:mail_type) { mail_type }
|
|
it "sets the locale" do
|
|
expects_build_with(has_entry(:locale, "en"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#participants" do
|
|
fab!(:group1) { Fabricate(:group, name: "group1") }
|
|
fab!(:group2) { Fabricate(:group, name: "group2") }
|
|
fab!(:group3) { Fabricate(:group, name: "group3") }
|
|
fab!(:user1) { Fabricate(:user, username: "one", name: nil, groups: [group1, group2]) }
|
|
fab!(:user2) { Fabricate(:user, username: "two", name: nil, groups: [group1]) }
|
|
fab!(:user3) { Fabricate(:user, username: "three", name: nil, groups: [group3]) }
|
|
fab!(:user4) { Fabricate(:user, username: "four", name: nil, groups: [group1, group3]) }
|
|
fab!(:admin) { Fabricate(:admin, username: "admin", name: nil) }
|
|
|
|
fab!(:topic) do
|
|
t = Fabricate(:private_message_topic, title: "Super cool topic")
|
|
t.allowed_users = [user1, user2, user3, user4, admin]
|
|
t.allowed_groups = [group1]
|
|
t
|
|
end
|
|
fab!(:posts) do
|
|
[
|
|
Fabricate(:post, topic: topic, post_number: 1, user: user2),
|
|
Fabricate(:post, topic: topic, post_number: 2, user: user1),
|
|
Fabricate(:post, topic: topic, post_number: 3, user: user2),
|
|
Fabricate(:small_action, topic: topic, post_number: 4, user: admin),
|
|
Fabricate(:post, topic: topic, post_number: 5, user: user4),
|
|
Fabricate(:post, topic: topic, post_number: 6, user: user3),
|
|
Fabricate(:post, topic: topic, post_number: 7, user: user4),
|
|
]
|
|
end
|
|
|
|
it "returns a list of participants (except for the recipient), groups first, followed by users in order of their last reply" do
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), " \
|
|
"[four](http://test.localhost/u/four), [two](http://test.localhost/u/two), [one](http://test.localhost/u/one), " \
|
|
"[admin](http://test.localhost/u/admin)",
|
|
)
|
|
end
|
|
|
|
it "caps the list according to site setting" do
|
|
SiteSetting.max_participant_names = 3
|
|
list =
|
|
"[group1 (3)](http://test.localhost/g/group1), [four](http://test.localhost/u/four), [two](http://test.localhost/u/two)"
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
I18n.t("user_notifications.more_pm_participants", participants: list, count: 2),
|
|
)
|
|
end
|
|
|
|
it "orders groups by user count" do
|
|
SiteSetting.max_participant_names = 3
|
|
topic.allowed_groups = [group1, group2, group3]
|
|
|
|
list =
|
|
"[group1 (3)](http://test.localhost/g/group1), [group3 (2)](http://test.localhost/g/group3), [group2 (1)](http://test.localhost/g/group2)"
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
I18n.t("user_notifications.more_pm_participants", participants: list, count: 4),
|
|
)
|
|
end
|
|
|
|
it "orders users by their last reply and user id" do
|
|
expect(UserNotifications.participants(posts[-3], user4)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), " \
|
|
"[two](http://test.localhost/u/two), [one](http://test.localhost/u/one), [three](http://test.localhost/u/three), " \
|
|
"[admin](http://test.localhost/u/admin)",
|
|
)
|
|
end
|
|
|
|
it "prefers full group names when available" do
|
|
SiteSetting.max_participant_names = 2
|
|
topic.allowed_groups = [group1, group2]
|
|
|
|
group2.update!(full_name: "Awesome Group")
|
|
|
|
list =
|
|
"[group1 (3)](http://test.localhost/g/group1), [Awesome Group (1)](http://test.localhost/g/group2)"
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
I18n.t("user_notifications.more_pm_participants", participants: list, count: 4),
|
|
)
|
|
end
|
|
|
|
it "always uses usernames when prioritize_username_in_ux is enabled" do
|
|
user4.update!(name: "James Bond")
|
|
user1.update!(name: "Indiana Jones")
|
|
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), " \
|
|
"[four](http://test.localhost/u/four), [two](http://test.localhost/u/two), [one](http://test.localhost/u/one), " \
|
|
"[admin](http://test.localhost/u/admin)",
|
|
)
|
|
|
|
SiteSetting.prioritize_username_in_ux = false
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), " \
|
|
"[James Bond](http://test.localhost/u/four), [two](http://test.localhost/u/two), [Indiana Jones](http://test.localhost/u/one), " \
|
|
"[admin](http://test.localhost/u/admin)",
|
|
)
|
|
end
|
|
|
|
it "reveals the email address of staged users if enabled" do
|
|
user4.update!(staged: true, email: "james.bond@mi6.invalid")
|
|
user1.update!(staged: true, email: "indiana.jones@example.com")
|
|
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
expect(UserNotifications.participants(posts.last, user3, reveal_staged_email: true)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), james.bond@mi6.invalid, [two](http://test.localhost/u/two), " \
|
|
"indiana.jones@example.com, [admin](http://test.localhost/u/admin)",
|
|
)
|
|
end
|
|
|
|
it "does only include human users" do
|
|
topic.allowed_users << Discourse.system_user
|
|
|
|
expect(UserNotifications.participants(posts.last, user3)).to eq(
|
|
"[group1 (3)](http://test.localhost/g/group1), " \
|
|
"[four](http://test.localhost/u/four), [two](http://test.localhost/u/two), [one](http://test.localhost/u/one), " \
|
|
"[admin](http://test.localhost/u/admin)",
|
|
)
|
|
end
|
|
end
|
|
|
|
describe ".account_silenced" do
|
|
fab!(:user_history) { Fabricate(:user_history, action: UserHistory.actions[:silence_user]) }
|
|
|
|
it "adds the silenced_till date in user's timezone" do
|
|
user.user_option.timezone = "Asia/Tbilisi" # GMT+4
|
|
user.silenced_till = DateTime.parse("May 25, 2020, 12:00pm")
|
|
|
|
mail = UserNotifications.account_silenced(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include("May 25, 2020, 4:00pm")
|
|
end
|
|
|
|
context "when user doesn't have timezone set" do
|
|
before { user.user_option.timezone = nil }
|
|
|
|
it "doesn't raise error" do
|
|
expect { UserNotifications.account_silenced(user) }.not_to raise_error
|
|
end
|
|
|
|
it "adds the silenced_till date in UTC" do
|
|
date = "May 25, 2020, 12:00pm"
|
|
user.silenced_till = DateTime.parse(date)
|
|
|
|
mail = UserNotifications.account_silenced(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include(date)
|
|
end
|
|
end
|
|
|
|
context "when user timezone is invalid" do
|
|
before { user.user_option.timezone = "" }
|
|
|
|
it "doesn't raise error" do
|
|
expect { UserNotifications.account_silenced(user) }.not_to raise_error
|
|
end
|
|
|
|
it "adds the silenced_till date in UTC" do
|
|
date = "May 25, 2020, 12:00pm"
|
|
user.silenced_till = DateTime.parse(date)
|
|
|
|
mail = UserNotifications.account_silenced(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include(date)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".account_suspended" do
|
|
fab!(:user_history) { Fabricate(:user_history, action: UserHistory.actions[:suspend_user]) }
|
|
|
|
it "adds the suspended_till date in user's timezone" do
|
|
user.user_option.timezone = "Asia/Tbilisi" # GMT+4
|
|
user.suspended_till = DateTime.parse("May 25, 2020, 12:00pm")
|
|
|
|
mail = UserNotifications.account_suspended(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include("May 25, 2020, 4:00pm")
|
|
end
|
|
|
|
context "when user doesn't have timezone set" do
|
|
before { user.user_option.timezone = nil }
|
|
|
|
it "doesn't raise error" do
|
|
expect { UserNotifications.account_suspended(user) }.not_to raise_error
|
|
end
|
|
|
|
it "adds the suspended_till date in UTC" do
|
|
date = "May 25, 2020, 12:00pm"
|
|
user.suspended_till = DateTime.parse(date)
|
|
|
|
mail = UserNotifications.account_suspended(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include(date)
|
|
end
|
|
end
|
|
|
|
context "when user timezone is invalid" do
|
|
before { user.user_option.timezone = "" }
|
|
|
|
it "doesn't raise error" do
|
|
expect { UserNotifications.account_suspended(user) }.not_to raise_error
|
|
end
|
|
|
|
it "adds the suspended_till date in UTC" do
|
|
date = "May 25, 2020, 12:00pm"
|
|
user.suspended_till = DateTime.parse(date)
|
|
|
|
mail = UserNotifications.account_suspended(user, { user_history: user_history })
|
|
|
|
expect(mail.body).to include(date)
|
|
end
|
|
end
|
|
end
|
|
end
|