diff --git a/app/controllers/email_controller.rb b/app/controllers/email_controller.rb index 22bbec051..bcc8041b6 100644 --- a/app/controllers/email_controller.rb +++ b/app/controllers/email_controller.rb @@ -1,45 +1,123 @@ class EmailController < ApplicationController - skip_before_filter :check_xhr, :preload_json + skip_before_filter :check_xhr, :preload_json, :redirect_to_login_if_required layout 'no_ember' before_filter :ensure_logged_in, only: :preferences_redirect - skip_before_filter :redirect_to_login_if_required def preferences_redirect redirect_to(email_preferences_path(current_user.username_lower)) end def unsubscribe - @user = DigestUnsubscribeKey.user_for_key(params[:key]) - RateLimiter.new(@user, "unsubscribe_via_email", 3, 1.day).performed! unless @user && @user.staff? + key = UnsubscribeKey.find_by(key: params[:key]) - # Don't allow the use of a key while logged in as a different user - if current_user.present? && (@user != current_user) - @different_user = true - return + if key + @user = key.user + post = key.post + @topic = (post && post.topic) || key.topic + @type = key.unsubscribe_key_type + + if current_user.present? && (@user != current_user) + @different_user = @user.name + @return_url = request.original_url + end + + @watching_topic = @topic && TopicUser.exists?(user_id: @user.id, + notification_level: TopicUser.notification_levels[:watching], + topic_id: @topic.id) + + @watched_count = nil + if @topic && @topic.category_id + if CategoryUser.exists?(user_id: @user.id, + notification_level: CategoryUser.notification_levels[:watching], + category_id: @topic.category_id) + @watched_count = TopicUser.joins(:topic) + .where(:user => @user, + :notification_level => TopicUser.notification_levels[:watching], + "topics.category_id" => @topic.category_id + ).count + end + end end if @user.blank? @not_found = true - return end - - if params[:from_all] - @user.user_option.update_columns(email_always: false, - email_digests: false, - email_direct: false, - email_private_messages: false) - else - @user.user_option.update_column(:email_digests, false) - end - - @success = true end - def resubscribe - @user = DigestUnsubscribeKey.user_for_key(params[:key]) - raise Discourse::NotFound unless @user.present? - @user.user_option.update_column(:email_digests, true) + def perform_unsubscribe + + key = UnsubscribeKey.find_by(key: params[:key]) + unless key && key.user + raise Discourse::NotFound + end + + topic = (key.post && key.post.topic) || key.topic + user = key.user + + updated = false + + 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.notification_levels[:watching] + ) + .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(email_always: false) + updated = true + end + + if params["disable_digest_emails"] + user.user_option.update_columns(email_digests: false) + updated = true + end + + if params["unsubscribe_all"] + user.user_option.update_columns(email_always: false, + email_digests: false, + email_direct: false, + email_private_messages: false) + updated = true + end + + unless updated + redirect_to :back + else + if topic + redirect_to path("/email/unsubscribed?topic_id=#{topic.id}") + else + redirect_to path("/email/unsubscribed") + end + end + + end + + def unsubscribed + @topic = Topic.find_by(id: params[:topic_id].to_i) if params[:topic_id] end end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index e252ec6b3..98d59f386 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -4,7 +4,7 @@ require_dependency 'single_sign_on' class SessionController < ApplicationController skip_before_filter :redirect_to_login_if_required - skip_before_filter :preload_json, :check_xhr, only: ['sso', 'sso_login', 'become', 'sso_provider'] + skip_before_filter :preload_json, :check_xhr, only: ['sso', 'sso_login', 'become', 'sso_provider', 'destroy'] def csrf render json: {csrf: form_authenticity_token } @@ -237,7 +237,11 @@ class SessionController < ApplicationController def destroy reset_session log_off_user - render nothing: true + if request.xhr? + render nothing: true + else + redirect_to (params[:return_url] || path("/")) + end end private diff --git a/app/jobs/scheduled/clean_up_digest_keys.rb b/app/jobs/scheduled/clean_up_digest_keys.rb deleted file mode 100644 index a74eee87e..000000000 --- a/app/jobs/scheduled/clean_up_digest_keys.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Jobs - - class CleanUpDigestKeys < Jobs::Scheduled - every 1.day - - def execute(args) - DigestUnsubscribeKey.where('created_at < ?', 2.months.ago).delete_all - end - - end - -end - diff --git a/app/jobs/scheduled/clean_up_unsubscribe_keys.rb b/app/jobs/scheduled/clean_up_unsubscribe_keys.rb new file mode 100644 index 000000000..053586667 --- /dev/null +++ b/app/jobs/scheduled/clean_up_unsubscribe_keys.rb @@ -0,0 +1,13 @@ +module Jobs + + class CleanUpUnsubscribeKeys < Jobs::Scheduled + every 1.day + + def execute(args) + UnsubscribeKey.where('created_at < ?', 2.months.ago).delete_all + end + + end + +end + diff --git a/app/mailers/subscription_mailer.rb b/app/mailers/subscription_mailer.rb index c36228713..51a66797a 100644 --- a/app/mailers/subscription_mailer.rb +++ b/app/mailers/subscription_mailer.rb @@ -4,11 +4,11 @@ class SubscriptionMailer < ActionMailer::Base include Email::BuildEmailHelper def confirm_unsubscribe(user, opts={}) - unsubscribe_key = DigestUnsubscribeKey.create_key_for(user) + unsubscribe_key = UnsubscribeKey.create_key_for(user, "all") build_email user.email, template: "unsubscribe_mailer", site_title: SiteSetting.title, site_domain_name: Discourse.current_hostname, - confirm_unsubscribe_link: "#{Discourse.base_url}/unsubscribe/#{unsubscribe_key}?from_all=true" + confirm_unsubscribe_link: "#{Discourse.base_url}/unsubscribe/#{unsubscribe_key}" end end diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb index b863955fe..be69a384e 100644 --- a/app/mailers/user_notifications.rb +++ b/app/mailers/user_notifications.rb @@ -382,7 +382,7 @@ class UserNotifications < ActionMailer::Base username: username, add_unsubscribe_link: !user.staged, mailing_list_mode: user.user_option.mailing_list_mode, - unsubscribe_url: post.topic.unsubscribe_url, + unsubscribe_url: post.unsubscribe_url(user), allow_reply_by_email: allow_reply_by_email, only_reply_by_email: allow_reply_by_email && user.staged, use_site_subject: use_site_subject, @@ -416,6 +416,6 @@ class UserNotifications < ActionMailer::Base @header_color = ColorScheme.hex_for_name('header_background') @anchor_color = ColorScheme.hex_for_name('tertiary') @markdown_linker = MarkdownLinker.new(@base_url) - @unsubscribe_key = DigestUnsubscribeKey.create_key_for(@user) + @unsubscribe_key = UnsubscribeKey.create_key_for(@user, "digest") end end diff --git a/app/models/digest_unsubscribe_key.rb b/app/models/digest_unsubscribe_key.rb deleted file mode 100644 index 34ed72fd1..000000000 --- a/app/models/digest_unsubscribe_key.rb +++ /dev/null @@ -1,33 +0,0 @@ -class DigestUnsubscribeKey < ActiveRecord::Base - belongs_to :user - - before_create :generate_random_key - - def self.create_key_for(user) - DigestUnsubscribeKey.create(user_id: user.id).key - end - - def self.user_for_key(key) - where(key: key).first.try(:user) - end - - private - - def generate_random_key - self.key = SecureRandom.hex(32) - end -end - -# == Schema Information -# -# Table name: digest_unsubscribe_keys -# -# key :string(64) not null, primary key -# user_id :integer not null -# created_at :datetime -# updated_at :datetime -# -# Indexes -# -# index_digest_unsubscribe_keys_on_created_at (created_at) -# diff --git a/app/models/post.rb b/app/models/post.rb index 65a1e7fcb..eaa3c7c25 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -385,6 +385,10 @@ class Post < ActiveRecord::Base end end + def unsubscribe_url(user) + "#{Discourse.base_url}/email/unsubscribe/#{UnsubscribeKey.create_key_for(user, self)}" + end + def self.url(slug, topic_id, post_number) "/t/#{slug}/#{topic_id}/#{post_number}" end diff --git a/app/models/unsubscribe_key.rb b/app/models/unsubscribe_key.rb new file mode 100644 index 000000000..c7220cf9e --- /dev/null +++ b/app/models/unsubscribe_key.rb @@ -0,0 +1,41 @@ +class UnsubscribeKey < ActiveRecord::Base + belongs_to :user + belongs_to :post + belongs_to :topic + + 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 + end + end + + def self.user_for_key(key) + where(key: key).first.try(:user) + end + + private + + def generate_random_key + self.key = SecureRandom.hex(32) + end +end + +# == Schema Information +# +# Table name: unsubscribe_keys +# +# key :string(64) not null, primary key +# user_id :integer not null +# created_at :datetime +# updated_at :datetime +# unsubscribe_key_type :string +# topic_id :integer +# +# Indexes +# +# index_unsubscribe_keys_on_created_at (created_at) +# diff --git a/app/views/email/unsubscribe.html.erb b/app/views/email/unsubscribe.html.erb index 488442965..b2df6ad2c 100644 --- a/app/views/email/unsubscribe.html.erb +++ b/app/views/email/unsubscribe.html.erb @@ -1,28 +1,79 @@ -
<%= t :'unsubscribed.description' %>
- -<%= t :'unsubscribed.oops' %>
- - <%= form_tag(email_resubscribe_path(key: params[:key])) do %> - <%= submit_tag t(:'resubscribe.action'), class: 'btn btn-danger' %> - <% end %> + <%if @not_found%> +<%= t "unsubscribe.not_found_description" %>
+ <%- else %> +<%= t("unsubscribe.different_user_description").html_safe %>
+ <%= form_tag(session_path(id: current_user.username_lower), method: :delete) do %> + <%= hidden_field_tag(:return_url, @return_url) %> + <%= submit_tag t('unsubscribe.log_out'), class: 'btn btn-danger' %> + <%- end%> + <%- end %> <%- else %> -<%= t :'unsubscribed.different_user_description' %>
++ +
+ <% else %> ++ +
+ <% end %> + + + <% if @watched_count %> ++ +
+ <% end %> + <% end %> + + <% if @user.user_option.email_always && !SiteSetting.disable_mailing_list_mode %> ++ +
+ <% end %> + + <% if !@topic %> + <% unless SiteSetting.disable_digest_emails %> ++ +
+ <% end %> + <% end %> + ++ +
+ +<%= t :'unsubscribed.not_found_description' %>
- <%- end %> - -<%=raw(t :'unsubscribed.preferences_link') %>
<%- end %> diff --git a/app/views/email/unsubscribed.html.erb b/app/views/email/unsubscribed.html.erb new file mode 100644 index 000000000..9bdcc0d46 --- /dev/null +++ b/app/views/email/unsubscribed.html.erb @@ -0,0 +1,14 @@ ++ <%=t("unsubscribed.description", url: path("/my/prefrences")).html_safe %> +
+ + <% if @topic %> ++ <%=t("unsubscribed.topic_description", link: render_topic_title(@topic)).html_safe%> +
+ <% end %> +