dawarich/app/services/reverse_geocoding/places/fetch_data.rb

159 lines
4 KiB
Ruby
Raw Normal View History

2024-08-05 15:23:08 -04:00
# frozen_string_literal: true
# This class uses Komoot's Photon API
2024-08-05 15:23:08 -04:00
class ReverseGeocoding::Places::FetchData
attr_reader :place
def initialize(place_id)
@place = Place.find(place_id)
end
def call
unless DawarichSettings.reverse_geocoding_enabled?
Rails.logger.warn('Reverse geocoding is not enabled')
2025-06-11 15:12:03 -04:00
2024-08-05 15:23:08 -04:00
return
end
0.36.0 (#1952) * Implement OmniAuth GitHub authentication * Fix omniauth GitHub scope to include user email access * Remove margin-bottom * Implement Google OAuth2 authentication * Implement OIDC authentication for Dawarich using omniauth_openid_connect gem. * Add patreon account linking and patron checking service * Update docker-compose.yml to use boolean values instead of strings * Add support for KML files * Add tests * Update changelog * Remove patreon OAuth integration * Move omniauthable to a concern * Update an icon in integrations * Update changelog * Update app version * Fix family location sharing toggle * Move family location sharing to its own controller * Update changelog * Implement basic tagging functionality for places, allowing users to categorize and label places with custom tags. * Add places management API and tags feature * Add some changes related to places management feature * Fix some tests * Fix sometests * Add places layer * Update places layer to use Leaflet.Control.Layers.Tree for hierarchical layer control * Rework tag form * Add hashtag * Add privacy zones to tags * Add notes to places and manage place tags * Update changelog * Update e2e tests * Extract tag serializer to its own file * Fix some tests * Fix tags request specs * Fix some tests * Fix rest of the tests * Revert some changes * Add missing specs * Revert changes in place export/import code * Fix some specs * Fix PlaceFinder to only consider global places when finding existing places * Fix few more specs * Fix visits creator spec * Fix last tests * Update place creating modal * Add home location based on "Home" tagged place * Save enabled tag layers * Some fixes * Fix bug where enabling place tag layers would trigger saving enabled layers, overwriting with incomplete data * Update migration to use disable_ddl_transaction! and add up/down methods * Fix tag layers restoration and filtering logic * Update OIDC auto-registration and email/password registration settings * Fix potential xss
2025-11-24 13:45:09 -05:00
places = geocoder_places
first_place = places.shift
2024-08-05 15:23:08 -04:00
update_place(first_place)
2025-07-26 19:08:29 -04:00
osm_ids = extract_osm_ids(places)
return if osm_ids.empty?
2025-07-26 19:08:29 -04:00
existing_places = find_existing_places(osm_ids)
2025-07-26 19:08:29 -04:00
places_to_create, places_to_update = prepare_places_for_bulk_operations(places, existing_places)
save_places(places_to_create, places_to_update)
2024-08-05 15:23:08 -04:00
end
private
def update_place(reverse_geocoded_place)
return if reverse_geocoded_place.nil?
data = reverse_geocoded_place.data
2024-08-05 15:23:08 -04:00
place.update!(
name: place_name(data),
2025-07-26 19:08:29 -04:00
lonlat: build_point_coordinates(data['geometry']['coordinates']),
city: data['properties']['city'],
country: data['properties']['country'],
geodata: data,
source: Place.sources[:photon],
2024-08-12 16:18:11 -04:00
reverse_geocoded_at: Time.current
2024-08-05 15:23:08 -04:00
)
end
def find_place(place_data, existing_places)
osm_id = place_data['properties']['osm_id'].to_s
2024-08-12 16:18:11 -04:00
existing_place = existing_places[osm_id]
2025-07-26 19:39:39 -04:00
return existing_place if existing_place.present?
2024-08-12 16:18:11 -04:00
2025-07-26 19:08:29 -04:00
coordinates = place_data['geometry']['coordinates']
2025-07-26 19:39:39 -04:00
Place.new(
2025-07-26 19:08:29 -04:00
lonlat: build_point_coordinates(coordinates),
latitude: coordinates[1].to_f.round(5),
longitude: coordinates[0].to_f.round(5)
2024-08-12 16:18:11 -04:00
)
end
def place_name(data)
name = data.dig('properties', 'name')
type = data.dig('properties', 'osm_value')&.capitalize&.gsub('_', ' ')
address = "#{data.dig('properties', 'postcode')} #{data.dig('properties', 'street')}"
address += " #{data.dig('properties', 'housenumber')}" if data.dig('properties', 'housenumber').present?
name ||= address
"#{name} (#{type})"
end
2025-07-26 19:08:29 -04:00
def extract_osm_ids(places)
places.map { |place| place.data['properties']['osm_id'].to_s }
end
def find_existing_places(osm_ids)
Place.where("geodata->'properties'->>'osm_id' IN (?)", osm_ids)
0.36.0 (#1952) * Implement OmniAuth GitHub authentication * Fix omniauth GitHub scope to include user email access * Remove margin-bottom * Implement Google OAuth2 authentication * Implement OIDC authentication for Dawarich using omniauth_openid_connect gem. * Add patreon account linking and patron checking service * Update docker-compose.yml to use boolean values instead of strings * Add support for KML files * Add tests * Update changelog * Remove patreon OAuth integration * Move omniauthable to a concern * Update an icon in integrations * Update changelog * Update app version * Fix family location sharing toggle * Move family location sharing to its own controller * Update changelog * Implement basic tagging functionality for places, allowing users to categorize and label places with custom tags. * Add places management API and tags feature * Add some changes related to places management feature * Fix some tests * Fix sometests * Add places layer * Update places layer to use Leaflet.Control.Layers.Tree for hierarchical layer control * Rework tag form * Add hashtag * Add privacy zones to tags * Add notes to places and manage place tags * Update changelog * Update e2e tests * Extract tag serializer to its own file * Fix some tests * Fix tags request specs * Fix some tests * Fix rest of the tests * Revert some changes * Add missing specs * Revert changes in place export/import code * Fix some specs * Fix PlaceFinder to only consider global places when finding existing places * Fix few more specs * Fix visits creator spec * Fix last tests * Update place creating modal * Add home location based on "Home" tagged place * Save enabled tag layers * Some fixes * Fix bug where enabling place tag layers would trigger saving enabled layers, overwriting with incomplete data * Update migration to use disable_ddl_transaction! and add up/down methods * Fix tag layers restoration and filtering logic * Update OIDC auto-registration and email/password registration settings * Fix potential xss
2025-11-24 13:45:09 -05:00
.global
2025-07-26 19:08:29 -04:00
.index_by { |p| p.geodata.dig('properties', 'osm_id').to_s }
.compact
end
def prepare_places_for_bulk_operations(places, existing_places)
places_to_create = []
places_to_update = []
places.each do |reverse_geocoded_place|
data = reverse_geocoded_place.data
new_place = find_place(data, existing_places)
populate_place_attributes(new_place, data)
if new_place.persisted?
places_to_update << new_place
else
places_to_create << new_place
end
end
[places_to_create, places_to_update]
end
def populate_place_attributes(place, data)
place.name = place_name(data)
place.city = data['properties']['city']
place.country = data['properties']['country']
place.geodata = data
place.source = :photon
2025-07-27 14:14:36 -04:00
if place.lonlat.blank?
2025-07-26 19:08:29 -04:00
place.lonlat = build_point_coordinates(data['geometry']['coordinates'])
end
end
def save_places(places_to_create, places_to_update)
2025-07-26 19:39:39 -04:00
if places_to_create.any?
place_attributes = places_to_create.map do |place|
{
name: place.name,
latitude: place.latitude,
longitude: place.longitude,
lonlat: place.lonlat,
city: place.city,
country: place.country,
geodata: place.geodata,
source: place.source,
created_at: Time.current,
updated_at: Time.current
}
end
Place.insert_all(place_attributes)
end
2025-07-27 14:14:36 -04:00
2025-07-26 19:39:39 -04:00
# Individual updates for existing places
2025-07-26 19:08:29 -04:00
places_to_update.each(&:save!) if places_to_update.any?
end
def build_point_coordinates(coordinates)
"POINT(#{coordinates[0]} #{coordinates[1]})"
end
0.36.0 (#1952) * Implement OmniAuth GitHub authentication * Fix omniauth GitHub scope to include user email access * Remove margin-bottom * Implement Google OAuth2 authentication * Implement OIDC authentication for Dawarich using omniauth_openid_connect gem. * Add patreon account linking and patron checking service * Update docker-compose.yml to use boolean values instead of strings * Add support for KML files * Add tests * Update changelog * Remove patreon OAuth integration * Move omniauthable to a concern * Update an icon in integrations * Update changelog * Update app version * Fix family location sharing toggle * Move family location sharing to its own controller * Update changelog * Implement basic tagging functionality for places, allowing users to categorize and label places with custom tags. * Add places management API and tags feature * Add some changes related to places management feature * Fix some tests * Fix sometests * Add places layer * Update places layer to use Leaflet.Control.Layers.Tree for hierarchical layer control * Rework tag form * Add hashtag * Add privacy zones to tags * Add notes to places and manage place tags * Update changelog * Update e2e tests * Extract tag serializer to its own file * Fix some tests * Fix tags request specs * Fix some tests * Fix rest of the tests * Revert some changes * Add missing specs * Revert changes in place export/import code * Fix some specs * Fix PlaceFinder to only consider global places when finding existing places * Fix few more specs * Fix visits creator spec * Fix last tests * Update place creating modal * Add home location based on "Home" tagged place * Save enabled tag layers * Some fixes * Fix bug where enabling place tag layers would trigger saving enabled layers, overwriting with incomplete data * Update migration to use disable_ddl_transaction! and add up/down methods * Fix tag layers restoration and filtering logic * Update OIDC auto-registration and email/password registration settings * Fix potential xss
2025-11-24 13:45:09 -05:00
def geocoder_places
data = Geocoder.search(
2025-03-03 14:50:49 -05:00
[place.lat, place.lon],
limit: 10,
distance_sort: true,
radius: 1,
2025-05-17 15:50:34 -04:00
units: :km
)
end
2024-08-05 15:23:08 -04:00
end