discourse/spec/requests/email_controller_spec.rb
Joshua Rosenfeld 75dc01627d
FEATURE: Mailing list mode default disabled (#11091)
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.
2021-03-04 15:24:37 -05:00

309 lines
10 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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("Dont 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