diff --git a/app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee b/app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee index 5435dc742f4..1c8264a2d2b 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee +++ b/app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee @@ -26,9 +26,20 @@ Discourse.PreferencesController = Ember.ObjectController.extend Discourse.Presen freqs.addObject(name: Em.String.i18n('user.auto_track_options.after_n_minutes', count: 1), value: 60000) freqs.addObject(name: Em.String.i18n('user.auto_track_options.after_n_minutes', count: 2), value: 120000) freqs.addObject(name: Em.String.i18n('user.auto_track_options.after_n_minutes', count: 5), value: 300000) + freqs.addObject(name: Em.String.i18n('user.auto_track_options.after_n_minutes', count: 10), value: 600000) freqs ).property() + considerNewTopicOptions: (-> + opts = Em.A() + opts.addObject(name: Em.String.i18n('user.new_topic_duration.not_viewed'), value: -1) # always + opts.addObject(name: Em.String.i18n('user.new_topic_duration.after_n_days', count: 1), value: 60 * 24) + opts.addObject(name: Em.String.i18n('user.new_topic_duration.after_n_days', count: 2), value: 60 * 48) + opts.addObject(name: Em.String.i18n('user.new_topic_duration.after_n_weeks', count: 1), value: 7 * 60 * 24) + opts.addObject(name: Em.String.i18n('user.new_topic_duration.last_here'), value: -2) # last visit + opts + ).property() + save: -> @set('saving', true) diff --git a/app/assets/javascripts/discourse/models/user.js.coffee b/app/assets/javascripts/discourse/models/user.js.coffee index 33e1e6390b7..49b17a876ab 100644 --- a/app/assets/javascripts/discourse/models/user.js.coffee +++ b/app/assets/javascripts/discourse/models/user.js.coffee @@ -41,7 +41,16 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence, save: (finished) -> jQuery.ajax "/users/" + @get('username').toLowerCase(), - data: @getProperties('auto_track_topics_after_msecs','bio_raw', 'website', 'name', 'email_digests', 'email_direct', 'email_private_messages', 'digest_after_days') + data: @getProperties('auto_track_topics_after_msecs', + 'bio_raw', + 'website', + 'name', + 'email_digests', + 'email_direct', + 'email_private_messages', + 'digest_after_days', + 'new_topic_duration_minutes' + ) type: 'PUT' success: => finished(true) error: => finished(false) diff --git a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars index ab97892edfc..f4373f98b3e 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/preferences.js.handlebars @@ -90,12 +90,17 @@ -
+
{{view Discourse.ComboboxView valueAttribute="value" contentBinding="controller.autoTrackDurations" valueBinding="content.auto_track_topics_after_msecs"}}
+ +
+ + {{view Discourse.ComboboxView valueAttribute="value" contentBinding="controller.considerNewTopicOptions" valueBinding="content.new_topic_duration_minutes"}} +
diff --git a/app/assets/stylesheets/application/user.css.scss b/app/assets/stylesheets/application/user.css.scss index a5e06e3a14d..adf60b25904 100644 --- a/app/assets/stylesheets/application/user.css.scss +++ b/app/assets/stylesheets/application/user.css.scss @@ -31,6 +31,13 @@ color: $white; width: 520px; } + + .other .controls { + margin-top: 10px; + select { + width: 280px; + } + } } #user-menu { diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 649a9c758e0..d49d6ee7096 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -34,6 +34,7 @@ class UsersController < ApplicationController u.website = website || u.website u.digest_after_days = params[:digest_after_days] || u.digest_after_days u.auto_track_topics_after_msecs = params[:auto_track_topics_after_msecs].to_i if params[:auto_track_topics_after_msecs] + u.new_topic_duration_minutes = params[:new_topic_duration_minutes].to_i if params[:new_topic_duration_minutes] [:email_digests, :email_direct, :email_private_messages].each do |i| if params[i].present? diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index e7f9ce208b1..4affb9f5da1 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -33,7 +33,8 @@ class SiteSetting < ActiveRecord::Base client_setting(:email_domains_blacklist, 'mailinator.com') # settings only available server side - setting(:auto_track_topics_after, 60000) + setting(:auto_track_topics_after, 300000) + setting(:new_topic_duration_minutes, 60 * 48) setting(:long_polling_interval, 15000) setting(:flags_required_to_hide_post, 3) setting(:cooldown_minutes_after_hiding_posts, 10) diff --git a/app/models/user.rb b/app/models/user.rb index 2be9c8d0715..50279fc020c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,5 @@ require_dependency 'email_token' require_dependency 'trust_level' -require_dependency 'sql_builder' class User < ActiveRecord::Base @@ -46,6 +45,11 @@ class User < ActiveRecord::Base # This is just used to pass some information into the serializer attr_accessor :notification_channel_position + module NewTopicDuration + ALWAYS = -1 + LAST_VISIT = -2 + end + def self.username_length 3..15 end @@ -416,6 +420,17 @@ class User < ActiveRecord::Base email_tokens.where(email: self.email, confirmed: true).present? or email_tokens.count == 0 end + def treat_as_new_topic_start_date + duration = new_topic_duration_minutes || SiteSetting.new_topic_duration_minutes + case duration + when User::NewTopicDuration::ALWAYS + created_at + when User::NewTopicDuration::LAST_VISIT + previous_visit_at || created_at + else + duration.minutes.ago + end + end protected diff --git a/app/serializers/basic_topic_serializer.rb b/app/serializers/basic_topic_serializer.rb index 13a073c4f48..e99d45ff0b5 100644 --- a/app/serializers/basic_topic_serializer.rb +++ b/app/serializers/basic_topic_serializer.rb @@ -18,14 +18,7 @@ class BasicTopicSerializer < ApplicationSerializer return false if scope.blank? return false if scope.user.blank? return false if object.user_data.present? - return false if object.created_at < scope.user.created_at - - # Only mark things as new since your last visit - if scope.user.previous_visit_at.present? - return false if object.created_at < scope.user.previous_visit_at - end - - + return false if object.created_at < scope.user.treat_as_new_topic_start_date true end diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f503f18a407..1b5ca50710f 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -43,11 +43,16 @@ class UserSerializer < BasicUserSerializer :email_private_messages, :email_direct, :digest_after_days, - :auto_track_topics_after_msecs + :auto_track_topics_after_msecs, + :new_topic_duration_minutes def auto_track_topics_after_msecs object.auto_track_topics_after_msecs || SiteSetting.auto_track_topics_after end + + def new_topic_duration_minutes + object.new_topic_duration_minutes || SiteSetting.new_topic_duration_minutes + end def can_send_private_message_to_user scope.can_send_private_message?(object) diff --git a/config/locales/en.yml b/config/locales/en.yml index c12c68b8625..d86a9767ec0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -243,6 +243,7 @@ en: anon_polling_interval: "How often should the anon clients poll in milliseconds" auto_track_topics_after: "How many milliseconds before a topic is automatically tracked (0 for always, -1 for never)" + new_topic_duration_minutes: "How many minutes is a topic considered new (-1 for always, -2 for last visit)" flags_required_to_hide_post: "Posts will be automatically hidden once the flag count reaches this threshold (0 for never)" cooldown_minutes_after_hiding_posts: "How many minutes must a user wait till they can edit their post after it is hidden due to flagging" @@ -536,6 +537,18 @@ en: email_private_messages: "Receive an email when someone sends you a private message" other_settings: "Other" + + new_topic_duration: + label: "Consider topics new when" + not_viewed: "I haven't viewed them yet" + last_here: "they were posted since I was here last" + after_n_days: + one: "they were posted in the last day" + other: "they were posted in the last {{count}} days" + after_n_weeks: + one: "they were posted in the last week" + other: "they were posted in the last {{count}} week" + auto_track_topics: "Automatically track topics I enter" auto_track_options: never: "never" diff --git a/db/migrate/20130213203300_add_new_topic_duration_minutes_to_users.rb b/db/migrate/20130213203300_add_new_topic_duration_minutes_to_users.rb new file mode 100644 index 00000000000..ed721502061 --- /dev/null +++ b/db/migrate/20130213203300_add_new_topic_duration_minutes_to_users.rb @@ -0,0 +1,8 @@ +class AddNewTopicDurationMinutesToUsers < ActiveRecord::Migration + def change + # note, no constants allowed here, -1 means since last visit + # -2 means always + # larger than 0 is an hour time span + add_column :users, :new_topic_duration_minutes, :integer + end +end diff --git a/db/structure.sql b/db/structure.sql index 0e011b5447f..d83aa74de3c 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1178,7 +1178,8 @@ CREATE TABLE users ( flag_level integer DEFAULT 0 NOT NULL, time_read integer DEFAULT 0 NOT NULL, days_visited integer DEFAULT 0 NOT NULL, - ip_address inet + ip_address inet, + new_topic_duration_minutes integer ); @@ -2537,4 +2538,6 @@ INSERT INTO schema_migrations (version) VALUES ('20130207200019'); INSERT INTO schema_migrations (version) VALUES ('20130208220635'); -INSERT INTO schema_migrations (version) VALUES ('20130213021450'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20130213021450'); + +INSERT INTO schema_migrations (version) VALUES ('20130213203300'); \ No newline at end of file diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 591607907a0..c57d1614fc4 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -128,12 +128,10 @@ class TopicQuery end def new_results(list_opts={}) - date = @user.previous_visit_at - date = @user.created_at unless date default_list(list_opts) .joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{@user_id})") - .where("topics.created_at >= :created_at", created_at: date) + .where("topics.created_at >= :created_at", created_at: @user.treat_as_new_topic_start_date) .where("tu.last_read_post_number IS NULL") .where("COALESCE(tu.notification_level, :tracking) >= :tracking", tracking: TopicUser::NotificationLevel::TRACKING) end diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index be06ed50527..7ae4ce930d6 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -155,6 +155,14 @@ describe TopicQuery do topics.should == [new_topic] end + it "contains no new topics for a user that has missed the window" do + user.new_topic_duration_minutes = 5 + user.save + new_topic.created_at = 10.minutes.ago + new_topic.save + topics.should == [] + end + context "muted topics" do before do new_topic.notify_muted!(user)