0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-14 13:58:53 +08:00
discourse/app/services/upcoming_changes/toggle.rb
Martin Brennan dd8c16cbd6
FEATURE: Allow upcoming changes to control site setting defaults (#38815)
We often need to change site setting defaults when we
would like to change default behaviour for the Discourse software.
However, we want to be non-disruptive to existing sites, as
some default changes can modify the behaviour of existing features
quite a lot.

In the past, when we did this we would write the old default to the
database for anyone who hadn't changed the setting, and then change
it for new sites going forward. However in practice means that there
are large portions of Discourse sites with "bad" defaults that we
no longer agree with, that slows adoption of best practices and makes
it harder to reason about our different features.

This change adds a way for upcoming changes to control the rollout
of changes to site setting defaults via additional metadata attached
to the setting whose default is changing.

This way, we can have a more gradual rollout of new defaults, and we can
also inform site admins about the upcoming change and give them a chance
to opt in early if they want to.
2026-04-08 13:05:44 +10:00

81 lines
2.1 KiB
Ruby
Vendored

# frozen_string_literal: true
class UpcomingChanges::Toggle
include Service::Base
# For cases like the UpcomingChanges::Promote where we don't want to log
# the change again since it's already being logged there.
options { attribute :log_change, default: true }
params do
attribute :setting_name, :symbol
attribute :enabled, :boolean
validates :setting_name, presence: true
validates :enabled, inclusion: [true, false]
def upcoming_change_event
enabled ? :upcoming_change_enabled : :upcoming_change_disabled
end
end
policy :current_user_is_admin
policy :setting_is_available
transaction { step :toggle }
step :clear_groups_if_disallowed
only_if(:should_log_change) do
step :log_change
step :log_event
end
step :trigger_event
private
def current_user_is_admin(guardian:)
guardian.is_admin?
end
def setting_is_available(params:)
SiteSetting.respond_to?(params.setting_name)
end
def toggle(params:, guardian:, options:)
context[:previous_value] = SiteSetting.public_send(params.setting_name)
SiteSetting.send("#{params.setting_name}=", params.enabled)
end
def clear_groups_if_disallowed(params:)
metadata = SiteSetting.upcoming_change_metadata[params.setting_name]
return if !metadata || !metadata[:disallow_enabled_for_groups]
SiteSettingGroup.find_by(name: params.setting_name)&.destroy!
SiteSetting.refresh_site_setting_group_ids!
end
def should_log_change(options:)
options.log_change
end
def log_change(params:, guardian:, options:)
StaffActionLogger.new(guardian.user).log_upcoming_change_toggle(
params.setting_name,
context[:previous_value],
params.enabled,
{ context: I18n.t("staff_action_logs.upcoming_changes.log_manually_toggled") },
)
end
def log_event(params:, guardian:, options:)
UpcomingChangeEvent.create!(
event_type: params.enabled ? :manual_opt_in : :manual_opt_out,
upcoming_change_name: params.setting_name,
acting_user: guardian.user,
)
end
def trigger_event(params:)
DiscourseEvent.trigger(params.upcoming_change_event, params.setting_name)
end
end