Created
September 5, 2012 19:07
-
-
Save aslam/3642741 to your computer and use it in GitHub Desktop.
Retina India - Seshpath MatchMaker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MatchMaker | |
# This method matches the volunteers with the request criteria and notifies them through | |
# email and sms. Volunteers can accept this request by clicking on a link sent in the email | |
# or sending an sms to <NO>. | |
# | |
# The student can freeze on a volunteer by clicking on a link provided next to the volunteer | |
# details and close this request. | |
# | |
# Then the actual searching starts by building the criteria for search. Various search scopes | |
# are merged together to form complete search criteria which is passed on to Oracle to do the | |
# searching. Oracle returns volunteers array, and matches are created and saved. Matched | |
# volunteers are notified about the request through email and sms. | |
# | |
# After volunteer notification, a new delayed job is created to run after <set time> which | |
# would repeat the process. | |
def match_and_notify(service_request) | |
rejects = ['id', 'student_id', 'service_provider_id', 'created_at', 'updated_at', 'status', | |
'pursuing', 'education', 'complete', 'from_date', 'to_date', 'timing', | |
'reading_at_a_different_place'] | |
exam_fields = ['paper', 'exam_date', 'start_time', 'end_time'] | |
# Start building search criteria | |
criteria = service_request.attributes | |
criteria.delete_if { |k, v| rejects.include?(k) } | |
exam_details = criteria.extract!(*exam_fields) | |
if service_request.is_a?(ScribeRequest) | |
streams = YAML.load service_request.streams | |
streams.delete_if { |s| s.blank? } | |
if streams.include?('Any') | |
criteria.delete('streams') | |
criteria.merge!({'stream' => 'any'}) | |
else | |
criteria['streams'] = streams | |
end | |
locations = Location.of_volunteers.near( service_request.location.address, Configuration.service_requests['boundary'] ) | |
criteria.merge!({ :located => locations.pluck(:id) }) | |
criteria.merge!({ :not_engaged_on => service_request.exam_date }) | |
elsif service_request.is_a?(ReaderRequest) | |
if service_request.for_date_range? | |
criteria.merge!({ :not_engaged_between => [service_request.from_date, service_request.to_date] }) | |
else | |
criteria.merge!({ :not_engaged_on => service_request.from_date }) | |
end | |
end | |
if service_request.matches.any? | |
ids = service_request.matches.pluck(:volunteer_id) | |
criteria.merge!({ :excluding => ids }) | |
end | |
batch = Oracle.new.search('Volunteer', criteria) | |
matches = matchify(service_request, batch) | |
messager = Messager.new | |
# Job for Email notification | |
if service_request.is_a?(ScribeRequest) | |
job = ScribeRequestEmailNotificationJob.new(service_request, matches) | |
else | |
job = ReaderRequestEmailNotificationJob.new(service_request, matches) | |
end | |
Delayed::Job.enqueue(job) | |
# Job for SMS notification | |
Delayed::Job.enqueue(ServiceRequestSmsNotificationJob.new(service_request, matches, messager)) | |
end | |
def matchify(service_request, batch) | |
service_request.update_status("notified") | |
batch.each do |m| | |
service_request.matches.build(:volunteer_id => m.id, :acceptance_token_expires_at => 1.days.from_now) | |
end | |
service_request.save! | |
service_request.matches | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Oracle | |
# Scopes | |
# Volunteer => [ * - 'q' is mandatory, # - 'q' is optional, ** - 's', 'e' are mandatory ] | |
# active - activation_state is 'active' | |
# scribes - type is 'scribe' | |
# readers - type is 'reader' | |
# *by_name - name like 'q' | |
# *by_email - email like 'q' | |
# educated - has education and title is not null | |
# any_stream - has education stream and is not null | |
# *streams - has education stream in 'q' | |
# #stream - has education stream like 'q' | |
# #education - has education and title like 'q' | |
# *level - education level (title) is 'q' | |
# *level_lt - education level (title) is < 'q' | |
# *level_lteq - education level (title) is <= 'q' | |
# *marks_lt - has education and marks obtained < 'q' | |
# *marks_lteq - has education and marks obtained <= 'q' | |
# *marks_gt - has education and marks obtained > 'q' | |
# *marks_gteq - has education and marks obtained >= 'q' | |
# *knows - knows language 'q' | |
# *reads - knows and reads language 'q' | |
# *writes - knows and writes language 'q' | |
# *not_engaged_on - doesn't have any volunteering engagements on 'q' | |
# **not_engaged_between - doesn't have any volunteering engagements betwee 'q' & 'q`' | |
def search(scope, criteria) | |
scope = scope.constantize.active.scoped | |
criteria, singular = singular(criteria) | |
singular.each do |k| | |
scope = scope.send(k.to_sym) | |
end | |
if criteria.has_key?(:not_engaged_between) | |
multi = criteria.select { |k, v| k.eql?(:not_engaged_between) } | |
criteria.delete(:not_engaged_between) | |
attrs = multi.values.flatten | |
scope = scope.send(:not_engaged_between, attrs[0], attrs[1]) | |
end | |
build(criteria).each do |k, v| | |
scope = scope.send(k.to_sym, v) | |
end | |
scope.includes(:account).limit(Configuration.service_requests['limit']).all | |
end | |
def build(params) | |
rejects = ['utf8', 'authenticity_token', 'action'] | |
required = ['by_name', 'by_email', 'streams', 'marks_lt', 'marks_lteq', 'marks_gt', 'marks_gteq', | |
'knows', 'reads', 'writes', 'not_engaged_on', 'located'] | |
optional = ['stream', 'education'] | |
params.delete_if { |k, v| rejects.include?(k) } | |
params.delete_if { |k, v| required.include?(k) && v.blank? } | |
params.each { |k, v| params.delete(k) if optional.include?(k.to_s) && v.blank? } | |
params | |
end | |
def singular(params) | |
singular = ['active', 'scribes', 'readers', 'educated', 'any_stream'] | |
original = [] | |
params.each { |k, v| original << k && params.delete(k) if singular.include?(k.to_s) } | |
[params, original] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment