diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index c694909cb..7e8f63da5 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -119,8 +119,7 @@ class TopicsController < ApplicationController raise Discourse::InvalidParameters.new(:auto_close_days) unless params.has_key?(:auto_close_days) @topic = Topic.where(id: params[:topic_id].to_i).first guardian.ensure_can_moderate!(@topic) - @topic.auto_close_days = params[:auto_close_days] - @topic.auto_close_user = current_user + @topic.set_auto_close(params[:auto_close_days], current_user) @topic.save render nothing: true end diff --git a/app/models/topic.rb b/app/models/topic.rb index a7bcc1558..1d632527a 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -107,8 +107,7 @@ class Topic < ActiveRecord::Base self.bumped_at ||= Time.now self.last_post_user_id ||= user_id if !@ignore_category_auto_close and self.category and self.category.auto_close_days and self.auto_close_at.nil? - self.auto_close_at = self.category.auto_close_days.days.from_now - self.auto_close_user = (self.user.staff? ? self.user : Discourse.system_user) + set_auto_close(self.category.auto_close_days) end end @@ -124,6 +123,7 @@ class Topic < ActiveRecord::Base before_save do if (auto_close_at_changed? and !auto_close_at_was.nil?) or (auto_close_user_id_changed? and auto_close_at) + self.auto_close_started_at ||= Time.zone.now Jobs.cancel_scheduled_job(:close_topic, {topic_id: id}) true end @@ -583,8 +583,23 @@ class Topic < ActiveRecord::Base def auto_close_days=(num_days) @ignore_category_auto_close = true + set_auto_close(num_days) + end + + def set_auto_close(num_days, by_user=nil) num_days = num_days.to_i self.auto_close_at = (num_days > 0 ? num_days.days.from_now : nil) + if num_days > 0 + self.auto_close_started_at ||= Time.zone.now + if by_user and by_user.staff? + self.auto_close_user = by_user + else + self.auto_close_user ||= (self.user.staff? ? self.user : Discourse.system_user) + end + else + self.auto_close_started_at = nil + end + self end def secure_category? @@ -641,6 +656,7 @@ end # slug :string(255) # auto_close_at :datetime # auto_close_user_id :integer +# auto_close_started_at :datetime # # Indexes # diff --git a/app/models/topic_status_update.rb b/app/models/topic_status_update.rb index d4925b4d0..d425b877e 100644 --- a/app/models/topic_status_update.rb +++ b/app/models/topic_status_update.rb @@ -25,7 +25,12 @@ TopicStatusUpdate = Struct.new(:topic, :user) do end def message_for(status) - I18n.t status.locale_key, count: topic.age_in_days + if status.autoclosed? + num_days = topic.auto_close_started_at ? ((Time.zone.now - topic.auto_close_started_at) / 1.day).round : topic.age_in_days + I18n.t status.locale_key, count: num_days + else + I18n.t status.locale_key + end end def options_for(status) diff --git a/db/migrate/20130606190601_add_auto_close_started_at_to_topics.rb b/db/migrate/20130606190601_add_auto_close_started_at_to_topics.rb new file mode 100644 index 000000000..76692e344 --- /dev/null +++ b/db/migrate/20130606190601_add_auto_close_started_at_to_topics.rb @@ -0,0 +1,5 @@ +class AddAutoCloseStartedAtToTopics < ActiveRecord::Migration + def change + add_column :topics, :auto_close_started_at, :datetime + end +end diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb index 6beae2019..59447e69d 100644 --- a/spec/controllers/topics_controller_spec.rb +++ b/spec/controllers/topics_controller_spec.rb @@ -612,17 +612,12 @@ describe TopicsController do end it "can set a topic's auto close time" do - Topic.any_instance.expects(:auto_close_days=).with { |arg| arg.to_i == 3 } + Topic.any_instance.expects(:set_auto_close).with("3", @admin) xhr :put, :autoclose, topic_id: @topic.id, auto_close_days: 3 end it "can remove a topic's auto close time" do - Topic.any_instance.expects(:auto_close_days=).with(nil) - xhr :put, :autoclose, topic_id: @topic.id, auto_close_days: nil - end - - it "sets the topic closer to the current user" do - Topic.any_instance.expects(:auto_close_user=).with(@admin) + Topic.any_instance.expects(:set_auto_close).with(nil, anything) xhr :put, :autoclose, topic_id: @topic.id, auto_close_days: nil end end diff --git a/spec/integration/topic_auto_close_spec.rb b/spec/integration/topic_auto_close_spec.rb index 97670f841..7adab420b 100644 --- a/spec/integration/topic_auto_close_spec.rb +++ b/spec/integration/topic_auto_close_spec.rb @@ -52,6 +52,7 @@ describe Topic do context 'category has a default auto-close' do Given(:category) { Fabricate(:category, auto_close_days: 2.0) } Then { topic.auto_close_at.should == 2.days.from_now } + And { topic.auto_close_started_at.should == Time.zone.now } And { scheduled_jobs_for(:close_topic, {topic_id: topic.id}).should have(1).job } And { scheduled_jobs_for(:close_topic, {topic_id: category.topic.id}).should be_empty } diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index f22d7a98e..e344465fa 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -657,15 +657,25 @@ describe Topic do let(:status) { 'autoclosed' } it_should_behave_like 'a status that closes a topic' - it 'puts the autoclose duration in the moderator post' do - @topic.created_at = 3.days.ago - @topic.update_status(status, true, @user) + context 'topic was set to close when it was created' do + it 'puts the autoclose duration in the moderator post' do + @topic.created_at = 3.days.ago + @topic.update_status(status, true, @user) + expect(@topic.posts.last.raw).to include "closed after 3 days" + end + end - expect(@topic.posts.last.raw).to include "closed after 3 days" + context 'topic was set to close after it was created' do + it 'puts the autoclose duration in the moderator post' do + @topic.created_at = 7.days.ago + Timecop.freeze(2.days.ago) do + @topic.set_auto_close(2) + end + @topic.update_status(status, true, @user) + expect(@topic.posts.last.raw).to include "closed after 2 days" + end end end - - end describe 'toggle_star' do @@ -1027,7 +1037,7 @@ describe Topic do it 'queues a job to close the topic' do Timecop.freeze(Time.zone.now) do Jobs.expects(:enqueue_at).with(7.days.from_now, :close_topic, all_of( has_key(:topic_id), has_key(:user_id) )) - Fabricate(:topic, auto_close_at: 7.days.from_now, user: Fabricate(:admin)) + Fabricate(:topic, auto_close_days: 7, user: Fabricate(:admin)) end end @@ -1036,7 +1046,7 @@ describe Topic do Jobs.expects(:enqueue_at).with do |datetime, job_name, job_args| job_args[:user_id] == topic_creator.id end - Fabricate(:topic, auto_close_at: 7.days.from_now, user: topic_creator) + Fabricate(:topic, auto_close_days: 7, user: topic_creator) end it 'when auto_close_user_id is set, it will use it as the topic closer' do @@ -1045,13 +1055,20 @@ describe Topic do Jobs.expects(:enqueue_at).with do |datetime, job_name, job_args| job_args[:user_id] == topic_closer.id end - Fabricate(:topic, auto_close_at: 7.days.from_now, auto_close_user: topic_closer, user: topic_creator) + Fabricate(:topic, auto_close_days: 7, auto_close_user: topic_closer, user: topic_creator) end it "ignores the category's default auto-close" do Timecop.freeze(Time.zone.now) do Jobs.expects(:enqueue_at).with(7.days.from_now, :close_topic, all_of( has_key(:topic_id), has_key(:user_id) )) - Fabricate(:topic, auto_close_at: 7.days.from_now, user: Fabricate(:admin), category: Fabricate(:category, auto_close_days: 2)) + Fabricate(:topic, auto_close_days: 7, user: Fabricate(:admin), category: Fabricate(:category, auto_close_days: 2)) + end + end + + it 'sets the time when auto_close timer starts' do + Timecop.freeze(Time.zone.now) do + topic = Fabricate(:topic, auto_close_days: 7, user: Fabricate(:admin)) + expect(topic.auto_close_started_at).to eq(Time.zone.now) end end end @@ -1142,6 +1159,65 @@ describe Topic do end end + describe 'set_auto_close' do + let(:topic) { Fabricate.build(:topic) } + let(:closing_topic) { Fabricate.build(:topic, auto_close_days: 5) } + let(:admin) { Fabricate.build(:user, id: 123) } + + before { Discourse.stubs(:system_user).returns(admin) } + + it 'sets auto_close_at' do + Timecop.freeze(Time.zone.now) do + topic.set_auto_close(3, admin) + expect(topic.auto_close_at).to eq(3.days.from_now) + end + end + + it 'sets auto_close_user to given user if it is a staff user' do + topic.set_auto_close(3, admin) + expect(topic.auto_close_user_id).to eq(admin.id) + end + + it 'sets auto_close_user to system user if given user is not staff' do + topic.set_auto_close(3, Fabricate.build(:user, id: 444)) + expect(topic.auto_close_user_id).to eq(admin.id) + end + + it 'sets auto_close_user to system_user if user is not given and topic creator is not staff' do + topic.set_auto_close(3) + expect(topic.auto_close_user_id).to eq(admin.id) + end + + it 'sets auto_close_user to topic creator if it is a staff user' do + staff_topic = Fabricate.build(:topic, user: Fabricate.build(:admin, id: 999)) + staff_topic.set_auto_close(3) + expect(staff_topic.auto_close_user_id).to eq(999) + end + + it 'clears auto_close_at if num_days is nil' do + closing_topic.set_auto_close(nil) + expect(closing_topic.auto_close_at).to be_nil + end + + it 'clears auto_close_started_at if num_days is nil' do + closing_topic.set_auto_close(nil) + expect(closing_topic.auto_close_started_at).to be_nil + end + + it 'updates auto_close_at if it was already set to close' do + Timecop.freeze(Time.zone.now) do + closing_topic.set_auto_close(14) + expect(closing_topic.auto_close_at).to eq(14.days.from_now) + end + end + + it 'does not update auto_close_started_at if it was already set to close' do + expect{ + closing_topic.set_auto_close(14) + }.to_not change(closing_topic, :auto_close_started_at) + end + end + describe '#secure_category?' do let(:category){ Category.new }