mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 07:33:37 +08:00
75dc01627d
Mailing list mode can generate significant email volume, especially on sites with a large user base. Disable mailing list mode via site settings by default so sites don't experience an unexpectedly large cost from outgoing email.
309 lines
10 KiB
Ruby
309 lines
10 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
require 'rails_helper'
|
||
|
||
RSpec.describe EmailController do
|
||
fab!(:user) { Fabricate(:user) }
|
||
fab!(:topic) { Fabricate(:topic) }
|
||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||
|
||
context '.perform unsubscribe' do
|
||
it 'raises not found on invalid key' do
|
||
post "/email/unsubscribe/123.json"
|
||
expect(response.status).to eq(404)
|
||
end
|
||
|
||
fab!(:user) { Fabricate(:user) }
|
||
let(:key) { UnsubscribeKey.create_key_for(user, "all") }
|
||
|
||
it 'can fully unsubscribe' do
|
||
user.user_option.update_columns(email_digests: true,
|
||
email_level: UserOption.email_level_types[:never],
|
||
email_messages_level: UserOption.email_level_types[:never],
|
||
mailing_list_mode: true)
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { unsubscribe_all: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
get response.redirect_url
|
||
|
||
# cause it worked ... yay
|
||
expect(body).to include(user.email)
|
||
|
||
user.user_option.reload
|
||
|
||
expect(user.user_option.email_digests).to eq(false)
|
||
expect(user.user_option.email_level).to eq(UserOption.email_level_types[:never])
|
||
expect(user.user_option.email_messages_level).to eq(UserOption.email_level_types[:never])
|
||
expect(user.user_option.mailing_list_mode).to eq(false)
|
||
end
|
||
|
||
it 'can disable mailing list' do
|
||
user.user_option.update_columns(mailing_list_mode: true)
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { disable_mailing_list: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
user.user_option.reload
|
||
|
||
expect(user.user_option.mailing_list_mode).to eq(false)
|
||
end
|
||
|
||
it 'Can change digest frequency' do
|
||
weekly_interval_minutes = 10080
|
||
user.user_option.update_columns(email_digests: true, digest_after_minutes: 0)
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { digest_after_minutes: weekly_interval_minutes.to_s }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
user.user_option.reload
|
||
|
||
expect(user.user_option.digest_after_minutes).to eq(weekly_interval_minutes)
|
||
end
|
||
|
||
it 'Can disable email digests setting frequency to zero' do
|
||
user.user_option.update_columns(email_digests: true, digest_after_minutes: 10080)
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { digest_after_minutes: '0' }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
user.user_option.reload
|
||
|
||
expect(user.user_option.digest_after_minutes).to be_zero
|
||
expect(user.user_option.email_digests).to eq(false)
|
||
end
|
||
|
||
it 'can unwatch topic' do
|
||
p = Fabricate(:post)
|
||
key = UnsubscribeKey.create_key_for(p.user, p)
|
||
|
||
TopicUser.change(p.user_id, p.topic_id, notification_level: TopicUser.notification_levels[:watching])
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { unwatch_topic: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
expect(TopicUser.get(p.topic, p.user).notification_level).to eq(TopicUser.notification_levels[:tracking])
|
||
end
|
||
|
||
it 'can mute topic' do
|
||
p = Fabricate(:post)
|
||
key = UnsubscribeKey.create_key_for(p.user, p)
|
||
|
||
TopicUser.change(p.user_id, p.topic_id, notification_level: TopicUser.notification_levels[:watching])
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { mute_topic: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
expect(TopicUser.get(p.topic, p.user).notification_level).to eq(TopicUser.notification_levels[:muted])
|
||
end
|
||
|
||
it 'can unwatch category' do
|
||
p = Fabricate(:post)
|
||
key = UnsubscribeKey.create_key_for(p.user, p)
|
||
|
||
cu = CategoryUser.create!(user_id: p.user.id,
|
||
category_id: p.topic.category_id,
|
||
notification_level: CategoryUser.notification_levels[:watching])
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { unwatch_category: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
|
||
end
|
||
|
||
it 'can unwatch first post from category' do
|
||
p = Fabricate(:post)
|
||
key = UnsubscribeKey.create_key_for(p.user, p)
|
||
|
||
cu = CategoryUser.create!(user_id: p.user.id,
|
||
category_id: p.topic.category_id,
|
||
notification_level: CategoryUser.notification_levels[:watching_first_post])
|
||
|
||
post "/email/unsubscribe/#{key}.json",
|
||
params: { unwatch_category: "1" }
|
||
|
||
expect(response.status).to eq(302)
|
||
|
||
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
|
||
end
|
||
end
|
||
|
||
describe '#unsubscribed' do
|
||
describe 'when email is invalid' do
|
||
it 'should return the right response' do
|
||
get '/email/unsubscribed', params: { email: 'somerandomstring' }
|
||
expect(response.status).to eq(404)
|
||
end
|
||
end
|
||
|
||
describe 'when topic is public' do
|
||
it 'should return the right response' do
|
||
key = SecureRandom.hex
|
||
Discourse.cache.write(key, user.email)
|
||
get '/email/unsubscribed', params: { key: key, topic_id: topic.id }
|
||
expect(response.status).to eq(200)
|
||
expect(response.body).to include(topic.title)
|
||
end
|
||
end
|
||
|
||
describe 'when topic is private' do
|
||
it 'should return the right response' do
|
||
key = SecureRandom.hex
|
||
Discourse.cache.write(key, user.email)
|
||
get '/email/unsubscribed', params: { key: key, topic_id: private_topic.id }
|
||
expect(response.status).to eq(200)
|
||
expect(response.body).to_not include(private_topic.title)
|
||
end
|
||
end
|
||
end
|
||
|
||
context '#unsubscribe' do
|
||
it 'displays not found if key is not found' do
|
||
navigate_to_unsubscribe(SecureRandom.hex)
|
||
|
||
expect(response.body).to include(CGI.escapeHTML(I18n.t("unsubscribe.not_found_description")))
|
||
end
|
||
|
||
fab!(:user) { Fabricate(:user) }
|
||
let(:unsubscribe_key) { UnsubscribeKey.create_key_for(user, key_type) }
|
||
|
||
context 'Unsubscribe from digest' do
|
||
let(:key_type) { 'digest' }
|
||
|
||
it 'displays log out button if wrong user logged in' do
|
||
sign_in(Fabricate(:admin))
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
expect(response.body).to include(I18n.t("unsubscribe.log_out"))
|
||
expect(response.body).to include(I18n.t("unsubscribe.different_user_description"))
|
||
end
|
||
|
||
it 'displays correct label when email_digests is set to false' do
|
||
user.user_option.update!(email_digests: false, digest_after_minutes: 10080)
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
expect(body).to include("You are not receiving summary emails")
|
||
expect(body).to include("Don’t send me any mail from Discourse")
|
||
end
|
||
|
||
it 'hides unsubscribe from all checkbox when user already unsubscribed' do
|
||
user.user_option.update!(email_digests: false, mailing_list_mode: false, email_level: 2, email_messages_level: 2)
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
expect(body).to include("You are not receiving summary emails")
|
||
expect(body).not_to include("Don't send me any mail from Discourse")
|
||
end
|
||
|
||
it 'correctly handles mailing list mode' do
|
||
SiteSetting.disable_mailing_list_mode = false
|
||
user.user_option.update_columns(mailing_list_mode: true)
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).to include(I18n.t("unsubscribe.mailing_list_mode"))
|
||
|
||
SiteSetting.disable_mailing_list_mode = true
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode"))
|
||
|
||
user.user_option.update_columns(mailing_list_mode: false)
|
||
SiteSetting.disable_mailing_list_mode = false
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode"))
|
||
end
|
||
|
||
it 'Lets you select the digest frequency ranging from never to half a year' do
|
||
selected_digest_frequency = 0
|
||
slow_digest_frequencies = ['weekly', 'every month', 'every six months', 'never']
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
source = Nokogiri::HTML5::fragment(response.body)
|
||
expect(source.css(".combobox option").map(&:inner_text)).to eq(slow_digest_frequencies)
|
||
end
|
||
|
||
it 'Selects the next slowest frequency by default' do
|
||
every_month_freq = 43200
|
||
six_months_freq = 259200
|
||
user.user_option.update_columns(digest_after_minutes: every_month_freq)
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
source = Nokogiri::HTML5::fragment(response.body)
|
||
expect(source.css(".combobox option[selected='selected']")[0]['value']).to eq(six_months_freq.to_s)
|
||
end
|
||
|
||
it 'Uses never as the selected frequency if current one is six months' do
|
||
never_frequency = 0
|
||
six_months_freq = 259200
|
||
user.user_option.update_columns(digest_after_minutes: six_months_freq)
|
||
|
||
navigate_to_unsubscribe
|
||
|
||
source = Nokogiri::HTML5::fragment(response.body)
|
||
expect(source.css(".combobox option[selected='selected']")[0]['value']).to eq(never_frequency.to_s)
|
||
end
|
||
end
|
||
|
||
context 'Unsubscribe from a post' do
|
||
fab!(:post) { Fabricate(:post) }
|
||
let(:user) { post.user }
|
||
let(:key_type) { post }
|
||
|
||
it 'correctly handles watched categories' do
|
||
cu = create_category_user(:watching)
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).to include("unwatch_category")
|
||
|
||
cu.destroy!
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).not_to include("unwatch_category")
|
||
end
|
||
|
||
it 'correctly handles watched first post categories' do
|
||
cu = create_category_user(:watching_first_post)
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).to include("unwatch_category")
|
||
|
||
cu.destroy!
|
||
|
||
navigate_to_unsubscribe
|
||
expect(response.body).not_to include("unwatch_category")
|
||
end
|
||
|
||
def create_category_user(notification_level)
|
||
CategoryUser.create!(
|
||
user_id: user.id,
|
||
category_id: post.topic.category_id,
|
||
notification_level: CategoryUser.notification_levels[notification_level]
|
||
)
|
||
end
|
||
end
|
||
|
||
def navigate_to_unsubscribe(key = unsubscribe_key)
|
||
get "/email/unsubscribe/#{key}"
|
||
end
|
||
end
|
||
end
|