From 02d20404bd88fea60fd35d93b4de49eb317ceb7d Mon Sep 17 00:00:00 2001 From: Girija Soni Date: Thu, 31 Aug 2023 19:25:09 +0530 Subject: [PATCH] Fixes #36711 - Add search by description in settings --- app/controllers/api/v2/settings_controller.rb | 1 - app/models/setting.rb | 8 ++- app/services/setting_registry.rb | 62 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v2/settings_controller.rb b/app/controllers/api/v2/settings_controller.rb index 1452c61a2a54..d562cba972c9 100644 --- a/app/controllers/api/v2/settings_controller.rb +++ b/app/controllers/api/v2/settings_controller.rb @@ -22,7 +22,6 @@ class SettingsController < V2::BaseController api :GET, "/settings/", N_("List all settings") param_group :search_and_pagination, ::Api::V2::BaseController - add_scoped_search_description_for(Setting) returns desc: N_('List of all settings') do property :results, Array end diff --git a/app/models/setting.rb b/app/models/setting.rb index 84ba764e21ba..e87b85480731 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -54,9 +54,7 @@ def validate(record) scope :order_by, ->(attr) { except(:order).order(attr) } - scoped_search :on => :id, :complete_enabled => false, :only_explicit => true, :validator => ScopedSearch::Validators::INTEGER - scoped_search on: :name, complete_value: :true, operators: ['=', '~'] - + delegate :settings_type, :encrypted, :encrypted?, :default, to: :setting_definition, allow_nil: true def self.config_file @@ -68,6 +66,10 @@ def self.per_page 20 end + def self.complete_for(search_query, opts = {}) + Foreman.settings.complete_for(search_query, opts) + end + def self.[](name) Foreman.settings[name] end diff --git a/app/services/setting_registry.rb b/app/services/setting_registry.rb index a393e0d0a3a4..c76fea41795b 100644 --- a/app/services/setting_registry.rb +++ b/app/services/setting_registry.rb @@ -1,6 +1,68 @@ class SettingRegistry include Singleton include Enumerable + extend ScopedSearch::ClassMethods + + class SettingCompleter < ScopedSearch::AutoCompleteBuilder + def initialize(registry, definition, query, options) + @registry = registry + super(definition, query, options) + end + + def self.auto_complete(registry, definition, query, options) + return [] if (query.nil? || definition.nil? || !definition.respond_to?(:fields)) + + new(registry, definition, query, options).build_autocomplete_options + end + + def is_query_valid + return if (last_token_is(NULL_PREFIX_OPERATORS, 2) && !(query =~ /(\s|\)|,)$/)) + true + end + + def complete_value + if last_token_is(COMPARISON_OPERATORS) + token = tokens[tokens.size - 2] + val = '' + else + token = tokens[tokens.size - 3] + val = tokens[tokens.size - 1] + end + + field = definition.field_by_name(token) + return [] unless field&.complete_value + return complete_set(field) if field.set? + return complete_key_value(field, token, val) if field.key_field + + special_values = field.special_values.select { |v| v =~ /\A#{val}/ } + special_values + complete_value_from_db(field, special_values, val) + end + + def complete_key(name, field, val) + raise ::Foreman::Exception.new N_('Unsupported completion, only name and description are supported') + end + + def complete_value_from_db(field, special_values, val) + count = 20 - special_values.count + if field.field == :name + results = @registry.map { |set| set.full_name if set.name.starts_with?(val) || set.full_name&.starts_with?(val) } + elsif field.field == :description + results = @registry.map { |set| set.description if set.description.starts_with?(val) } + else + raise ::Foreman::Exception.new N_('Unsupported completion, only name and description are supported') + end + + results.first(count) + end + end + + scoped_search :on => :id, :complete_enabled => false, :only_explicit => true, :validator => ScopedSearch::Validators::INTEGER + scoped_search on: :name, complete_value: :true, operators: ['~'] + scoped_search on: :description, complete_value: :true, operators: ['~'] + + def complete_for(query, opts = {}) + SettingCompleter.auto_complete(self, scoped_search_definition, query, opts) + end def self.subset_registry(subset) new(subset)