FEATURE: silently close topic (#11392)
New TopicTimer to silently close topic. It will be used by discourse-solved plugin Meta: https://meta.discourse.org/t/allow-auto-close-for-solved-to-do-so-silently/169300
This commit is contained in:
parent
1c87038255
commit
9c5ee4923b
|
@ -126,7 +126,10 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
_noticeKey() {
|
||||
const statusType = this.statusType;
|
||||
let statusType = this.statusType;
|
||||
if (statusType === "silent_close") {
|
||||
statusType = "close";
|
||||
}
|
||||
|
||||
if (this.basedOnLastPost) {
|
||||
return `topic.status_update_notice.auto_${statusType}_based_on_last_post`;
|
||||
|
|
|
@ -5,6 +5,7 @@ module Jobs
|
|||
def execute(args)
|
||||
topic_timer = TopicTimer.find_by(id: args[:topic_timer_id] || args[:topic_status_update_id])
|
||||
state = !!args[:state]
|
||||
timer_type = args[:silent] ? :silent_close : :close
|
||||
|
||||
if topic_timer.blank? || topic_timer.execute_at > Time.zone.now
|
||||
return
|
||||
|
@ -25,16 +26,16 @@ module Jobs
|
|||
by_user: Discourse.system_user
|
||||
)
|
||||
else
|
||||
topic.update_status('autoclosed', state, user)
|
||||
topic.update_status('autoclosed', state, user, { silent: args[:silent] })
|
||||
end
|
||||
|
||||
topic.inherit_auto_close_from_category if state == false
|
||||
topic.inherit_auto_close_from_category(timer_type: timer_type) if state == false
|
||||
else
|
||||
topic_timer.destroy!
|
||||
topic.reload
|
||||
|
||||
if topic_timer.based_on_last_post
|
||||
topic.inherit_auto_close_from_category
|
||||
topic.inherit_auto_close_from_category(timer_type: timer_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -368,7 +368,7 @@ class Topic < ActiveRecord::Base
|
|||
self.last_post_user_id ||= user_id
|
||||
end
|
||||
|
||||
def inherit_auto_close_from_category
|
||||
def inherit_auto_close_from_category(timer_type: :close)
|
||||
if !self.closed &&
|
||||
!@ignore_category_auto_close &&
|
||||
self.category &&
|
||||
|
@ -379,7 +379,7 @@ class Topic < ActiveRecord::Base
|
|||
duration = based_on_last_post ? self.category.auto_close_hours : nil
|
||||
|
||||
self.set_or_create_timer(
|
||||
TopicTimer.types[:close],
|
||||
TopicTimer.types[timer_type],
|
||||
self.category.auto_close_hours,
|
||||
by_user: Discourse.system_user,
|
||||
based_on_last_post: based_on_last_post,
|
||||
|
@ -902,6 +902,7 @@ class Topic < ActiveRecord::Base
|
|||
action_code: opts[:action_code],
|
||||
no_bump: opts[:bump].blank?,
|
||||
topic_id: self.id,
|
||||
silent: opts[:silent],
|
||||
skip_validations: true,
|
||||
custom_fields: opts[:custom_fields],
|
||||
import_mode: opts[:import_mode])
|
||||
|
@ -1299,12 +1300,13 @@ class Topic < ActiveRecord::Base
|
|||
# * by_user: User who is setting the topic's status update.
|
||||
# * based_on_last_post: True if time should be based on timestamp of the last post.
|
||||
# * category_id: Category that the update will apply to.
|
||||
def set_or_create_timer(status_type, time, by_user: nil, based_on_last_post: false, category_id: SiteSetting.uncategorized_category_id, duration: nil)
|
||||
def set_or_create_timer(status_type, time, by_user: nil, based_on_last_post: false, category_id: SiteSetting.uncategorized_category_id, duration: nil, silent: nil)
|
||||
return delete_topic_timer(status_type, by_user: by_user) if time.blank? && duration.blank?
|
||||
|
||||
public_topic_timer = !!TopicTimer.public_types[status_type]
|
||||
topic_timer_options = { topic: self, public_type: public_topic_timer }
|
||||
topic_timer_options.merge!(user: by_user) unless public_topic_timer
|
||||
topic_timer_options.merge!(silent: silent) if silent
|
||||
topic_timer = TopicTimer.find_or_initialize_by(topic_timer_options)
|
||||
topic_timer.status_type = status_type
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ class TopicTimer < ActiveRecord::Base
|
|||
delete: 4,
|
||||
reminder: 5,
|
||||
bump: 6,
|
||||
delete_replies: 7
|
||||
delete_replies: 7,
|
||||
silent_close: 8
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -97,6 +98,10 @@ class TopicTimer < ActiveRecord::Base
|
|||
end
|
||||
alias_method :cancel_auto_open_job, :cancel_auto_close_job
|
||||
|
||||
def cancel_auto_silent_close_job
|
||||
Jobs.cancel_scheduled_job(:toggle_topic_closed, topic_timer_id: id)
|
||||
end
|
||||
|
||||
def cancel_auto_publish_to_category_job
|
||||
Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_timer_id: id)
|
||||
end
|
||||
|
@ -143,6 +148,16 @@ class TopicTimer < ActiveRecord::Base
|
|||
)
|
||||
end
|
||||
|
||||
def schedule_auto_silent_close_job(time)
|
||||
topic.update_status('closed', false, user) if topic&.closed
|
||||
|
||||
Jobs.enqueue_at(time, :toggle_topic_closed,
|
||||
topic_timer_id: id,
|
||||
silent: true,
|
||||
state: true
|
||||
)
|
||||
end
|
||||
|
||||
def schedule_auto_publish_to_category_job(time)
|
||||
Jobs.enqueue_at(time, :publish_topic_to_category, topic_timer_id: id)
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ TopicStatusUpdater = Struct.new(:topic, :user) do
|
|||
updated = change(status, opts)
|
||||
if updated
|
||||
highest_post_number = topic.highest_post_number
|
||||
create_moderator_post_for(status, opts[:message])
|
||||
create_moderator_post_for(status, opts)
|
||||
update_read_state_for(status, highest_post_number)
|
||||
end
|
||||
end
|
||||
|
@ -49,6 +49,7 @@ TopicStatusUpdater = Struct.new(:topic, :user) do
|
|||
if @topic_status_update
|
||||
if status.manually_closing_topic? || status.closing_topic?
|
||||
topic.delete_topic_timer(TopicTimer.types[:close])
|
||||
topic.delete_topic_timer(TopicTimer.types[:silent_close])
|
||||
elsif status.manually_opening_topic? || status.opening_topic?
|
||||
topic.delete_topic_timer(TopicTimer.types[:open])
|
||||
end
|
||||
|
@ -65,8 +66,9 @@ TopicStatusUpdater = Struct.new(:topic, :user) do
|
|||
result
|
||||
end
|
||||
|
||||
def create_moderator_post_for(status, message = nil)
|
||||
topic.add_moderator_post(user, message || message_for(status), options_for(status))
|
||||
def create_moderator_post_for(status, opts)
|
||||
message = opts[:message]
|
||||
topic.add_moderator_post(user, message || message_for(status), options_for(status, opts))
|
||||
topic.reload
|
||||
end
|
||||
|
||||
|
@ -110,9 +112,10 @@ TopicStatusUpdater = Struct.new(:topic, :user) do
|
|||
end
|
||||
end
|
||||
|
||||
def options_for(status)
|
||||
def options_for(status, opts = {})
|
||||
{ bump: status.opening_topic?,
|
||||
post_type: Post.types[:small_action],
|
||||
silent: opts[:silent],
|
||||
action_code: status.action_code }
|
||||
end
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ class PostCreator
|
|||
# hidden_reason_id - Reason for hiding the post (optional)
|
||||
# skip_validations - Do not validate any of the content in the post
|
||||
# draft_key - the key of the draft we are creating (will be deleted on success)
|
||||
# silent - Do not update topic stats and fields like last_post_user_id
|
||||
#
|
||||
# When replying to a topic:
|
||||
# topic_id - topic we're replying to
|
||||
|
@ -506,13 +507,12 @@ class PostCreator
|
|||
def update_topic_stats
|
||||
attrs = { updated_at: Time.now }
|
||||
|
||||
if @post.post_type != Post.types[:whisper]
|
||||
if @post.post_type != Post.types[:whisper] && !@opts[:silent]
|
||||
attrs[:last_posted_at] = @post.created_at
|
||||
attrs[:last_post_user_id] = @post.user_id
|
||||
attrs[:word_count] = (@topic.word_count || 0) + @post.word_count
|
||||
attrs[:excerpt] = @post.excerpt_for_topic if new_topic?
|
||||
attrs[:bumped_at] = @post.created_at unless @post.no_bump
|
||||
@topic.update_columns(attrs)
|
||||
end
|
||||
|
||||
@topic.update_columns(attrs)
|
||||
|
|
|
@ -581,6 +581,36 @@ describe PostCreator do
|
|||
end
|
||||
end
|
||||
|
||||
context 'silent' do
|
||||
fab!(:topic) { Fabricate(:topic, user: user) }
|
||||
|
||||
it 'silent do not mess up the public view' do
|
||||
freeze_time DateTime.parse('2010-01-01 12:00')
|
||||
|
||||
first = PostCreator.new(
|
||||
user,
|
||||
topic_id: topic.id,
|
||||
raw: 'this is the first post'
|
||||
).create
|
||||
|
||||
freeze_time 1.year.from_now
|
||||
|
||||
PostCreator.new(user,
|
||||
topic_id: topic.id,
|
||||
reply_to_post_number: 1,
|
||||
silent: true,
|
||||
post_type: Post.types[:regular],
|
||||
raw: 'this is a whispered reply').create
|
||||
|
||||
topic.reload
|
||||
|
||||
# silent post should not muck up that number
|
||||
expect(topic.last_posted_at).to eq_time(first.created_at)
|
||||
expect(topic.last_post_user_id).to eq(first.user_id)
|
||||
expect(topic.word_count).to eq(5)
|
||||
end
|
||||
end
|
||||
|
||||
context 'uniqueness' do
|
||||
|
||||
fab!(:topic) { Fabricate(:topic, user: user) }
|
||||
|
|
Loading…
Reference in New Issue