Skip to content

Commit

Permalink
ignore polygon for in memory location search
Browse files Browse the repository at this point in the history
  • Loading branch information
starswan committed Dec 2, 2024
1 parent d2b64a2 commit 4a7fd07
Show file tree
Hide file tree
Showing 18 changed files with 2,137 additions and 200 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ group :test do
gem "rack_session_access"
gem "selenium-webdriver"
gem "shoulda-matchers"
gem "uri-query_params"
gem "vcr"
gem "webmock"
end
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@ GEM
unicode-version (~> 1.0)
unicode-version (1.4.0)
uri (1.0.1)
uri-query_params (0.8.2)
useragent (0.16.10)
valid_email2 (6.0.0)
activemodel (>= 6.0)
Expand Down Expand Up @@ -864,6 +865,7 @@ DEPENDENCIES
slim_lint
solargraph
tzinfo-data
uri-query_params
valid_email2
validate_url
vcr
Expand Down
32 changes: 2 additions & 30 deletions app/jobs/alert_email/base.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
class AlertEmail::Base < ApplicationJob
MAXIMUM_RESULTS_PER_RUN = 500

FILTERS = {
teaching_job_roles: ->(vacancy, value) { (vacancy.job_roles & value).any? },
support_job_roles: ->(vacancy, value) { (vacancy.job_roles & value).any? },
visa_sponsorship_availability: ->(vacancy, value) { value.include? vacancy.visa_sponsorship_available.to_s },
ect_statuses: ->(vacancy, value) { value.include?(vacancy.ect_status) },
subjects: ->(vacancy, value) { (vacancy.subjects & value).any? },
phases: ->(vacancy, value) { (vacancy.phases & value).any? },
working_patterns: ->(vacancy, value) { (vacancy.working_patterns & value).any? },
organisation_slug: ->(vacancy, value) { vacancy.organisations.map(&:slug).include?(value) },
keyword: ->(vacancy, value) { vacancy.searchable_content.include? value.downcase.strip },
}.freeze

def perform # rubocop:disable Metrics/AbcSize
def perform
return if DisableExpensiveJobs.enabled?

# The intent here is that if we don't have keyword or location searches, then this operation can all be done in memory
Expand All @@ -23,26 +11,10 @@ def perform # rubocop:disable Metrics/AbcSize
already_run_ids = AlertRun.for_today.map(&:subscription_id)

subscriptions.find_each.reject { |sub| already_run_ids.include?(sub.id) }.each do |subscription|
scope = default_scope
criteria = subscription.search_criteria.symbolize_keys
scope, criteria = handle_location(scope, criteria)

vacancies = scope.select do |vacancy|
criteria.all? { |criterion, value| FILTERS.fetch(criterion).call(vacancy, value) }
end
vacancies = subscription.vacancies_matching default_scope

Jobseekers::AlertMailer.alert(subscription.id, vacancies.pluck(:id)).deliver_later if vacancies.any?
end
Sentry.capture_message("#{self.class.name} run successfully", level: :info)
end

private

def handle_location(scope, criteria)
if criteria.key?(:location)
[scope.search_by_location(criteria[:location], criteria[:radius]), criteria.except(:location, :radius)]
else
[scope, criteria]
end
end
end
57 changes: 57 additions & 0 deletions app/models/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ class Subscription < ApplicationRecord

validates :email, email_address: true, if: -> { email_changed? } # Allows data created prior to validation to still be valid

FILTERS = {
teaching_job_roles: ->(vacancy, value) { (vacancy.job_roles & value).any? },
support_job_roles: ->(vacancy, value) { (vacancy.job_roles & value).any? },
visa_sponsorship_availability: ->(vacancy, value) { value.include? vacancy.visa_sponsorship_available.to_s },
ect_statuses: ->(vacancy, value) { value.include?(vacancy.ect_status) },
subjects: ->(vacancy, value) { (vacancy.subjects & value).any? },
phases: ->(vacancy, value) { (vacancy.phases & value).any? },
working_patterns: ->(vacancy, value) { (vacancy.working_patterns & value).any? },
organisation_slug: ->(vacancy, value) { vacancy.organisations.map(&:slug).include?(value) },
keyword: ->(vacancy, value) { vacancy.searchable_content.include? value.downcase.strip },
}.freeze

def self.encryptor(serializer: :json_allow_marshal)
key_generator_secret = SUBSCRIPTION_KEY_GENERATOR_SECRET
key_generator_salt = SUBSCRIPTION_KEY_GENERATOR_SALT
Expand Down Expand Up @@ -54,4 +66,49 @@ def create_alert_run
def organisation
Organisation.find_by(slug: search_criteria["organisation_slug"]) if search_criteria["organisation_slug"]
end

def vacancies_matching(default_scope)
scope = default_scope
criteria = search_criteria.symbolize_keys
scope, criteria = handle_location(scope, criteria)

scope.select do |vacancy|
criteria.all? { |criterion, value| FILTERS.fetch(criterion).call(vacancy, value) }
end
end

private

extend DistanceHelper

class << self
def limit_by_location(vacancies, location, radius_in_miles)
query = location.strip.downcase
if query.blank? || LocationQuery::NATIONWIDE_LOCATIONS.include?(query)
vacancies
else
radius_in_metres = convert_miles_to_metres radius_in_miles
LocationPolygon.with_name(query)
polygon = nil
if polygon.present?
vacancies.select { |v| v.organisations.map(&:geopoint).any? { |point| polygon.area.contains?(point) } }
# vacancies.select {|v| v.organisations.map(&:geopoint).any? { |point| polygon.area.intersects? point.buffer(radius_in_metres) } }
else
coordinates = Geocoding.new(query).coordinates
search_point = RGeo::Geographic.spherical_factory.point(coordinates.second, coordinates.first)
vacancies.select { |v| v.organisations.map(&:geopoint).any? { |point| search_point.distance(point) < radius_in_metres } }
end
end
end
end

def handle_location(scope, criteria)
if criteria.key?(:location)
# [scope.search_by_location(criteria[:location], criteria[:radius]), criteria.except(:location, :radius)]
[self.class.limit_by_location(scope, criteria[:location], criteria[:radius]), criteria.except(:location, :radius)]

else
[scope, criteria]
end
end
end
2 changes: 1 addition & 1 deletion config/initializers/geocoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
http_headers: { "User-Agent" => "Teaching Vacancies Service [email protected]" },

google: {
api_key: Rails.env.test? ? "placeholder_key" : ENV.fetch("GOOGLE_LOCATION_SEARCH_API_KEY", ""),
api_key: ENV.fetch("GOOGLE_LOCATION_SEARCH_API_KEY", "placeholder_key"),
always_raise: [Geocoder::OverQueryLimitError],
},

Expand Down
Loading

0 comments on commit 4a7fd07

Please sign in to comment.