FEATURE: keep the topic in closed status until the community flags are handled

FEATURE: keep the topic in closed status until the community flags are handled

diff --git a/app/jobs/regular/toggle_topic_closed.rb b/app/jobs/regular/toggle_topic_closed.rb
index 7a77f02..99a446a 100644
--- a/app/jobs/regular/toggle_topic_closed.rb
+++ b/app/jobs/regular/toggle_topic_closed.rb
@@ -15,7 +15,16 @@ module Jobs
       user = topic_timer.user
 
       if Guardian.new(user).can_close?(topic)
-        topic.update_status('autoclosed', state, user)
+        if state == false && PostAction.auto_close_threshold_reached?(topic)
+          topic.set_or_create_timer(
+            TopicTimer.types[:open],
+            SiteSetting.num_hours_to_close_topic,
+            by_user: Discourse.system_user
+          )
+        else
+          topic.update_status('autoclosed', state, user)
+        end
+
         topic.inherit_auto_close_from_category if state == false
       end
     end
diff --git a/app/models/post_action.rb b/app/models/post_action.rb
index 1e533b0..a042a6e 100644
--- a/app/models/post_action.rb
+++ b/app/models/post_action.rb
@@ -564,9 +564,7 @@ class PostAction < ActiveRecord::Base
 
   MAXIMUM_FLAGS_PER_POST = 3
 
-  def self.auto_close_if_threshold_reached(topic)
-    return if topic.nil? || topic.closed?
-
+  def self.auto_close_threshold_reached?(topic)
     flags = PostAction.active
       .flags
       .joins(:post)
@@ -580,6 +578,13 @@ class PostAction < ActiveRecord::Base
     # we need a minimum number of flags
     return if flags.sum { |f| f[1] } < SiteSetting.num_flags_to_close_topic
 
+    true
+  end
+
+  def self.auto_close_if_threshold_reached(topic)
+    return if topic.nil? || topic.closed?
+    return unless auto_close_threshold_reached?(topic)
+
     # the threshold has been reached, we will close the topic waiting for intervention
     topic.update_status("closed", true, Discourse.system_user,
       message: I18n.t(
diff --git a/spec/models/post_action_spec.rb b/spec/models/post_action_spec.rb
index 823128d..11ad4f4 100644
--- a/spec/models/post_action_spec.rb
+++ b/spec/models/post_action_spec.rb
@@ -589,54 +589,100 @@ describe PostAction do
       expect(post.hidden).to eq(false)
     end
 
-    it "will automatically pause a topic due to large community flagging" do
-      SiteSetting.flags_required_to_hide_post = 0
-      SiteSetting.num_flags_to_close_topic = 3
-      SiteSetting.num_flaggers_to_close_topic = 2
-      SiteSetting.num_hours_to_close_topic = 1
-
-      topic = Fabricate(:topic)
-      post1 = create_post(topic: topic)
-      post2 = create_post(topic: topic)
-      post3 = create_post(topic: topic)
-
-      flagger1 = Fabricate(:user)
-      flagger2 = Fabricate(:user)
-
-      # reaching `num_flaggers_to_close_topic` isn't enough
-      [flagger1, flagger2].each do |flagger|
-        PostAction.act(flagger, post1, PostActionType.types[:inappropriate])
-      end
-
-      expect(topic.reload.closed).to eq(false)
+    context "topic auto closing" do
+      let(:topic) { Fabricate(:topic) }
+      let(:post1) { create_post(topic: topic) }
+      let(:post2) { create_post(topic: topic) }
+      let(:post3) { create_post(topic: topic) }
 
-      # clean up
-      PostAction.where(post: post1).delete_all
+      let(:flagger1) { Fabricate(:user) }
+      let(:flagger2) { Fabricate(:user) }
 
-      # reaching `num_flags_to_close_topic` isn't enough
-      [post1, post2, post3].each do |post|
-        PostAction.act(flagger1, post, PostActionType.types[:inappropriate])
+      before do
+        SiteSetting.flags_required_to_hide_post = 0
+        SiteSetting.num_flags_to_close_topic = 3
+        SiteSetting.num_flaggers_to_close_topic = 2
+        SiteSetting.num_hours_to_close_topic = 1
       end
 
-      expect(topic.reload.closed).to eq(false)
+      it "will automatically pause a topic due to large community flagging" do
+        # reaching `num_flaggers_to_close_topic` isn't enough
+        [flagger1, flagger2].each do |flagger|
+          PostAction.act(flagger, post1, PostActionType.types[:inappropriate])
+        end
+
+        expect(topic.reload.closed).to eq(false)
 
-      # clean up
-      PostAction.where(post: [post1, post2, post3]).delete_all
+        # clean up
+        PostAction.where(post: post1).delete_all
 
-      # reaching both should close the topic
-      [flagger1, flagger2].each do |flagger|
+        # reaching `num_flags_to_close_topic` isn't enough
         [post1, post2, post3].each do |post|
-          PostAction.act(flagger, post, PostActionType.types[:inappropriate])
+          PostAction.act(flagger1, post, PostActionType.types[:inappropriate])
+        end
+
+        expect(topic.reload.closed).to eq(false)
+
+        # clean up
+        PostAction.where(post: [post1, post2, post3]).delete_all
+
+        # reaching both should close the topic
+        [flagger1, flagger2].each do |flagger|
+          [post1, post2, post3].each do |post|
+            PostAction.act(flagger, post, PostActionType.types[:inappropriate])
+          end
         end
+
+        expect(topic.reload.closed).to eq(true)
+
+        topic_status_update = TopicTimer.last
+
+        expect(topic_status_update.topic).to eq(topic)
+        expect(topic_status_update.execute_at).to be_within(1.second).of(1.hour.from_now)
+        expect(topic_status_update.status_type).to eq(TopicTimer.types[:open])
       end
 
-      expect(topic.reload.closed).to eq(true)
+      it "will keep the topic in closed status until the community flags are handled" do
+        freeze_time
 
-      topic_status_update = TopicTimer.last
+        PostAction.stubs(:auto_close_threshold_reached?).returns(true)
+        PostAction.auto_close_if_threshold_reached(topic)
 
-      expect(topic_status_update.topic).to eq(topic)
-      expect(topic_status_update.execute_at).to be_within(1.second).of(1.hour.from_now)
-      expect(topic_status_update.status_type).to eq(TopicTimer.types[:open])
+        expect(topic.reload.closed).to eq(true)
+        
+        timer = TopicTimer.last
+        expect(timer.execute_at).to eq(1.hour.from_now)
+
+        freeze_time timer.execute_at
+        Jobs.expects(:enqueue_in).with(1.hour.to_i, :toggle_topic_closed, topic_timer_id: timer.id, state: false).returns(true)
+        Jobs::ToggleTopicClosed.new.execute(topic_timer_id: timer.id, state: false)
+
+        expect(topic.reload.closed).to eq(true)
+        expect(timer.reload.execute_at).to eq(1.hour.from_now)
+
+        freeze_time timer.execute_at
+        PostAction.stubs(:auto_close_threshold_reached?).returns(false)
+        Jobs::ToggleTopicClosed.new.execute(topic_timer_id: timer.id, state: false)
+
+        expect(topic.reload.closed).to eq(false)
+      end
+
+      it "will reopen topic after the flags are auto handled" do
+        freeze_time
+        [flagger1, flagger2].each do |flagger|
+          [post1, post2, post3].each do |post|
+            PostAction.act(flagger, post, PostActionType.types[:inappropriate])
+          end
+        end
+
+        expect(topic.reload.closed).to eq(true)
+
+        freeze_time 61.days.from_now
+        Jobs::AutoQueueHandler.new.execute({})
+        Jobs::ToggleTopicClosed.new.execute(topic_timer_id: TopicTimer.last.id, state: false)
+
+        expect(topic.reload.closed).to eq(false)
+      end
     end
 
   end

GitHub sha: 8f602be2