mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Rework countries and cities service
This commit is contained in:
parent
c159b56e25
commit
5cde596884
4 changed files with 31 additions and 41 deletions
|
|
@ -13,11 +13,14 @@ class Stats::CalculatingJob < ApplicationJob
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_stats_updated_notification(user_id)
|
def create_stats_updated_notification(user_id, year, month)
|
||||||
user = User.find(user_id)
|
user = User.find(user_id)
|
||||||
|
|
||||||
Notifications::Create.new(
|
Notifications::Create.new(
|
||||||
user:, kind: :info, title: 'Stats updated', content: 'Stats updated'
|
user:,
|
||||||
|
kind: :info,
|
||||||
|
title: "Stats updated: #{year}-#{month}",
|
||||||
|
content: "Stats updated for #{year}-#{month}"
|
||||||
).call
|
).call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,46 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CountriesAndCities
|
class CountriesAndCities
|
||||||
|
CityStats = Struct.new(:points, :last_timestamp, :stayed_for, keyword_init: true)
|
||||||
|
CountryData = Struct.new(:country, :cities, keyword_init: true)
|
||||||
|
CityData = Struct.new(:city, :points, :timestamp, :stayed_for, keyword_init: true)
|
||||||
|
|
||||||
def initialize(points)
|
def initialize(points)
|
||||||
@points = points
|
@points = points
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
grouped_records = group_points
|
points
|
||||||
mapped_with_cities = map_with_cities(grouped_records)
|
.reject { |point| point.country.nil? || point.city.nil? }
|
||||||
filtered_cities = filter_cities(mapped_with_cities)
|
.group_by(&:country)
|
||||||
normalize_result(filtered_cities)
|
.transform_values { |country_points| process_country_points(country_points) }
|
||||||
|
.map { |country, cities| CountryData.new(country: country, cities: cities) }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :points
|
attr_reader :points
|
||||||
|
|
||||||
def group_points
|
def process_country_points(country_points)
|
||||||
points.group_by(&:country)
|
country_points
|
||||||
|
.group_by(&:city)
|
||||||
|
.transform_values do |city_points|
|
||||||
|
timestamps = city_points.map(&:timestamp)
|
||||||
|
build_city_data(city_points.first.city, city_points.size, timestamps)
|
||||||
|
end
|
||||||
|
.values
|
||||||
end
|
end
|
||||||
|
|
||||||
def map_with_cities(grouped_records)
|
def build_city_data(city, points_count, timestamps)
|
||||||
grouped_records.transform_values do |grouped_points|
|
CityData.new(
|
||||||
grouped_points
|
city: city,
|
||||||
.pluck(:city, :timestamp) # Extract city and timestamp
|
points: points_count,
|
||||||
.delete_if { _1.first.nil? } # Remove records without city
|
timestamp: timestamps.max,
|
||||||
.group_by { |city, _| city } # Group by city
|
stayed_for: calculate_duration_in_minutes(timestamps)
|
||||||
.transform_values do |cities|
|
)
|
||||||
{
|
|
||||||
points: cities.count,
|
|
||||||
last_timestamp: cities.map(&:last).max, # Get the maximum timestamp
|
|
||||||
stayed_for: ((cities.map(&:last).max - cities.map(&:last).min).to_i / 60) # Calculate the time stayed in minutes
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_cities(mapped_with_cities)
|
def calculate_duration_in_minutes(timestamps)
|
||||||
# Remove cities where user stayed for less than 1 hour
|
((timestamps.max - timestamps.min).to_i / 60)
|
||||||
mapped_with_cities.transform_values do |cities|
|
|
||||||
cities.reject { |_, data| data[:stayed_for] < MIN_MINUTES_SPENT_IN_CITY }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize_result(hash)
|
|
||||||
hash.map do |country, cities|
|
|
||||||
{
|
|
||||||
country:,
|
|
||||||
cities: cities.map do |city, data|
|
|
||||||
{ city:, points: data[:points], timestamp: data[:last_timestamp], stayed_for: data[:stayed_for] }
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,7 @@
|
||||||
|
|
||||||
<% if REVERSE_GEOCODING_ENABLED && @countries_and_cities&.any? %>
|
<% if REVERSE_GEOCODING_ENABLED && @countries_and_cities&.any? %>
|
||||||
<hr class='my-5'>
|
<hr class='my-5'>
|
||||||
<h2 class='text-lg font-semibold'>Countries and cities</h2>
|
|
||||||
<% @countries_and_cities.each do |country| %>
|
<% @countries_and_cities.each do |country| %>
|
||||||
<% next if country[:cities].empty? %>
|
|
||||||
|
|
||||||
<h2 class="text-lg font-semibold mt-5">
|
<h2 class="text-lg font-semibold mt-5">
|
||||||
<%= country[:country] %> (<%= country[:cities].count %> cities)
|
<%= country[:country] %> (<%= country[:cities].count %> cities)
|
||||||
</h2>
|
</h2>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue