0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-07 13:19:19 +08:00
discourse/app/services/upcoming_changes/action/backfill_notified_events.rb
Martin Brennan 4de06a006b
FIX: Do not notify new sites or plugins enabled of old upcoming changes (#42045)
For upcoming changes, we were having a problem where we
were notifying admins of upcoming changes in brand new sites.
A previous fix 2e5afb46e2f5c0547bc298b2bd1a9c39e813dc17 tried
to remedy this, but since it relies on the `new_site?` method, which
isn't true after 1 hour, the next time the scheduled notifications are
run for an admin they will be sent them even if their site is relatively
new.

This commit attempts to conclusively fix the issue by inserting
upcoming change `admins_notified_automatic_promotion` and
`admins_notified_available_change` events via `BackfillNotifiedEvents`
for changes that exist in particular statuses when the site is first
created. These events will have `event_data: {"backfilled" => true}`
to distinguish them from others.

It also fixes an adjacent issue where an admin was notified of a
plugin's upcoming changes as soon as they enable the plugin,
which isn't useful as the intent of upcoming changes is to notify
of changes for things the admin has already been using.

**Before this change, on brand new site with current upcoming change
state**

<img width="401" height="429" alt="image"
src="https://github.com/user-attachments/assets/a89cd641-59aa-4c48-a57c-9692021df176"
/>

**After this change**

No notification to show :) But when I moved an upcoming change to `beta`
it showed
the notification for the enabled upcoming change correctly:

<img width="378" height="174" alt="image"
src="https://github.com/user-attachments/assets/20e4096f-e83f-4c06-970d-a9b43561b12e"
/>
2026-07-30 09:51:08 +10:00

74 lines
2.4 KiB
Ruby
Vendored

# frozen_string_literal: true
# Marks upcoming changes as "already notified about", so admins are never told
# about a back-catalogue of changes that pre-dates them being able to act on it.
#
# Called at the two points where a site gains a set of upcoming changes it was
# never in a position to hear about:
#
# * Site creation (db/fixtures/995_upcoming_changes.rb)
# * A plugin being enabled (config/initializers/015-track-upcoming-change-toggle.rb),
# since a disabled plugin's settings are still registered, and therefore its
# changes are only held back by ConditionalDisplay, not by the audit trail.
#
# Only changes that are *notifiable right now* are marked. A change still sitting
# below the notification threshold is left alone, so it notifies normally when it
# later reaches that threshold -- the site genuinely pre-dates that milestone.
#
# Deliberately does not write `automatically_promoted` or fire
# :upcoming_change_enabled. Promotion still has to happen for real (see
# UpcomingChanges::NotifyPromotion) -- it is only the notification we suppress.
class UpcomingChanges::Action::BackfillNotifiedEvents < Service::ActionBase
option :upcoming_change_names, default: -> { SiteSetting.upcoming_change_site_settings }
def call
return [] if upcoming_change_names.blank?
UpcomingChangeEvent.insert_all(
event_records_to_insert,
unique_by: :idx_upcoming_change_events_unique_once_off,
)
upcoming_change_names
end
private
def event_records_to_insert
now = Time.zone.now
upcoming_change_names.flat_map do |change_name|
event_types_for(change_name).map do |event_type|
{
event_type: UpcomingChangeEvent.event_types[event_type],
event_data: {
backfilled: true,
},
upcoming_change_name: change_name,
created_at: now,
updated_at: now,
}
end
end
end
def event_types_for(change_name)
event_types = [:added]
if UpcomingChanges.meets_or_exceeds_status?(change_name, promote_status)
event_types << :admins_notified_automatic_promotion
elsif UpcomingChanges.meets_or_exceeds_status?(change_name, available_status)
event_types << :admins_notified_available_change
end
event_types
end
def promote_status
@promote_status ||= SiteSetting.promote_upcoming_changes_on_status.to_sym
end
def available_status
@available_status ||= UpcomingChanges.previous_status(promote_status)
end
end