diff --git a/app/controllers/points_controller.rb b/app/controllers/points_controller.rb index f9c1f88b..cdb725d3 100644 --- a/app/controllers/points_controller.rb +++ b/app/controllers/points_controller.rb @@ -4,10 +4,15 @@ class PointsController < ApplicationController def index @points = Point.where('timestamp >= ? AND timestamp <= ?', start_at, end_at).order(timestamp: :asc) - @countries_and_cities = @points.group_by(&:country).transform_values { _1.pluck(:city).uniq.compact } + @countries_and_cities = CountriesAndCities.new(@points).call @coordinates = @points.pluck(:latitude, :longitude).map { [_1.to_f, _2.to_f] } + @distance = distance + @start_at = Time.at(start_at) + @end_at = Time.at(end_at) end + private + def start_at return 1.month.ago.beginning_of_day.to_i if params[:start_at].nil? @@ -19,4 +24,14 @@ class PointsController < ApplicationController params[:end_at].to_datetime.to_i end + + def distance + @distance ||= 0 + + @coordinates.each_cons(2) do + @distance += Geocoder::Calculations.distance_between(_1[0], _1[1], units: :km) + end + + @distance.round(1) + end end diff --git a/app/models/point.rb b/app/models/point.rb index 3d0405e6..56543b9e 100644 --- a/app/models/point.rb +++ b/app/models/point.rb @@ -17,10 +17,6 @@ class Point < ApplicationRecord Time.at(timestamp).strftime('%Y-%m-%d %H:%M:%S') end - def cities_by_countries - group_by { _1.country }.compact.map { |k, v| { k => v.pluck(:city).uniq.compact } } - end - private def async_reverse_geocode @@ -28,7 +24,6 @@ class Point < ApplicationRecord end end - def group_records_by_hour(records) grouped_records = Hash.new { |hash, key| hash[key] = [] } diff --git a/app/services/countries_and_cities.rb b/app/services/countries_and_cities.rb new file mode 100644 index 00000000..fa952448 --- /dev/null +++ b/app/services/countries_and_cities.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class CountriesAndCities + def initialize(points) + @points = points + end + + def call + grouped_records = group_points + mapped_with_cities = map_with_cities(grouped_records) + + filtered_cities = filter_cities(mapped_with_cities) + + normalize_result(filtered_cities) + end + + private + + attr_reader :points + + def group_points + points.group_by(&:country) + end + + def map_with_cities(grouped_records) + grouped_records.transform_values do |grouped_points| + grouped_points + .pluck(:city, :timestamp) # Extract city and timestamp + .delete_if { _1.first.nil? } # Remove records without city + .group_by { |city, _| city } + .transform_values do |cities| + { + points: cities.count, + timestamp: cities.map(&:last).max # Get the maximum timestamp + } + end + end + end + + + def filter_cities(mapped_with_cities) + # Remove cities with less than MINIMUM_POINTS_IN_CITY + mapped_with_cities.transform_values do |cities| + cities.reject { |_, data| data[:points] < MINIMUM_POINTS_IN_CITY } + end + end + + def normalize_result(hash) + hash.map do |country, cities| + { + country: country, + cities: cities.map { |city, data| { city: city, points: data[:points], timestamp: data[:timestamp] } } + } + end + end +end diff --git a/app/services/google_maps/timeline_parser.rb b/app/services/google_maps/timeline_parser.rb index ff568f87..5196e601 100644 --- a/app/services/google_maps/timeline_parser.rb +++ b/app/services/google_maps/timeline_parser.rb @@ -17,6 +17,8 @@ class GoogleMaps::TimelineParser points_data = parse_json points_data.each do |point_data| + # next if Point.exists?(timestamp: point_data[:timestamp]) + Point.create( latitude: point_data[:latitude], longitude: point_data[:longitude], diff --git a/app/views/points/index.html.erb b/app/views/points/index.html.erb index 276d5eaf..b201664c 100644 --- a/app/views/points/index.html.erb +++ b/app/views/points/index.html.erb @@ -5,13 +5,13 @@