mirror of
https://github.com/discourse/discourse.git
synced 2026-03-04 01:15:08 +08:00
We notify admins both when an upcoming change is available for preview (at promotion status - 1) and when an upcoming change is automatically promoted. There are cases where multiple changes might be deployed at the same time, and we want to avoid sending multiple notifications to admins in a short period of time. This PR consolidates the notifications for both events into a single notification that includes all relevant changes. So for new upcoming changes, admins will receive a single notification that lists all the changes that are now available for preview. For automatic promotions, admins will receive a single notification that lists all the changes that were automatically promoted. In addition, this PR follows up on https://github.com/discourse/discourse/pull/38051 and directly links the notifications to a filtered list of upcoming changes by setting name. <img width="338" alt="image" src="https://github.com/user-attachments/assets/6febc7d7-0122-4f3b-8cbe-04d03721a709" /> <img width="332" alt="image" src="https://github.com/user-attachments/assets/46f2f886-8a6f-46f5-8038-bce3305d788f" /> ### Testing * Start with a fresh DB * Make sure `upcoming_change_verbose_logging` and `enable_upcoming_changes` are true * Choose a couple of upcoming changes and update their statuses in `site_settings.yml` to `beta` * Log in to the site and go to http://localhost:4200/sidekiq/scheduler and find the CheckUpcomingChanges job and run it * You should receive a notification for the changes becoming available, do not read the notification * Change another upcoming change to beta and run the job again * You should not get another notification, the third change should be merged into the first notification * Now update some of the same changes to `stable` status * Run the job again * You should get a new notification saying the changes were automatically enabled * Now update another of the same changes to `stable` status * You should not get another notification, the third change should be merged into the notification for enabled changes --------- Co-authored-by: awesomerobot <kris.aubuchon@discourse.org>
125 lines
3.8 KiB
Ruby
125 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Notify admins of a specific upcoming change's promotion,
|
|
# which occurs when the change has reached the promotion status
|
|
# defined by SiteSetting.promote_upcoming_changes_on_status.
|
|
#
|
|
# Since the site setting is not actually changed in the database
|
|
# when an upcoming change is automatically promoted, we also
|
|
# fire off a DiscourseEvent that developers can listen to
|
|
# in 015-track-upcoming-change-toggle.rb.
|
|
#
|
|
# Admins will only be notified once for each upcoming change,
|
|
# both via a staff action log and a Notification in the UI.
|
|
# We don't need to notify admins if they have manually opted in
|
|
# or out of the change, since that overrides the automatic promotion.
|
|
class UpcomingChanges::NotifyPromotion
|
|
include Service::Base
|
|
|
|
params do
|
|
attribute :setting_name, :symbol
|
|
attribute :admin_user_ids, :array
|
|
attribute :changes_already_notified_about_promotion, :array, default: []
|
|
|
|
validates :setting_name, presence: true
|
|
validates :admin_user_ids, presence: true
|
|
end
|
|
|
|
policy :setting_is_available
|
|
policy :meets_or_exceeds_status
|
|
policy :change_has_not_already_been_notified_about_promotion
|
|
policy :admin_has_not_manually_toggled
|
|
|
|
try do
|
|
step :log_promotion
|
|
model :existing_notifications, optional: true
|
|
model :bulk_notification_new_records
|
|
step :notify_admins
|
|
step :create_event
|
|
step :trigger_discourse_event
|
|
end
|
|
|
|
private
|
|
|
|
def setting_is_available(params:)
|
|
SiteSetting.respond_to?(params.setting_name)
|
|
end
|
|
|
|
def meets_or_exceeds_status(params:)
|
|
UpcomingChanges.meets_or_exceeds_status?(
|
|
params.setting_name,
|
|
SiteSetting.promote_upcoming_changes_on_status.to_sym,
|
|
)
|
|
end
|
|
|
|
def change_has_not_already_been_notified_about_promotion(params:)
|
|
!params.changes_already_notified_about_promotion.include?(params.setting_name)
|
|
end
|
|
|
|
def admin_has_not_manually_toggled(params:)
|
|
!SiteSetting.modified.key?(params.setting_name)
|
|
end
|
|
|
|
def log_promotion(params:, guardian:)
|
|
context =
|
|
I18n.t(
|
|
"staff_action_logs.upcoming_changes.log_promoted",
|
|
change_status: UpcomingChanges.change_status(params.setting_name).to_s.titleize,
|
|
base_path: Discourse.base_path,
|
|
)
|
|
|
|
StaffActionLogger.new(Discourse.system_user).log_upcoming_change_toggle(
|
|
params.setting_name,
|
|
false,
|
|
true,
|
|
{ context: },
|
|
)
|
|
end
|
|
|
|
def fetch_existing_notifications(params:)
|
|
Notification.where(
|
|
notification_type: Notification.types[:upcoming_change_automatically_promoted],
|
|
user_id: params.admin_user_ids,
|
|
read: false,
|
|
)
|
|
end
|
|
|
|
def fetch_bulk_notification_new_records(params:, existing_notifications:)
|
|
existing_by_user = existing_notifications.to_a.index_by(&:user_id)
|
|
params.admin_user_ids.map do |admin_id|
|
|
{
|
|
user_id: admin_id,
|
|
notification_type: Notification.types[:upcoming_change_automatically_promoted],
|
|
data:
|
|
UpcomingChanges::Action::NotificationDataMerger.call(
|
|
existing_notification: existing_by_user[admin_id],
|
|
new_change_name: params.setting_name,
|
|
).to_json,
|
|
}
|
|
end
|
|
end
|
|
|
|
def notify_admins(params:, bulk_notification_new_records:, existing_notifications:)
|
|
merge_with_existing = existing_notifications.to_a.any?
|
|
|
|
Notification.transaction do
|
|
existing_notifications.delete_all if merge_with_existing
|
|
Notification::Action::BulkCreate.call(
|
|
records: bulk_notification_new_records,
|
|
skip_send_email: merge_with_existing,
|
|
)
|
|
end
|
|
end
|
|
|
|
def create_event(params:)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :admins_notified_automatic_promotion,
|
|
upcoming_change_name: params.setting_name,
|
|
acting_user: Discourse.system_user,
|
|
)
|
|
end
|
|
|
|
def trigger_discourse_event(params:)
|
|
DiscourseEvent.trigger(:upcoming_change_enabled, params.setting_name)
|
|
end
|
|
end
|