0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-09 21:45:25 +08:00
discourse/app/services/upcoming_changes/action/track_status_changes.rb
Martin Brennan 02edc8a05b
FEATURE: Change upcoming change available notification cadence (#40157)
Since we have been using the upcoming change system
more heavily, we noticed that notifications for available changes
(i.e. changes that have been added at promotion status - 1 OR
changes that recently reached promotion status - 1) are crowding
the admin's notifications a lot.

To address this, we already allowed admins to opt out of these
in 0c46a2e805 . However, we also
want to reduce the cadence of these notifications for admins who do want
to opt out completely.

This commit changes upcoming change available notifications to be
collected & sent in a weekly job, rather than in the job that runs
every 20 minutes & logs added/status changed events.

This weekly job will also handle consolidating existing unread upcoming
change available notifications, and making sure that we do not send
N new notifications per change when an admin has no existing unread
notification.

Upcoming change promoted notifications will still happen "instantly"
2026-05-25 09:38:33 +10:00

88 lines
2.6 KiB
Ruby
Vendored

# frozen_string_literal: true
# Intended to be called from UpcomingChanges::Track service,
# not standalone.
#
# Lookup any previous event_type: status_changed (5) events for the change
# * If there are none, create one for the current status
class UpcomingChanges::Action::TrackStatusChanges < Service::ActionBase
# Every admin user that are not bots
option :all_admins
# All changes that were added at the same time, we
# create a special status changed event for these with
# no previous value.
option :added_changes
# All changes that were removed at the same time, we don't care about
# their statuses anymore.
option :removed_changes
def call
status_changes = {}
SiteSetting.upcoming_change_site_settings.each do |change_name|
if no_previous_status_event?(change_name)
UpcomingChangeEvent.create!(
event_type: :status_changed,
upcoming_change_name: change_name,
event_data: {
previous_value: nil,
new_value: UpcomingChanges.change_status(change_name),
},
)
status_changes[change_name] = {
previous_value: "N/A",
new_value: UpcomingChanges.change_status(change_name),
}
next
end
next if added_changes.include?(change_name)
next if removed_changes.include?(change_name)
previous_status = previous_status_for(change_name)
current_status = UpcomingChanges.change_status(change_name)
if status_changed?(previous_status, current_status)
UpcomingChangeEvent.create!(
event_type: :status_changed,
upcoming_change_name: change_name,
event_data: {
previous_value: previous_status,
new_value: current_status,
},
)
status_changes[change_name] = { previous_value: previous_status, new_value: current_status }
end
end
UpcomingChanges.clear_caches!
DiscourseUpdates.clear_latest_new_feature_created_at_cache
status_changes
end
private
def previous_status_events
@previous_status_events ||= UpcomingChangeEvent.status_changed.to_a
end
def no_previous_status_event?(change_name)
previous_status_events.none? { |event| event.upcoming_change_name == change_name.to_s }
end
def previous_status_for(change_name)
previous_status_events
.select { |event| event.upcoming_change_name == change_name.to_s }
.last
.event_data[
"new_value"
]
end
def status_changed?(previous_status, current_status)
previous_status&.to_sym != current_status
end
end