FIX: Autoclose message was not correct when immediate

FEATURE: Warn when setting auto-close for right now
This commit is contained in:
Arpit Jalan 2015-12-08 18:13:23 +05:30
parent b09ee9cb82
commit e52852dd0f
8 changed files with 103 additions and 8 deletions

View File

@ -5,6 +5,8 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
auto_close_valid: true,
auto_close_invalid: Em.computed.not('auto_close_valid'),
disable_submit: Em.computed.or('auto_close_invalid', 'loading'),
loading: false,
@observes("model.details.auto_close_at", "model.details.auto_close_hours")
setAutoCloseTime() {
@ -29,7 +31,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
setAutoClose(time) {
const self = this;
this.send('hideModal');
this.set('loading', true);
Discourse.ajax({
url: `/t/${this.get('model.id')}/autoclose`,
type: 'PUT',
@ -40,16 +42,34 @@ export default Ember.Controller.extend(ModalFunctionality, {
timezone_offset: (new Date().getTimezoneOffset())
}
}).then(result => {
self.set('loading', false);
if (result.success) {
this.send('closeModal');
this.set('model.details.auto_close_at', result.auto_close_at);
this.set('model.details.auto_close_hours', result.auto_close_hours);
} else {
bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } );
bootbox.alert(I18n.t('composer.auto_close.error'));
}
}).catch(() => {
bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } );
// TODO - incorrectly responds to network errors as bad input
bootbox.alert(I18n.t('composer.auto_close.error'));
self.set('loading', false);
});
}
},
willCloseImmediately: function() {
if (!this.get('model.details.auto_close_based_on_last_post')) {
return false;
}
let closeDate = new Date(this.get('model.last_posted_at'));
closeDate.setHours(closeDate.getHours() + this.get('model.auto_close_time'));
return closeDate < new Date();
}.property('model.details.auto_close_based_on_last_post', 'model.auto_close_time', 'model.last_posted_at'),
willCloseI18n: function() {
if (this.get('model.details.auto_close_based_on_last_post')) {
return I18n.t('topic.auto_close_immediate', {hours: this.get('model.auto_close_time')});
}
}.property('model.details.auto_close_based_on_last_post', 'model.auto_close_time')
});

View File

@ -340,6 +340,13 @@ const Topic = RestModel.extend({
keys.forEach(key => this.set(key, json[key]));
},
reload() {
const self = this;
return Discourse.ajax('/t/' + this.get('id'), { type: 'GET' }).then(function(topic_json) {
self.updateFromJson(topic_json);
});
},
isPinnedUncategorized: function() {
return this.get('pinned') && this.get('category.isUncategorizedCategory');
}.property('pinned', 'category.isUncategorizedCategory'),

View File

@ -4,10 +4,17 @@
autoCloseValid=auto_close_valid
autoCloseBasedOnLastPost=model.details.auto_close_based_on_last_post
limited=model.details.auto_close_based_on_last_post }}
{{#if willCloseImmediately}}
<div class="warning">
{{fa-icon "warning"}}
{{willCloseI18n}}
</div>
{{/if}}
</div>
<div class="modal-footer">
{{d-button class="btn-primary" disabled=auto_close_invalid label="topic.auto_close_save" action="saveAutoClose"}}
{{d-button class="btn-primary" disabled=disable_submit label="topic.auto_close_save" action="saveAutoClose"}}
<a {{action "closeModal"}}>{{i18n 'cancel'}}</a>
{{conditional-loading-spinner size="small" condition=loading}}
{{d-button class="pull-right" action="removeAutoClose" label="topic.auto_close_remove"}}
</div>
</form>

View File

@ -835,10 +835,12 @@ class Topic < ActiveRecord::Base
self.auto_close_at = utc.local(now.year, now.month, now.day, m[1].to_i, m[2].to_i)
self.auto_close_at += offset_minutes * 60 if offset_minutes
self.auto_close_at += 1.day if self.auto_close_at < now
self.auto_close_hours = -1
elsif arg.is_a?(String) && arg.include?("-") && timestamp = utc.parse(arg)
# a timestamp in client's time zone, like "2015-5-27 12:00"
self.auto_close_at = timestamp
self.auto_close_at += offset_minutes * 60 if offset_minutes
self.auto_close_hours = -1
self.errors.add(:auto_close_at, :invalid) if timestamp < Time.zone.now
else
num_hours = arg.to_f
@ -864,6 +866,10 @@ class Topic < ActiveRecord::Base
else
self.auto_close_user ||= (self.user.staff? || self.user.trust_level == TrustLevel[4] ? self.user : Discourse.system_user)
end
if self.auto_close_at.try(:<, Time.zone.now)
auto_close(auto_close_user)
end
end
self

View File

@ -52,7 +52,16 @@ TopicStatusUpdate = Struct.new(:topic, :user) do
end
def message_for_autoclosed(locale_key)
num_minutes = topic.auto_close_started_at ? ((Time.zone.now - topic.auto_close_started_at) / 1.minute).round : topic.age_in_minutes
num_minutes = ((
if topic.auto_close_based_on_last_post
topic.auto_close_hours.hours
elsif topic.auto_close_started_at
Time.zone.now - topic.auto_close_started_at
else
Time.zone.now - topic.created_at
end
) / 1.minute).round
if num_minutes.minutes >= 2.days
I18n.t("#{locale_key}_days", count: (num_minutes.minutes / 1.day).round)
else

View File

@ -1142,6 +1142,7 @@ en:
auto_close_title: 'Auto-Close Settings'
auto_close_save: "Save"
auto_close_remove: "Don't Auto-Close This Topic"
auto_close_immediate: "The last post in the topic is already %{hours} hours old, so the topic will be closed immediately."
progress:
title: topic progress

View File

@ -1036,6 +1036,46 @@ describe TopicsController do
Topic.any_instance.expects(:set_auto_close).with(nil, anything)
xhr :put, :autoclose, topic_id: @topic.id, auto_close_time: nil, auto_close_based_on_last_post: false, timezone_offset: -240
end
it "will close a topic when the time expires" do
topic = Fabricate(:topic)
Timecop.freeze(20.hours.ago) do
create_post(topic: topic, raw: "This is the body of my cool post in the topic, but it's a bit old now")
end
topic.save
Jobs.expects(:enqueue_at).at_least_once
xhr :put, :autoclose, topic_id: topic.id, auto_close_time: 24, auto_close_based_on_last_post: true
topic.reload
expect(topic.closed).to eq(false)
expect(topic.posts.last.raw).to match(/cool post/)
Timecop.freeze(5.hours.from_now) do
Jobs::CloseTopic.new.execute({topic_id: topic.id, user_id: @admin.id})
end
topic.reload
expect(topic.closed).to eq(true)
expect(topic.posts.last.raw).to match(/automatically closed/)
end
it "will immediately close if the last post is old enough" do
topic = Fabricate(:topic)
Timecop.freeze(20.hours.ago) do
create_post(topic: topic)
end
topic.save
Topic.reset_highest(topic.id)
topic.reload
xhr :put, :autoclose, topic_id: topic.id, auto_close_time: 10, auto_close_based_on_last_post: true
topic.reload
expect(topic.closed).to eq(true)
expect(topic.posts.last.raw).to match(/after the last reply/)
expect(topic.posts.last.raw).to match(/10 hours/)
end
end
end

View File

@ -3,18 +3,21 @@
require 'rails_helper'
require_dependency 'post_destroyer'
# TODO - test pinning, create_moderator_post
describe TopicStatusUpdate do
let(:user) { Fabricate(:user) }
let(:admin) { Fabricate(:admin) }
it "avoids notifying on automatically closed topics" do
# TODO: TopicStatusUpdate should supress message bus updates from the users it "pretends to read"
# TODO: TopicStatusUpdate should suppress message bus updates from the users it "pretends to read"
post = PostCreator.create(user,
raw: "this is a test post 123 this is a test post",
title: "hello world title",
)
# TODO needed so counts sync up, PostCreator really should not give back out-of-date Topic
post.topic.set_auto_close('10')
post.topic.reload
TopicStatusUpdate.new(post.topic, admin).update!("autoclosed", true)
@ -27,6 +30,7 @@ describe TopicStatusUpdate do
it "adds an autoclosed message" do
topic = create_topic
topic.set_auto_close('10')
TopicStatusUpdate.new(topic, admin).update!("autoclosed", true)
@ -39,13 +43,14 @@ describe TopicStatusUpdate do
it "adds an autoclosed message based on last post" do
topic = create_topic
topic.auto_close_based_on_last_post = true
topic.set_auto_close('10')
TopicStatusUpdate.new(topic, admin).update!("autoclosed", true)
last_post = topic.posts.last
expect(last_post.post_type).to eq(Post.types[:small_action])
expect(last_post.action_code).to eq('autoclosed.enabled')
expect(last_post.raw).to eq(I18n.t("topic_statuses.autoclosed_enabled_lastpost_minutes", count: 0))
expect(last_post.raw).to eq(I18n.t("topic_statuses.autoclosed_enabled_lastpost_hours", count: 10))
end
end