From 5bf16d7d107fa8c5654f56e83a3b72e6005bf1c6 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 4 Jan 2019 13:08:04 +0000 Subject: [PATCH] FEATURE: Topic timer for bumping a topic in the future --- .../components/edit-topic-timer-form.js.es6 | 11 ++++-- .../controllers/edit-topic-timer.js.es6 | 5 +++ app/jobs/regular/bump_topic.rb | 20 +++++++++++ app/models/topic_timer.rb | 11 +++++- config/locales/client.en.yml | 3 ++ spec/jobs/bump_topic_spec.rb | 35 +++++++++++++++++++ 6 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 app/jobs/regular/bump_topic.rb create mode 100644 spec/jobs/bump_topic_spec.rb 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 d231539ccf2..e343187acb0 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 205bc1e6ef6..5b7dec66a1c 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 00000000000..f4e21937541 --- /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 e884f33aded..c8229bcca4c 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 15b5420da12..979520d084f 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 #%{categoryName} %{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 00000000000..1f90d54db2b --- /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