FEATURE: set a timer to delete a topic

This commit is contained in:
Neil Lalonde 2017-05-11 12:52:15 -04:00
parent 21238692d9
commit 1019bbda46
7 changed files with 105 additions and 3 deletions

View File

@ -6,6 +6,7 @@ import { popupAjaxError } from 'discourse/lib/ajax-error';
export const CLOSE_STATUS_TYPE = 'close'; export const CLOSE_STATUS_TYPE = 'close';
const OPEN_STATUS_TYPE = 'open'; const OPEN_STATUS_TYPE = 'open';
const PUBLISH_TO_CATEGORY_STATUS_TYPE = 'publish_to_category'; const PUBLISH_TO_CATEGORY_STATUS_TYPE = 'publish_to_category';
const DELETE_STATUS_TYPE = 'delete';
export default Ember.Controller.extend(ModalFunctionality, { export default Ember.Controller.extend(ModalFunctionality, {
loading: false, loading: false,
@ -14,14 +15,18 @@ export default Ember.Controller.extend(ModalFunctionality, {
selection: Ember.computed.alias('model.topic_status_update.status_type'), selection: Ember.computed.alias('model.topic_status_update.status_type'),
autoOpen: Ember.computed.equal('selection', OPEN_STATUS_TYPE), autoOpen: Ember.computed.equal('selection', OPEN_STATUS_TYPE),
autoClose: Ember.computed.equal('selection', CLOSE_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), publishToCategory: Ember.computed.equal('selection', PUBLISH_TO_CATEGORY_STATUS_TYPE),
showTimeOnly: Ember.computed.or('autoOpen', 'autoDelete'),
@computed("model.closed") @computed("model.closed")
statusUpdates(closed) { statusUpdates(closed) {
return [ return [
{ id: CLOSE_STATUS_TYPE, name: I18n.t(closed ? 'topic.temp_open.title' : 'topic.auto_close.title'), }, { 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: 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') }
]; ];
}, },

View File

@ -5,7 +5,7 @@
</div> </div>
<div> <div>
{{#if autoOpen}} {{#if showTimeOnly}}
{{auto-update-input {{auto-update-input
input=updateTime input=updateTime
statusType=selection statusType=selection

View File

@ -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

View File

@ -35,7 +35,8 @@ class TopicStatusUpdate < ActiveRecord::Base
@types ||= Enum.new( @types ||= Enum.new(
close: 1, close: 1,
open: 2, open: 2,
publish_to_category: 3 publish_to_category: 3,
delete: 4
) )
end end
@ -77,6 +78,10 @@ class TopicStatusUpdate < ActiveRecord::Base
Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_status_update_id: id) Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_status_update_id: id)
end end
def cancel_auto_delete_job
Jobs.cancel_scheduled_job(:delete_topic, topic_status_update_id: id)
end
def schedule_auto_open_job(time) def schedule_auto_open_job(time)
return unless topic return unless topic
topic.update_status('closed', true, user) if !topic.closed topic.update_status('closed', true, user) if !topic.closed
@ -104,6 +109,10 @@ class TopicStatusUpdate < ActiveRecord::Base
def publishing_to_category? def publishing_to_category?
self.status_type.to_i == TopicStatusUpdate.types[:publish_to_category] self.status_type.to_i == TopicStatusUpdate.types[:publish_to_category]
end end
def schedule_auto_delete_job(time)
Jobs.enqueue_at(time, :delete_topic, topic_status_update_id: id)
end
end end
# == Schema Information # == Schema Information

View File

@ -1524,12 +1524,15 @@ en:
label: "Auto-close topic hours:" label: "Auto-close topic hours:"
error: "Please enter a valid value." 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." 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: status_update_notice:
auto_open: "This topic will automatically open %{timeLeft}." auto_open: "This topic will automatically open %{timeLeft}."
auto_close: "This topic will automatically close %{timeLeft}." auto_close: "This topic will automatically close %{timeLeft}."
auto_publish_to_category: "This topic will be published to <a href=%{categoryUrl}>#%{categoryName}</a> %{timeLeft}." 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_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_title: 'Auto-Close Settings'
auto_close_immediate: auto_close_immediate:
one: "The last post in the topic is already 1 hour old, so the topic will be closed immediately." one: "The last post in the topic is already 1 hour old, so the topic will be closed immediately."

View File

@ -1656,6 +1656,7 @@ en:
pinned_globally_disabled: "This topic is now unpinned. It will no longer appear at the top of its category." 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_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." 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: login:
not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in." not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in."

View File

@ -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