diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js index a33d6bca01c..0a651c01aba 100644 --- a/app/assets/javascripts/discourse/models/user.js +++ b/app/assets/javascripts/discourse/models/user.js @@ -178,7 +178,7 @@ Discourse.User = Discourse.Model.extend({ 'digest_after_days', 'new_topic_duration_minutes', 'external_links_in_new_tab', - 'watch_new_topics', + 'mailing_list_mode', 'enable_quoting'); _.each(['muted','watched','tracked'], function(s){ diff --git a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars index 0d0f723bd74..d2547025795 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars @@ -83,6 +83,13 @@
+ {{#if Discourse.SiteSettings.enable_mailing_list_mode}} + + {{/if}} + @@ -116,15 +123,6 @@ {{combobox valueAttribute="value" content=considerNewTopicOptions value=new_topic_duration_minutes}}
- {{#if Discourse.SiteSettings.enable_watch_new_topics}} -
- -
- {{/if}} -
diff --git a/app/jobs/regular/notify_mailing_list_subscribers.rb b/app/jobs/regular/notify_mailing_list_subscribers.rb new file mode 100644 index 00000000000..31ac2d5e85d --- /dev/null +++ b/app/jobs/regular/notify_mailing_list_subscribers.rb @@ -0,0 +1,37 @@ +module Jobs + + class NotifyMailingListSubscribers < Jobs::Base + + def execute(args) + post_id = args[:post_id] + post = Post.find(post_id) if post_id + + raise Discourse::InvalidParameters.new(:post_id) unless post + + User.not_suspended + .not_blocked + .real + .where(mailing_list_mode: true) + .where('NOT EXISTS( + SELECT 1 + FROM topic_users tu + WHERE + tu.topic_id = ? AND + tu.user_id = users.id AND + tu.notification_level = ? + )', post.topic_id, TopicUser.notification_levels[:muted]) + .where('NOT EXISTS( + SELECT 1 + FROM category_users cu + WHERE + cu.category_id = ? AND + cu.user_id = users.id AND + cu.notification_level = ? + )', post.topic.category_id, CategoryUser.notification_levels[:muted]) + .each do |user| + UserNotifications.mailing_list_notify(user, post).deliver + end + + end + end +end diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb index f2d5cd661bc..bea3c7e45be 100644 --- a/app/mailers/user_notifications.rb +++ b/app/mailers/user_notifications.rb @@ -93,6 +93,17 @@ class UserNotifications < ActionMailer::Base notification_email(user, opts) end + def mailing_list_notify(user, post) + send_notification_email( + title: post.topic.title, + post: post, + from_alias: post.user.username, + allow_reply_by_email: true, + notification_type: "posted", + user: user + ) + end + protected def email_post_markdown(post) @@ -130,9 +141,34 @@ class UserNotifications < ActionMailer::Base username = @notification.data_hash[:original_username] notification_type = opts[:notification_type] || Notification.types[@notification.notification_type].to_s + return if SiteSetting.enable_mailing_list_mode && + ["replied", "mentioned", "quoted", "posted"].include?(notification_type) + + title = @notification.data_hash[:topic_title] + allow_reply_by_email = opts[:allow_reply_by_email] + + send_notification_email( + title: title, + post: @post, + from_alias: username, + allow_reply_by_email: allow_reply_by_email, + notification_type: notification_type, + user: user + ) + + end + + def send_notification_email(opts) + post = opts[:post] + title = opts[:title] + allow_reply_by_email = opts[:allow_reply_by_email] + from_alias = opts[:from_alias] + notification_type = opts[:notification_type] + user = opts[:user] + context = "" - tu = TopicUser.get(@post.topic_id, user) - context_posts = self.class.get_context_posts(@post, tu) + tu = TopicUser.get(post.topic_id, user) + context_posts = self.class.get_context_posts(post, tu) # make .present? cheaper context_posts = context_posts.to_a @@ -147,37 +183,36 @@ class UserNotifications < ActionMailer::Base html = UserNotificationRenderer.new(Rails.configuration.paths["app/views"]).render( template: 'email/notification', format: :html, - locals: { context_posts: context_posts, post: @post } + locals: { context_posts: context_posts, post: post } ) template = "user_notifications.user_#{notification_type}" - if @post.topic.private_message? + if post.topic.private_message? template << "_pm" end email_opts = { - topic_title: @notification.data_hash[:topic_title], - message: email_post_markdown(@post), - url: @post.url, - post_id: @post.id, - topic_id: @post.topic_id, + topic_title: title, + message: email_post_markdown(post), + url: post.url, + post_id: post.id, + topic_id: post.topic_id, context: context, - username: username, + username: from_alias, add_unsubscribe_link: true, - allow_reply_by_email: opts[:allow_reply_by_email], + allow_reply_by_email: allow_reply_by_email, template: template, html_override: html, style: :notification } # If we have a display name, change the from address - if username.present? - email_opts[:from_alias] = username + if from_alias.present? + email_opts[:from_alias] = from_alias end - TopicUser.change(user.id, @post.topic_id, last_emailed_post_number: @post.post_number) + TopicUser.change(user.id, post.topic_id, last_emailed_post_number: post.post_number) build_email(user.email, email_opts) end - end diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index b69216b800a..ba64e223874 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -72,23 +72,6 @@ class TopicUser < ActiveRecord::Base TopicUser.where('topic_id = ? and user_id = ?', topic, user).first end - def auto_watch_new_topic(topic_id) - # Can not afford to slow down creation of topics when a pile of users are watching new topics, reverting to SQL for max perf here - sql = < { where(blocked: true) } # no index + scope :not_blocked, -> { where(blocked: false) } # no index scope :suspended, -> { where('suspended_till IS NOT NULL AND suspended_till > ?', Time.zone.now) } # no index scope :not_suspended, -> { where('suspended_till IS NULL') } # excluding fake users like the community user diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f7f30c17c88..411e306a0ab 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -51,7 +51,7 @@ class UserSerializer < BasicUserSerializer :email_direct, :email_always, :digest_after_days, - :watch_new_topics, + :mailing_list_mode, :auto_track_topics_after_msecs, :new_topic_duration_minutes, :external_links_in_new_tab, diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 40801d664d1..ade9dd64c72 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -14,7 +14,7 @@ class UserUpdater :external_links_in_new_tab, :enable_quoting, :dynamic_favicon, - :watch_new_topics + :mailing_list_mode ] def initialize(actor, user) diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index 4423b7ec7ed..11cb97bce33 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -229,7 +229,6 @@ da: deleted: "(slettet)" suspended_notice: "Denne bruger er suspenderet indtil {{date}}." suspended_reason: "Begrundelse: " - watch_new_topics: "Overvåg automatisk alle nye emner i forummet" watched_categories: "Overvåget" watched_categories_instructions: "Du overvåger automatisk alle emner i disse kategorier" tracked_categories: "Fulgt" diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 363e378e8a5..c0292426331 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -230,7 +230,6 @@ de: deleted: "(gelöscht)" suspended_notice: "Diser Benutzer ist bis zum {{date}} susperndiert." suspended_reason: "Grund: " - watch_new_topics: "Automatische alle neuen Themen dieses Forums beobachten" watched_categories: "Beobachten" watched_categories_instructions: "Das selbe wie 'verfolgen', zusätzlich wirst du über alle neuen Beiträge und Themen informiert." tracked_categories: "Verfolgen" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index d8bccf977eb..08928b2b44f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -231,7 +231,7 @@ en: deleted: "(deleted)" suspended_notice: "This user is suspended until {{date}}." suspended_reason: "Reason: " - watch_new_topics: "Automatically watch all new topics posted on the forum" + mailing_list_mode: "Automatically recieve an email every time a post is made on the forum (unless you have the topic or category muted)" watched_categories: "Watched" watched_categories_instructions: "Same as Tracking, plus you will be notified of all new posts and topics." tracked_categories: "Tracked" diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index c5a009596a5..f0ee7401337 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -229,7 +229,6 @@ fr: deleted: "(supprimé)" suspended_notice: "L'utilisateur est suspendu jusqu'au {{date}}." suspended_reason: "Raison :" - watch_new_topics: "Surveiller automatiquement toutes les nouvelles discussions postées sur le forum" watched_categories: "Surveillées" watched_categories_instructions: "Vous allez surveiller automatiquement toutes les discussions de ces catégories" tracked_categories: "Suivies" diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 513689274d1..1e4c084479b 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -233,7 +233,6 @@ nl: deleted: (verwijderd) suspended_notice: "Deze gebruiker is geschorst tot {{date}}." suspended_reason: "Reden: " - watch_new_topics: "Houd alle nieuwe topics in het forum automatisch in de gaten" watched_categories: "In de gaten gehouden" watched_categories_instructions: "Zelfde als volgen, daarnaast zou je een notificatie ontvangen voor alle nieuwe berichten en topics" tracked_categories: "Gevolgd" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index 0cc6afcf0ec..44fb33e9be2 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -229,7 +229,6 @@ zh_CN: deleted: "(已删除)" suspended_notice: "该用户将被禁止登录,直至{{date}}." suspended_reason: "原因:" - watch_new_topics: "自动关注论坛中所有新发表的主题" watched_categories: "已关注" watched_categories_instructions: "和跟踪相同,此外你还将收到新的帖子和主题的通知。" tracked_categories: "已跟踪" diff --git a/config/locales/server.da.yml b/config/locales/server.da.yml index 600f8a6e004..7ccd13d0155 100644 --- a/config/locales/server.da.yml +++ b/config/locales/server.da.yml @@ -749,7 +749,6 @@ da: pop3s_polling_host: "Host til polling af POP3S-konto." pop3s_polling_username: "Brugernavn til polling af POP3S-konto." pop3s_polling_password: "Adgangskode til polling af POP3S-konto." - enable_watch_new_topics: "Lad brugerne overvåge alle nye emner (valgfrit) via en brugerindstilling" minimum_topics_similar: "Hvor emner der skal eksistere i databasen før der vises tilsvarende emner." diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 363d3de9d45..ca4d099f09a 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -761,7 +761,7 @@ en: pop3s_polling_host: "The host to poll for email via POP3S" pop3s_polling_username: "The username for the POP3S account to poll for email" pop3s_polling_password: "The password for the POP3S account to poll for email" - enable_watch_new_topics: "Allow users to watch all new topics (optionally) via a user preference" + enable_mailing_list_mode: "Allow users to (optionally) opt-in to mailing list mode via a user preference" minimum_topics_similar: "How many topics need to exist in the database before similar topics are presented." diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index 5ae5b133239..cda482b48d1 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -663,7 +663,6 @@ fr: pop3s_polling_host: "L'hôte utilisé pour le polling pour l'email via POP3S" pop3s_polling_username: "Le nom d'utilisateur pour le polling POPS3 par email" pop3s_polling_password: "Le mot de passe pour le polling POPS3 par email" - enable_watch_new_topics: "Autoriser les utilisateurs à suivre toutes les nouvelles discussions (optionnellement) via une préférence de l'utilisateur" minimum_topics_similar: "Combien de topics ont besoin d'exister dans la base de données avant que des topics similaires soit présentés." relative_date_duration: "Nombre de jours après la création d'un message à partir desquels les dates seront affichées en absolu plutôt qu'en relatif. Exemple: relatif : 7j, absolut : 20 Fév" delete_user_max_age: "L'age maximum d'un utilisateur, en jours, qui permet à un administrateur de le supprimer." diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 4508dec7a76..3308a42b4e0 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -753,7 +753,6 @@ nl: pop3s_polling_host: "De host voor POP3S" pop3s_polling_username: "De username voor het POP3S e-mailaccount" pop3s_polling_password: "Het wachtwoord voor het POP3S e-mailaccount" - enable_watch_new_topics: "Sta toe dat gebruikers alle nieuwe topics in de gaten houden (optioneel) via hun gebruikersinstellingen" minimum_topics_similar: "Hoeveel topics moeten er in de database staan voordat er vergelijkbare topics getoond worden?" diff --git a/config/site_settings.yml b/config/site_settings.yml index 5b43ab241ec..ebe34472984 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -232,7 +232,7 @@ email: pop3s_polling_port: 995 pop3s_polling_username: '' pop3s_polling_password: '' - enable_watch_new_topics: + enable_mailing_list_mode: default: false client: true diff --git a/db/migrate/20140206215029_add_mailing_list_mode_to_users.rb b/db/migrate/20140206215029_add_mailing_list_mode_to_users.rb new file mode 100644 index 00000000000..c4de0991fda --- /dev/null +++ b/db/migrate/20140206215029_add_mailing_list_mode_to_users.rb @@ -0,0 +1,5 @@ +class AddMailingListModeToUsers < ActiveRecord::Migration + def change + rename_column :users, :watch_new_topics, :mailing_list_mode + end +end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index fd57cd80c82..46f5ecce994 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -135,8 +135,17 @@ class PostCreator end def after_post_create - if !@topic.private_message? && @post.post_number > 1 && @post.post_type != Post.types[:moderator_action] - TopicTrackingState.publish_unread(@post) + if !@topic.private_message? && @post.post_type != Post.types[:moderator_action] + if @post.post_number > 1 + TopicTrackingState.publish_unread(@post) + end + if SiteSetting.enable_mailing_list_mode + Jobs.enqueue_in( + SiteSetting.email_time_window_mins.minutes, + :notify_mailing_list_subscribers, + post_id: @post.id + ) + end end end diff --git a/lib/topic_creator.rb b/lib/topic_creator.rb index 37a497446b2..62202f4c6a9 100644 --- a/lib/topic_creator.rb +++ b/lib/topic_creator.rb @@ -39,7 +39,6 @@ class TopicCreator @topic.notifier.watch_topic!(id, nil) end - TopicUser.auto_watch_new_topic(@topic.id) CategoryUser.auto_watch_new_topic(@topic) end diff --git a/spec/models/topic_user_spec.rb b/spec/models/topic_user_spec.rb index cccaf2acd9b..4e11d9c3b2f 100644 --- a/spec/models/topic_user_spec.rb +++ b/spec/models/topic_user_spec.rb @@ -268,21 +268,28 @@ describe TopicUser do tu.seen_post_count.should == 2 end - describe "auto_watch_new_topic" do + describe "mailing_list_mode" do + + it "will receive email notification for every topic" do + SiteSetting.stubs(:enable_mailing_list_mode).returns(true) - it "auto watches topics when called" do user1 = Fabricate(:user) - user2 = Fabricate(:user, watch_new_topics: true) - user3 = Fabricate(:user, watch_new_topics: true) - TopicUser.auto_watch_new_topic(topic.id) + user2 = Fabricate(:user, mailing_list_mode: true) + post = create_post + user3 = Fabricate(:user, mailing_list_mode: true) + create_post(topic_id: post.topic_id) - TopicUser.get(topic, user1).should == nil + # mails posts from earlier topics + tu = TopicUser.where(user_id: user3.id, topic_id: post.topic_id).first + tu.last_emailed_post_number.should == 2 - tu = TopicUser.get(topic, user2) - tu.notification_level.should == TopicUser.notification_levels[:watching] - tu.notifications_reason_id.should == TopicUser.notification_reasons[:auto_watch] + # mails nothing to random users + tu = TopicUser.where(user_id: user1.id, topic_id: post.topic_id).first + tu.should be_nil - TopicUser.get(topic, user3).notification_level.should == TopicUser.notification_levels[:watching] + # mails other user + tu = TopicUser.where(user_id: user2.id, topic_id: post.topic_id).first + tu.last_emailed_post_number.should == 2 end end