diff --git a/app/assets/javascripts/discourse/views/auto_close_form_view.js b/app/assets/javascripts/discourse/views/auto_close_form_view.js
deleted file mode 100644
index 8bfc25f73..000000000
--- a/app/assets/javascripts/discourse/views/auto_close_form_view.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- This view renders the form to set or change a topic or category's auto-close setting.
-
- @class AutoCloseFormView
- @extends Ember.View
- @namespace Discourse
- @module Discourse
- **/
-Discourse.AutoCloseFormView = Ember.View.extend({
- templateName: 'auto_close_form',
-
- label: function() {
- return I18n.t( this.get('labelKey') || 'composer.auto_close_label' );
- }.property('labelKey'),
-
- autoCloseChanged: function() {
- if( this.get('autoCloseDays') && this.get('autoCloseDays').length > 0 ) {
- this.set('autoCloseDays', this.get('autoCloseDays').replace(/[^\d]/g, '') );
- }
- }.observes('autoCloseDays')
-});
-
-Discourse.View.registerHelper('autoCloseForm', Discourse.AutoCloseFormView);
diff --git a/app/assets/stylesheets/desktop/compose.scss b/app/assets/stylesheets/desktop/compose.scss
index d395f21c5..e4d7ae085 100644
--- a/app/assets/stylesheets/desktop/compose.scss
+++ b/app/assets/stylesheets/desktop/compose.scss
@@ -334,8 +334,12 @@
display: block;
bottom: 8px;
}
+ .auto-close-fields .examples {
+ margin-top: 0;
+ padding-bottom: 8px;
+ }
}
- .title-input, .category-input {
+ .title-input, .category-input, .show-admin-options {
position: relative;
display: inline;
}
@@ -523,7 +527,11 @@ div.ac-wrap {
.auto-close-fields {
input {
- width: 50px;
+ width: 150px;
+ }
+ .examples {
+ margin: 12px 0 0 17px;
+ color: $dark_gray;
}
}
@@ -543,7 +551,7 @@ div.ac-wrap {
}
#reply-control button.btn.no-text {
- margin: 7px 0 0 5px;
- position: absolute;
+ margin: 7px 0 0 5px; // works in safari, but not chrome and firefox
+ position: relative;
}
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 070e022c5..2a0f35291 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -225,7 +225,7 @@ class PostsController < ApplicationController
:category,
:target_usernames,
:reply_to_post_number,
- :auto_close_days,
+ :auto_close_time,
:auto_track
]
diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb
index c2b2daff4..58c32a75d 100644
--- a/app/controllers/topics_controller.rb
+++ b/app/controllers/topics_controller.rb
@@ -153,12 +153,15 @@ class TopicsController < ApplicationController
end
def autoclose
- 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.set_auto_close(params[:auto_close_days], current_user)
- @topic.save
- render nothing: true
+ raise Discourse::InvalidParameters.new(:auto_close_time) unless params.has_key?(:auto_close_time)
+ topic = Topic.where(id: params[:topic_id].to_i).first
+ guardian.ensure_can_moderate!(topic)
+ topic.set_auto_close(params[:auto_close_time], current_user)
+ if topic.save
+ render json: success_json.merge!(auto_close_at: topic.auto_close_at)
+ else
+ render_json_error(topic)
+ end
end
def destroy
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 33eb6ad35..301c83400 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -146,7 +146,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?
- set_auto_close(self.category.auto_close_days)
+ set_auto_close(self.category.auto_close_days * 24)
end
end
@@ -602,9 +602,10 @@ class Topic < ActiveRecord::Base
end
end
+ # TODO: change this method, along with category's auto_close_days. Use hours.
def auto_close_days=(num_days)
@ignore_category_auto_close = true
- set_auto_close(num_days)
+ set_auto_close(num_days * 24)
end
def self.auto_close
@@ -622,10 +623,27 @@ class Topic < ActiveRecord::Base
end
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
+ # Valid arguments for the auto close time:
+ # * An integer, which is the number of hours from now to close the topic.
+ # * A time, like "12:00", which is the time at which the topic will close in the current day
+ # or the next day if that time has already passed today.
+ # * A timestamp, like "2013-11-25 13:00", when the topic should close.
+ # * A timestamp with timezone in JSON format. (e.g., "2013-11-26T21:00:00.000Z")
+ # * nil, to prevent the topic from automatically closing.
+ def set_auto_close(arg, by_user=nil)
+ if arg.is_a?(String) and matches = /^([\d]{1,2}):([\d]{1,2})$/.match(arg.strip)
+ now = Time.zone.now
+ self.auto_close_at = Time.zone.local(now.year, now.month, now.day, matches[1].to_i, matches[2].to_i)
+ self.auto_close_at += 1.day if self.auto_close_at < now
+ elsif arg.is_a?(String) and arg.include?('-') and timestamp = Time.zone.parse(arg)
+ self.auto_close_at = timestamp
+ self.errors.add(:auto_close_at, :invalid) if timestamp < Time.zone.now
+ else
+ num_hours = arg.to_i
+ self.auto_close_at = (num_hours > 0 ? num_hours.hours.from_now : nil)
+ end
+
+ unless self.auto_close_at.nil?
self.auto_close_started_at ||= Time.zone.now
if by_user and by_user.staff?
self.auto_close_user = by_user
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 8225d4c92..c2e693b70 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -517,8 +517,10 @@ en:
toggler: "hide or show the composer panel"
admin_options_title: "Optional staff settings for this topic"
- auto_close_label: "Auto-close topic after:"
- auto_close_units: "days"
+ auto_close_label: "Auto-close topic time:"
+ auto_close_units: "(# of hours, a time, or a timestamp)"
+ auto_close_examples: 'Examples: 24, 17:00, 2013-11-22 14:00'
+ auto_close_error: "Please enter a valid value."
notifications:
title: "notifications of @name mentions, replies to your posts and topics, private messages, etc"
diff --git a/lib/topic_creator.rb b/lib/topic_creator.rb
index e60051e1a..0965683b5 100644
--- a/lib/topic_creator.rb
+++ b/lib/topic_creator.rb
@@ -16,7 +16,7 @@ class TopicCreator
topic_params = setup
@topic = Topic.new(topic_params)
- setup_auto_close_days if @opts[:auto_close_days]
+ setup_auto_close_time if @opts[:auto_close_time]
process_private_message if @opts[:archetype] == Archetype.private_message
save_topic
@@ -55,9 +55,9 @@ class TopicCreator
topic_params
end
- def setup_auto_close_days
+ def setup_auto_close_time
@guardian.ensure_can_moderate!(@topic)
- @topic.auto_close_days = @opts[:auto_close_days]
+ @topic.set_auto_close(@opts[:auto_close_time], @user)
end
def process_private_message
diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb
index fed5a5cff..9ecbdf4f0 100644
--- a/spec/components/post_creator_spec.rb
+++ b/spec/components/post_creator_spec.rb
@@ -190,7 +190,7 @@ describe PostCreator do
it 'ensures the user can auto-close the topic' do
Guardian.any_instance.stubs(:can_moderate?).returns(false)
expect {
- PostCreator.new(user, basic_topic_params.merge(auto_close_days: 2)).create
+ PostCreator.new(user, basic_topic_params.merge(auto_close_time: 2)).create
}.to raise_error(Discourse::InvalidAccess)
end
end
diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb
index 9c54976c9..e8500332f 100644
--- a/spec/controllers/topics_controller_spec.rb
+++ b/spec/controllers/topics_controller_spec.rb
@@ -739,12 +739,12 @@ describe TopicsController do
describe 'autoclose' do
it 'needs you to be logged in' do
- lambda { xhr :put, :autoclose, topic_id: 99, auto_close_days: 3}.should raise_error(Discourse::NotLoggedIn)
+ lambda { xhr :put, :autoclose, topic_id: 99, auto_close_time: '24'}.should raise_error(Discourse::NotLoggedIn)
end
it 'needs you to be an admin or mod' do
user = log_in
- xhr :put, :autoclose, topic_id: 99, auto_close_days: 3
+ xhr :put, :autoclose, topic_id: 99, auto_close_time: '24'
response.should be_forbidden
end
@@ -755,13 +755,15 @@ describe TopicsController do
end
it "can set a topic's auto close time" do
- Topic.any_instance.expects(:set_auto_close).with("3", @admin)
- xhr :put, :autoclose, topic_id: @topic.id, auto_close_days: 3
+ Topic.any_instance.expects(:set_auto_close).with("24", @admin)
+ xhr :put, :autoclose, topic_id: @topic.id, auto_close_time: '24'
+ json = ::JSON.parse(response.body)
+ json.should have_key('auto_close_at')
end
it "can remove a topic's auto close time" do
Topic.any_instance.expects(:set_auto_close).with(nil, anything)
- xhr :put, :autoclose, topic_id: @topic.id, auto_close_days: nil
+ xhr :put, :autoclose, topic_id: @topic.id, auto_close_time: nil
end
end
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index 394d68add..e4055793d 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -1074,13 +1074,56 @@ describe Topic do
before { Discourse.stubs(:system_user).returns(admin) }
- it 'sets auto_close_at' do
+ it 'can take a number of hours as an integer' do
Timecop.freeze(Time.zone.now) do
- topic.set_auto_close(3, admin)
+ topic.set_auto_close(72, admin)
expect(topic.auto_close_at).to eq(3.days.from_now)
end
end
+ it 'can take a number of hours as a string' do
+ Timecop.freeze(Time.zone.now) do
+ topic.set_auto_close('18', admin)
+ expect(topic.auto_close_at).to eq(18.hours.from_now)
+ end
+ end
+
+ it "can take a time later in the day" do
+ Timecop.freeze(Time.zone.local(2013,11,20,8,0)) do
+ topic.set_auto_close('13:00', admin)
+ topic.auto_close_at.should == Time.zone.local(2013,11,20,13,0)
+ end
+ end
+
+ it "can take a time for the next day" do
+ Timecop.freeze(Time.zone.local(2013,11,20,8,0)) do
+ topic.set_auto_close('5:00', admin)
+ topic.auto_close_at.should == Time.zone.local(2013,11,21,5,0)
+ end
+ end
+
+ it "can take a timestamp for a future time" do
+ Timecop.freeze(Time.zone.local(2013,11,20,8,0)) do
+ topic.set_auto_close('2013-11-22 5:00', admin)
+ topic.auto_close_at.should == Time.zone.local(2013,11,22,5,0)
+ end
+ end
+
+ it "sets a validation error when given a timestamp in the past" do
+ Timecop.freeze(Time.zone.local(2013,11,20,8,0)) do
+ topic.set_auto_close('2013-11-19 5:00', admin)
+ topic.auto_close_at.should == Time.zone.local(2013,11,19,5,0)
+ topic.errors[:auto_close_at].should be_present
+ end
+ end
+
+ it "can take a timestamp with timezone" do
+ Timecop.freeze(Time.utc(2013,11,20,12,0)) do
+ topic.set_auto_close('2013-11-25T01:35:00-08:00', admin)
+ topic.auto_close_at.should == Time.utc(2013,11,25,9,35)
+ 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)
@@ -1102,20 +1145,20 @@ describe Topic do
expect(staff_topic.auto_close_user_id).to eq(999)
end
- it 'clears auto_close_at if num_days is nil' do
+ it 'clears auto_close_at if arg 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
+ it 'clears auto_close_started_at if arg 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)
+ closing_topic.set_auto_close(48)
+ expect(closing_topic.auto_close_at).to eq(2.days.from_now)
end
end