diff --git a/app/controllers/email_controller.rb b/app/controllers/email_controller.rb
index b4aebf910cc..de0c1cc2413 100644
--- a/app/controllers/email_controller.rb
+++ b/app/controllers/email_controller.rb
@@ -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
diff --git a/app/mailers/subscription_mailer.rb b/app/mailers/subscription_mailer.rb
index a8c4234f6bd..c2c40752c84 100644
--- a/app/mailers/subscription_mailer.rb
+++ b/app/mailers/subscription_mailer.rb
@@ -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,
diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb
index d3bc5e0bb45..0c36b6aeea8 100644
--- a/app/mailers/user_notifications.rb
+++ b/app/mailers/user_notifications.rb
@@ -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
diff --git a/app/models/post.rb b/app/models/post.rb
index 5cfccffe554..185fd941f56 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -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)
diff --git a/app/models/unsubscribe_key.rb b/app/models/unsubscribe_key.rb
index 308d2d5205f..da81fdfb33c 100644
--- a/app/models/unsubscribe_key.rb
+++ b/app/models/unsubscribe_key.rb
@@ -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
diff --git a/app/views/email/unsubscribe.html.erb b/app/views/email/unsubscribe.html.erb
index 6351b5ef999..522b27d59a1 100644
--- a/app/views/email/unsubscribe.html.erb
+++ b/app/views/email/unsubscribe.html.erb
@@ -1,7 +1,7 @@
- <%- if @not_found || @different_user %>
+ <%- if !@found || @different_user %>
- <%if @not_found%>
+ <%if !@found %>
<%= t "unsubscribe.not_found_description" %>
<%- else %>
<%= t("unsubscribe.different_user_description").html_safe %>
@@ -78,6 +78,8 @@
<% end %>
+ <%= server_plugin_outlet "unsubscribe_options" %>
+
<% unless @unsubscribed_from_all %>