From 6f1c31d777b5b8817baa29e396cc3c0d646e54fa Mon Sep 17 00:00:00 2001 From: cpradio Date: Fri, 30 Sep 2016 12:36:43 -0400 Subject: [PATCH] Add notification level user preference when replying to a topic --- .../discourse/controllers/preferences.js.es6 | 5 +++ .../javascripts/discourse/models/user.js.es6 | 1 + .../discourse/templates/user/preferences.hbs | 5 +++ ...cation_level_when_replying_site_setting.rb | 26 ++++++++++++ app/models/topic_user.rb | 10 ++--- app/models/user_option.rb | 42 ++++++++++--------- app/serializers/user_option_serializer.rb | 5 +++ app/services/user_updater.rb | 1 + config/locales/client.en.yml | 2 + config/locales/server.en.yml | 1 + config/site_settings.yml | 3 ++ ...30_add_notification_level_when_replying.rb | 5 +++ lib/post_creator.rb | 6 ++- spec/components/post_creator_spec.rb | 36 ++++++++++++++++ spec/models/user_spec.rb | 2 + spec/serializers/user_serializer_spec.rb | 2 + spec/services/user_updater_spec.rb | 2 + 17 files changed, 127 insertions(+), 27 deletions(-) create mode 100644 app/models/notification_level_when_replying_site_setting.rb create mode 100644 db/migrate/20160930123330_add_notification_level_when_replying.rb diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index 98e0b05f7ce..e2d49339f31 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -3,6 +3,7 @@ import CanCheckEmails from 'discourse/mixins/can-check-emails'; import { popupAjaxError } from 'discourse/lib/ajax-error'; import computed from "ember-addons/ember-computed-decorators"; import { cook } from 'discourse/lib/text'; +import { NotificationLevels } from 'discourse/lib/notification-levels'; export default Ember.Controller.extend(CanCheckEmails, { @@ -115,6 +116,10 @@ export default Ember.Controller.extend(CanCheckEmails, { { name: I18n.t('user.auto_track_options.after_5_minutes'), value: 300000 }, { name: I18n.t('user.auto_track_options.after_10_minutes'), value: 600000 }], + notificationLevelsForReplying: [{ name: I18n.t('topic.notifications.watching.title'), value: NotificationLevels.WATCHING }, + { name: I18n.t('topic.notifications.tracking.title'), value: NotificationLevels.TRACKING }], + + considerNewTopicOptions: [{ name: I18n.t('user.new_topic_duration.not_viewed'), value: -1 }, { name: I18n.t('user.new_topic_duration.after_1_day'), value: 60 * 24 }, { name: I18n.t('user.new_topic_duration.after_2_days'), value: 60 * 48 }, diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index a8ba8682fae..3644f7f5e96 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -222,6 +222,7 @@ const User = RestModel.extend({ 'digest_after_minutes', 'new_topic_duration_minutes', 'auto_track_topics_after_msecs', + 'notification_level_when_replying', 'like_notification_frequency', 'include_tl0_in_digests' ].forEach(s => { diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index 96c061cfb31..7fc1666d906 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -234,6 +234,11 @@ {{combo-box valueAttribute="value" content=autoTrackDurations value=model.user_option.auto_track_topics_after_msecs}} +
+ + {{combo-box valueAttribute="value" content=notificationLevelsForReplying value=model.user_option.notification_level_when_replying}} +
+
{{combo-box valueAttribute="value" content=likeNotificationFrequencies value=model.user_option.like_notification_frequency}} diff --git a/app/models/notification_level_when_replying_site_setting.rb b/app/models/notification_level_when_replying_site_setting.rb new file mode 100644 index 00000000000..66b07cb5453 --- /dev/null +++ b/app/models/notification_level_when_replying_site_setting.rb @@ -0,0 +1,26 @@ +require_dependency 'enum_site_setting' +require_dependency 'notification_levels' + +class NotificationLevelWhenReplyingSiteSetting < EnumSiteSetting + + def self.valid_value?(val) + val.to_i.to_s == val.to_s && + values.any? { |v| v[:value] == val.to_i } + end + + def self.notification_levels + NotificationLevels.topic_levels + end + + def self.values + @values ||= [ + { name: 'topic.notifications.watching.title', value: notification_levels[:watching] }, + { name: 'topic.notifications.tracking.title', value: notification_levels[:tracking] } + ] + end + + def self.translate_names? + true + end + +end diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index c07907e8162..9738083ba7a 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -37,24 +37,24 @@ class TopicUser < ActiveRecord::Base auto_track_tag: 12) end - def auto_track(user_id, topic_id, reason) + def auto_notification(user_id, topic_id, reason, notification_level) if TopicUser.where(user_id: user_id, topic_id: topic_id, notifications_reason_id: nil).exists? change(user_id, topic_id, - notification_level: notification_levels[:tracking], + notification_level: notification_level, notifications_reason_id: reason ) MessageBus.publish("/topic/#{topic_id}", { - notification_level_change: notification_levels[:tracking], + notification_level_change: notification_level, notifications_reason_id: reason }, user_ids: [user_id]) end end - def auto_watch(user_id, topic_id) + def auto_notification_for_staging(user_id, topic_id, reason) topic_user = TopicUser.find_or_initialize_by(user_id: user_id, topic_id: topic_id) topic_user.notification_level = notification_levels[:watching] - topic_user.notifications_reason_id = notification_reasons[:auto_watch] + topic_user.notifications_reason_id = reason topic_user.save end diff --git a/app/models/user_option.rb b/app/models/user_option.rb index 7e13a4d8f85..1071026c183 100644 --- a/app/models/user_option.rb +++ b/app/models/user_option.rb @@ -38,6 +38,7 @@ class UserOption < ActiveRecord::Base self.new_topic_duration_minutes = SiteSetting.default_other_new_topic_duration_minutes self.auto_track_topics_after_msecs = SiteSetting.default_other_auto_track_topics_after_msecs + self.notification_level_when_replying = SiteSetting.default_other_notification_level_when_replying self.like_notification_frequency = SiteSetting.default_other_like_notification_frequency @@ -129,26 +130,27 @@ end # # Table name: user_options # -# user_id :integer not null, primary key -# email_always :boolean default(FALSE), not null -# mailing_list_mode :boolean default(FALSE), not null -# email_digests :boolean -# email_direct :boolean default(TRUE), not null -# email_private_messages :boolean default(TRUE), not null -# external_links_in_new_tab :boolean default(FALSE), not null -# enable_quoting :boolean default(TRUE), not null -# dynamic_favicon :boolean default(FALSE), not null -# disable_jump_reply :boolean default(FALSE), not null -# automatically_unpin_topics :boolean default(TRUE), not null -# digest_after_minutes :integer -# auto_track_topics_after_msecs :integer -# new_topic_duration_minutes :integer -# last_redirected_to_top_at :datetime -# email_previous_replies :integer default(2), not null -# email_in_reply_to :boolean default(TRUE), not null -# like_notification_frequency :integer default(1), not null -# include_tl0_in_digests :boolean default(FALSE) -# mailing_list_mode_frequency :integer default(0), not null +# user_id :integer not null, primary key +# email_always :boolean default(FALSE), not null +# mailing_list_mode :boolean default(FALSE), not null +# email_digests :boolean +# email_direct :boolean default(TRUE), not null +# email_private_messages :boolean default(TRUE), not null +# external_links_in_new_tab :boolean default(FALSE), not null +# enable_quoting :boolean default(TRUE), not null +# dynamic_favicon :boolean default(FALSE), not null +# disable_jump_reply :boolean default(FALSE), not null +# automatically_unpin_topics :boolean default(TRUE), not null +# digest_after_minutes :integer +# auto_track_topics_after_msecs :integer +# notification_level_when_replying :integer +# new_topic_duration_minutes :integer +# last_redirected_to_top_at :datetime +# email_previous_replies :integer default(2), not null +# email_in_reply_to :boolean default(TRUE), not null +# like_notification_frequency :integer default(1), not null +# include_tl0_in_digests :boolean default(FALSE) +# mailing_list_mode_frequency :integer default(0), not null # # Indexes # diff --git a/app/serializers/user_option_serializer.rb b/app/serializers/user_option_serializer.rb index 7d7dedfa8ae..33cc3f4cc8a 100644 --- a/app/serializers/user_option_serializer.rb +++ b/app/serializers/user_option_serializer.rb @@ -13,6 +13,7 @@ class UserOptionSerializer < ApplicationSerializer :digest_after_minutes, :automatically_unpin_topics, :auto_track_topics_after_msecs, + :notification_level_when_replying, :new_topic_duration_minutes, :email_previous_replies, :email_in_reply_to, @@ -24,6 +25,10 @@ class UserOptionSerializer < ApplicationSerializer object.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs end + def notification_level_when_replying + object.notification_level_when_replying || SiteSetting.default_other_notification_level_when_replying + end + def new_topic_duration_minutes object.new_topic_duration_minutes || SiteSetting.default_other_new_topic_duration_minutes end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index ad25b23fa3e..44d217e3bd1 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -29,6 +29,7 @@ class UserUpdater :digest_after_minutes, :new_topic_duration_minutes, :auto_track_topics_after_msecs, + :notification_level_when_replying, :email_previous_replies, :email_in_reply_to, :like_notification_frequency, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index d7d843602b3..9395c5ac4bd 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -739,6 +739,8 @@ en: after_5_minutes: "after 5 minutes" after_10_minutes: "after 10 minutes" + notification_level_when_replying: "When I post in a topic, set that topic to" + invited: search: "type to search invites..." title: "Invites" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 649f99fe9af..61988898c10 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1373,6 +1373,7 @@ en: default_other_new_topic_duration_minutes: "Global default condition for which a topic is considered new." default_other_auto_track_topics_after_msecs: "Global default time before a topic is automatically tracked." + default_other_notification_level_when_replying: "Global default notification level when the user replies to a topic." default_other_external_links_in_new_tab: "Open external links in a new tab by default." default_other_enable_quoting: "Enable quote reply for highlighted text by default." default_other_dynamic_favicon: "Show new/updated topic count on browser icon by default." diff --git a/config/site_settings.yml b/config/site_settings.yml index 3a80594f62b..e44994e8b15 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1247,6 +1247,9 @@ user_preferences: default_other_auto_track_topics_after_msecs: enum: 'AutoTrackDurationSiteSetting' default: 240000 + default_other_notification_level_when_replying: + enum: 'NotificationLevelWhenReplyingSiteSetting' + default: 2 default_other_external_links_in_new_tab: false default_other_enable_quoting: true default_other_dynamic_favicon: false diff --git a/db/migrate/20160930123330_add_notification_level_when_replying.rb b/db/migrate/20160930123330_add_notification_level_when_replying.rb new file mode 100644 index 00000000000..0d3a9f6a5a3 --- /dev/null +++ b/db/migrate/20160930123330_add_notification_level_when_replying.rb @@ -0,0 +1,5 @@ +class AddNotificationLevelWhenReplying < ActiveRecord::Migration + def change + add_column :user_options, :notification_level_when_replying, :integer + end +end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index b03af3d8683..0cd26aa33d9 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -452,9 +452,11 @@ class PostCreator end if @user.staged - TopicUser.auto_watch(@user.id, @topic.id) + TopicUser.auto_notification_for_staging(@user.id, @topic.id, TopicUser.notification_reasons[:auto_watch]) + elsif @user.user_option.notification_level_when_replying === NotificationLevels.topic_levels[:watching] + TopicUser.auto_notification(@user.id, @topic.id, TopicUser.notification_reasons[:created_post], NotificationLevels.topic_levels[:watching]) else - TopicUser.auto_track(@user.id, @topic.id, TopicUser.notification_reasons[:created_post]) + TopicUser.auto_notification(@user.id, @topic.id, TopicUser.notification_reasons[:created_post], NotificationLevels.topic_levels[:tracking]) end end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 54efd31cc9b..ab1bd548663 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -798,6 +798,42 @@ describe PostCreator do end end + context "topic tracking" do + it "automatically watches topic based on preference" do + user.user_option.notification_level_when_replying = 3 + + admin = Fabricate(:admin) + topic = PostCreator.create(admin, + title: "this is the title of a topic created by an admin for watching notification", + raw: "this is the content of a topic created by an admin for keeping a watching notification state on a topic ;)" + ) + + post = PostCreator.create(user, + topic_id: topic.topic_id, + raw: "this is a reply to set the tracking state to watching ;)" + ) + topic_user = TopicUser.find_by(user_id: user.id, topic_id: post.topic_id) + expect(topic_user.notification_level).to eq(TopicUser.notification_levels[:watching]) + end + + it "topic notification level remains tracking based on preference" do + user.user_option.notification_level_when_replying = 2 + + admin = Fabricate(:admin) + topic = PostCreator.create(admin, + title: "this is the title of a topic created by an admin for tracking notification", + raw: "this is the content of a topic created by an admin for keeping a tracking notification state on a topic ;)" + ) + + post = PostCreator.create(user, + topic_id: topic.topic_id, + raw: "this is a reply to set the tracking state to tracking ;)" + ) + topic_user = TopicUser.find_by(user_id: user.id, topic_id: post.topic_id) + expect(topic_user.notification_level).to eq(TopicUser.notification_levels[:tracking]) + end + end + describe '#create!' do it "should return the post if it was successfully created" do title = "This is a valid title" diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2552c11f496..f0bea747de3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1246,6 +1246,7 @@ describe User do SiteSetting.default_other_new_topic_duration_minutes = -1 # not viewed SiteSetting.default_other_auto_track_topics_after_msecs = 0 # immediately + SiteSetting.default_other_notification_level_when_replying = 3 # immediately SiteSetting.default_other_external_links_in_new_tab = true SiteSetting.default_other_enable_quoting = false SiteSetting.default_other_dynamic_favicon = true @@ -1273,6 +1274,7 @@ describe User do expect(options.email_direct).to eq(false) expect(options.new_topic_duration_minutes).to eq(-1) expect(options.auto_track_topics_after_msecs).to eq(0) + expect(options.notification_level_when_replying).to eq(3) expect(CategoryUser.lookup(user, :watching).pluck(:category_id)).to eq([1]) expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to eq([2]) diff --git a/spec/serializers/user_serializer_spec.rb b/spec/serializers/user_serializer_spec.rb index 09213ea23fb..52613f9d501 100644 --- a/spec/serializers/user_serializer_spec.rb +++ b/spec/serializers/user_serializer_spec.rb @@ -19,6 +19,7 @@ describe UserSerializer do it "serializes options correctly" do # so we serialize more stuff SiteSetting.default_other_auto_track_topics_after_msecs = 0 + SiteSetting.default_other_notification_level_when_replying = 3 SiteSetting.default_other_new_topic_duration_minutes = 60*24 user = Fabricate.build(:user, @@ -32,6 +33,7 @@ describe UserSerializer do expect(json[:user_option][:dynamic_favicon]).to eq(true) expect(json[:user_option][:new_topic_duration_minutes]).to eq(60*24) expect(json[:user_option][:auto_track_topics_after_msecs]).to eq(0) + expect(json[:user_option][:notification_level_when_replying]).to eq(3) end end diff --git a/spec/services/user_updater_spec.rb b/spec/services/user_updater_spec.rb index 7a7de4234b1..a9a69ef6d7d 100644 --- a/spec/services/user_updater_spec.rb +++ b/spec/services/user_updater_spec.rb @@ -71,6 +71,7 @@ describe UserUpdater do digest_after_minutes: "45", new_topic_duration_minutes: 100, auto_track_topics_after_msecs: 101, + notification_level_when_replying: 3, email_in_reply_to: false ) expect(val).to be_truthy @@ -83,6 +84,7 @@ describe UserUpdater do expect(user.user_option.digest_after_minutes).to eq 45 expect(user.user_option.new_topic_duration_minutes).to eq 100 expect(user.user_option.auto_track_topics_after_msecs).to eq 101 + expect(user.user_option.notification_level_when_replying).to eq 3 expect(user.user_option.email_in_reply_to).to eq false end