Fix api point serializer to return correct latitude and longitude values

This commit is contained in:
Eugene Burmakin 2025-09-22 20:01:58 +02:00
parent 2af1aab787
commit f8a05e68e3
5 changed files with 49 additions and 14 deletions

View file

@ -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

View file

@ -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

View file

@ -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')}"

View file

@ -76,7 +76,11 @@
<div class="join">
<%= link_to "#{MANAGER_URL}/auth/dawarich?token=#{current_user.generate_subscription_token}" do %>
<span class="join-item btn btn-sm <%= trial_button_class(current_user) %>">
<span class="tooltip tooltip-bottom" data-tip="Your trial will end in <%= distance_of_time_in_words(current_user.active_until, Time.current) %>"><%= (current_user.active_until.to_date - Time.current.to_date).to_i %> days remaining</span>
<% if current_user.active_until.past? %>
<span class="tooltip tooltip-bottom">Trial expired 🥺</span>
<% else %>
<span class="tooltip tooltip-bottom" data-tip="Your trial will end in <%= distance_of_time_in_words(current_user.active_until, Time.current) %>"><%= (current_user.active_until.to_date - Time.current.to_date).to_i %> days remaining</span>
<% end %>
</span><span class="join-item btn btn-sm btn-success">
Subscribe
</span>

View file

@ -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