FEATURE: set a timer to delete a topic
This commit is contained in:
parent
21238692d9
commit
1019bbda46
|
@ -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') }
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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."
|
||||||
|
|
|
@ -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."
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue