mirror of
https://github.com/discourse/discourse.git
synced 2024-12-14 14:13:45 +08:00
30990006a9
This reduces chances of errors where consumers of strings mutate inputs and reduces memory usage of the app. Test suite passes now, but there may be some stuff left, so we will run a few sites on a branch prior to merging
153 lines
4.2 KiB
Ruby
153 lines
4.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
TopicStatusUpdater = Struct.new(:topic, :user) do
|
|
def update!(status, enabled, opts = {})
|
|
status = Status.new(status, enabled)
|
|
|
|
@topic_status_update = topic.public_topic_timer
|
|
|
|
updated = nil
|
|
Topic.transaction do
|
|
updated = change(status, opts)
|
|
if updated
|
|
highest_post_number = topic.highest_post_number
|
|
create_moderator_post_for(status, opts[:message])
|
|
update_read_state_for(status, highest_post_number)
|
|
end
|
|
end
|
|
|
|
updated
|
|
end
|
|
|
|
private
|
|
|
|
def change(status, opts = {})
|
|
result = true
|
|
|
|
if status.pinned? || status.pinned_globally?
|
|
topic.update_pinned(status.enabled?, status.pinned_globally?, opts[:until])
|
|
elsif status.autoclosed?
|
|
rc = Topic.where(id: topic.id, closed: !status.enabled?).update_all(closed: status.enabled?)
|
|
topic.closed = status.enabled?
|
|
result = false if rc == 0
|
|
else
|
|
rc = Topic.where(:id => topic.id, status.name => !status.enabled)
|
|
.update_all(status.name => status.enabled?)
|
|
|
|
topic.public_send("#{status.name}=", status.enabled?)
|
|
result = false if rc == 0
|
|
end
|
|
|
|
if status.manually_closing_topic?
|
|
DiscourseEvent.trigger(:topic_closed, topic)
|
|
end
|
|
|
|
if @topic_status_update
|
|
if status.manually_closing_topic? || status.closing_topic?
|
|
topic.delete_topic_timer(TopicTimer.types[:close])
|
|
elsif status.manually_opening_topic? || status.opening_topic?
|
|
topic.delete_topic_timer(TopicTimer.types[:open])
|
|
end
|
|
end
|
|
|
|
# remove featured topics if we close/archive/make them invisible. Previously we used
|
|
# to run the whole featuring logic but that could be very slow and have concurrency
|
|
# errors on large sites with many autocloses and topics being created.
|
|
if ((status.enabled? && (status.autoclosed? || status.closed? || status.archived?)) ||
|
|
(status.disabled? && status.visible?))
|
|
CategoryFeaturedTopic.where(topic_id: topic.id).delete_all
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
def create_moderator_post_for(status, message = nil)
|
|
topic.add_moderator_post(user, message || message_for(status), options_for(status))
|
|
topic.reload
|
|
end
|
|
|
|
def update_read_state_for(status, old_highest_read)
|
|
if status.autoclosed? && status.enabled?
|
|
# let's pretend all the people that read up to the autoclose message
|
|
# actually read the topic
|
|
PostTiming.pretend_read(topic.id, old_highest_read, topic.highest_post_number)
|
|
end
|
|
end
|
|
|
|
def message_for(status)
|
|
if status.autoclosed?
|
|
locale_key = status.locale_key.dup
|
|
locale_key << "_lastpost" if @topic_status_update&.based_on_last_post
|
|
message_for_autoclosed(locale_key)
|
|
end
|
|
end
|
|
|
|
def message_for_autoclosed(locale_key)
|
|
num_minutes =
|
|
if @topic_status_update&.based_on_last_post
|
|
@topic_status_update.duration.hours
|
|
elsif @topic_status_update&.created_at
|
|
Time.zone.now - @topic_status_update.created_at
|
|
else
|
|
Time.zone.now - topic.created_at
|
|
end
|
|
|
|
num_minutes = (num_minutes / 1.minute).round
|
|
|
|
if num_minutes.minutes >= 2.days
|
|
I18n.t("#{locale_key}_days", count: (num_minutes.minutes / 1.day).round)
|
|
else
|
|
num_hours = (num_minutes.minutes / 1.hour).round
|
|
if num_hours >= 2
|
|
I18n.t("#{locale_key}_hours", count: num_hours)
|
|
else
|
|
I18n.t("#{locale_key}_minutes", count: num_minutes)
|
|
end
|
|
end
|
|
end
|
|
|
|
def options_for(status)
|
|
{ bump: status.opening_topic?,
|
|
post_type: Post.types[:small_action],
|
|
action_code: status.action_code }
|
|
end
|
|
|
|
Status = Struct.new(:name, :enabled) do
|
|
%w(pinned_globally pinned autoclosed closed visible archived).each do |status|
|
|
define_method("#{status}?") { name == status }
|
|
end
|
|
|
|
def enabled?
|
|
enabled
|
|
end
|
|
|
|
def disabled?
|
|
!enabled?
|
|
end
|
|
|
|
def action_code
|
|
"#{name}.#{enabled? ? 'enabled' : 'disabled'}"
|
|
end
|
|
|
|
def locale_key
|
|
"topic_statuses.#{action_code.tr('.', '_')}"
|
|
end
|
|
|
|
def opening_topic?
|
|
(closed? || autoclosed?) && disabled?
|
|
end
|
|
|
|
def closing_topic?
|
|
(closed? || autoclosed?) && enabled?
|
|
end
|
|
|
|
def manually_closing_topic?
|
|
closed? && enabled?
|
|
end
|
|
|
|
def manually_opening_topic?
|
|
closed? && disabled?
|
|
end
|
|
end
|
|
end
|