0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 21:57:36 +08:00
discourse/app/services/upcoming_changes/notify_promotions.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

94 lines
3.2 KiB
Ruby
Vendored

# frozen_string_literal: true
# Notify admins of all upcoming changes' promotions,
# which is called from the Jobs::Scheduled::CheckUpcomingChanges job.
class UpcomingChanges::NotifyPromotions
include Service::Base
model :changes_already_notified_about_promotion, optional: true
model :changes_already_promoted, optional: true
model :admin_user_ids
model :change_notification_statuses
private
def fetch_changes_already_notified_about_promotion
UpcomingChangeEvent.change_names_with_event(:admins_notified_automatic_promotion)
end
def fetch_changes_already_promoted
UpcomingChangeEvent.change_names_with_event(:automatically_promoted)
end
def fetch_admin_user_ids
User.human_users.admins.pluck(:id)
end
def fetch_change_notification_statuses(
changes_already_notified_about_promotion:,
changes_already_promoted:,
admin_user_ids:
)
SiteSetting.upcoming_change_site_settings.index_with do |setting_name|
status_hash = {}
# NOTE: Make sure to handle additional error_key values in the
# CheckUpcomingChanges job's verbose_log.
UpcomingChanges::NotifyPromotion.call(
params: {
setting_name: setting_name.to_sym,
changes_already_notified_about_promotion:,
changes_already_promoted:,
admin_user_ids:,
},
guardian: Discourse.system_user.guardian,
) do |result|
status_hash[:success] = result.success?
on_failed_policy(:setting_is_available) do |policy|
status_hash[:error] = "Setting #{setting_name} is not available"
status_hash[:error_key] = :setting_not_available
end
on_failed_policy(:should_notify_admins) do |policy|
status_hash[:error] = "Setting #{setting_name} should not notify admins about promotion"
status_hash[:error_key] = :should_not_notify_admins
end
on_failed_policy(:change_should_be_displayed) do |policy|
status_hash[
:error
] = "Setting #{setting_name} is not displayed on this site, skipping promotion notification"
status_hash[:error_key] = :should_not_be_displayed
end
on_failed_policy(:meets_or_exceeds_status) do |policy|
status_hash[
:error
] = "Setting #{setting_name} does not meet or exceed the promotion status"
status_hash[:error_key] = :does_not_meet_or_exceed_promotion_status
end
on_failed_policy(:promotion_not_already_handled) do |policy|
status_hash[:error] = "Setting #{setting_name} has already been promoted"
status_hash[:error_key] = :already_promoted
end
on_failed_policy(:admin_has_not_manually_toggled) do |policy|
status_hash[
:error
] = "Setting #{setting_name} has been manually opted in or out by an admin, we did not notify admins about promotion"
status_hash[:error_key] = :already_manually_toggled
end
on_exceptions do |exception|
status_hash[:error] = exception.message
status_hash[:error_key] = :unexpected_error
status_hash[:backtrace] = exception.backtrace
end
end
status_hash
end
end
end