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 class StatsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
def index def index
@stats = current_user.stats.group_by(&:year).sort_by { _1 }.reverse @stats = current_user.stats.group_by(&:year).sort.reverse
end end
def show def show

View file

@ -37,10 +37,23 @@ module ApplicationHelper
%w[info success warning error accent secondary primary] %w[info success warning error accent secondary primary]
end end
def countries_and_cities_stat(year, user) def countries_and_cities_stat_for_year(year, stats)
data = Stat.year_cities_and_countries(year, user) data = { countries: [], cities: [] }
countries = data[:countries]
cities = data[: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" "#{countries} countries, #{cities} cities"
end end

View file

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

View file

@ -41,13 +41,16 @@ class Stat < ApplicationRecord
end end
def self.year_cities_and_countries(year, user) 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 data = CountriesAndCities.new(points).call
{ {
countries: data.map { _1[:country] }.uniq.count, countries: data.map { _1[:country] }.uniq.count,
cities: data.sum { |country| country[:cities].count } cities: data.sum { _1[:cities].count }
} }
end end

View file

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

View file

@ -8,9 +8,7 @@ class CountriesAndCities
def call def call
grouped_records = group_points grouped_records = group_points
mapped_with_cities = map_with_cities(grouped_records) mapped_with_cities = map_with_cities(grouped_records)
filtered_cities = filter_cities(mapped_with_cities) filtered_cities = filter_cities(mapped_with_cities)
normalize_result(filtered_cities) normalize_result(filtered_cities)
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> <p><%= stat.distance %>km</p>
<% if REVERSE_GEOCODING_ENABLED %> <% if REVERSE_GEOCODING_ENABLED %>
<div class="card-actions justify-end"> <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> </div>
<% end %> <% end %>
<% if stat.daily_distance %> <% if stat.daily_distance %>

View file

@ -9,59 +9,13 @@
<div class="stat text-center"> <div class="stat text-center">
<div class="stat-value text-success"> <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>
<div class="stat-title">Geopoints tracked</div> <div class="stat-title">Geopoints tracked</div>
</div> </div>
<% if REVERSE_GEOCODING_ENABLED %> <% if REVERSE_GEOCODING_ENABLED %>
<div class="stat text-center"> <%= render 'stats/reverse_geocoding_stats' %>
<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>
<% end %> <% end %>
</div> </div>
@ -82,9 +36,7 @@
</p> </p>
<% if REVERSE_GEOCODING_ENABLED %> <% if REVERSE_GEOCODING_ENABLED %>
<div class="card-actions justify-end"> <div class="card-actions justify-end">
<% cache [current_user, 'countries_and_cities_stat', year], skip_digest: true do %> <%= countries_and_cities_stat_for_year(year, stats) %>
<%= countries_and_cities_stat(year, current_user) %>
<% end %>
</div> </div>
<% end %> <% end %>
<%= column_chart( <%= column_chart(

View file

@ -3,16 +3,13 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Exports', type: :request do RSpec.describe 'Exports', type: :request do
describe 'GET /create' do describe 'GET /download' do
before 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) sign_in create(:user)
end end
it 'returns http success' do it 'returns http success' do
get '/export' get '/export/download'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end

View file

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