From 07e7544f6923e4defa38bc840cda288bbd06d3ab Mon Sep 17 00:00:00 2001 From: Andrej Date: Thu, 16 May 2024 14:00:36 +0200 Subject: [PATCH] Implement quick search logic to work with boolean search [SCI-10707][SCI-10704] --- app/controllers/search_controller.rb | 15 +++--- .../concerns/searchable_by_name_model.rb | 14 ++++++ app/models/protocol.rb | 49 ++++++++++++------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 11450163c..be39a4b35 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -150,13 +150,16 @@ class SearchController < ApplicationController def object_quick_search(class_name) search_model = class_name.to_s.camelize.constantize - search_method = search_model.method(search_model.respond_to?(:code) ? :search_by_name_and_id : :search_by_name) + search_object_classes = ["#{class_name.pluralize}.name"] + search_object_classes << search_model::PREFIXED_ID_SQL if search_model.respond_to?(:code) - search_method.call(current_user, - current_team, - params[:query], - limit: Constants::QUICK_SEARCH_LIMIT) - .order(updated_at: :desc) + search_model.search_by_search_fields_with_boolean(current_user, + current_team, + params[:query], + search_object_classes, + limit: Constants::QUICK_SEARCH_LIMIT, + fetch_latest_versions: class_name == 'protocol') + .order(updated_at: :desc) end def load_vars diff --git a/app/models/concerns/searchable_by_name_model.rb b/app/models/concerns/searchable_by_name_model.rb index 6754f7691..a7d05a805 100644 --- a/app/models/concerns/searchable_by_name_model.rb +++ b/app/models/concerns/searchable_by_name_model.rb @@ -36,6 +36,20 @@ module SearchableByNameModel sql_q.limit(options[:limit] || Constants::SEARCH_LIMIT) end + + def self.search_by_search_fields_with_boolean(user, teams = [], query = nil, search_fields = [], options = {}) + return if user.blank? || teams.blank? + + sanitized_query = ActiveRecord::Base.sanitize_sql_like(query.to_s) + sql_q = if options[:fetch_latest_versions] + viewable_by_user(user, teams, options) + .where_attributes_like_boolean(search_fields, sanitized_query, options) + else + viewable_by_user(user, teams).where_attributes_like_boolean(search_fields, sanitized_query, options) + end + + sql_q.limit(options[:limit] || Constants::SEARCH_LIMIT) + end end # rubocop:enable Metrics/BlockLength end diff --git a/app/models/protocol.rb b/app/models/protocol.rb index 9d2f147be..2c826461c 100644 --- a/app/models/protocol.rb +++ b/app/models/protocol.rb @@ -178,12 +178,7 @@ class Protocol < ApplicationRecord end || [] protocol_my_modules = if options[:options]&.dig(:in_repository).blank? - protocols = distinct.joins(:my_module) - .joins("INNER JOIN user_assignments my_module_user_assignments " \ - "ON my_module_user_assignments.assignable_type = 'MyModule' " \ - "AND my_module_user_assignments.assignable_id = my_modules.id") - .where(my_module_user_assignments: { user_id: user }) - .where(team: teams) + protocols = viewable_by_user_my_module_protocols(user, teams) unless include_archived protocols = protocols.joins(my_module: { experiment: :project }) .active @@ -233,19 +228,37 @@ class Protocol < ApplicationRecord where('protocols.id IN ((?) UNION (?) UNION (?))', original_without_versions, published_versions, new_drafts) end - def self.viewable_by_user(user, teams) - # Team owners see all protocol templates in the team - owner_role = UserRole.find_predefined_owner_role - protocols = Protocol.where(team: teams) - .where(protocol_type: REPOSITORY_TYPES) - viewable_as_team_owner = protocols.joins("INNER JOIN user_assignments team_user_assignments " \ - "ON team_user_assignments.assignable_type = 'Team' " \ - "AND team_user_assignments.assignable_id = protocols.team_id") - .where(team_user_assignments: { user_id: user, user_role_id: owner_role }) - .select(:id) - viewable_as_assigned = protocols.with_granted_permissions(user, ProtocolPermissions::READ).select(:id) + def self.viewable_by_user(user, teams, options = {}) + if options[:fetch_latest_versions] + protocol_templates = latest_available_versions(teams) + .with_granted_permissions(user, ProtocolPermissions::READ) + .select(:id) + protocol_my_modules = viewable_by_user_my_module_protocols(user, teams).select(:id) - where('protocols.id IN ((?) UNION (?))', viewable_as_team_owner, viewable_as_assigned) + where('protocols.id IN ((?) UNION (?))', protocol_templates, protocol_my_modules) + else + # Team owners see all protocol templates in the team + owner_role = UserRole.find_predefined_owner_role + protocols = Protocol.where(team: teams) + .where(protocol_type: REPOSITORY_TYPES) + viewable_as_team_owner = protocols.joins("INNER JOIN user_assignments team_user_assignments " \ + "ON team_user_assignments.assignable_type = 'Team' " \ + "AND team_user_assignments.assignable_id = protocols.team_id") + .where(team_user_assignments: { user_id: user, user_role_id: owner_role }) + .select(:id) + viewable_as_assigned = protocols.with_granted_permissions(user, ProtocolPermissions::READ).select(:id) + + where('protocols.id IN ((?) UNION (?))', viewable_as_team_owner, viewable_as_assigned) + end + end + + def self.viewable_by_user_my_module_protocols(user, teams) + distinct.joins(:my_module) + .joins("INNER JOIN user_assignments my_module_user_assignments " \ + "ON my_module_user_assignments.assignable_type = 'MyModule' " \ + "AND my_module_user_assignments.assignable_id = my_modules.id") + .where(my_module_user_assignments: { user_id: user }) + .where(team: teams) end def self.filter_by_teams(teams = [])