mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-27 18:59:19 +08:00
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"
130 lines
4 KiB
Ruby
Vendored
130 lines
4 KiB
Ruby
Vendored
# 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
|
|
policy :should_notify_admins
|
|
|
|
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.setting_modified_from_default?(params.setting_name)
|
|
end
|
|
|
|
def should_notify_admins(params:)
|
|
UpcomingChanges.should_notify_admins?
|
|
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_data: existing_by_user[admin_id]&.data,
|
|
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
|