FEATURE: Topic timer for bumping a topic in the future

FEATURE: Topic timer for bumping a topic in the future

diff --git a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6 b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6
index d231539..e343187 100644
--- a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6
@@ -9,7 +9,8 @@ import {
   OPEN_STATUS_TYPE,
   DELETE_STATUS_TYPE,
   REMINDER_TYPE,
-  CLOSE_STATUS_TYPE
+  CLOSE_STATUS_TYPE,
+  BUMP_TYPE
 } from "discourse/controllers/edit-topic-timer";
 
 export default Ember.Component.extend({
@@ -17,12 +18,18 @@ export default Ember.Component.extend({
   autoOpen: Ember.computed.equal("selection", OPEN_STATUS_TYPE),
   autoClose: Ember.computed.equal("selection", CLOSE_STATUS_TYPE),
   autoDelete: Ember.computed.equal("selection", DELETE_STATUS_TYPE),
+  autoBump: Ember.computed.equal("selection", BUMP_TYPE),
   publishToCategory: Ember.computed.equal(
     "selection",
     PUBLISH_TO_CATEGORY_STATUS_TYPE
   ),
   reminder: Ember.computed.equal("selection", REMINDER_TYPE),
-  showTimeOnly: Ember.computed.or("autoOpen", "autoDelete", "reminder"),
+  showTimeOnly: Ember.computed.or(
+    "autoOpen",
+    "autoDelete",
+    "reminder",
+    "autoBump"
+  ),
 
   @computed(
     "topicTimer.updateTime",
diff --git a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6
index 205bc1e..5b7dec6 100644
--- a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6
+++ b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6
@@ -8,6 +8,7 @@ export const OPEN_STATUS_TYPE = "open";
 export const PUBLISH_TO_CATEGORY_STATUS_TYPE = "publish_to_category";
 export const DELETE_STATUS_TYPE = "delete";
 export const REMINDER_TYPE = "reminder";
+export const BUMP_TYPE = "bump";
 
 export default Ember.Controller.extend(ModalFunctionality, {
   loading: false,
@@ -31,6 +32,10 @@ export default Ember.Controller.extend(ModalFunctionality, {
       {
         id: PUBLISH_TO_CATEGORY_STATUS_TYPE,
         name: I18n.t("topic.publish_to_category.title")
+      },
+      {
+        id: BUMP_TYPE,
+        name: I18n.t("topic.auto_bump.title")
       }
     ];
     if (this.currentUser.get("staff")) {
diff --git a/app/jobs/regular/bump_topic.rb b/app/jobs/regular/bump_topic.rb
new file mode 100644
index 0000000..f4e2193
--- /dev/null
+++ b/app/jobs/regular/bump_topic.rb
@@ -0,0 +1,20 @@
+module Jobs
+  class BumpTopic < Jobs::Base
+
+    def execute(args)
+      topic_timer = TopicTimer.find_by(id: args[:topic_timer_id] || args[:topic_status_update_id])
+
+      topic = topic_timer&.topic
+
+      if topic_timer.blank? || topic.blank? || topic_timer.execute_at > Time.zone.now
+        return
+      end
+
+      if Guardian.new(topic_timer.user).can_create_post_on_topic?(topic)
+        topic.add_small_action(Discourse.system_user, "autobumped", nil, bump: true)
+      end
+      topic_timer.trash!(Discourse.system_user)
+    end
+
+  end
+end
diff --git a/app/models/topic_timer.rb b/app/models/topic_timer.rb
index e884f33..c8229bc 100644
--- a/app/models/topic_timer.rb
+++ b/app/models/topic_timer.rb
@@ -42,7 +42,8 @@ class TopicTimer < ActiveRecord::Base
       open: 2,
       publish_to_category: 3,
       delete: 4,
-      reminder: 5
+      reminder: 5,
+      bump: 6
     )
   end
 
@@ -108,6 +109,14 @@ class TopicTimer < ActiveRecord::Base
     Jobs.cancel_scheduled_job(:topic_reminder, topic_timer_id: id)
   end
 
+  def cancel_auto_bump_job
+    Jobs.cancel_scheduled_job(:bump_topic, topic_timer_id: id)
+  end
+
+  def schedule_auto_bump_job(time)
+    Jobs.enqueue_at(time, :bump_topic, topic_timer_id: id)
+  end
+
   def schedule_auto_open_job(time)
     return unless topic
     topic.update_status('closed', true, user) if !topic.closed
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 15b5420..979520d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1817,6 +1817,8 @@ en:
         based_on_last_post: "Don't close until the last post in the topic is at least this old."
       auto_delete:
         title: "Auto-Delete Topic"
+      auto_bump:
+        title: "Auto-Bump Topic"
       reminder:
         title: "Remind Me"
 
@@ -1826,6 +1828,7 @@ en:
         auto_publish_to_category: "This topic will be published to <a href=%{categoryUrl}>#%{categoryName}</a> %{timeLeft}."
         auto_close_based_on_last_post: "This topic will close %{duration} after the last reply."
         auto_delete: "This topic will be automatically deleted %{timeLeft}."
+        auto_bump: "This topic will be automatically bumped %{timeLeft}."
         auto_reminder: "You will be reminded about this topic %{timeLeft}."
       auto_close_title: 'Auto-Close Settings'
       auto_close_immediate:
diff --git a/spec/jobs/bump_topic_spec.rb b/spec/jobs/bump_topic_spec.rb
new file mode 100644
index 0000000..1f90d54
--- /dev/null
+++ b/spec/jobs/bump_topic_spec.rb
@@ -0,0 +1,35 @@
+require 'rails_helper'
+
+describe Jobs::BumpTopic do
+  let(:admin) { Fabricate(:admin) }
+  let(:user) { Fabricate(:user) }
+
+  it "can bump a topic" do
+    topic = Fabricate(:topic_timer, user: admin).topic
+    create_post(topic: topic)
+
+    freeze_time (2.hours.from_now)
+
+    expect do
+      described_class.new.execute(topic_timer_id: topic.public_topic_timer.id)
+    end.to change { topic.posts.count }.by (1)
+
+    expect(topic.reload.public_topic_timer).to eq(nil)
+  end
+
+  it "respects the guardian" do
+    topic = Fabricate(:topic_timer, user: user).topic
+    create_post(topic: topic)
+    topic.category = Fabricate(:private_category, group: Fabricate(:group))
+    topic.save!
+
+    freeze_time (2.hours.from_now)
+
+    expect do
+      described_class.new.execute(topic_timer_id: topic.public_topic_timer.id)
+    end.to change { topic.posts.count }.by (0)
+
+    expect(topic.reload.public_topic_timer).to eq(nil)
+  end
+
+end

GitHub
sha: 5bf16d7d