canvas-lms/lib/user_search.rb

88 lines
2.9 KiB
Ruby
Raw Normal View History

user searching module refs #CNVS-2326 Added a UserSearch module that provides and interface for searching across the name, the email, and the sis id (and the database id), and added a trigram index on the columns that will be searched against. also made a slight refactor to the AR initializer in order to expose some of the behavior I wanted more granularly and added some specs to cover it fixed a small permissions bug in course.rb and pulled some scoping out of the courses controller down into the user search module TEST PLAN: This is currently not accessible from the site itself, this is just the ground work for the eventual user search api endpoint. The code is not called by anything currently in production either so there is no need for regression testing. The one thing to check would be the creation of new users (and pseudonyms and communication channels). There have been new indexes added to columns on those tables and there is some documentation indicating that writing to these indexes can be time consuming if the data set is quite large. It would be worth making sure that there have not been any unacceptable performance regressions in the creation of any of those record types in a database that has a full load of data (comparable to the production environment) Change-Id: I8fb13a6ec714f27efc8012c5ed2bed4d963c24e6 Reviewed-on: https://gerrit.instructure.com/16459 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Clare Hetherington <clare@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
2012-12-29 03:28:09 +08:00
module UserSearch
def self.for_user_in_course(search_term, course, searcher, options = {})
limit = options.fetch(:limit, 20)
base_scope = scope_for(course, searcher, options.slice(:enrollment_type, :enrollment_role))
if search_term.to_s =~ /^\d+$/
begin
user = base_scope.find(search_term)
return [user]
rescue ActiveRecord::RecordNotFound
#no user found by id, so lets go ahead with the regular search, maybe this person just has a ton of numbers in their name
end
end
base_scope.find(:all, :conditions => conditions_statement(search_term), :limit => limit)
end
def self.conditions_statement(search_term)
pattern = like_string_for(search_term)
conditions = []
if complex_search_enabled?
conditions << complex_sql << pattern << pattern << CommunicationChannel::TYPE_EMAIL << pattern
else
conditions << like_condition('users.name') << pattern
end
conditions
end
def self.like_string_for(search_term)
pattern_type = (gist_search_enabled? ? :full : :right)
wildcard_pattern(search_term, :type => pattern_type)
end
def self.scope_for(course, searcher, options={})
enrollment_role = Array(options[:enrollment_role]) if options[:enrollment_role]
enrollment_type = Array(options[:enrollment_type]) if options[:enrollment_type]
users = course.users_visible_to(searcher).scoped(:order => "users.sortable_name")
if enrollment_role
users = users.scoped(:conditions => ["COALESCE(enrollments.role_name, enrollments.type) IN (?) ", enrollment_role])
elsif enrollment_type
enrollment_type = enrollment_type.map { |e| "#{e.capitalize}Enrollment" }
raise(ArgumentError, 'Invalid Enrollment Type') if enrollment_type.any?{ |et| !Enrollment::READABLE_TYPES.keys.include?(et) }
users = users.scoped(:conditions => ["enrollments.type IN (?) ", enrollment_type])
end
users
end
private
def self.complex_sql
@_complex_sql ||= <<-SQL
(EXISTS (SELECT 1 FROM pseudonyms
WHERE #{like_condition('pseudonyms.sis_user_id')}
AND pseudonyms.user_id = users.id
AND (pseudonyms.workflow_state IS NULL
OR pseudonyms.workflow_state != 'deleted'))
OR (#{like_condition('users.name')})
OR EXISTS (SELECT 1 FROM communication_channels
WHERE communication_channels.user_id = users.id
AND (communication_channels.path_type = ?
AND #{like_condition('communication_channels.path')})))
SQL
end
def self.gist_search_enabled?
Setting.get_cached('user_search_with_gist', false) == 'true'
end
def self.complex_search_enabled?
Setting.get_cached('user_search_with_full_complexity', false) == 'true'
end
def self.like_condition(value)
ActiveRecord::Base.like_condition(value)
end
def self.wildcard_pattern(value, options)
ActiveRecord::Base.wildcard_pattern(value, options)
end
end