mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-07 15:53:29 +08:00
When the `set_topic_timer` automation script saves a `:close` or `:silent_close` timer on a topic that is already closed, `TopicTimer#after_save` treats that state mismatch as the "Open Temporarily" UI intent and immediately reopens the topic as the system user. Example seen on meta: an automation configured to add a 3-day close timer whenever the `fixed` tag is present and a bug post is edited was inadvertently reopening already-closed bug topics. Editing such a topic fired the automation, the `:close` timer was saved, and the topic was reopened by `system` before a moderator noticed and re-closed it. Guard `auto_close` and `auto_close_after_last_post` in the script with an early `next` when `topic.closed?` so the automation no-ops on closed topics rather than triggering the reopen side-effect.
172 lines
5 KiB
Ruby
172 lines
5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
describe "SetTopicTimer" do
|
|
fab!(:automation) do
|
|
Fabricate(
|
|
:automation,
|
|
script: DiscourseAutomation::Scripts::SET_TOPIC_TIMER,
|
|
trigger: DiscourseAutomation::Triggers::POST_CREATED_EDITED,
|
|
)
|
|
end
|
|
|
|
def configure_automation(type, duration)
|
|
automation.fields.create!(
|
|
component: "choices",
|
|
name: "type",
|
|
metadata: {
|
|
value: type,
|
|
},
|
|
target: "script",
|
|
)
|
|
automation.fields.create!(
|
|
component: "relative_time",
|
|
name: "duration",
|
|
metadata: {
|
|
value: duration,
|
|
},
|
|
target: "script",
|
|
)
|
|
end
|
|
|
|
before { SiteSetting.discourse_automation_enabled = true }
|
|
|
|
it "handles auto_close timer" do
|
|
configure_automation("auto_close", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer.status_type).to eq(TopicTimer.types[:close])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.based_on_last_post).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "skips auto_close timer when topic is already closed" do
|
|
configure_automation("auto_close", 60)
|
|
|
|
post =
|
|
PostCreator.new(Fabricate(:admin), raw: "my new topic", title: "Test topic for timer").create!
|
|
post.topic.update_status("closed", true, Discourse.system_user)
|
|
|
|
expect { PostRevisor.new(post).revise!(post.user, raw: "an edit") }.not_to change {
|
|
post.topic.reload.topic_timers.count
|
|
}
|
|
expect(post.topic.reload.closed).to eq(true)
|
|
end
|
|
|
|
it "skips auto_close_after_last_post timer when topic is already closed" do
|
|
configure_automation("auto_close_after_last_post", 60)
|
|
|
|
post =
|
|
PostCreator.new(Fabricate(:admin), raw: "my new topic", title: "Test topic for timer").create!
|
|
post.topic.update_status("closed", true, Discourse.system_user)
|
|
|
|
expect { PostRevisor.new(post).revise!(post.user, raw: "an edit") }.not_to change {
|
|
post.topic.reload.topic_timers.count
|
|
}
|
|
expect(post.topic.reload.closed).to eq(true)
|
|
end
|
|
|
|
it "handles auto_close_after_last_post timer" do
|
|
configure_automation("auto_close_after_last_post", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer.status_type).to eq(TopicTimer.types[:close])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.duration_minutes).to eq(60)
|
|
expect(timer.based_on_last_post).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "handles auto_delete timer" do
|
|
configure_automation("auto_delete", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer.status_type).to eq(TopicTimer.types[:delete])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.duration_minutes).to eq(nil)
|
|
expect(timer.based_on_last_post).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "handles auto_delete_replies timer" do
|
|
configure_automation("auto_delete_replies", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer.status_type).to eq(TopicTimer.types[:delete_replies])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.duration_minutes).to eq(60)
|
|
expect(timer.based_on_last_post).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "handles auto_delete_after_last_post timer" do
|
|
configure_automation("auto_delete_after_last_post", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer).not_to be_nil
|
|
expect(timer.status_type).to eq(TopicTimer.types[:delete])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.duration_minutes).to eq(60)
|
|
expect(timer.based_on_last_post).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "handles auto_bump timer" do
|
|
configure_automation("auto_bump", 60)
|
|
|
|
freeze_time do
|
|
post =
|
|
PostCreator.new(
|
|
Fabricate(:admin),
|
|
raw: "my new topic",
|
|
title: "Test topic for timer",
|
|
).create!
|
|
|
|
timer = post.topic.reload.topic_timers[0]
|
|
expect(timer.status_type).to eq(TopicTimer.types[:bump])
|
|
expect(timer.execute_at).to be_within(1.second).of(60.minutes.from_now)
|
|
expect(timer.duration_minutes).to eq(nil)
|
|
expect(timer.based_on_last_post).to eq(false)
|
|
end
|
|
end
|
|
end
|