mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 08:43:25 +08:00
FEATURE: Custom unsubscribe options (#17090)
With this change, plugins can create custom unsubscribe keys, extend the unsubscribe view with custom preferences, and decide how they are updated.
This commit is contained in:
parent
deee3c6f02
commit
e0ba35350e
|
@ -6,38 +6,17 @@ class EmailController < ApplicationController
|
|||
skip_before_action :check_xhr, :preload_json, :redirect_to_login_if_required
|
||||
|
||||
def unsubscribe
|
||||
@not_found = true
|
||||
@watched_count = nil
|
||||
key = UnsubscribeKey.find_by(key: params[:key])
|
||||
@found = key.present?
|
||||
|
||||
if key = UnsubscribeKey.find_by(key: params[:key])
|
||||
if @user = key.user
|
||||
post = key.post
|
||||
@topic = post&.topic || key.topic
|
||||
@digest_unsubscribe = !@topic && !SiteSetting.disable_digest_emails
|
||||
@type = key.unsubscribe_key_type
|
||||
@not_found = false
|
||||
if @found
|
||||
UnsubscribeKey
|
||||
.get_unsubscribe_strategy_for(key)
|
||||
&.prepare_unsubscribe_options(self)
|
||||
|
||||
if current_user.present? && (@user != current_user)
|
||||
@different_user = @user.name
|
||||
@return_url = request.original_url
|
||||
end
|
||||
|
||||
watching = TopicUser.notification_levels[:watching]
|
||||
|
||||
@unsubscribed_from_all = @user.user_option.unsubscribed_from_all?
|
||||
|
||||
if @topic
|
||||
@watching_topic = TopicUser.exists?(user_id: @user.id, notification_level: watching, topic_id: @topic.id)
|
||||
if @topic.category_id
|
||||
if CategoryUser.exists?(user_id: @user.id, notification_level: CategoryUser.watching_levels, category_id: @topic.category_id)
|
||||
@watched_count = TopicUser.joins(:topic)
|
||||
.where(user: @user, notification_level: watching, "topics.category_id" => @topic.category_id)
|
||||
.count
|
||||
end
|
||||
end
|
||||
else
|
||||
@digest_frequencies = digest_frequencies(@user)
|
||||
end
|
||||
if current_user.present? && (@user != current_user)
|
||||
@different_user = @user.name
|
||||
@return_url = request.original_url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -46,80 +25,24 @@ class EmailController < ApplicationController
|
|||
RateLimiter.new(nil, "unsubscribe_#{request.ip}", 10, 1.minute).performed!
|
||||
|
||||
key = UnsubscribeKey.find_by(key: params[:key])
|
||||
raise Discourse::NotFound unless key && key.user
|
||||
|
||||
topic = key&.post&.topic || key.topic
|
||||
raise Discourse::NotFound if key.nil? || key.user.nil?
|
||||
user = key.user
|
||||
updated = UnsubscribeKey.get_unsubscribe_strategy_for(key)
|
||||
&.unsubscribe(params)
|
||||
|
||||
updated = false
|
||||
if updated
|
||||
cache_key = "unsub_#{SecureRandom.hex}"
|
||||
Discourse.cache.write cache_key, user.email, expires_in: 1.hour
|
||||
|
||||
if topic
|
||||
if params["unwatch_topic"]
|
||||
TopicUser.where(topic_id: topic.id, user_id: user.id)
|
||||
.update_all(notification_level: TopicUser.notification_levels[:tracking])
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params["unwatch_category"] && topic.category_id
|
||||
TopicUser.joins(:topic)
|
||||
.where(:user => user,
|
||||
:notification_level => TopicUser.notification_levels[:watching],
|
||||
"topics.category_id" => topic.category_id)
|
||||
.update_all(notification_level: TopicUser.notification_levels[:tracking])
|
||||
|
||||
CategoryUser.where(user_id: user.id,
|
||||
category_id: topic.category_id,
|
||||
notification_level: CategoryUser.watching_levels
|
||||
)
|
||||
.destroy_all
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params["mute_topic"]
|
||||
TopicUser.where(topic_id: topic.id, user_id: user.id)
|
||||
.update_all(notification_level: TopicUser.notification_levels[:muted])
|
||||
updated = true
|
||||
end
|
||||
end
|
||||
|
||||
if params["disable_mailing_list"]
|
||||
user.user_option.update_columns(mailing_list_mode: false)
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params['digest_after_minutes']
|
||||
digest_frequency = params['digest_after_minutes'].to_i
|
||||
|
||||
user.user_option.update_columns(
|
||||
digest_after_minutes: digest_frequency,
|
||||
email_digests: digest_frequency.positive?
|
||||
)
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params["unsubscribe_all"]
|
||||
user.user_option.update_columns(email_digests: false,
|
||||
email_level: UserOption.email_level_types[:never],
|
||||
email_messages_level: UserOption.email_level_types[:never],
|
||||
mailing_list_mode: false)
|
||||
updated = true
|
||||
end
|
||||
|
||||
unless updated
|
||||
redirect_back fallback_location: path("/")
|
||||
else
|
||||
|
||||
key = "unsub_#{SecureRandom.hex}"
|
||||
Discourse.cache.write key, user.email, expires_in: 1.hour
|
||||
|
||||
url = path("/email/unsubscribed?key=#{key}")
|
||||
if topic
|
||||
url += "&topic_id=#{topic.id}"
|
||||
url = path("/email/unsubscribed?key=#{cache_key}")
|
||||
if key.associated_topic
|
||||
url += "&topic_id=#{key.associated_topic.id}"
|
||||
end
|
||||
|
||||
redirect_to url
|
||||
else
|
||||
redirect_back fallback_location: path("/")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def unsubscribed
|
||||
|
@ -130,31 +53,4 @@ class EmailController < ApplicationController
|
|||
topic = Topic.find_by(id: params[:topic_id].to_i) if @topic_id
|
||||
@topic = topic if topic && Guardian.new(nil).can_see?(topic)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def digest_frequencies(user)
|
||||
frequency_in_minutes = user.user_option.digest_after_minutes
|
||||
email_digests = user.user_option.email_digests
|
||||
frequencies = DigestEmailSiteSetting.values.dup
|
||||
never = frequencies.delete_at(0)
|
||||
allowed_frequencies = %w[never weekly every_month every_six_months]
|
||||
|
||||
result = frequencies.reduce(frequencies: [], current: nil, selected: nil, take_next: false) do |memo, v|
|
||||
memo[:current] = v[:name] if v[:value] == frequency_in_minutes && email_digests
|
||||
next(memo) unless allowed_frequencies.include?(v[:name])
|
||||
|
||||
memo.tap do |m|
|
||||
m[:selected] = v[:value] if m[:take_next] && email_digests
|
||||
m[:frequencies] << [I18n.t("unsubscribe.digest_frequency.#{v[:name]}"), v[:value]]
|
||||
m[:take_next] = !m[:take_next] && m[:current]
|
||||
end
|
||||
end
|
||||
|
||||
result.slice(:frequencies, :current, :selected).tap do |r|
|
||||
r[:frequencies] << [I18n.t("unsubscribe.digest_frequency.#{never[:name]}"), never[:value]]
|
||||
r[:selected] ||= never[:value]
|
||||
r[:current] ||= never[:name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class SubscriptionMailer < ActionMailer::Base
|
|||
include Email::BuildEmailHelper
|
||||
|
||||
def confirm_unsubscribe(user, opts = {})
|
||||
unsubscribe_key = UnsubscribeKey.create_key_for(user, "all")
|
||||
unsubscribe_key = UnsubscribeKey.create_key_for(user, UnsubscribeKey::ALL_TYPE)
|
||||
build_email user.email,
|
||||
template: "unsubscribe_mailer",
|
||||
site_title: SiteSetting.title,
|
||||
|
|
|
@ -216,6 +216,8 @@ class UserNotifications < ActionMailer::Base
|
|||
|
||||
def digest(user, opts = {})
|
||||
build_summary_for(user)
|
||||
@unsubscribe_key = UnsubscribeKey.create_key_for(@user, UnsubscribeKey::DIGEST_TYPE)
|
||||
|
||||
min_date = opts[:since] || user.last_emailed_at || user.last_seen_at || 1.month.ago
|
||||
|
||||
# Fetch some topics and posts to show
|
||||
|
@ -753,7 +755,6 @@ class UserNotifications < ActionMailer::Base
|
|||
@header_bgcolor = ColorScheme.hex_for_name('header_background')
|
||||
@anchor_color = ColorScheme.hex_for_name('tertiary')
|
||||
@markdown_linker = MarkdownLinker.new(@base_url)
|
||||
@unsubscribe_key = UnsubscribeKey.create_key_for(@user, "digest")
|
||||
@disable_email_custom_styles = !SiteSetting.apply_custom_styles_to_digest
|
||||
end
|
||||
|
||||
|
|
|
@ -616,7 +616,9 @@ class Post < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def unsubscribe_url(user)
|
||||
"#{Discourse.base_url}/email/unsubscribe/#{UnsubscribeKey.create_key_for(user, self)}"
|
||||
key_value = UnsubscribeKey.create_key_for(user, UnsubscribeKey::TOPIC_TYPE, post: self)
|
||||
|
||||
"#{Discourse.base_url}/email/unsubscribe/#{key_value}"
|
||||
end
|
||||
|
||||
def self.url(slug, topic_id, post_number, opts = nil)
|
||||
|
|
|
@ -7,16 +7,44 @@ class UnsubscribeKey < ActiveRecord::Base
|
|||
|
||||
before_create :generate_random_key
|
||||
|
||||
def self.create_key_for(user, type)
|
||||
if Post === type
|
||||
create(user_id: user.id, unsubscribe_key_type: "topic", topic_id: type.topic_id, post_id: type.id).key
|
||||
else
|
||||
create(user_id: user.id, unsubscribe_key_type: type).key
|
||||
ALL_TYPE = 'all'
|
||||
DIGEST_TYPE = 'digest'
|
||||
TOPIC_TYPE = 'topic'
|
||||
|
||||
class << self
|
||||
def create_key_for(user, type, post: nil)
|
||||
unsubscribe_key = new(user_id: user.id, unsubscribe_key_type: type)
|
||||
|
||||
if type == TOPIC_TYPE
|
||||
unsubscribe_key.topic_id = post.topic_id
|
||||
unsubscribe_key.post_id = post.id
|
||||
end
|
||||
|
||||
unsubscribe_key.save!
|
||||
unsubscribe_key.key
|
||||
end
|
||||
|
||||
def user_for_key(key)
|
||||
where(key: key).first&.user
|
||||
end
|
||||
|
||||
def get_unsubscribe_strategy_for(key)
|
||||
strategies = {
|
||||
DIGEST_TYPE => EmailControllerHelper::DigestEmailUnsubscriber,
|
||||
TOPIC_TYPE => EmailControllerHelper::TopicEmailUnsubscriber,
|
||||
ALL_TYPE => EmailControllerHelper::BaseEmailUnsubscriber
|
||||
}
|
||||
|
||||
DiscoursePluginRegistry.email_unsubscribers.each do |unsubcriber|
|
||||
strategies.merge!(unsubcriber)
|
||||
end
|
||||
|
||||
strategies[key.unsubscribe_key_type]&.new(key)
|
||||
end
|
||||
end
|
||||
|
||||
def self.user_for_key(key)
|
||||
where(key: key).first.try(:user)
|
||||
def associated_topic
|
||||
@associated_topic ||= topic || post&.topic
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class='container unsubscribe'>
|
||||
<%- if @not_found || @different_user %>
|
||||
<%- if !@found || @different_user %>
|
||||
|
||||
<%if @not_found%>
|
||||
<%if !@found %>
|
||||
<p><%= t "unsubscribe.not_found_description" %></p>
|
||||
<%- else %>
|
||||
<p><%= t("unsubscribe.different_user_description").html_safe %></p>
|
||||
|
@ -78,6 +78,8 @@
|
|||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= server_plugin_outlet "unsubscribe_options" %>
|
||||
|
||||
<% unless @unsubscribed_from_all %>
|
||||
<p>
|
||||
<label>
|
||||
|
|
|
@ -95,6 +95,8 @@ class DiscoursePluginRegistry
|
|||
|
||||
define_filtered_register :notification_consolidation_plans
|
||||
|
||||
define_filtered_register :email_unsubscribers
|
||||
|
||||
def self.register_auth_provider(auth_provider)
|
||||
self.auth_providers << auth_provider
|
||||
end
|
||||
|
|
57
lib/email_controller_helper/base_email_unsubscriber.rb
Normal file
57
lib/email_controller_helper/base_email_unsubscriber.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This class and its children are instantiated and used by the EmailController.
|
||||
module EmailControllerHelper
|
||||
class BaseEmailUnsubscriber
|
||||
def initialize(unsubscribe_key)
|
||||
@unsubscribe_key = unsubscribe_key
|
||||
end
|
||||
|
||||
attr_reader :unsubscribe_key
|
||||
|
||||
# Sets instance variables in the `EmailController#unsubscribe`, which are later available in the view.
|
||||
# Don't forget to call super when extending this method.
|
||||
def prepare_unsubscribe_options(controller)
|
||||
controller.instance_variable_set(:@digest_unsubscribe, false)
|
||||
controller.instance_variable_set(:@watched_count, nil)
|
||||
controller.instance_variable_set(:@type, unsubscribe_key.unsubscribe_key_type)
|
||||
|
||||
controller.instance_variable_set(:@user, key_owner)
|
||||
|
||||
controller.instance_variable_set(
|
||||
:@unsubscribed_from_all,
|
||||
key_owner.user_option.unsubscribed_from_all?
|
||||
)
|
||||
end
|
||||
|
||||
# Called by the `EmailController#perform_unsubscribe` and defines what unsubscribing means.
|
||||
#
|
||||
# Receives the request params and returns a boolean indicating if any preferences were updated.
|
||||
#
|
||||
# Don't forget to call super when extending this method.
|
||||
def unsubscribe(params)
|
||||
updated = false
|
||||
|
||||
if params[:disable_mailing_list]
|
||||
key_owner.user_option.update_columns(mailing_list_mode: false)
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params[:unsubscribe_all]
|
||||
key_owner.user_option.update_columns(email_digests: false,
|
||||
email_level: UserOption.email_level_types[:never],
|
||||
email_messages_level: UserOption.email_level_types[:never],
|
||||
mailing_list_mode: false)
|
||||
updated = true
|
||||
end
|
||||
|
||||
updated
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def key_owner
|
||||
unsubscribe_key.user
|
||||
end
|
||||
end
|
||||
end
|
51
lib/email_controller_helper/digest_email_unsubscriber.rb
Normal file
51
lib/email_controller_helper/digest_email_unsubscriber.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module EmailControllerHelper
|
||||
class DigestEmailUnsubscriber < BaseEmailUnsubscriber
|
||||
def prepare_unsubscribe_options(controller)
|
||||
super(controller)
|
||||
controller.instance_variable_set(:@digest_unsubscribe, !SiteSetting.disable_digest_emails)
|
||||
|
||||
frequency_in_minutes = key_owner.user_option.digest_after_minutes
|
||||
email_digests = key_owner.user_option.email_digests
|
||||
frequencies = DigestEmailSiteSetting.values.dup
|
||||
never = frequencies.delete_at(0)
|
||||
allowed_frequencies = %w[never weekly every_month every_six_months]
|
||||
|
||||
result = frequencies.reduce(frequencies: [], current: nil, selected: nil, take_next: false) do |memo, v|
|
||||
memo[:current] = v[:name] if v[:value] == frequency_in_minutes && email_digests
|
||||
next(memo) unless allowed_frequencies.include?(v[:name])
|
||||
|
||||
memo.tap do |m|
|
||||
m[:selected] = v[:value] if m[:take_next] && email_digests
|
||||
m[:frequencies] << [I18n.t("unsubscribe.digest_frequency.#{v[:name]}"), v[:value]]
|
||||
m[:take_next] = !m[:take_next] && m[:current]
|
||||
end
|
||||
end
|
||||
|
||||
digest_frequencies = result.slice(:frequencies, :current, :selected).tap do |r|
|
||||
r[:frequencies] << [I18n.t("unsubscribe.digest_frequency.#{never[:name]}"), never[:value]]
|
||||
r[:selected] ||= never[:value]
|
||||
r[:current] ||= never[:name]
|
||||
end
|
||||
|
||||
controller.instance_variable_set(:@digest_frequencies, digest_frequencies)
|
||||
end
|
||||
|
||||
def unsubscribe(params)
|
||||
updated = super(params)
|
||||
|
||||
if params[:digest_after_minutes]
|
||||
digest_frequency = params[:digest_after_minutes].to_i
|
||||
|
||||
unsubscribe_key.user.user_option.update_columns(
|
||||
digest_after_minutes: digest_frequency,
|
||||
email_digests: digest_frequency.positive?
|
||||
)
|
||||
updated = true
|
||||
end
|
||||
|
||||
updated
|
||||
end
|
||||
end
|
||||
end
|
62
lib/email_controller_helper/topic_email_unsubscriber.rb
Normal file
62
lib/email_controller_helper/topic_email_unsubscriber.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module EmailControllerHelper
|
||||
class TopicEmailUnsubscriber < BaseEmailUnsubscriber
|
||||
def prepare_unsubscribe_options(controller)
|
||||
super(controller)
|
||||
watching = TopicUser.notification_levels[:watching]
|
||||
|
||||
topic = unsubscribe_key.associated_topic
|
||||
|
||||
controller.instance_variable_set(:@topic, topic)
|
||||
controller.instance_variable_set(
|
||||
:@watching_topic,
|
||||
TopicUser.exists?(user: key_owner, notification_level: watching, topic_id: topic.id)
|
||||
)
|
||||
|
||||
return if topic.category_id.blank?
|
||||
return if !CategoryUser.exists?(user: key_owner, notification_level: CategoryUser.watching_levels, category_id: topic.category_id)
|
||||
|
||||
controller.instance_variable_set(
|
||||
:@watched_count,
|
||||
TopicUser.joins(:topic)
|
||||
.where(user: key_owner, notification_level: watching).where(topics: { category_id: topic.category_id }).count
|
||||
)
|
||||
end
|
||||
|
||||
def unsubscribe(params)
|
||||
updated = super(params)
|
||||
|
||||
topic = unsubscribe_key.associated_topic
|
||||
return updated if topic.nil?
|
||||
|
||||
if params[:unwatch_topic]
|
||||
TopicUser.where(topic_id: topic.id, user_id: key_owner.id)
|
||||
.update_all(notification_level: TopicUser.notification_levels[:tracking])
|
||||
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params[:unwatch_category] && topic.category_id
|
||||
TopicUser.joins(:topic)
|
||||
.where(user: key_owner, notification_level: TopicUser.notification_levels[:watching])
|
||||
.where(topics: { category_id: topic.category_id })
|
||||
.update_all(notification_level: TopicUser.notification_levels[:tracking])
|
||||
|
||||
CategoryUser
|
||||
.where(user_id: key_owner.id, category_id: topic.category_id, notification_level: CategoryUser.watching_levels)
|
||||
.destroy_all
|
||||
|
||||
updated = true
|
||||
end
|
||||
|
||||
if params[:mute_topic]
|
||||
TopicUser.where(topic_id: topic.id, user_id: key_owner.id).update_all(notification_level: TopicUser.notification_levels[:muted])
|
||||
|
||||
updated = true
|
||||
end
|
||||
|
||||
updated
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1018,6 +1018,29 @@ class Plugin::Instance
|
|||
StaticController::CUSTOM_PAGES[page] = blk ? { topic_id: blk } : options
|
||||
end
|
||||
|
||||
# Let plugin define custom unsubscribe keys,
|
||||
# set custom instance variables on the `EmailController#unsubscribe` action,
|
||||
# and describe what unsubscribing for that key does.
|
||||
#
|
||||
# The method receives a class that inherits from `Email::BaseEmailUnsubscriber`.
|
||||
# Take a look at it to know how to implement your child class.
|
||||
#
|
||||
# In conjunction with this, you'll have to:
|
||||
#
|
||||
# - Register a new connector under app/views/connectors/unsubscribe_options.
|
||||
# We'll include the HTML inside the unsubscribe form, so you can add your fields using the
|
||||
# instance variables you set in the controller previously. When the form is submitted,
|
||||
# it sends the updated preferences to `EmailController#perform_unsubscribe`.
|
||||
#
|
||||
# - Your code is responsible for creating the custom key by calling `UnsubscribeKey#create_key_for`.
|
||||
def register_email_unsubscriber(type, unsubscriber)
|
||||
core_types = [UnsubscribeKey::ALL_TYPE, UnsubscribeKey::DIGEST_TYPE, UnsubscribeKey::TOPIC_TYPE]
|
||||
raise ArgumentError.new('Type already exists') if core_types.include?(type)
|
||||
raise ArgumentError.new('Not an email unsubscriber') if !unsubscriber.ancestors.include?(EmailControllerHelper::BaseEmailUnsubscriber)
|
||||
|
||||
DiscoursePluginRegistry.register_email_unsubscriber({ type => unsubscriber }, self)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.js_path
|
||||
|
|
|
@ -720,4 +720,26 @@ describe Plugin::Instance do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#register_email_unsubscriber' do
|
||||
let(:plugin) { Plugin::Instance.new }
|
||||
|
||||
after do
|
||||
DiscoursePluginRegistry.reset_register!(:email_unsubscribers)
|
||||
end
|
||||
|
||||
it "doesn't let you override core unsubscribers" do
|
||||
expect { plugin.register_email_unsubscriber(UnsubscribeKey::ALL_TYPE, Object) }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "finds the plugin's custom unsubscriber" do
|
||||
new_unsubscriber_type = 'new_type'
|
||||
key = UnsubscribeKey.new(unsubscribe_key_type: new_unsubscriber_type)
|
||||
CustomUnsubscriber = Class.new(EmailControllerHelper::BaseEmailUnsubscriber)
|
||||
|
||||
plugin.register_email_unsubscriber(new_unsubscriber_type, CustomUnsubscriber)
|
||||
|
||||
expect(UnsubscribeKey.get_unsubscribe_strategy_for(key).class).to eq(CustomUnsubscriber)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ describe UnsubscribeKey do
|
|||
describe 'key' do
|
||||
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
let!(:key) { UnsubscribeKey.create_key_for(user, "digest") }
|
||||
let!(:key) { UnsubscribeKey.create_key_for(user, UnsubscribeKey::DIGEST_TYPE) }
|
||||
|
||||
it 'has a temporary key' do
|
||||
expect(key).to be_present
|
||||
|
|
|
@ -1,142 +1,121 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe EmailController do
|
||||
describe EmailController do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||||
|
||||
context '.perform unsubscribe' do
|
||||
describe '#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") }
|
||||
describe 'unsubscribe from all emails' do
|
||||
let(:key) { UnsubscribeKey.create_key_for(user, UnsubscribeKey::ALL_TYPE) }
|
||||
|
||||
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)
|
||||
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" }
|
||||
post "/email/unsubscribe/#{key}.json", params: { unsubscribe_all: "1" }
|
||||
|
||||
expect(response.status).to eq(302)
|
||||
expect(response.status).to eq(302)
|
||||
|
||||
get response.redirect_url
|
||||
get response.redirect_url
|
||||
|
||||
# cause it worked ... yay
|
||||
expect(body).to include(user.email)
|
||||
# cause it worked ... yay
|
||||
expect(body).to include(user.email)
|
||||
|
||||
user.user_option.reload
|
||||
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)
|
||||
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)
|
||||
expect(user.user_option.reload.mailing_list_mode).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'can disable mailing list' do
|
||||
user.user_option.update_columns(mailing_list_mode: true)
|
||||
describe 'unsubscribe from digest' do
|
||||
let(:key) { UnsubscribeKey.create_key_for(user, UnsubscribeKey::DIGEST_TYPE) }
|
||||
|
||||
post "/email/unsubscribe/#{key}.json",
|
||||
params: { disable_mailing_list: "1" }
|
||||
it 'Can change digest frequency' do
|
||||
weekly_interval_minutes = 10080
|
||||
user.user_option.update_columns(email_digests: true, digest_after_minutes: 0)
|
||||
|
||||
expect(response.status).to eq(302)
|
||||
post "/email/unsubscribe/#{key}.json",
|
||||
params: { digest_after_minutes: weekly_interval_minutes.to_s }
|
||||
|
||||
user.user_option.reload
|
||||
expect(response.status).to eq(302)
|
||||
expect(user.user_option.reload.digest_after_minutes).to eq(weekly_interval_minutes)
|
||||
end
|
||||
|
||||
expect(user.user_option.mailing_list_mode).to eq(false)
|
||||
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
|
||||
end
|
||||
|
||||
it 'Can change digest frequency' do
|
||||
weekly_interval_minutes = 10080
|
||||
user.user_option.update_columns(email_digests: true, digest_after_minutes: 0)
|
||||
describe 'unsubscribe from a topic' do
|
||||
fab!(:a_post) { Fabricate(:post) }
|
||||
let(:key) { UnsubscribeKey.create_key_for(user, UnsubscribeKey::TOPIC_TYPE, post: a_post) }
|
||||
|
||||
post "/email/unsubscribe/#{key}.json",
|
||||
params: { digest_after_minutes: weekly_interval_minutes.to_s }
|
||||
it 'can unwatch topic' do
|
||||
TopicUser.change(user.id, a_post.topic_id, notification_level: TopicUser.notification_levels[:watching])
|
||||
|
||||
expect(response.status).to eq(302)
|
||||
post "/email/unsubscribe/#{key}.json", params: { unwatch_topic: "1" }
|
||||
|
||||
user.user_option.reload
|
||||
expect(response.status).to eq(302)
|
||||
expect(TopicUser.get(a_post.topic, user).notification_level).to eq(TopicUser.notification_levels[:tracking])
|
||||
end
|
||||
|
||||
expect(user.user_option.digest_after_minutes).to eq(weekly_interval_minutes)
|
||||
end
|
||||
it 'can mute topic' do
|
||||
TopicUser.change(user.id, a_post.topic_id, notification_level: TopicUser.notification_levels[:watching])
|
||||
|
||||
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: { mute_topic: "1" }
|
||||
|
||||
post "/email/unsubscribe/#{key}.json",
|
||||
params: { digest_after_minutes: '0' }
|
||||
expect(response.status).to eq(302)
|
||||
expect(TopicUser.get(a_post.topic, user).notification_level).to eq(TopicUser.notification_levels[:muted])
|
||||
end
|
||||
|
||||
expect(response.status).to eq(302)
|
||||
it 'can unwatch category' do
|
||||
cu = CategoryUser.create!(user_id: user.id,
|
||||
category_id: a_post.topic.category_id,
|
||||
notification_level: CategoryUser.notification_levels[:watching])
|
||||
|
||||
user.user_option.reload
|
||||
post "/email/unsubscribe/#{key}.json", params: { unwatch_category: "1" }
|
||||
|
||||
expect(user.user_option.digest_after_minutes).to be_zero
|
||||
expect(user.user_option.email_digests).to eq(false)
|
||||
end
|
||||
expect(response.status).to eq(302)
|
||||
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
|
||||
end
|
||||
|
||||
it 'can unwatch topic' do
|
||||
p = Fabricate(:post)
|
||||
key = UnsubscribeKey.create_key_for(p.user, p)
|
||||
it 'can unwatch first post from category' do
|
||||
cu = CategoryUser.create!(user_id: user.id,
|
||||
category_id: a_post.topic.category_id,
|
||||
notification_level: CategoryUser.notification_levels[:watching_first_post])
|
||||
|
||||
TopicUser.change(p.user_id, p.topic_id, notification_level: TopicUser.notification_levels[:watching])
|
||||
post "/email/unsubscribe/#{key}.json", params: { unwatch_category: "1" }
|
||||
|
||||
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)
|
||||
expect(response.status).to eq(302)
|
||||
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,6 +128,8 @@ RSpec.describe EmailController do
|
|||
end
|
||||
|
||||
describe 'when topic is public' do
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
|
||||
it 'should return the right response' do
|
||||
key = SecureRandom.hex
|
||||
Discourse.cache.write(key, user.email)
|
||||
|
@ -159,6 +140,8 @@ RSpec.describe EmailController do
|
|||
end
|
||||
|
||||
describe 'when topic is private' do
|
||||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||||
|
||||
it 'should return the right response' do
|
||||
key = SecureRandom.hex
|
||||
Discourse.cache.write(key, user.email)
|
||||
|
@ -177,10 +160,11 @@ RSpec.describe EmailController do
|
|||
end
|
||||
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
let(:unsubscribe_key) { UnsubscribeKey.create_key_for(user, key_type) }
|
||||
let(:unsubscribe_key) { UnsubscribeKey.create_key_for(user, key_type, post: post) }
|
||||
|
||||
context 'Unsubscribe from digest' do
|
||||
let(:key_type) { 'digest' }
|
||||
let(:key_type) { UnsubscribeKey::DIGEST_TYPE }
|
||||
let(:post) { nil }
|
||||
|
||||
it 'displays log out button if wrong user logged in' do
|
||||
sign_in(Fabricate(:admin))
|
||||
|
@ -264,7 +248,7 @@ RSpec.describe EmailController do
|
|||
context 'Unsubscribe from a post' do
|
||||
fab!(:post) { Fabricate(:post) }
|
||||
let(:user) { post.user }
|
||||
let(:key_type) { post }
|
||||
let(:key_type) { UnsubscribeKey::TOPIC_TYPE }
|
||||
|
||||
it 'correctly handles watched categories' do
|
||||
cu = create_category_user(:watching)
|
||||
|
|
|
@ -646,9 +646,9 @@ describe UserMerger do
|
|||
end
|
||||
|
||||
it "updates unsubscribe keys" do
|
||||
UnsubscribeKey.create_key_for(source_user, "digest")
|
||||
UnsubscribeKey.create_key_for(target_user, "digest")
|
||||
UnsubscribeKey.create_key_for(walter, "digest")
|
||||
UnsubscribeKey.create_key_for(source_user, UnsubscribeKey::DIGEST_TYPE)
|
||||
UnsubscribeKey.create_key_for(target_user, UnsubscribeKey::DIGEST_TYPE)
|
||||
UnsubscribeKey.create_key_for(walter, UnsubscribeKey::DIGEST_TYPE)
|
||||
|
||||
merge_users!
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user