discourse/app/services/upcoming_changes/list.rb
Martin Brennan dcf6da9cef
UX: Allow more specific enabled for options for upcoming changes (#39916)
Certain upcoming changes do not make sense to enable for "Everyone",
like changes that will only affect the admin UI. We currently have
a disallow_enabled_for_groups option that changes the "Enabled for"
dropdown to only show Everyone and No one, but this is a bit of a blunt
instrument.

This change adds an `allow_enabled_for` option for upcoming changes
which is a YAML array:

* When omitted, the "Enabled for" dropdown will show Everyone, Staff,
Specific group(s) and No one.
* When set to everyone, the dropdown will only show Everyone and No one.
* When set to staff, the dropdown will only show Staff and No one.
* It can also be set to staff and specific_groups

This commit also changes the reporting_improvements upcoming change
to be staff, specific_groups and adds a DB migration to account for
this.
2026-05-13 10:22:06 +10:00

105 lines
3.1 KiB
Ruby
Vendored

# frozen_string_literal: true
class UpcomingChanges::List
include Service::Base
options { attribute :filter_statuses, :array, default: [] }
policy :current_user_is_admin
model :upcoming_changes, optional: true
step :load_upcoming_change_groups
step :sort_changes
step :update_last_visited
private
def current_user_is_admin(guardian:)
guardian.is_admin?
end
def fetch_upcoming_changes(options:)
SiteSetting
.all_settings(
only_upcoming_changes: true,
include_hidden: true,
include_locale_setting: false,
)
.select do |setting|
if options.filter_statuses.any?
options
.filter_statuses
.map(&:to_sym)
.include?(UpcomingChanges.change_status(setting[:setting]))
else
true
end
end
.select { |setting| UpcomingChanges::ConditionalDisplay.should_display?(setting[:setting]) }
.each do |setting|
setting[:value] = setting[:value] == "true"
if UpcomingChanges.image_exists?(setting[:setting])
setting[:upcoming_change][:image] = UpcomingChanges.image_data(setting[:setting])
end
if setting[:plugin]
plugin = Discourse.plugins_by_name[setting[:plugin]]
# NOTE (martin) Maybe later we add a URL or something? Not sure.
# Then the plugin name could be clicked in the UI
setting[:plugin] = plugin.humanized_name
end
end
.map do |setting|
# We don't need to return all the other setting metadata for
# endpoints that use this.
setting.slice(
:setting,
:humanized_name,
:description,
:value,
:upcoming_change,
:plugin,
).merge(
dependents: UpcomingChanges.find_dependents_for_change(setting[:setting]),
overriding_defaults:
SiteSetting.upcoming_change_default_overrides.values.any? do |override|
override[:upcoming_change] == setting[:setting]
end,
)
end
end
def load_upcoming_change_groups(upcoming_changes:)
group_ids =
(
upcoming_changes.flat_map do |change|
SiteSetting.site_setting_group_ids[change[:setting]]
end + [Group::AUTO_GROUPS[:staff]]
).compact.uniq
groups = Group.where(id: group_ids).pluck(:id, :name).to_h
upcoming_changes.each do |setting|
enabled_for, setting_groups =
UpcomingChanges.enabled_for_with_groups(
setting[:setting],
setting[:value],
groups,
).values_at(:enabled_for, :setting_groups)
setting[:upcoming_change][:enabled_for] = enabled_for
setting[:groups] = setting_groups
end
end
def sort_changes(upcoming_changes:)
context[:upcoming_changes] = upcoming_changes.sort_by { |change| change[:setting] }
end
def update_last_visited(guardian:)
return if guardian.user.is_system_user? || guardian.user.bot?
guardian.user.custom_fields["last_visited_upcoming_changes_at"] = Time.current.iso8601
guardian.user.save_custom_fields
end
end