From f8a05e68e3d2125ca7f5c2e310f1b678b87a1b31 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Mon, 22 Sep 2025 20:01:58 +0200 Subject: [PATCH] Fix api point serializer to return correct latitude and longitude values --- CHANGELOG.md | 1 + app/serializers/api/point_serializer.rb | 23 ++++++++++++++++--- .../location_search/result_aggregator.rb | 17 +++++++------- app/views/shared/_navbar.html.erb | 6 ++++- spec/serializers/api/point_serializer_spec.rb | 16 +++++++++++-- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc4da0a6..7d661d1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Hexagons for the stats page are now being calculated a lot faster. - Prometheus exporter is now not being started when console is being run. - Stats will now properly reflect countries and cities visited after importing new points. +- `GET /api/v1/points will now return correct latitude and longitude values. #1502 ## Changed diff --git a/app/serializers/api/point_serializer.rb b/app/serializers/api/point_serializer.rb index e8484d38..1f5e3a0d 100644 --- a/app/serializers/api/point_serializer.rb +++ b/app/serializers/api/point_serializer.rb @@ -1,9 +1,26 @@ # frozen_string_literal: true -class Api::PointSerializer < PointSerializer - EXCLUDED_ATTRIBUTES = %w[created_at updated_at visit_id import_id user_id raw_data country_id].freeze +class Api::PointSerializer + EXCLUDED_ATTRIBUTES = %w[ + created_at updated_at visit_id import_id user_id raw_data + country_id + ].freeze + + def initialize(point) + @point = point + end def call - point.attributes.except(*EXCLUDED_ATTRIBUTES) + point.attributes.except(*EXCLUDED_ATTRIBUTES).tap do |attributes| + lat = point.lat + lon = point.lon + + attributes['latitude'] = lat.nil? ? nil : lat.to_s + attributes['longitude'] = lon.nil? ? nil : lon.to_s + end end + + private + + attr_reader :point end diff --git a/app/services/location_search/result_aggregator.rb b/app/services/location_search/result_aggregator.rb index 0c28000a..52d5d950 100644 --- a/app/services/location_search/result_aggregator.rb +++ b/app/services/location_search/result_aggregator.rb @@ -48,15 +48,16 @@ module LocationSearch last_point = sorted_points.last # Calculate visit duration - duration_minutes = if sorted_points.length > 1 - ((last_point[:timestamp] - first_point[:timestamp]) / 60.0).round - else - # Single point visit - estimate based on typical stay time - 15 # minutes - end + duration_minutes = + if sorted_points.any? + ((last_point[:timestamp] - first_point[:timestamp]) / 60.0).round + else + # Single point visit - estimate based on typical stay time + 15 # minutes + end # Find the most accurate point (lowest accuracy value means higher precision) - most_accurate_point = points.min_by { |p| p[:accuracy] || 999999 } + most_accurate_point = points.min_by { |p| p[:accuracy] || 999_999 } # Calculate average distance from search center average_distance = (points.sum { |p| p[:distance_meters] } / points.length).round(2) @@ -86,7 +87,7 @@ module LocationSearch hours = minutes / 60 remaining_minutes = minutes % 60 - if remaining_minutes == 0 + if remaining_minutes.zero? "~#{pluralize(hours, 'hour')}" else "~#{pluralize(hours, 'hour')} #{pluralize(remaining_minutes, 'minute')}" diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index c00c405f..9778627c 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -76,7 +76,11 @@
<%= link_to "#{MANAGER_URL}/auth/dawarich?token=#{current_user.generate_subscription_token}" do %> - <%= (current_user.active_until.to_date - Time.current.to_date).to_i %> days remaining + <% if current_user.active_until.past? %> + Trial expired 🥺 + <% else %> + <%= (current_user.active_until.to_date - Time.current.to_date).to_i %> days remaining + <% end %> Subscribe diff --git a/spec/serializers/api/point_serializer_spec.rb b/spec/serializers/api/point_serializer_spec.rb index 8e7b51e5..4e4453e2 100644 --- a/spec/serializers/api/point_serializer_spec.rb +++ b/spec/serializers/api/point_serializer_spec.rb @@ -7,14 +7,26 @@ RSpec.describe Api::PointSerializer do subject(:serializer) { described_class.new(point).call } let(:point) { create(:point) } - let(:expected_json) { point.attributes.except(*Api::PointSerializer::EXCLUDED_ATTRIBUTES) } + let(:all_excluded) { PointSerializer::EXCLUDED_ATTRIBUTES + Api::PointSerializer::ADDITIONAL_EXCLUDED_ATTRIBUTES } + let(:expected_json) do + point.attributes.except(*all_excluded).tap do |attributes| + # API serializer extracts coordinates from PostGIS geometry + attributes['latitude'] = point.lat.to_s + attributes['longitude'] = point.lon.to_s + end + end it 'returns JSON with correct attributes' do expect(serializer.to_json).to eq(expected_json.to_json) end it 'does not include excluded attributes' do - expect(serializer).not_to include(*Api::PointSerializer::EXCLUDED_ATTRIBUTES) + expect(serializer).not_to include(*all_excluded) + end + + it 'extracts coordinates from PostGIS geometry' do + expect(serializer['latitude']).to eq(point.lat.to_s) + expect(serializer['longitude']).to eq(point.lon.to_s) end end end