Use Stat's toponyms to calculate the number of countries and cities visited in a month

This commit is contained in:
Eugene Burmakin 2024-06-07 21:22:57 +02:00
parent 94ae8a3c9f
commit 08be01ebf6
11 changed files with 82 additions and 72 deletions

View file

@ -1,8 +1,10 @@
# frozen_string_literal: true
class StatsController < ApplicationController
before_action :authenticate_user!
def index
@stats = current_user.stats.group_by(&:year).sort_by { _1 }.reverse
@stats = current_user.stats.group_by(&:year).sort.reverse
end
def show

View file

@ -37,10 +37,23 @@ module ApplicationHelper
%w[info success warning error accent secondary primary]
end
def countries_and_cities_stat(year, user)
data = Stat.year_cities_and_countries(year, user)
countries = data[:countries]
cities = data[:cities]
def countries_and_cities_stat_for_year(year, stats)
data = { countries: [], cities: [] }
stats.select { _1.year == year }.each do
data[:countries] << _1.toponyms.flatten.map { |t| t['country'] }.uniq.compact
data[:cities] << _1.toponyms.flatten.flat_map { |t| t['cities'].map { |c| c['city'] } }.compact.uniq
end
data[:cities].flatten!.uniq!
data[:countries].flatten!.uniq!
"#{data[:countries].count} countries, #{data[:cities].count} cities"
end
def countries_and_cities_stat_for_month(stat)
countries = stat.toponyms.count { _1['country'] }
cities = stat.toponyms.sum { _1['cities'].count }
"#{countries} countries, #{cities} cities"
end

View file

@ -1,8 +1,6 @@
# frozen_string_literal: true
class Point < ApplicationRecord
# self.ignored_columns = %w[raw_data]
belongs_to :import, optional: true
belongs_to :user, optional: true

View file

@ -41,13 +41,16 @@ class Stat < ApplicationRecord
end
def self.year_cities_and_countries(year, user)
points = user.tracked_points.where(timestamp: DateTime.new(year).beginning_of_year..DateTime.new(year).end_of_year)
start_at = DateTime.new(year).beginning_of_year
end_at = DateTime.new(year).end_of_year
points = user.tracked_points.without_raw_data.where(timestamp: start_at..end_at)
data = CountriesAndCities.new(points).call
{
countries: data.map { _1[:country] }.uniq.count,
cities: data.sum { |country| country[:cities].count }
cities: data.sum { _1[:cities].count }
}
end

View file

@ -9,7 +9,7 @@ class ExportSerializer
end
def call
Oj.dump({ user_email => { 'dawarich-export' => export_points } })
{ user_email => { 'dawarich-export' => export_points } }.to_json
end
private

View file

@ -8,9 +8,7 @@ class CountriesAndCities
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
@ -50,7 +48,7 @@ class CountriesAndCities
{
country:,
cities: cities.map do |city, data|
{ city:, points: data[:points], timestamp: data[:last_timestamp], stayed_for: data[:stayed_for]}
{ city:, points: data[:points], timestamp: data[:last_timestamp], stayed_for: data[:stayed_for] }
end
}
end

View file

@ -0,0 +1,47 @@
<div class="stat text-center">
<div class="stat-value text-secondary">
<%= number_with_delimiter current_user.total_reverse_geocoded %>
</div>
<div class="stat-title">Reverse geocoded points</div>
</div>
<div class="stat text-center">
<div class="stat-value text-warning underline hover:no-underline hover:cursor-pointer" onclick="countries_visited.showModal()">
<%= number_with_delimiter current_user.total_countries %>
</div>
<div class="stat-title">Countries visited</div>
<dialog id="countries_visited" class="modal">
<div class="modal-box">
<h3 class="font-bold text-lg">Countries visited</h3>
<p class="py-4">
<% current_user.countries_visited.each do |country| %>
<p><%= country %></p>
<% end %>
</p>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
</div>
<div class="stat text-center">
<div class="stat-value hover:cursor-pointer hover:no-underline underline" onclick="cities_visited.showModal()">
<%= current_user.total_cities %>
</div>
<div class="stat-title">Cities visited</div>
<dialog id="cities_visited" class="modal">
<div class="modal-box">
<h3 class="font-bold text-lg">Cities visited</h3>
<p class="py-4">
<% current_user.cities_visited.each do |city| %>
<p><%= city %></p>
<% end %>
</p>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
</div>

View file

@ -8,7 +8,7 @@
<p><%= stat.distance %>km</p>
<% if REVERSE_GEOCODING_ENABLED %>
<div class="card-actions justify-end">
<%= stat.toponyms.count %> countries, <%= stat.toponyms.sum { _1['cities'].count } %> cities
<%= countries_and_cities_stat_for_month(stat) %>
</div>
<% end %>
<% if stat.daily_distance %>

View file

@ -9,59 +9,13 @@
<div class="stat text-center">
<div class="stat-value text-success">
<%= number_with_delimiter current_user.tracked_points.without_raw_data.count(:id) %>
<%= number_with_delimiter current_user.tracked_points.count %>
</div>
<div class="stat-title">Geopoints tracked</div>
</div>
<% if REVERSE_GEOCODING_ENABLED %>
<div class="stat text-center">
<div class="stat-value text-secondary">
<%= number_with_delimiter current_user.total_reverse_geocoded %>
</div>
<div class="stat-title">Reverse geocoded points</div>
</div>
<div class="stat text-center">
<div class="stat-value text-warning underline hover:no-underline hover:cursor-pointer" onclick="countries_visited.showModal()">
<%= number_with_delimiter current_user.total_countries %>
</div>
<div class="stat-title">Countries visited</div>
<dialog id="countries_visited" class="modal">
<div class="modal-box">
<h3 class="font-bold text-lg">Countries visited</h3>
<p class="py-4">
<% current_user.countries_visited.each do |country| %>
<p><%= country %></p>
<% end %>
</p>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
</div>
<div class="stat text-center">
<div class="stat-value hover:cursor-pointer hover:no-underline underline" onclick="cities_visited.showModal()">
<%= current_user.total_cities %>
</div>
<div class="stat-title">Cities visited</div>
<dialog id="cities_visited" class="modal">
<div class="modal-box">
<h3 class="font-bold text-lg">Cities visited</h3>
<p class="py-4">
<% current_user.cities_visited.each do |city| %>
<p><%= city %></p>
<% end %>
</p>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
</div>
<%= render 'stats/reverse_geocoding_stats' %>
<% end %>
</div>
@ -78,13 +32,11 @@
<p>
<% cache [current_user, 'year_distance_stat_in_km', year], skip_digest: true do %>
<%= number_with_delimiter year_distance_stat_in_km(year, current_user) %>km
<% end %>
<% end %>
</p>
<% if REVERSE_GEOCODING_ENABLED %>
<div class="card-actions justify-end">
<% cache [current_user, 'countries_and_cities_stat', year], skip_digest: true do %>
<%= countries_and_cities_stat(year, current_user) %>
<% end %>
<%= countries_and_cities_stat_for_year(year, stats) %>
</div>
<% end %>
<%= column_chart(

View file

@ -3,16 +3,13 @@
require 'rails_helper'
RSpec.describe 'Exports', type: :request do
describe 'GET /create' do
describe 'GET /download' do
before do
stub_request(:any, 'https://api.github.com/repos/Freika/dawarich/tags')
.to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {})
sign_in create(:user)
end
it 'returns http success' do
get '/export'
get '/export/download'
expect(response).to have_http_status(:success)
end

View file

@ -180,7 +180,7 @@ paths:
lat: 52.502397
lon: 13.356718
tid: Swagger
tst: 1717062606
tst: 1717786543
servers:
- url: http://{defaultHost}
variables: