mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Merge branch 'dev' into feature/trial
This commit is contained in:
commit
ead1673cc5
8 changed files with 179 additions and 100 deletions
|
|
@ -1 +1 @@
|
|||
0.30.8
|
||||
0.30.9
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [0.30.9] - 2025-08-13
|
||||
|
||||
# [0.30.9] - 2025-08-19
|
||||
|
||||
## Changed
|
||||
|
||||
- Countries, visited during a trip, are now being calculated from points to improve performance.
|
||||
|
||||
## Added
|
||||
|
||||
|
|
@ -13,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
- Trial version for cloud users is now available.
|
||||
|
||||
|
||||
|
||||
# [0.30.8] - 2025-08-01
|
||||
|
||||
## Fixed
|
||||
|
|
|
|||
108
Gemfile.lock
108
Gemfile.lock
|
|
@ -10,29 +10,29 @@ GIT
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actioncable (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actionmailbox (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
activejob (= 8.0.2.1)
|
||||
activerecord (= 8.0.2.1)
|
||||
activestorage (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actionmailer (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
actionview (= 8.0.2.1)
|
||||
activejob (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actionpack (8.0.2.1)
|
||||
actionview (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
|
|
@ -40,38 +40,38 @@ GEM
|
|||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actiontext (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
activerecord (= 8.0.2.1)
|
||||
activestorage (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
actionview (8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
activejob (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
activejob (8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
activerecord (8.0.2)
|
||||
activemodel (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
activemodel (8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
activerecord (8.0.2.1)
|
||||
activemodel (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
timeout (>= 0.4.0)
|
||||
activerecord-postgis-adapter (11.0.0)
|
||||
activerecord (~> 8.0.0)
|
||||
rgeo-activerecord (~> 8.0.0)
|
||||
activestorage (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
activestorage (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
activejob (= 8.0.2.1)
|
||||
activerecord (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
marcel (~> 1.0)
|
||||
activesupport (8.0.2)
|
||||
activesupport (8.0.2.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
|
|
@ -298,7 +298,7 @@ GEM
|
|||
date
|
||||
stringio
|
||||
public_suffix (6.0.1)
|
||||
puma (6.6.0)
|
||||
puma (6.6.1)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.5.0)
|
||||
activesupport (>= 3.0.0)
|
||||
|
|
@ -312,20 +312,20 @@ GEM
|
|||
rack (>= 1.3)
|
||||
rackup (2.2.1)
|
||||
rack (>= 3)
|
||||
rails (8.0.2)
|
||||
actioncable (= 8.0.2)
|
||||
actionmailbox (= 8.0.2)
|
||||
actionmailer (= 8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
actiontext (= 8.0.2)
|
||||
actionview (= 8.0.2)
|
||||
activejob (= 8.0.2)
|
||||
activemodel (= 8.0.2)
|
||||
activerecord (= 8.0.2)
|
||||
activestorage (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
rails (8.0.2.1)
|
||||
actioncable (= 8.0.2.1)
|
||||
actionmailbox (= 8.0.2.1)
|
||||
actionmailer (= 8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
actiontext (= 8.0.2.1)
|
||||
actionview (= 8.0.2.1)
|
||||
activejob (= 8.0.2.1)
|
||||
activemodel (= 8.0.2.1)
|
||||
activerecord (= 8.0.2.1)
|
||||
activestorage (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 8.0.2)
|
||||
railties (= 8.0.2.1)
|
||||
rails-dom-testing (2.3.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
|
|
@ -333,9 +333,9 @@ GEM
|
|||
rails-html-sanitizer (1.6.2)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
railties (8.0.2)
|
||||
actionpack (= 8.0.2)
|
||||
activesupport (= 8.0.2)
|
||||
railties (8.0.2.1)
|
||||
actionpack (= 8.0.2.1)
|
||||
activesupport (= 8.0.2.1)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ module Calculateable
|
|||
|
||||
def calculate_distance
|
||||
calculated_distance_meters = calculate_distance_from_coordinates
|
||||
|
||||
self.distance = convert_distance_for_storage(calculated_distance_meters)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,6 @@ class Trip < ApplicationRecord
|
|||
user.tracked_points.where(timestamp: started_at.to_i..ended_at.to_i).order(:timestamp)
|
||||
end
|
||||
|
||||
def countries
|
||||
return points.pluck(:country).uniq.compact if DawarichSettings.store_geodata?
|
||||
|
||||
visited_countries
|
||||
end
|
||||
|
||||
def photo_previews
|
||||
@photo_previews ||= select_dominant_orientation(photos).sample(12)
|
||||
end
|
||||
|
|
@ -35,13 +29,8 @@ class Trip < ApplicationRecord
|
|||
@photo_sources ||= photos.map { _1[:source] }.uniq
|
||||
end
|
||||
|
||||
|
||||
|
||||
def calculate_countries
|
||||
countries =
|
||||
Country.where(id: points.pluck(:country_id).compact.uniq).pluck(:name)
|
||||
|
||||
self.visited_countries = countries
|
||||
self.visited_countries = points.pluck(:country_name).uniq.compact
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -15,12 +15,9 @@
|
|||
<div class="card-body p-4">
|
||||
<div class="stat-title text-xs">Countries</div>
|
||||
<div class="stat-value text-lg">
|
||||
<% if trip.countries.any? %>
|
||||
<%= trip.countries.join(', ') %>
|
||||
<% elsif trip.visited_countries.present? %>
|
||||
<% if trip.visited_countries.any? %>
|
||||
<%= trip.visited_countries.join(', ') %>
|
||||
<% else %>
|
||||
<span class="text-xs">Countries are being calculated...</span>
|
||||
<span class="loading loading-dots loading-sm"></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
|||
114
spec/jobs/trips/calculate_countries_job_spec.rb
Normal file
114
spec/jobs/trips/calculate_countries_job_spec.rb
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Trips::CalculateCountriesJob, type: :job do
|
||||
describe '#perform' do
|
||||
let(:user) { create(:user) }
|
||||
let(:trip) { create(:trip, user: user) }
|
||||
let(:distance_unit) { 'km' }
|
||||
let(:points) do
|
||||
[
|
||||
create(:point, user: user, country_name: 'Germany', timestamp: trip.started_at.to_i + 1.hour),
|
||||
create(:point, user: user, country_name: 'France', timestamp: trip.started_at.to_i + 2.hours),
|
||||
create(:point, user: user, country_name: 'Germany', timestamp: trip.started_at.to_i + 3.hours),
|
||||
create(:point, user: user, country_name: 'Italy', timestamp: trip.started_at.to_i + 4.hours)
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
points # Create the points
|
||||
end
|
||||
|
||||
it 'finds the trip and calculates countries' do
|
||||
expect(Trip).to receive(:find).with(trip.id).and_return(trip)
|
||||
expect(trip).to receive(:calculate_countries)
|
||||
expect(trip).to receive(:save!)
|
||||
|
||||
described_class.perform_now(trip.id, distance_unit)
|
||||
end
|
||||
|
||||
it 'calculates unique countries from trip points' do
|
||||
described_class.perform_now(trip.id, distance_unit)
|
||||
|
||||
trip.reload
|
||||
expect(trip.visited_countries).to contain_exactly('Germany', 'France', 'Italy')
|
||||
end
|
||||
|
||||
it 'broadcasts the update with correct parameters' do
|
||||
expect(Turbo::StreamsChannel).to receive(:broadcast_update_to).with(
|
||||
"trip_#{trip.id}",
|
||||
target: "trip_countries",
|
||||
partial: "trips/countries",
|
||||
locals: { trip: trip, distance_unit: distance_unit }
|
||||
)
|
||||
|
||||
described_class.perform_now(trip.id, distance_unit)
|
||||
end
|
||||
|
||||
context 'when trip has no points' do
|
||||
let(:trip_without_points) { create(:trip, user: user) }
|
||||
|
||||
it 'sets visited_countries to empty array' do
|
||||
trip_without_points.points.destroy_all
|
||||
described_class.perform_now(trip_without_points.id, distance_unit)
|
||||
|
||||
trip_without_points.reload
|
||||
|
||||
expect(trip_without_points.visited_countries).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when points have nil country names' do
|
||||
let(:points_with_nil_countries) do
|
||||
[
|
||||
create(:point, user: user, country_name: 'Germany', timestamp: trip.started_at.to_i + 1.hour),
|
||||
create(:point, user: user, country_name: nil, timestamp: trip.started_at.to_i + 2.hours),
|
||||
create(:point, user: user, country_name: 'France', timestamp: trip.started_at.to_i + 3.hours)
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
# Remove existing points and create new ones with nil countries
|
||||
Point.where(user: user).destroy_all
|
||||
points_with_nil_countries
|
||||
end
|
||||
|
||||
it 'filters out nil country names' do
|
||||
described_class.perform_now(trip.id, distance_unit)
|
||||
|
||||
trip.reload
|
||||
expect(trip.visited_countries).to contain_exactly('Germany', 'France')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when trip is not found' do
|
||||
it 'raises ActiveRecord::RecordNotFound' do
|
||||
expect {
|
||||
described_class.perform_now(999999, distance_unit)
|
||||
}.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when distance_unit is different' do
|
||||
let(:distance_unit) { 'mi' }
|
||||
|
||||
it 'passes the correct distance_unit to broadcast' do
|
||||
expect(Turbo::StreamsChannel).to receive(:broadcast_update_to).with(
|
||||
"trip_#{trip.id}",
|
||||
target: "trip_countries",
|
||||
partial: "trips/countries",
|
||||
locals: { trip: trip, distance_unit: 'mi' }
|
||||
)
|
||||
|
||||
described_class.perform_now(trip.id, distance_unit)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'queue configuration' do
|
||||
it 'uses the trips queue' do
|
||||
expect(described_class.queue_name).to eq('trips')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -26,34 +26,6 @@ RSpec.describe Trip, type: :model do
|
|||
trip.save
|
||||
end
|
||||
end
|
||||
|
||||
context 'when DawarichSettings.store_geodata? is enabled' do
|
||||
before do
|
||||
allow(DawarichSettings).to receive(:store_geodata?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sets the countries' do
|
||||
expect(trip.countries).to eq(trip.points.pluck(:country).uniq.compact)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#countries' do
|
||||
let(:user) { create(:user) }
|
||||
let(:trip) { create(:trip, user:) }
|
||||
let(:points) do
|
||||
create_list(
|
||||
:point,
|
||||
25,
|
||||
:reverse_geocoded,
|
||||
user:,
|
||||
timestamp: (trip.started_at.to_i..trip.ended_at.to_i).to_a.sample
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns the unique countries of the points' do
|
||||
expect(trip.countries).to eq(trip.points.pluck(:country).uniq.compact)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#photo_previews' do
|
||||
|
|
|
|||
Loading…
Reference in a new issue