diff --git a/app/assets/javascripts/discourse/controllers/edit-topic-status-update.js.es6 b/app/assets/javascripts/discourse/controllers/edit-topic-status-update.js.es6
index bde5384560e..f56b55dc93f 100644
--- a/app/assets/javascripts/discourse/controllers/edit-topic-status-update.js.es6
+++ b/app/assets/javascripts/discourse/controllers/edit-topic-status-update.js.es6
@@ -6,6 +6,7 @@ import { popupAjaxError } from 'discourse/lib/ajax-error';
export const CLOSE_STATUS_TYPE = 'close';
const OPEN_STATUS_TYPE = 'open';
const PUBLISH_TO_CATEGORY_STATUS_TYPE = 'publish_to_category';
+const DELETE_STATUS_TYPE = 'delete';
export default Ember.Controller.extend(ModalFunctionality, {
loading: false,
@@ -14,14 +15,18 @@ export default Ember.Controller.extend(ModalFunctionality, {
selection: Ember.computed.alias('model.topic_status_update.status_type'),
autoOpen: Ember.computed.equal('selection', OPEN_STATUS_TYPE),
autoClose: Ember.computed.equal('selection', CLOSE_STATUS_TYPE),
+ autoDelete: Ember.computed.equal('selection', DELETE_STATUS_TYPE),
publishToCategory: Ember.computed.equal('selection', PUBLISH_TO_CATEGORY_STATUS_TYPE),
+ showTimeOnly: Ember.computed.or('autoOpen', 'autoDelete'),
+
@computed("model.closed")
statusUpdates(closed) {
return [
{ id: CLOSE_STATUS_TYPE, name: I18n.t(closed ? 'topic.temp_open.title' : 'topic.auto_close.title'), },
{ id: OPEN_STATUS_TYPE, name: I18n.t(closed ? 'topic.auto_reopen.title' : 'topic.temp_close.title') },
- { id: PUBLISH_TO_CATEGORY_STATUS_TYPE, name: I18n.t('topic.publish_to_category.title') }
+ { id: PUBLISH_TO_CATEGORY_STATUS_TYPE, name: I18n.t('topic.publish_to_category.title') },
+ { id: DELETE_STATUS_TYPE, name: I18n.t('topic.auto_delete.title') }
];
},
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-topic-status-update.hbs b/app/assets/javascripts/discourse/templates/modal/edit-topic-status-update.hbs
index c1039fd9b42..6b40e09f039 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-topic-status-update.hbs
+++ b/app/assets/javascripts/discourse/templates/modal/edit-topic-status-update.hbs
@@ -5,7 +5,7 @@
- {{#if autoOpen}}
+ {{#if showTimeOnly}}
{{auto-update-input
input=updateTime
statusType=selection
diff --git a/app/jobs/regular/delete_topic.rb b/app/jobs/regular/delete_topic.rb
new file mode 100644
index 00000000000..83a37517f38
--- /dev/null
+++ b/app/jobs/regular/delete_topic.rb
@@ -0,0 +1,21 @@
+module Jobs
+ class DeleteTopic < Jobs::Base
+
+ def execute(args)
+ topic_status_update = TopicStatusUpdate.find_by(id: args[:topic_status_update_id])
+
+ topic = topic_status_update&.topic
+
+ if topic_status_update.blank? || topic.blank? ||
+ topic_status_update.execute_at > Time.zone.now
+ return
+ end
+
+ if Guardian.new(topic_status_update.user).can_delete?(topic)
+ first_post = topic.ordered_posts.first
+ PostDestroyer.new(topic_status_update.user, first_post, { context: I18n.t("topic_statuses.auto_deleted_by_timer") }).destroy
+ end
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/app/models/topic_status_update.rb b/app/models/topic_status_update.rb
index d5e59c67373..fae22a90181 100644
--- a/app/models/topic_status_update.rb
+++ b/app/models/topic_status_update.rb
@@ -35,7 +35,8 @@ class TopicStatusUpdate < ActiveRecord::Base
@types ||= Enum.new(
close: 1,
open: 2,
- publish_to_category: 3
+ publish_to_category: 3,
+ delete: 4
)
end
@@ -77,6 +78,10 @@ class TopicStatusUpdate < ActiveRecord::Base
Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_status_update_id: id)
end
+ def cancel_auto_delete_job
+ Jobs.cancel_scheduled_job(:delete_topic, topic_status_update_id: id)
+ end
+
def schedule_auto_open_job(time)
return unless topic
topic.update_status('closed', true, user) if !topic.closed
@@ -104,6 +109,10 @@ class TopicStatusUpdate < ActiveRecord::Base
def publishing_to_category?
self.status_type.to_i == TopicStatusUpdate.types[:publish_to_category]
end
+
+ def schedule_auto_delete_job(time)
+ Jobs.enqueue_at(time, :delete_topic, topic_status_update_id: id)
+ end
end
# == Schema Information
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 68853da6288..18f4ef79adb 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1524,12 +1524,15 @@ en:
label: "Auto-close topic hours:"
error: "Please enter a valid value."
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"
status_update_notice:
auto_open: "This topic will automatically open %{timeLeft}."
auto_close: "This topic will automatically close %{timeLeft}."
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_close_title: 'Auto-Close Settings'
auto_close_immediate:
one: "The last post in the topic is already 1 hour old, so the topic will be closed immediately."
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 4fa51fa6e77..8363974f390 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1656,6 +1656,7 @@ en:
pinned_globally_disabled: "This topic is now unpinned. It will no longer appear at the top of its category."
visible_enabled: "This topic is now listed. It will be displayed in topic lists."
visible_disabled: "This topic is now unlisted. It will no longer be displayed in any topic lists. The only way to access this topic is via direct link."
+ auto_deleted_by_timer: "Automatically deleted by timer."
login:
not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in."
diff --git a/spec/jobs/delete_topic_spec.rb b/spec/jobs/delete_topic_spec.rb
new file mode 100644
index 00000000000..aa820a44b1f
--- /dev/null
+++ b/spec/jobs/delete_topic_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+describe Jobs::DeleteTopic do
+ let(:admin) { Fabricate(:admin) }
+
+ let(:topic) do
+ Fabricate(:topic,
+ topic_status_updates: [Fabricate(:topic_status_update, user: admin)]
+ )
+ end
+
+ let(:first_post) { create_post(topic: topic) }
+
+ before do
+ SiteSetting.queue_jobs = true
+ end
+
+ it "can close a topic" do
+ first_post
+ Timecop.freeze(2.hours.from_now) do
+ described_class.new.execute(topic_status_update_id: topic.topic_status_update.id)
+ expect(topic.reload).to be_trashed
+ expect(first_post.reload).to be_trashed
+ end
+ end
+
+ it "should do nothing if topic is already deleted" do
+ first_post
+ topic.trash!
+ Timecop.freeze(2.hours.from_now) do
+ Topic.any_instance.expects(:trash!).never
+ described_class.new.execute(topic_status_update_id: topic.topic_status_update.id)
+ end
+ end
+
+ it "should do nothing if it's too early" do
+ t = Fabricate(:topic,
+ topic_status_updates: [Fabricate(:topic_status_update, user: admin, execute_at: 5.hours.from_now)]
+ )
+ create_post(topic: t)
+ Timecop.freeze(4.hours.from_now) do
+ described_class.new.execute(topic_status_update_id: t.topic_status_update.id)
+ expect(t.reload).to_not be_trashed
+ end
+ end
+
+ describe "user isn't authorized to delete topics" do
+ let(:topic) {
+ Fabricate(:topic,
+ topic_status_updates: [Fabricate(:topic_status_update, user: Fabricate(:user))]
+ )
+ }
+
+ it "shouldn't delete the topic" do
+ create_post(topic: topic)
+ Timecop.freeze(2.hours.from_now) do
+ described_class.new.execute(topic_status_update_id: topic.topic_status_update.id)
+ expect(topic.reload).to_not be_trashed
+ end
+ end
+ end
+
+end