mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Extract tracks calculation to serializer
This commit is contained in:
parent
862f601e1d
commit
7bd098b54f
5 changed files with 150 additions and 29 deletions
|
|
@ -6,31 +6,10 @@ class MapController < ApplicationController
|
|||
def index
|
||||
@points = points.where('timestamp >= ? AND timestamp <= ?', start_at, end_at)
|
||||
|
||||
@coordinates = []
|
||||
# @points.pluck(:lonlat, :battery, :altitude, :timestamp, :velocity, :id, :country)
|
||||
# .map { |lonlat, *rest| [lonlat.y, lonlat.x, *rest.map(&:to_s)] }
|
||||
tracks_data = current_user.tracks
|
||||
.where('start_at <= ? AND end_at >= ?', Time.zone.at(end_at), Time.zone.at(start_at))
|
||||
.order(start_at: :asc)
|
||||
.pluck(:id, :start_at, :end_at, :distance, :avg_speed, :duration,
|
||||
:elevation_gain, :elevation_loss, :elevation_max, :elevation_min, :original_path)
|
||||
|
||||
@tracks = tracks_data.map do |id, start_at, end_at, distance, avg_speed, duration,
|
||||
elevation_gain, elevation_loss, elevation_max, elevation_min, original_path|
|
||||
{
|
||||
id: id,
|
||||
start_at: start_at.iso8601,
|
||||
end_at: end_at.iso8601,
|
||||
distance: distance&.to_f || 0,
|
||||
avg_speed: avg_speed&.to_f || 0,
|
||||
duration: duration || 0,
|
||||
elevation_gain: elevation_gain || 0,
|
||||
elevation_loss: elevation_loss || 0,
|
||||
elevation_max: elevation_max || 0,
|
||||
elevation_min: elevation_min || 0,
|
||||
original_path: original_path&.to_s
|
||||
}
|
||||
end
|
||||
@coordinates =
|
||||
@points.pluck(:lonlat, :battery, :altitude, :timestamp, :velocity, :id, :country)
|
||||
.map { |lonlat, *rest| [lonlat.y, lonlat.x, *rest.map(&:to_s)] }
|
||||
@tracks = TrackSerializer.new(current_user, start_at, end_at).call
|
||||
@distance = distance
|
||||
@start_at = Time.zone.at(start_at)
|
||||
@end_at = Time.zone.at(end_at)
|
||||
|
|
|
|||
|
|
@ -56,13 +56,19 @@ export function minutesToDaysHoursMinutes(minutes) {
|
|||
export function formatDate(timestamp, timezone) {
|
||||
let date;
|
||||
|
||||
// Handle both Unix timestamps (numbers) and ISO8601 strings
|
||||
// Handle different timestamp formats
|
||||
if (typeof timestamp === 'number') {
|
||||
// Unix timestamp in seconds, convert to milliseconds
|
||||
date = new Date(timestamp * 1000);
|
||||
} else if (typeof timestamp === 'string') {
|
||||
// ISO8601 string, parse directly
|
||||
date = new Date(timestamp);
|
||||
// Check if string is a numeric timestamp
|
||||
if (/^\d+$/.test(timestamp)) {
|
||||
// String representation of Unix timestamp in seconds
|
||||
date = new Date(parseInt(timestamp) * 1000);
|
||||
} else {
|
||||
// Assume it's an ISO8601 string, parse directly
|
||||
date = new Date(timestamp);
|
||||
}
|
||||
} else {
|
||||
// Invalid input
|
||||
return 'Invalid Date';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { minutesToDaysHoursMinutes } from "../maps/helpers";
|
|||
|
||||
// Track-specific color palette - different from regular polylines
|
||||
export const trackColorPalette = {
|
||||
default: 'blue', // Green - distinct from blue polylines
|
||||
default: 'red', // Green - distinct from blue polylines
|
||||
hover: '#FF6B35', // Orange-red for hover
|
||||
active: '#E74C3C', // Red for active/clicked
|
||||
start: '#2ECC71', // Green for start marker
|
||||
|
|
|
|||
47
app/serializers/track_serializer.rb
Normal file
47
app/serializers/track_serializer.rb
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TrackSerializer
|
||||
def initialize(user, start_at, end_at)
|
||||
@user = user
|
||||
@start_at = start_at
|
||||
@end_at = end_at
|
||||
end
|
||||
|
||||
def call
|
||||
tracks_data = user.tracks
|
||||
.where('start_at <= ? AND end_at >= ?', Time.zone.at(end_at), Time.zone.at(start_at))
|
||||
.order(start_at: :asc)
|
||||
.pluck(:id, :start_at, :end_at, :distance, :avg_speed, :duration,
|
||||
:elevation_gain, :elevation_loss, :elevation_max, :elevation_min, :original_path)
|
||||
|
||||
tracks_data.map do |id, start_at, end_at, distance, avg_speed, duration,
|
||||
elevation_gain, elevation_loss, elevation_max, elevation_min, original_path|
|
||||
serialize_track_data(id, start_at, end_at, distance, avg_speed, duration,
|
||||
elevation_gain, elevation_loss, elevation_max, elevation_min, original_path)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user, :start_at, :end_at
|
||||
|
||||
def serialize_track_data(
|
||||
id, start_at, end_at, distance, avg_speed, duration, elevation_gain,
|
||||
elevation_loss, elevation_max, elevation_min, original_path
|
||||
)
|
||||
|
||||
{
|
||||
id: id,
|
||||
start_at: start_at.iso8601,
|
||||
end_at: end_at.iso8601,
|
||||
distance: distance.to_f,
|
||||
avg_speed: avg_speed.to_f,
|
||||
duration: duration,
|
||||
elevation_gain: elevation_gain,
|
||||
elevation_loss: elevation_loss,
|
||||
elevation_max: elevation_max,
|
||||
elevation_min: elevation_min,
|
||||
original_path: original_path.to_s
|
||||
}
|
||||
end
|
||||
end
|
||||
89
spec/serializers/track_serializer_spec.rb
Normal file
89
spec/serializers/track_serializer_spec.rb
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TrackSerializer do
|
||||
describe '#call' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'when serializing user tracks without date range restrictions' do
|
||||
subject(:serializer) { described_class.new(user, 1.year.ago.to_i, 1.year.from_now.to_i).call }
|
||||
|
||||
let!(:track1) { create(:track, user: user, start_at: 2.hours.ago, end_at: 1.hour.ago) }
|
||||
let!(:track2) { create(:track, user: user, start_at: 4.hours.ago, end_at: 3.hours.ago) }
|
||||
|
||||
it 'returns an array of serialized tracks' do
|
||||
expect(serializer).to be_an(Array)
|
||||
expect(serializer.length).to eq(2)
|
||||
end
|
||||
|
||||
it 'serializes each track correctly' do
|
||||
serialized_ids = serializer.map { |track| track[:id] }
|
||||
expect(serialized_ids).to contain_exactly(track1.id, track2.id)
|
||||
end
|
||||
|
||||
it 'formats timestamps as ISO8601 for all tracks' do
|
||||
serializer.each do |track|
|
||||
expect(track[:start_at]).to match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
||||
expect(track[:end_at]).to match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes all required fields for each track' do
|
||||
serializer.each do |track|
|
||||
expect(track.keys).to contain_exactly(
|
||||
:id, :start_at, :end_at, :distance, :avg_speed, :duration,
|
||||
:elevation_gain, :elevation_loss, :elevation_max, :elevation_min, :original_path
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'handles numeric values correctly' do
|
||||
serializer.each do |track|
|
||||
expect(track[:distance]).to be_a(Numeric)
|
||||
expect(track[:avg_speed]).to be_a(Numeric)
|
||||
expect(track[:duration]).to be_a(Numeric)
|
||||
expect(track[:elevation_gain]).to be_a(Numeric)
|
||||
expect(track[:elevation_loss]).to be_a(Numeric)
|
||||
expect(track[:elevation_max]).to be_a(Numeric)
|
||||
expect(track[:elevation_min]).to be_a(Numeric)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when serializing user tracks with date range' do
|
||||
subject(:serializer) { described_class.new(user, start_at.to_i, end_at.to_i).call }
|
||||
|
||||
let(:start_at) { 6.hours.ago }
|
||||
let(:end_at) { 30.minutes.ago }
|
||||
let!(:track_in_range) { create(:track, user: user, start_at: 2.hours.ago, end_at: 1.hour.ago) }
|
||||
let!(:track_out_of_range) { create(:track, user: user, start_at: 10.hours.ago, end_at: 9.hours.ago) }
|
||||
|
||||
it 'returns an array of serialized tracks' do
|
||||
expect(serializer).to be_an(Array)
|
||||
expect(serializer.length).to eq(1)
|
||||
end
|
||||
|
||||
it 'only includes tracks within the date range' do
|
||||
serialized_ids = serializer.map { |track| track[:id] }
|
||||
expect(serialized_ids).to contain_exactly(track_in_range.id)
|
||||
expect(serialized_ids).not_to include(track_out_of_range.id)
|
||||
end
|
||||
|
||||
it 'formats timestamps as ISO8601' do
|
||||
serializer.each do |track|
|
||||
expect(track[:start_at]).to match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
||||
expect(track[:end_at]).to match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has no tracks' do
|
||||
subject(:serializer) { described_class.new(user, 1.day.ago.to_i, Time.current.to_i).call }
|
||||
|
||||
it 'returns an empty array' do
|
||||
expect(serializer).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue