diff --git a/.app_version b/.app_version index 379191a4..2094a100 100644 --- a/.app_version +++ b/.app_version @@ -1 +1 @@ -0.23.7 +0.24.0 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a61f0adb..6569b129 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # Base-Image for Ruby and Node.js -FROM ruby:3.3.4-alpine +FROM ruby:3.4.1-alpine ENV APP_PATH=/var/app ENV BUNDLE_VERSION=2.5.21 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d85eadd..fb1a5bb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.3.4' + ruby-version: '3.4.1' bundler-cache: true - name: Set up Node.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 095bcdb4..372d12b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,54 @@ - # Change Log 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.23.7 - 2025-02-06 +# 0.24.0 - 2025-02-09 + +## Points speed units + +Dawarich expects speed to be sent in meters per second. It's already known that OwnTracks and GPSLogger (in some configurations) are sending speed in kilometers per hour. + +In GPSLogger it's easily fixable: if you previously had `"vel": "%SPD_KMH"`, change it to `"vel": "%SPD"`, like it's described in the [docs](https://dawarich.app/docs/tutorials/track-your-location#gps-logger). + +In OwnTracks it's a bit more complicated. You can't change the speed unit in the settings, so Dawarich will expect speed in kilometers per hour and will convert it to meters per second. Nothing is needed to be done from your side. + +Now, we need to fix existing points with speed in kilometers per hour. The following guide assumes that you have been tracking your location exclusively with speed in kilometers per hour. If you have been using both speed units (say, were tracking with OwnTracks in kilometers per hour and with GPSLogger in meters per second), you need to decide what to do with points that have speed in kilometers per hour, as there is no easy way to distinguish them from points with speed in meters per second. + +To convert speed in kilometers per hour to meters per second in your points, follow these steps: + +1. Enter [Dawarich console](https://dawarich.app/docs/FAQ#how-to-enter-dawarich-console) +2. Run `points = Point.where(import_id: nil).where.not(velocity: [nil, "0"]).where("velocity NOT LIKE '%.%'")`. This will return all tracked (not imported) points. +3. Run +```ruby +points.update_all("velocity = CAST(ROUND(CAST((CAST(velocity AS FLOAT) * 1000 / 3600) AS NUMERIC), 1) AS TEXT)") + +``` + +This will convert speed in kilometers per hour to meters per second and round it to 1 decimal place. + +If you have been using both speed units, but you know the dates where you were tracking with speed in kilometers per hour, on the second step of the instruction above, you can add `where("timestamp BETWEEN ? AND ?", Date.parse("2025-01-01").beginning_of_day.to_i, Date.parse("2025-01-31").end_of_day.to_i)` to the query to convert speed in kilometers per hour to meters per second only for a specific period of time. Resulting query will look like this: + +```ruby +start_at = DateTime.new(2025, 1, 1, 0, 0, 0).in_time_zone(Time.current.time_zone).to_i +end_at = DateTime.new(2025, 1, 31, 23, 59, 59).in_time_zone(Time.current.time_zone).to_i +points = Point.where(import_id: nil).where.not(velocity: [nil, "0"]).where("timestamp BETWEEN ? AND ?", start_at, end_at).where("velocity NOT LIKE '%.%'") +``` + +This will select points tracked between January 1st and January 31st 2025. Then just use step 3 to convert speed in kilometers per hour to meters per second. + +### Changed + +- Speed for points, that are sent to Dawarich via `POST /api/v1/owntracks/points` endpoint, will now be converted to meters per second, if `topic` param is sent. The official GPSLogger instructions are assuming user won't be sending `topic` param, so this shouldn't affect you if you're using GPSLogger. + +### Fixed + +- After deleting one point from the map, other points can now be deleted as well. #723 #678 +- Fixed a bug where export file was not being deleted from the server after it was deleted. #808 +- After an area was drawn on the map, a popup is now being shown to allow user to provide a name and save the area. #740 +- Docker entrypoints now use database name to fix problem with custom database names. +- Garmin GPX files with empty tracks are now being imported correctly. #827 ### Added @@ -287,7 +330,7 @@ To mount a custom `postgresql.conf` file, you need to create a `postgresql.conf` ```diff dawarich_db: - image: postgres:14.2-alpine + image: postgis/postgis:14-3.5-alpine shm_size: 1G container_name: dawarich_db volumes: @@ -318,7 +361,7 @@ An example of a custom `postgresql.conf` file is provided in the `postgresql.con ```diff ... dawarich_db: - image: postgres:14.2-alpine + image: postgis/postgis:14-3.5-alpine + shm_size: 1G ... ``` @@ -1259,7 +1302,7 @@ deploy: - shared_data:/var/shared/redis + restart: always dawarich_db: - image: postgres:14.2-alpine + image: postgis/postgis:14-3.5-alpine container_name: dawarich_db volumes: - db_data:/var/lib/postgresql/data diff --git a/app/controllers/exports_controller.rb b/app/controllers/exports_controller.rb index 6f9b4c65..34b239dc 100644 --- a/app/controllers/exports_controller.rb +++ b/app/controllers/exports_controller.rb @@ -23,7 +23,11 @@ class ExportsController < ApplicationController end def destroy - @export.destroy + ActiveRecord::Base.transaction do + @export.destroy + + File.delete(Rails.root.join('public', 'exports', @export.name)) + end redirect_to exports_url, notice: 'Export was successfully destroyed.', status: :see_other end diff --git a/app/javascript/controllers/maps_controller.js b/app/javascript/controllers/maps_controller.js index 997821da..2e921c86 100644 --- a/app/javascript/controllers/maps_controller.js +++ b/app/javascript/controllers/maps_controller.js @@ -13,8 +13,7 @@ import { getSpeedColor } from "../maps/polylines"; -import { fetchAndDrawAreas } from "../maps/areas"; -import { handleAreaCreated } from "../maps/areas"; +import { fetchAndDrawAreas, handleAreaCreated } from "../maps/areas"; import { showFlashMessage, fetchAndDisplayPhotos, debounce } from "../maps/helpers"; @@ -67,7 +66,7 @@ export default class extends Controller { imperial: this.distanceUnit === 'mi', metric: this.distanceUnit === 'km', maxWidth: 120 - }).addTo(this.map) + }).addTo(this.map); // Add stats control const StatsControl = L.Control.extend({ @@ -107,7 +106,13 @@ export default class extends Controller { // Create a proper Leaflet layer for fog this.fogOverlay = createFogOverlay(); - this.areasLayer = L.layerGroup(); // Initialize areas layer + // Create custom pane for areas + this.map.createPane('areasPane'); + this.map.getPane('areasPane').style.zIndex = 650; + this.map.getPane('areasPane').style.pointerEvents = 'all'; + + // Initialize areasLayer as a feature group and add it to the map immediately + this.areasLayer = new L.FeatureGroup(); this.photoMarkers = L.layerGroup(); this.setupScratchLayer(this.countryCodesMap); @@ -248,10 +253,13 @@ export default class extends Controller { } // Store panel state before disconnecting if (this.rightPanel) { - const finalState = document.querySelector('.leaflet-right-panel').style.display !== 'none' ? 'true' : 'false'; + const panel = document.querySelector('.leaflet-right-panel'); + const finalState = panel ? (panel.style.display !== 'none' ? 'true' : 'false') : 'false'; localStorage.setItem('mapPanelOpen', finalState); } - this.map.remove(); + if (this.map) { + this.map.remove(); + } } setupSubscription() { @@ -565,18 +573,23 @@ export default class extends Controller { fillOpacity: 0.5, }, }, - }, + } }); // Handle circle creation - this.map.on(L.Draw.Event.CREATED, (event) => { + this.map.on('draw:created', (event) => { const layer = event.layer; if (event.layerType === 'circle') { - handleAreaCreated(this.areasLayer, layer, this.apiKey); + try { + // Add the layer to the map first + layer.addTo(this.map); + handleAreaCreated(this.areasLayer, layer, this.apiKey); + } catch (error) { + console.error("Error in handleAreaCreated:", error); + console.error(error.stack); // Add stack trace + } } - - this.drawnItems.addLayer(layer); }); } diff --git a/app/javascript/maps/areas.js b/app/javascript/maps/areas.js index 10402c13..66d5442b 100644 --- a/app/javascript/maps/areas.js +++ b/app/javascript/maps/areas.js @@ -1,49 +1,83 @@ +import { showFlashMessage } from "./helpers"; + export function handleAreaCreated(areasLayer, layer, apiKey) { const radius = layer.getRadius(); const center = layer.getLatLng(); const formHtml = ` -
+

New Area

-
+
- - +
-
- +
+ +
`; - layer.bindPopup( - formHtml, { - maxWidth: "auto", - minWidth: 300 - } - ).openPopup(); + layer.bindPopup(formHtml, { + maxWidth: "auto", + minWidth: 300, + closeButton: true, + closeOnClick: false, + className: 'area-form-popup' + }).openPopup(); - layer.on('popupopen', () => { - const form = document.getElementById('circle-form'); - - if (!form) return; - - form.addEventListener('submit', (e) => { - e.preventDefault(); - saveArea(new FormData(form), areasLayer, layer, apiKey); - }); - }); - - // Add the layer to the areas layer group areasLayer.addLayer(layer); + + // Bind the event handler immediately after opening the popup + setTimeout(() => { + const form = document.getElementById('circle-form'); + const saveButton = document.getElementById('save-area-btn'); + const nameInput = document.getElementById('circle-name'); + + if (!form || !saveButton || !nameInput) { + console.error('Required elements not found'); + return; + } + + // Focus the name input + nameInput.focus(); + + // Remove any existing click handlers + const newSaveButton = saveButton.cloneNode(true); + saveButton.parentNode.replaceChild(newSaveButton, saveButton); + + // Add click handler + newSaveButton.addEventListener('click', (e) => { + console.log('Save button clicked'); + e.preventDefault(); + e.stopPropagation(); + + if (!nameInput.value.trim()) { + nameInput.classList.add('input-error'); + return; + } + + const formData = new FormData(form); + + saveArea(formData, areasLayer, layer, apiKey); + }); + }, 100); // Small delay to ensure DOM is ready } export function saveArea(formData, areasLayer, layer, apiKey) { @@ -79,9 +113,13 @@ export function saveArea(formData, areasLayer, layer, apiKey) { // Add event listener for the delete button layer.on('popupopen', () => { - document.querySelector('.delete-area').addEventListener('click', () => { - deleteArea(data.id, areasLayer, layer, apiKey); - }); + const deleteButton = document.querySelector('.delete-area'); + if (deleteButton) { + deleteButton.addEventListener('click', (e) => { + e.preventDefault(); + deleteArea(data.id, areasLayer, layer, apiKey); + }); + } }); }) .catch(error => { @@ -104,6 +142,8 @@ export function deleteArea(id, areasLayer, layer, apiKey) { }) .then(data => { areasLayer.removeLayer(layer); // Remove the layer from the areas layer group + + showFlashMessage('notice', `Area was successfully deleted!`); }) .catch(error => { console.error('There was a problem with the delete request:', error); @@ -124,33 +164,91 @@ export function fetchAndDrawAreas(areasLayer, apiKey) { return response.json(); }) .then(data => { + // Clear existing areas + areasLayer.clearLayers(); + data.forEach(area => { - // Check if necessary fields are present if (area.latitude && area.longitude && area.radius && area.name && area.id) { - const layer = L.circle([area.latitude, area.longitude], { - radius: area.radius, + // Convert string coordinates to numbers + const lat = parseFloat(area.latitude); + const lng = parseFloat(area.longitude); + const radius = parseFloat(area.radius); + + // Create circle with custom pane + const circle = L.circle([lat, lng], { + radius: radius, color: 'red', fillColor: '#f03', - fillOpacity: 0.5 - }).bindPopup(` - Name: ${area.name}
- Radius: ${Math.round(area.radius)} meters
- [Delete] - `); - - areasLayer.addLayer(layer); // Add to areas layer group - - // Add event listener for the delete button - layer.on('popupopen', () => { - document.querySelector('.delete-area').addEventListener('click', (e) => { - e.preventDefault(); - if (confirm('Are you sure you want to delete this area?')) { - deleteArea(area.id, areasLayer, layer, apiKey); - } - }); + fillOpacity: 0.5, + weight: 2, + interactive: true, + bubblingMouseEvents: false, + pane: 'areasPane' }); - } else { - console.error('Area missing required fields:', area); + + // Bind popup content + const popupContent = ` +
+
+

${area.name}

+

Radius: ${Math.round(radius)} meters

+

Center: [${lat.toFixed(4)}, ${lng.toFixed(4)}]

+
+ +
+
+
+ `; + circle.bindPopup(popupContent); + + // Add delete button handler when popup opens + circle.on('popupopen', () => { + const deleteButton = document.querySelector('.delete-area[data-id="' + area.id + '"]'); + if (deleteButton) { + deleteButton.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + if (confirm('Are you sure you want to delete this area?')) { + deleteArea(area.id, areasLayer, circle, apiKey); + } + }); + } + }); + + // Add to layer group + areasLayer.addLayer(circle); + + // Wait for the circle to be added to the DOM + setTimeout(() => { + const circlePath = circle.getElement(); + if (circlePath) { + // Add CSS styles + circlePath.style.cursor = 'pointer'; + circlePath.style.transition = 'all 0.3s ease'; + + // Add direct DOM event listeners + circlePath.addEventListener('click', (e) => { + e.stopPropagation(); + circle.openPopup(); + }); + + circlePath.addEventListener('mouseenter', (e) => { + e.stopPropagation(); + circle.setStyle({ + fillOpacity: 0.8, + weight: 3 + }); + }); + + circlePath.addEventListener('mouseleave', (e) => { + e.stopPropagation(); + circle.setStyle({ + fillOpacity: 0.5, + weight: 2 + }); + }); + } + }, 100); } }); }) diff --git a/app/services/google_maps/phone_takeout_parser.rb b/app/services/google_maps/phone_takeout_parser.rb index 27b65885..8721f8d5 100644 --- a/app/services/google_maps/phone_takeout_parser.rb +++ b/app/services/google_maps/phone_takeout_parser.rb @@ -144,7 +144,7 @@ class GoogleMaps::PhoneTakeoutParser end def parse_raw_array(raw_data) - raw_data.map do |data_point| + raw_data.flat_map do |data_point| if data_point.dig('visit', 'topCandidate', 'placeLocation') parse_visit_place_location(data_point) elsif data_point.dig('activity', 'start') && data_point.dig('activity', 'end') @@ -152,7 +152,7 @@ class GoogleMaps::PhoneTakeoutParser elsif data_point['timelinePath'] parse_timeline_path(data_point) end - end.flatten.compact + end.compact end def parse_semantic_segments(semantic_segments) diff --git a/app/services/gpx/track_parser.rb b/app/services/gpx/track_parser.rb index 10f13983..20c2837a 100644 --- a/app/services/gpx/track_parser.rb +++ b/app/services/gpx/track_parser.rb @@ -28,7 +28,7 @@ class Gpx::TrackParser segments = track['trkseg'] segments_array = segments.is_a?(Array) ? segments : [segments] - segments_array.map { |segment| segment['trkpt'] } + segments_array.compact.map { |segment| segment['trkpt'] } end def create_point(point, index) diff --git a/app/services/own_tracks/params.rb b/app/services/own_tracks/params.rb index 16ef464d..e5319893 100644 --- a/app/services/own_tracks/params.rb +++ b/app/services/own_tracks/params.rb @@ -16,7 +16,7 @@ class OwnTracks::Params altitude: params[:alt], accuracy: params[:acc], vertical_accuracy: params[:vac], - velocity: params[:vel], + velocity: speed, ssid: params[:SSID], bssid: params[:BSSID], tracker_id: params[:tid], @@ -69,4 +69,16 @@ class OwnTracks::Params else 'unknown' end end + + def speed + return params[:vel] unless owntracks_point? + + # OwnTracks speed is in km/h, so we need to convert it to m/s + # Reference: https://owntracks.org/booklet/tech/json/ + ((params[:vel].to_f * 1000) / 3600).round(1).to_s + end + + def owntracks_point? + params[:topic].present? + end end diff --git a/docker/Dockerfile.prod b/docker/Dockerfile.prod index 8e801e98..1d383cc7 100644 --- a/docker/Dockerfile.prod +++ b/docker/Dockerfile.prod @@ -1,4 +1,4 @@ -FROM ruby:3.3.4-alpine +FROM ruby:3.4.1-alpine ENV APP_PATH=/var/app ENV BUNDLE_VERSION=2.5.21 diff --git a/docker/docker-compose.production.yml b/docker/docker-compose.production.yml index a4b83a34..42b64370 100644 --- a/docker/docker-compose.production.yml +++ b/docker/docker-compose.production.yml @@ -17,7 +17,7 @@ services: start_period: 30s timeout: 10s dawarich_db: - image: postgres:17-alpine + image: postgres:17-alpine # TODO: Use postgis here shm_size: 1G container_name: dawarich_db volumes: diff --git a/docker/docker-compose_mounted_volumes.yml b/docker/docker-compose_mounted_volumes.yml deleted file mode 100644 index ef61f49a..00000000 --- a/docker/docker-compose_mounted_volumes.yml +++ /dev/null @@ -1,159 +0,0 @@ -networks: - dawarich: - - -volumes: - dawarich_public: - name: dawarich_public - dawarich_keydb: - name: dawarich_keydb - dawarich_shared: - name: dawarich_shared - watched: - name: dawarich_watched - -services: - app: - container_name: dawarich_app - image: freikin/dawarich:latest - restart: unless-stopped - depends_on: - db: - condition: service_healthy - restart: true - keydb: - condition: service_healthy - restart: true - networks: - - dawarich - ports: - - 3000:3000 - environment: - TIME_ZONE: Europe/London - RAILS_ENV: development - REDIS_URL: redis://keydb:6379/0 - DATABASE_HOST: db - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: password - DATABASE_NAME: dawarich_development - MIN_MINUTES_SPENT_IN_CITY: 60 - APPLICATION_HOSTS: localhost - APPLICATION_PROTOCOL: http - DISTANCE_UNIT: km - stdin_open: true - tty: true - entrypoint: dev-entrypoint.sh - command: [ 'bin/dev' ] - volumes: - - dawarich_public:/var/app/dawarich_public - - watched:/var/app/tmp/imports/watched - healthcheck: - test: [ "CMD-SHELL", "wget -qO - http://127.0.0.1:3000/api/v1/health | grep -q '\"status\"\\s*:\\s*\"ok\"'" ] - start_period: 60s - interval: 15s - timeout: 5s - retries: 3 - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "5" - deploy: - resources: - limits: - cpus: '0.50' # Limit CPU usage to 50% of one core - memory: '2G' # Limit memory usage to 2GB - - sidekiq: - container_name: dawarich_sidekiq - hostname: sidekiq - image: freikin/dawarich:latest - restart: unless-stopped - depends_on: - app: - condition: service_healthy - restart: true - db: - condition: service_healthy - restart: true - keydb: - condition: service_healthy - restart: true - networks: - - dawarich - environment: - RAILS_ENV: development - REDIS_URL: redis://keydb:6379/0 - DATABASE_HOST: db - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: password - DATABASE_NAME: dawarich_development - APPLICATION_HOSTS: localhost - BACKGROUND_PROCESSING_CONCURRENCY: 10 - APPLICATION_PROTOCOL: http - DISTANCE_UNIT: km - stdin_open: true - tty: true - entrypoint: dev-entrypoint.sh - command: [ 'sidekiq' ] - volumes: - - dawarich_public:/var/app/dawarich_public - - watched:/var/app/tmp/imports/watched - logging: - driver: "json-file" - options: - max-size: "100m" - max-file: "5" - healthcheck: - test: [ "CMD-SHELL", "bundle exec sidekiqmon processes | grep $${HOSTNAME}" ] - interval: 10s - retries: 5 - start_period: 30s - timeout: 10s - deploy: - resources: - limits: - cpus: '0.50' # Limit CPU usage to 50% of one core - memory: '2G' # Limit memory usage to 2GB - - keydb: - container_name: dawarich-keydb - image: eqalpha/keydb:x86_64_v6.3.4 - restart: unless-stopped - networks: - - dawarich - environment: - - TZ=Europe/London - - PUID=1000 - - PGID=1000 - command: keydb-server /etc/keydb/keydb.conf --appendonly yes --server-threads 4 --active-replica no - volumes: - - dawarich_keydb:/data - - dawarich_shared:/var/shared/redis - healthcheck: - test: [ "CMD", "keydb-cli", "ping" ] - start_period: 60s - interval: 15s - timeout: 5s - retries: 3 - - db: - container_name: dawarich-db - hostname: db - image: postgres:16.4-alpine3.20 - restart: unless-stopped - networks: - - dawarich - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DATABASE: dawarich - volumes: - - ./db:/var/lib/postgresql/data - - dawarich_shared:/var/shared - healthcheck: - test: [ "CMD-SHELL", "pg_isready -q -d $${POSTGRES_DATABASE} -U $${POSTGRES_USER} -h localhost" ] - start_period: 60s - interval: 15s - timeout: 5s - retries: 3 diff --git a/docker/sidekiq-entrypoint.sh b/docker/sidekiq-entrypoint.sh index 1083891b..cc4e20cd 100644 --- a/docker/sidekiq-entrypoint.sh +++ b/docker/sidekiq-entrypoint.sh @@ -24,7 +24,7 @@ fi # Wait for the database to become available echo "⏳ Waiting for database to be ready..." -until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -c '\q'; do +until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -d "$DATABASE_NAME" -c '\q'; do >&2 echo "Postgres is unavailable - retrying..." sleep 2 done diff --git a/docker/web-entrypoint.sh b/docker/web-entrypoint.sh index 230f91cc..5c82d1b0 100644 --- a/docker/web-entrypoint.sh +++ b/docker/web-entrypoint.sh @@ -29,14 +29,14 @@ rm -f $APP_PATH/tmp/pids/server.pid # Wait for the database to become available echo "⏳ Waiting for database to be ready..." -until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -c '\q'; do +until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -d "$DATABASE_NAME" -c '\q'; do >&2 echo "Postgres is unavailable - retrying..." sleep 2 done echo "✅ PostgreSQL is ready!" # Create database if it doesn't exist -if ! PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -c "SELECT 1 FROM pg_database WHERE datname='$DATABASE_NAME'" | grep -q 1; then +if ! PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USERNAME" -d "$DATABASE_NAME" -c "SELECT 1 FROM pg_database WHERE datname='$DATABASE_NAME'" | grep -q 1; then echo "Creating database $DATABASE_NAME..." bundle exec rails db:create fi diff --git a/docs/synology/docker-compose.yml b/docs/synology/docker-compose.yml index 62092437..5b06bc21 100644 --- a/docs/synology/docker-compose.yml +++ b/docs/synology/docker-compose.yml @@ -10,7 +10,7 @@ services: - ./redis:/var/shared/redis dawarich_db: - image: postgres:14.2-alpine + image: postgis/postgis:14-3.5-alpine container_name: dawarich_db restart: unless-stopped environment: diff --git a/spec/fixtures/files/gpx/garmin_example.gpx b/spec/fixtures/files/gpx/garmin_example.gpx index 04c7a6dd..d3b2ee30 100644 --- a/spec/fixtures/files/gpx/garmin_example.gpx +++ b/spec/fixtures/files/gpx/garmin_example.gpx @@ -27,5 +27,6 @@ 8.8 + diff --git a/spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx b/spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx index 8797d0a2..fbf74bcb 100644 --- a/spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx +++ b/spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx @@ -135,206 +135,6 @@ 0 - - 719 - - 3.8 - - 0 - - - - 719.2 - - 3.8 - - 0 - - - - 719.2 - - 4.2 - - 0 - - - - 719.2 - - 3.8 - - 0 - - - - 719.1 - - 4.2 - - 0 - - - - 719.1 - - 4.4 - - 0 - - - - 719 - - 4.2 - - 0 - - - - 719.1 - - 4.5 - - 0 - - - - 719.1 - - 7.2 - - 0 - - - - 719.1 - - 6.3 - - 0 - - - - 719 - - 5.8 - - 0 - - - - 719.1 - - 5 - - 0 - - - - 719.1 - - 4.6 - - 0 - - - - 719.1 - - 5.1 - - 0 - - - - 719 - - 4.9 - - 0 - - - - 719 - - 4.8 - - 0 - - - - 719 - - 5.5 - - 0 - - - - 719 - - 4.7 - - 0.4 - - - - 719 - - 4.4 - - 0.2 - - - - 719 - - 4.3 - - 0.1 - - - - 719.1 - - 3.9 - - 0 - - - - 719.1 - - 3.8 - - 0 - - - - 719.1 - - 3.9 - - 0 - - - - 719 - - 3.9 - - 0 - - - - 719.1 - - 4 - - 0 - - @@ -441,1262 +241,6 @@ 0 - - 1011.2 - - 4.1 - - 1.7 - - - - 1011 - - 4.1 - - 1.9 - - - - 1011.4 - - 3.8 - - 2.9 - - - - 1013.9 - - 3.8 - - 3.1 - - - - 1015.7 - - 3.8 - - 3.2 - - - - 1018.5 - - 3.8 - - 2.7 - - - - 1019.6 - - 3.8 - - 2.6 - - - - 1022.5 - - 3.8 - - 2.9 - - - - 1022.4 - - 3.8 - - 2.2 - - - - 1021.3 - - 3.8 - - 1.2 - - - - 1023.4 - - 3.8 - - 0.6 - - - - 1022.3 - - 3.8 - - 0.4 - - - - 1024.7 - - 3.8 - - 0.2 - - - - 1024.7 - - 3.8 - - 0.1 - - - - 1025.6 - - 3.8 - - 4.2 - - - - 1027.6 - - 3.8 - - 6.4 - - - - 1027.3 - - 3.8 - - 3.8 - - - - 1028.1 - - 3.8 - - 5.8 - - - - 1029.6 - - 3.8 - - 1.3 - - - - 1028.8 - - 3.8 - - 0.1 - - - - 1029.2 - - 3.8 - - 0.7 - - - - 1027.8 - - 3.8 - - 0.4 - - - - 1028.2 - - 3.8 - - 0.3 - - - - 1028.4 - - 3.8 - - 2.8 - - - - 1029.9 - - 3.8 - - 4.9 - - - - 1031.5 - - 3.8 - - 0.1 - - - - 1031.8 - - 3.8 - - 0.2 - - - - 1032.7 - - 3.8 - - 0.1 - - - - 1032.7 - - 3.8 - - 0 - - - - 1032.4 - - 3.8 - - 2.7 - - - - 1032.8 - - 3.8 - - 2 - - - - 1033.1 - - 3.8 - - 3.1 - - - - 1035.3 - - 3.8 - - 4.2 - - - - 1037 - - 3.8 - - 4.8 - - - - 1039.6 - - 3.8 - - 3.4 - - - - 1041.5 - - 3.8 - - 1.4 - - - - 1041.4 - - 3.8 - - 0 - - - - 1040.5 - - 3.8 - - 0.1 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1040.2 - - 3.8 - - 0 - - - - 1039.9 - - 3.8 - - 3.2 - - - - 1042.2 - - 3.8 - - 5.6 - - - - 1045.7 - - 3.8 - - 5.2 - - - - 1048 - - 3.8 - - 5 - - - - 1048.5 - - 3.8 - - 4 - - - - 1049.7 - - 3.8 - - 0.1 - - - - 1049.9 - - 3.8 - - 0.1 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.2 - - 3.8 - - 0 - - - - 1050.3 - - 3.8 - - 0 - - - - 1050.3 - - 3.8 - - 0 - - - - 1049.9 - - 3.8 - - 0.3 - - - - 1049.9 - - 3.8 - - 0.1 - - - - 1049.3 - - 3.8 - - 0 - - - - 1049.2 - - 3.8 - - 0 - - - - 1049.3 - - 3.8 - - 0 - - - - 1049.8 - - 3.8 - - 1.3 - - - - 1050.6 - - 3.8 - - 3.2 - - - - 1051.7 - - 3.8 - - 4.5 - - - - 1054 - - 3.8 - - 4.6 - - - - 1057.6 - - 3.8 - - 4.3 - - - - 1059.3 - - 3.8 - - 4.8 - - - - 1060.7 - - 3.8 - - 4.3 - - - - 1063.2 - - 3.8 - - 2.3 - - - - 1063.7 - - 3.8 - - 1.7 - - - - 1064.8 - - 3.8 - - 0.6 - - - - 1064.9 - - 3.8 - - 0.3 - - - - 1064.7 - - 3.8 - - 0 - - - - 1064.7 - - 3.8 - - 0 - - - - 1064.7 - - 3.8 - - 0 - - - - 1064.7 - - 3.8 - - 0 - - - - 1064.7 - - 3.8 - - 0 - - - - 1064.7 - - 3.8 - - 0 - - - - 1065.3 - - 3.8 - - 1.4 - - - - 1065.1 - - 3.8 - - 3 - - - - 1063.7 - - 3.8 - - 1.9 - - - - 1065.5 - - 3.8 - - 2 - - - - 1065 - - 3.8 - - 2.3 - - - - 1065.1 - - 3.8 - - 3.2 - - - - 1066.4 - - 3.8 - - 2.6 - - - - 1065.9 - - 3.8 - - 3.9 - - - - 1066.4 - - 3.8 - - 2.9 - - - - 1066.4 - - 3.8 - - 4.1 - - - - 1064.8 - - 3.8 - - 4.2 - - - - 1062.8 - - 3.8 - - 5.8 - - - - 1059.8 - - 3.8 - - 7.3 - - - - 1060.6 - - 3.8 - - 8 - - - - 1060.9 - - 3.8 - - 7.4 - - - - 1060 - - 3.8 - - 7.8 - - - - 1058.2 - - 3.8 - - 5.3 - - - - 1053.7 - - 3.8 - - 7.1 - - - - 1055.1 - - 3.8 - - 6.3 - - - - 1056.1 - - 3.8 - - 7.1 - - - - 1053.5 - - 3.8 - - 5.9 - - - - 1054.6 - - 3.8 - - 2.8 - - - - 1053.8 - - 3.8 - - 4.5 - - - - 1053.2 - - 3.8 - - 5.4 - - - - 1054.2 - - 3.8 - - 5 - - - - 1053.7 - - 3.8 - - 6 - - - - 1053.9 - - 3.8 - - 5.5 - - - - 1054.9 - - 3.8 - - 3 - - - - 1056.4 - - 3.8 - - 4.3 - - - - 1057.2 - - 3.8 - - 2.9 - - - - 1057.5 - - 3.8 - - 3.9 - - - - 1059.1 - - 3.8 - - 6.6 - - - - 1062 - - 3.8 - - 5.9 - - - - 1064.6 - - 3.8 - - 3.9 - - - - 1065.8 - - 3.8 - - 5.3 - - - - 1067.7 - - 3.8 - - 5.4 - - - - 1068.6 - - 3.8 - - 4.1 - - - - 1068.2 - - 3.8 - - 0.9 - - - - 1069.5 - - 3.8 - - 1.5 - - - - 1069.4 - - 3.8 - - 0.1 - - - - 1069.4 - - 3.8 - - 0.1 - - - - 1069.4 - - 3.8 - - 0 - - - - 1068.9 - - 3.8 - - 2 - - - - 1069.9 - - 3.8 - - 4.9 - - - - 1070 - - 3.8 - - 3.4 - - - - 1070.8 - - 3.8 - - 2.5 - - - - 1072.1 - - 3.8 - - 2.3 - - - - 1072.3 - - 3.8 - - 3.2 - - - - 1073.2 - - 3.8 - - 2.2 - - - - 1072.8 - - 3.8 - - 2.6 - - - - 1073.9 - - 3.8 - - 2.2 - - - - 1075.8 - - 3.8 - - 3.7 - - - - 1078.4 - - 3.8 - - 5.2 - - - - 1079.7 - - 3.8 - - 5.7 - - - - 1084.2 - - 3.8 - - 6.3 - - - - 1085.7 - - 3.8 - - 3 - - - - 1086.8 - - 3.8 - - 0.8 - - - - 1086.1 - - 3.9 - - 0.6 - - - - 1085.8 - - 3.8 - - 0.9 - - - - 1086.8 - - 3.8 - - 0.6 - - - - 1086.3 - - 3.8 - - 2.5 - - - - 1088.1 - - 3.8 - - 1.6 - - - - 1087.7 - - 3.8 - - 0.6 - - - - 1087.3 - - 3.8 - - 1.9 - - - - 1086.6 - - 3.8 - - 0.3 - - - - 1086.4 - - 3.8 - - 0.2 - - - - 1085.9 - - 3.8 - - 0.5 - - - - 1085.5 - - 3.8 - - 0.6 - - - - 1084.2 - - 3.8 - - 1 - - - - 1085.8 - - 3.8 - - 0.1 - - @@ -1811,2672 +355,6 @@ 0.7 - - 1085.8 - - 3.8 - - 0.1 - - - - 1085.6 - - 3.8 - - 0 - - - - 1085.6 - - 3.8 - - 0 - - - - 1085.6 - - 3.8 - - 0 - - - - 1084.1 - - 3.8 - - 5.8 - - - - 1081.1 - - 3.8 - - 6.4 - - - - 1081 - - 3.8 - - 6.2 - - - - 1079 - - 3.8 - - 5.3 - - - - 1076.6 - - 3.8 - - 4 - - - - 1074.3 - - 3.8 - - 7.5 - - - - 1071.8 - - 3.8 - - 7.3 - - - - 1069.4 - - 3.8 - - 6.8 - - - - 1066.8 - - 3.8 - - 5.7 - - - - 1063.1 - - 3.8 - - 6.1 - - - - 1061.3 - - 3.8 - - 7.4 - - - - 1058.7 - - 3.8 - - 6.6 - - - - 1056.3 - - 3.8 - - 6.7 - - - - 1052.6 - - 3.8 - - 6.5 - - - - 1054.2 - - 3.8 - - 5.6 - - - - 1054.6 - - 3.8 - - 1.6 - - - - 1054.1 - - 3.8 - - 1.7 - - - - 1054.1 - - 3.9 - - 0.1 - - - - 1053.9 - - 3.8 - - 0 - - - - 1054.7 - - 3.8 - - 3.1 - - - - 1051.4 - - 3.8 - - 3.1 - - - - 1048.3 - - 3.8 - - 2.2 - - - - 1046.8 - - 3.8 - - 1.1 - - - - 1044.3 - - 3.8 - - 1.7 - - - - 1043.5 - - 3.8 - - 0.2 - - - - 1043.1 - - 3.8 - - 0.1 - - - - 1043 - - 3.8 - - 0.3 - - - - 1043 - - 3.8 - - 0.1 - - - - 1043.4 - - 3.8 - - 0.1 - - - - 1043.2 - - 3.8 - - 0.3 - - - - 1042.2 - - 3.8 - - 0.1 - - - - 1041 - - 3.8 - - 1.7 - - - - 1039.8 - - 3.8 - - 1.9 - - - - 1038.7 - - 3.8 - - 0.3 - - - - 1037 - - 3.8 - - 0.3 - - - - 1036.9 - - 3.8 - - 0 - - - - 1036.9 - - 3.8 - - 0 - - - - 1035.5 - - 3.8 - - 3.7 - - - - 1032.2 - - 3.8 - - 3.3 - - - - 1029.1 - - 3.8 - - 3.3 - - - - 1025.4 - - 3.8 - - 2.4 - - - - 1022.2 - - 3.8 - - 6 - - - - 1019.4 - - 3.8 - - 4.6 - - - - 1017 - - 3.8 - - 4.6 - - - - 1014.6 - - 3.8 - - 1.8 - - - - 1011.3 - - 3.8 - - 1.4 - - - - 1010.4 - - 3.8 - - 0.8 - - - - 1006.2 - - 3.8 - - 1 - - - - 1007.5 - - 3.8 - - 0.2 - - - - 1007.7 - - 3.8 - - 0.1 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.5 - - 3.8 - - 0.8 - - - - 1007.5 - - 3.8 - - 0.2 - - - - 1005.9 - - 3.8 - - 0.2 - - - - 1006.2 - - 3.9 - - 0.6 - - - - 1005.9 - - 3.8 - - 0.6 - - - - 1007.4 - - 3.8 - - 0.4 - - - - 1007.1 - - 3.8 - - 0.5 - - - - 1002.9 - - 3.8 - - 0.6 - - - - 1002.7 - - 3.8 - - 1.1 - - - - 1002.6 - - 3.8 - - 0.3 - - - - 1004.1 - - 3.8 - - 0.1 - - - - 1004.4 - - 3.8 - - 0 - - - - 1004.4 - - 3.8 - - 0 - - - - 1002.6 - - 3.8 - - 0.9 - - - - 1002.3 - - 3.8 - - 1.4 - - - - 1001.3 - - 3.8 - - 0.7 - - - - 1000.8 - - 3.8 - - 0.7 - - - - 997.5 - - 3.8 - - 1.5 - - - - 997.2 - - 3.8 - - 0.2 - - - - 996.2 - - 3.8 - - 1.8 - - - - 993.6 - - 3.8 - - 1.6 - - - - 993.9 - - 3.8 - - 0.4 - - - - 990.8 - - 3.8 - - 4.4 - - - - 990.6 - - 3.8 - - 0.1 - - - - 990.4 - - 3.8 - - 0.6 - - - - 989.6 - - 3.8 - - 0.2 - - - - 989.8 - - 3.8 - - 0.1 - - - - 989.7 - - 3.8 - - 0 - - - - 989.6 - - 3.8 - - 0.6 - - - - 989.3 - - 3.8 - - 0.4 - - - - 989.9 - - 3.8 - - 0.2 - - - - 990.2 - - 3.8 - - 0 - - - - 990.2 - - 3.8 - - 0 - - - - 990.6 - - 3.8 - - 3 - - - - 992.4 - - 3.8 - - 3.5 - - - - 991.3 - - 3.8 - - 3.4 - - - - 992.4 - - 3.8 - - 1.2 - - - - 991.9 - - 3.8 - - 0.1 - - - - 991.6 - - 4.2 - - 0 - - - - 991.7 - - 4.4 - - 0 - - - - 991.7 - - 4.9 - - 0 - - - - 991.7 - - 5.5 - - 0 - - - - 991.7 - - 4.8 - - 0 - - - - 991.7 - - 4.1 - - 0 - - - - 992 - - 4.1 - - 1.4 - - - - 992.9 - - 4.5 - - 3.8 - - - - 995.9 - - 3.9 - - 3.4 - - - - 997 - - 3.8 - - 3 - - - - 995.6 - - 3.8 - - 4.2 - - - - 996.7 - - 3.8 - - 3.8 - - - - 995.5 - - 3.8 - - 4.9 - - - - 994.2 - - 3.8 - - 3.7 - - - - 995.1 - - 3.8 - - 3.6 - - - - 993 - - 3.8 - - 5.7 - - - - 991.6 - - 3.8 - - 5.3 - - - - 986.7 - - 3.8 - - 5.4 - - - - 982.3 - - 3.8 - - 8 - - - - 981.5 - - 3.8 - - 4.4 - - - - 983.4 - - 3.8 - - 5.4 - - - - 984.4 - - 3.8 - - 4.3 - - - - 983.4 - - 3.8 - - 3.3 - - - - 984.5 - - 3.8 - - 4.2 - - - - 985.3 - - 3.8 - - 3 - - - - 984.4 - - 3.8 - - 1.7 - - - - 982.6 - - 3.8 - - 3.3 - - - - 980.2 - - 3.8 - - 5.1 - - - - 976.3 - - 3.8 - - 10.9 - - - - 970.9 - - 3.8 - - 7.6 - - - - 969.7 - - 3.8 - - 0.9 - - - - 969.7 - - 3.8 - - 0.1 - - - - 969.6 - - 3.9 - - 0.7 - - - - 969.7 - - 3.8 - - 0.1 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 968.5 - - 3.8 - - 0.5 - - - - 968.3 - - 3.8 - - 0.2 - - - - 968.7 - - 3.8 - - 0.1 - - - - 969 - - 3.8 - - 0 - - - - 966.7 - - 3.8 - - 1.7 - - - - 966.5 - - 3.8 - - 0.9 - - - - 966.7 - - 3.8 - - 0.4 - - - - 966.7 - - 4.4 - - 0 - - - - 965.3 - - 3.8 - - 2.1 - - - - 962.7 - - 3.8 - - 9 - - - - 962.5 - - 3.8 - - 8.8 - - - - 964.3 - - 3.8 - - 8.3 - - - - 963.8 - - 3.8 - - 7.5 - - - - 965.3 - - 3.8 - - 7 - - - - 964.6 - - 3.8 - - 7.3 - - - - 965.3 - - 3.8 - - 7.5 - - - - 965.9 - - 3.8 - - 7.4 - - - - 965.5 - - 3.8 - - 7.1 - - - - 966 - - 3.8 - - 3.8 - - - - 964.6 - - 3.8 - - 2 - - - - 964.3 - - 3.8 - - 0.1 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 966.5 - - 3.8 - - 0.9 - - - - 966.6 - - 3.8 - - 0.1 - - - - 966 - - 3.8 - - 0.1 - - - - 966.1 - - 3.8 - - 0 - - - - 966 - - 3.8 - - 0 - - - - 965.6 - - 3.8 - - 0.8 - - - - 965.8 - - 3.8 - - 0.4 - - - - 967 - - 3.8 - - 2.5 - - - - 967.4 - - 3.9 - - 0.1 - - - - 967.3 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.2 - - 3.8 - - 1.4 - - - - 966.9 - - 3.8 - - 0.1 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 966.9 - - 3.8 - - 0.4 - - - - 967.3 - - 3.8 - - 0.1 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.5 - - 3.8 - - 0.6 - - - - 968.5 - - 3.8 - - 0.1 - - - - 967.7 - - 3.8 - - 1.4 - - - - 968.5 - - 3.8 - - 1.4 - - - - 969.3 - - 3.8 - - 2.3 - - - - 970.3 - - 3.8 - - 1.7 - - - - 970.3 - - 3.8 - - 1.4 - - - - 970.7 - - 3.9 - - 1 - - - - 972.4 - - 3.8 - - 0.1 - - - - 973.6 - - 3.8 - - 0 - - - - 973.7 - - 3.8 - - 0 - - - - 974.2 - - 3.8 - - 1.2 - - - - 975.7 - - 3.8 - - 2.8 - - - - 977.4 - - 3.9 - - 3 - - - - 981 - - 3.8 - - 3.1 - - - - 984.9 - - 3.8 - - 2.9 - - - - 987 - - 3.8 - - 1.7 - - - - 988.2 - - 3.8 - - 3.4 - - - - 989.6 - - 3.8 - - 4 - - - - 991.6 - - 3.8 - - 3.3 - - - - 992.5 - - 3.8 - - 4.8 - - - - 995.7 - - 3.8 - - 3 - - - - 999.5 - - 3.8 - - 2.8 - - - - 1002.7 - - 3.8 - - 2.7 - - - - 1005.8 - - 3.8 - - 3.2 - - - - 1008.5 - - 3.8 - - 3.6 - - - - 1012.1 - - 3.8 - - 3.4 - - - - 1015.9 - - 3.8 - - 3.9 - - - - 1019.1 - - 3.8 - - 4.1 - - - - 1021.1 - - 3.8 - - 3.5 - - - - 1021.4 - - 3.8 - - 4.4 - - - - 1023.1 - - 3.8 - - 5.3 - - - - 1022.9 - - 3.8 - - 3.4 - - - - 1025.2 - - 3.8 - - 2.3 - - - - 1023.2 - - 3.8 - - 3.5 - - - - 1023 - - 3.8 - - 0.1 - - - - 1023.1 - - 3.8 - - 0.2 - - - - 1023.8 - - 3.8 - - 0.1 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.7 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1053.6 - - 10.3 - - 0.7 - - - - 1037.4 - - 4.3 - - 0.2 - - - - 1036.7 - - 3.8 - - 0.1 - - - - 1037.2 - - 3.3 - - 0.1 - - - - 1038 - - 3 - - 0.1 - - - - 1038.2 - - 3 - - 0.1 - - - - 1038.2 - - 3.4 - - 0.1 - - - - 1038.8 - - 3.8 - - 0 - - - - 1039.2 - - 3.8 - - 0.3 - - - - 1038.5 - - 3.8 - - 0.2 - - - - 1038.2 - - 6.9 - - - - - - 1091.2 - - 7.2 - - 0.2 - - - - 1088.4 - - 5 - - 0.1 - - - - 1095.6 - - 8.4 - - 0.2 - - - - 1065.6 - - 4.9 - - 2.9 - - - - 1071.3 - - 5 - - 0.1 - - - - 1070.4 - - 3.8 - - 0.1 - - - - 1070.7 - - 3.8 - - 0 - - - - 1070.7 - - 3.8 - - 0 - - - - 1070.7 - - 3.8 - - 0 - - - - 1070.7 - - 3.8 - - 0 - - - - 1070.6 - - 3.8 - - 0 - - - - 1070.6 - - 3.8 - - 0 - - - - 1070.6 - - 3.8 - - 0 - - - - 1070.4 - - 3.8 - - 0.6 - - - - 1070.8 - - 3.8 - - 0.1 - - - - 1070.7 - - 3.8 - - 0.1 - - - - 1070.7 - - 3.8 - - 0 - - - - - - 975.4 - - 14.5 - - 0.7 - - - - 974.7 - - 4 - - 0.5 - - - - 972.5 - - 3.8 - - 0.1 - - - - 971 - - 3.8 - - 0.9 - - - - 971.1 - - 3.1 - - 0.1 - - - - 971.5 - - 3 - - 0.1 - - - - 928 - - 8.1 - - 0.2 - - - - 928 - - 4.6 - - 0.3 - - - - 973.4 - - 3.7 - - 0.2 - - - - 971.6 - - 3 - - 0 - - - - 971.9 - - 3 - - 0 - - - - 971.9 - - 3.5 - - 0 - - - - 971.7 - - 3.8 - - 0 - - - - 971.4 - - 3.8 - - 0.4 - - - - 971.9 - - 3.8 - - 0.1 - - - - 971.4 - - 3.8 - - 0.4 - - - - 970.6 - - 4.1 - - 0.1 - - - - 971.3 - - 3 - - 0 - - - - 971.4 - - 3 - - 0 - - - - 971.4 - - 3 - - 0 - - @@ -4491,4 +369,4 @@ thin solid - \ No newline at end of file + diff --git a/spec/fixtures/files/gpx/gpx_track_multiple_tracks.gpx b/spec/fixtures/files/gpx/gpx_track_multiple_tracks.gpx index 757aaffd..38524c57 100644 --- a/spec/fixtures/files/gpx/gpx_track_multiple_tracks.gpx +++ b/spec/fixtures/files/gpx/gpx_track_multiple_tracks.gpx @@ -100,414 +100,6 @@ 6.3 - - 1056.1 - - 3.8 - - 7.1 - - - - 1053.5 - - 3.8 - - 5.9 - - - - 1054.6 - - 3.8 - - 2.8 - - - - 1053.8 - - 3.8 - - 4.5 - - - - 1053.2 - - 3.8 - - 5.4 - - - - 1054.2 - - 3.8 - - 5 - - - - 1053.7 - - 3.8 - - 6 - - - - 1053.9 - - 3.8 - - 5.5 - - - - 1054.9 - - 3.8 - - 3 - - - - 1056.4 - - 3.8 - - 4.3 - - - - 1057.2 - - 3.8 - - 2.9 - - - - 1057.5 - - 3.8 - - 3.9 - - - - 1059.1 - - 3.8 - - 6.6 - - - - 1062 - - 3.8 - - 5.9 - - - - 1064.6 - - 3.8 - - 3.9 - - - - 1065.8 - - 3.8 - - 5.3 - - - - 1067.7 - - 3.8 - - 5.4 - - - - 1068.6 - - 3.8 - - 4.1 - - - - 1068.2 - - 3.8 - - 0.9 - - - - 1069.5 - - 3.8 - - 1.5 - - - - 1069.4 - - 3.8 - - 0.1 - - - - 1069.4 - - 3.8 - - 0.1 - - - - 1069.4 - - 3.8 - - 0 - - - - 1068.9 - - 3.8 - - 2 - - - - 1069.9 - - 3.8 - - 4.9 - - - - 1070 - - 3.8 - - 3.4 - - - - 1070.8 - - 3.8 - - 2.5 - - - - 1072.1 - - 3.8 - - 2.3 - - - - 1072.3 - - 3.8 - - 3.2 - - - - 1073.2 - - 3.8 - - 2.2 - - - - 1072.8 - - 3.8 - - 2.6 - - - - 1073.9 - - 3.8 - - 2.2 - - - - 1075.8 - - 3.8 - - 3.7 - - - - 1078.4 - - 3.8 - - 5.2 - - - - 1079.7 - - 3.8 - - 5.7 - - - - 1084.2 - - 3.8 - - 6.3 - - - - 1085.7 - - 3.8 - - 3 - - - - 1086.8 - - 3.8 - - 0.8 - - - - 1086.1 - - 3.9 - - 0.6 - - - - 1085.8 - - 3.8 - - 0.9 - - - - 1086.8 - - 3.8 - - 0.6 - - - - 1086.3 - - 3.8 - - 2.5 - - - - 1088.1 - - 3.8 - - 1.6 - - - - 1087.7 - - 3.8 - - 0.6 - - - - 1087.3 - - 3.8 - - 1.9 - - - - 1086.6 - - 3.8 - - 0.3 - - - - 1086.4 - - 3.8 - - 0.2 - - - - 1085.9 - - 3.8 - - 0.5 - - - - 1085.5 - - 3.8 - - 0.6 - - - - 1084.2 - - 3.8 - - 1 - - - - 1085.8 - - 3.8 - - 0.1 - - @@ -606,2372 +198,6 @@ 3.5 - - 1086.4 - - 3.8 - - 3.6 - - - - 1085.4 - - 3.8 - - 0.7 - - - - 1085.8 - - 3.8 - - 0.1 - - - - 1085.6 - - 3.8 - - 0 - - - - 1085.6 - - 3.8 - - 0 - - - - 1085.6 - - 3.8 - - 0 - - - - 1084.1 - - 3.8 - - 5.8 - - - - 1081.1 - - 3.8 - - 6.4 - - - - 1081 - - 3.8 - - 6.2 - - - - 1079 - - 3.8 - - 5.3 - - - - 1076.6 - - 3.8 - - 4 - - - - 1074.3 - - 3.8 - - 7.5 - - - - 1071.8 - - 3.8 - - 7.3 - - - - 1069.4 - - 3.8 - - 6.8 - - - - 1066.8 - - 3.8 - - 5.7 - - - - 1063.1 - - 3.8 - - 6.1 - - - - 1061.3 - - 3.8 - - 7.4 - - - - 1058.7 - - 3.8 - - 6.6 - - - - 1056.3 - - 3.8 - - 6.7 - - - - 1052.6 - - 3.8 - - 6.5 - - - - 1054.2 - - 3.8 - - 5.6 - - - - 1054.6 - - 3.8 - - 1.6 - - - - 1054.1 - - 3.8 - - 1.7 - - - - 1054.1 - - 3.9 - - 0.1 - - - - 1053.9 - - 3.8 - - 0 - - - - 1054.7 - - 3.8 - - 3.1 - - - - 1051.4 - - 3.8 - - 3.1 - - - - 1048.3 - - 3.8 - - 2.2 - - - - 1046.8 - - 3.8 - - 1.1 - - - - 1044.3 - - 3.8 - - 1.7 - - - - 1043.5 - - 3.8 - - 0.2 - - - - 1043.1 - - 3.8 - - 0.1 - - - - 1043 - - 3.8 - - 0.3 - - - - 1043 - - 3.8 - - 0.1 - - - - 1043.4 - - 3.8 - - 0.1 - - - - 1043.2 - - 3.8 - - 0.3 - - - - 1042.2 - - 3.8 - - 0.1 - - - - 1041 - - 3.8 - - 1.7 - - - - 1039.8 - - 3.8 - - 1.9 - - - - 1038.7 - - 3.8 - - 0.3 - - - - 1037 - - 3.8 - - 0.3 - - - - 1036.9 - - 3.8 - - 0 - - - - 1036.9 - - 3.8 - - 0 - - - - 1035.5 - - 3.8 - - 3.7 - - - - 1032.2 - - 3.8 - - 3.3 - - - - 1029.1 - - 3.8 - - 3.3 - - - - 1025.4 - - 3.8 - - 2.4 - - - - 1022.2 - - 3.8 - - 6 - - - - 1019.4 - - 3.8 - - 4.6 - - - - 1017 - - 3.8 - - 4.6 - - - - 1014.6 - - 3.8 - - 1.8 - - - - 1011.3 - - 3.8 - - 1.4 - - - - 1010.4 - - 3.8 - - 0.8 - - - - 1006.2 - - 3.8 - - 1 - - - - 1007.5 - - 3.8 - - 0.2 - - - - 1007.7 - - 3.8 - - 0.1 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.7 - - 3.8 - - 0 - - - - 1007.5 - - 3.8 - - 0.8 - - - - 1007.5 - - 3.8 - - 0.2 - - - - 1005.9 - - 3.8 - - 0.2 - - - - 1006.2 - - 3.9 - - 0.6 - - - - 1005.9 - - 3.8 - - 0.6 - - - - 1007.4 - - 3.8 - - 0.4 - - - - 1007.1 - - 3.8 - - 0.5 - - - - 1002.9 - - 3.8 - - 0.6 - - - - 1002.7 - - 3.8 - - 1.1 - - - - 1002.6 - - 3.8 - - 0.3 - - - - 1004.1 - - 3.8 - - 0.1 - - - - 1004.4 - - 3.8 - - 0 - - - - 1004.4 - - 3.8 - - 0 - - - - 1002.6 - - 3.8 - - 0.9 - - - - 1002.3 - - 3.8 - - 1.4 - - - - 1001.3 - - 3.8 - - 0.7 - - - - 1000.8 - - 3.8 - - 0.7 - - - - 997.5 - - 3.8 - - 1.5 - - - - 997.2 - - 3.8 - - 0.2 - - - - 996.2 - - 3.8 - - 1.8 - - - - 993.6 - - 3.8 - - 1.6 - - - - 993.9 - - 3.8 - - 0.4 - - - - 990.8 - - 3.8 - - 4.4 - - - - 990.6 - - 3.8 - - 0.1 - - - - 990.4 - - 3.8 - - 0.6 - - - - 989.6 - - 3.8 - - 0.2 - - - - 989.8 - - 3.8 - - 0.1 - - - - 989.7 - - 3.8 - - 0 - - - - 989.6 - - 3.8 - - 0.6 - - - - 989.3 - - 3.8 - - 0.4 - - - - 989.9 - - 3.8 - - 0.2 - - - - 990.2 - - 3.8 - - 0 - - - - 990.2 - - 3.8 - - 0 - - - - 990.6 - - 3.8 - - 3 - - - - 992.4 - - 3.8 - - 3.5 - - - - 991.3 - - 3.8 - - 3.4 - - - - 992.4 - - 3.8 - - 1.2 - - - - 991.9 - - 3.8 - - 0.1 - - - - 991.6 - - 4.2 - - 0 - - - - 991.7 - - 4.4 - - 0 - - - - 991.7 - - 4.9 - - 0 - - - - 991.7 - - 5.5 - - 0 - - - - 991.7 - - 4.8 - - 0 - - - - 991.7 - - 4.1 - - 0 - - - - 992 - - 4.1 - - 1.4 - - - - 992.9 - - 4.5 - - 3.8 - - - - 995.9 - - 3.9 - - 3.4 - - - - 997 - - 3.8 - - 3 - - - - 995.6 - - 3.8 - - 4.2 - - - - 996.7 - - 3.8 - - 3.8 - - - - 995.5 - - 3.8 - - 4.9 - - - - 994.2 - - 3.8 - - 3.7 - - - - 995.1 - - 3.8 - - 3.6 - - - - 993 - - 3.8 - - 5.7 - - - - 991.6 - - 3.8 - - 5.3 - - - - 986.7 - - 3.8 - - 5.4 - - - - 982.3 - - 3.8 - - 8 - - - - 981.5 - - 3.8 - - 4.4 - - - - 983.4 - - 3.8 - - 5.4 - - - - 984.4 - - 3.8 - - 4.3 - - - - 983.4 - - 3.8 - - 3.3 - - - - 984.5 - - 3.8 - - 4.2 - - - - 985.3 - - 3.8 - - 3 - - - - 984.4 - - 3.8 - - 1.7 - - - - 982.6 - - 3.8 - - 3.3 - - - - 980.2 - - 3.8 - - 5.1 - - - - 976.3 - - 3.8 - - 10.9 - - - - 970.9 - - 3.8 - - 7.6 - - - - 969.7 - - 3.8 - - 0.9 - - - - 969.7 - - 3.8 - - 0.1 - - - - 969.6 - - 3.9 - - 0.7 - - - - 969.7 - - 3.8 - - 0.1 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 969.1 - - 3.8 - - 0 - - - - 968.3 - - 3.8 - - 0.2 - - - - 968.7 - - 3.8 - - 0.1 - - - - 969 - - 3.8 - - 0 - - - - 966.7 - - 3.8 - - 1.7 - - - - 966.5 - - 3.8 - - 0.9 - - - - 966.7 - - 3.8 - - 0.4 - - - - 966.7 - - 4.4 - - 0 - - - - 965.3 - - 3.8 - - 2.1 - - - - 962.7 - - 3.8 - - 9 - - - - 962.5 - - 3.8 - - 8.8 - - - - 964.3 - - 3.8 - - 8.3 - - - - 963.8 - - 3.8 - - 7.5 - - - - 965.3 - - 3.8 - - 7 - - - - 964.6 - - 3.8 - - 7.3 - - - - 965.3 - - 3.8 - - 7.5 - - - - 965.9 - - 3.8 - - 7.4 - - - - 965.5 - - 3.8 - - 7.1 - - - - 966 - - 3.8 - - 3.8 - - - - 964.6 - - 3.8 - - 2 - - - - 964.3 - - 3.8 - - 0.1 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 964.5 - - 3.8 - - 0 - - - - 966.5 - - 3.8 - - 0.9 - - - - 966.6 - - 3.8 - - 0.1 - - - - 966 - - 3.8 - - 0.1 - - - - 966.1 - - 3.8 - - 0 - - - - 966 - - 3.8 - - 0 - - - - 965.6 - - 3.8 - - 0.8 - - - - 965.8 - - 3.8 - - 0.4 - - - - 967 - - 3.8 - - 2.5 - - - - 967.4 - - 3.9 - - 0.1 - - - - 967.3 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.9 - - 3.8 - - 0 - - - - 967.2 - - 3.8 - - 1.4 - - - - 966.9 - - 3.8 - - 0.1 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 967.1 - - 3.8 - - 0 - - - - 966.9 - - 3.8 - - 0.4 - - - - 967.3 - - 3.8 - - 0.1 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.8 - - 3.8 - - 0 - - - - 967.5 - - 3.8 - - 0.6 - - - - 968.5 - - 3.8 - - 0.1 - - - - 967.7 - - 3.8 - - 1.4 - - - - 968.5 - - 3.8 - - 1.4 - - - - 969.3 - - 3.8 - - 2.3 - - - - 970.3 - - 3.8 - - 1.7 - - - - 970.3 - - 3.8 - - 1.4 - - - - 970.7 - - 3.9 - - 1 - - - - 972.4 - - 3.8 - - 0.1 - - - - 973.6 - - 3.8 - - 0 - - - - 973.7 - - 3.8 - - 0 - - - - 974.2 - - 3.8 - - 1.2 - - - - 975.7 - - 3.8 - - 2.8 - - - - 977.4 - - 3.9 - - 3 - - - - 981 - - 3.8 - - 3.1 - - - - 984.9 - - 3.8 - - 2.9 - - - - 987 - - 3.8 - - 1.7 - - - - 988.2 - - 3.8 - - 3.4 - - - - 989.6 - - 3.8 - - 4 - - - - 991.6 - - 3.8 - - 3.3 - - - - 992.5 - - 3.8 - - 4.8 - - - - 995.7 - - 3.8 - - 3 - - - - 999.5 - - 3.8 - - 2.8 - - - - 1002.7 - - 3.8 - - 2.7 - - - - 1005.8 - - 3.8 - - 3.2 - - - - 1008.5 - - 3.8 - - 3.6 - - - - 1012.1 - - 3.8 - - 3.4 - - - - 1015.9 - - 3.8 - - 3.9 - - - - 1019.1 - - 3.8 - - 4.1 - - - - 1021.1 - - 3.8 - - 3.5 - - - - 1021.4 - - 3.8 - - 4.4 - - - - 1023.1 - - 3.8 - - 5.3 - - - - 1022.9 - - 3.8 - - 3.4 - - - - 1025.2 - - 3.8 - - 2.3 - - - - 1023.2 - - 3.8 - - 3.5 - - - - 1023 - - 3.8 - - 0.1 - - - - 1023.1 - - 3.8 - - 0.2 - - - - 1023.8 - - 3.8 - - 0.1 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.7 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1023.6 - - 3.8 - - 0 - - - - 1053.6 - - 10.3 - - 0.7 - - - - 1037.4 - - 4.3 - - 0.2 - - - - 1036.7 - - 3.8 - - 0.1 - - - - 1037.2 - - 3.3 - - 0.1 - - - - 1038 - - 3 - - 0.1 - - - - 1038.2 - - 3 - - 0.1 - - - - 1038.2 - - 3.4 - - 0.1 - - - - 1038.8 - - 3.8 - - 0 - - - - 1039.2 - - 3.8 - - 0.3 - - - - 1038.5 - - 3.8 - - 0.2 - - - - 1038.2 - - 6.9 - - @@ -3064,216 +290,6 @@ 0 - - 1070.6 - - 3.8 - - 0 - - - - 1070.6 - - 3.8 - - 0 - - - - 1070.4 - - 3.8 - - 0.6 - - - - 1070.8 - - 3.8 - - 0.1 - - - - 1070.7 - - 3.8 - - 0.1 - - - - 1070.7 - - 3.8 - - 0 - - - - - - 975.4 - - 14.5 - - 0.7 - - - - 974.7 - - 4 - - 0.5 - - - - 972.5 - - 3.8 - - 0.1 - - - - 971 - - 3.8 - - 0.9 - - - - 971.1 - - 3.1 - - 0.1 - - - - 971.5 - - 3 - - 0.1 - - - - 928 - - 8.1 - - 0.2 - - - - 928 - - 4.6 - - 0.3 - - - - 973.4 - - 3.7 - - 0.2 - - - - 971.6 - - 3 - - 0 - - - - 971.9 - - 3 - - 0 - - - - 971.9 - - 3.5 - - 0 - - - - 971.7 - - 3.8 - - 0 - - - - 971.4 - - 3.8 - - 0.4 - - - - 971.9 - - 3.8 - - 0.1 - - - - 971.4 - - 3.8 - - 0.4 - - - - 970.6 - - 4.1 - - 0.1 - - - - 971.3 - - 3 - - 0 - - - - 971.4 - - 3 - - 0 - - - - 971.4 - - 3 - - 0 - - @@ -3288,4 +304,4 @@ thin solid - \ No newline at end of file + diff --git a/spec/fixtures/files/gpx/gpx_track_single_segment.gpx b/spec/fixtures/files/gpx/gpx_track_single_segment.gpx index c7447af0..44125aa7 100644 --- a/spec/fixtures/files/gpx/gpx_track_single_segment.gpx +++ b/spec/fixtures/files/gpx/gpx_track_single_segment.gpx @@ -54,1186 +54,6 @@ 798.9 - - 797.19 - - - - 795.8 - - - - 794.31 - - - - 793.25 - - - - 792.19 - - - - 791.44 - - - - 791.24 - - - - 791.47 - - - - 792.04 - - - - 792.18 - - - - 793.94 - - - - 795.29 - - - - 796.89 - - - - 798.7 - - - - 801.44 - - - - 803.97 - - - - 806.6 - - - - 809.27 - - - - 811.96 - - - - 814.62 - - - - 817.54 - - - - 820.18 - - - - 822.76 - - - - 825.25 - - - - 827.89 - - - - 830.82 - - - - 833.17 - - - - 835.42 - - - - 837.9 - - - - 839.89 - - - - 841.98 - - - - 844.17 - - - - 846.01 - - - - 847.32 - - - - 848.51 - - - - 849.54 - - - - 850.3 - - - - 850.74 - - - - 851.11 - - - - 851.31 - - - - 851.37 - - - - 851.36 - - - - 851.21 - - - - 851.04 - - - - 850.86 - - - - 850.41 - - - - 849.94 - - - - 849.54 - - - - 849.08 - - - - 848.67 - - - - 848.36 - - - - 848.08 - - - - 847.87 - - - - 847.77 - - - - 847.74 - - - - 847.75 - - - - 847.81 - - - - 847.96 - - - - 848.17 - - - - 848.37 - - - - 848.68 - - - - 849.01 - - - - 849.24 - - - - 849.47 - - - - 849.7 - - - - 849.88 - - - - 850.1 - - - - 850.25 - - - - 850.38 - - - - 850.47 - - - - 850.46 - - - - 850.35 - - - - 850.35 - - - - 850.02 - - - - 849.6 - - - - 849.05 - - - - 848.37 - - - - 847.54 - - - - 846.57 - - - - 845.55 - - - - 844.29 - - - - 842.85 - - - - 841.43 - - - - 839.98 - - - - 838.63 - - - - 837.18 - - - - 835.48 - - - - 833.92 - - - - 832.43 - - - - 831.06 - - - - 829.84 - - - - 829.04 - - - - 828.42 - - - - 828.15 - - - - 828.11 - - - - 828.51 - - - - 829.55 - - - - 830.31 - - - - 831.12 - - - - 831.93 - - - - 832.91 - - - - 833.85 - - - - 834.91 - - - - 836.07 - - - - 837.2 - - - - 838.38 - - - - 839.56 - - - - 840.58 - - - - 841.58 - - - - 842.46 - - - - 843.23 - - - - 843.46 - - - - 843.41 - - - - 842.64 - - - - 841.84 - - - - 840.81 - - - - 839.56 - - - - 837.86 - - - - 836.03 - - - - 833.91 - - - - 831.55 - - - - 828.71 - - - - 825.47 - - - - 820.96 - - - - 817.85 - - - - 814.71 - - - - 811.52 - - - - 808.25 - - - - 805.03 - - - - 801.68 - - - - 798.27 - - - - 794.91 - - - - 791.73 - - - - 788.61 - - - - 785.48 - - - - 782.4 - - - - 779.42 - - - - 776.47 - - - - 773.67 - - - - 770.99 - - - - 768.4 - - - - 765.66 - - - - 763.1 - - - - 760.26 - - - - 757.88 - - - - 755.75 - - - - 753.7 - - - - 751.75 - - - - 749.94 - - - - 748.17 - - - - 746.34 - - - - 744.47 - - - - 743.18 - - - - 742.0 - - - - 741.01 - - - - 740.17 - - - - 739.53 - - - - 738.88 - - - - 738.42 - - - - 738.16 - - - - 738.01 - - - - 738.01 - - - - 738.11 - - - - 738.36 - - - - 738.8 - - - - 739.13 - - - - 739.78 - - - - 740.12 - - - - 740.55 - - - - 740.93 - - - - 741.31 - - - - 741.6 - - - - 741.82 - - - - 741.89 - - - - 741.94 - - - - 741.89 - - - - 742.0 - - - - 742.05 - - - - 742.17 - - - - 742.28 - - - - 742.49 - - - - 742.74 - - - - 742.86 - - - - 743.34 - - - - 744.01 - - - - 744.96 - - - - 746.14 - - - - 747.41 - - - - 748.68 - - - - 750.03 - - - - 751.57 - - - - 753.47 - - - - 755.4 - - - - 757.49 - - - - 759.68 - - - - 762.09 - - - - 764.56 - - - - 767.4 - - - - 770.3 - - - - 773.45 - - - - 776.83 - - - - 780.51 - - - - 783.74 - - - - 786.94 - - - - 790.76 - - - - 794.06 - - - - 797.36 - - - - 800.75 - - - - 804.12 - - - - 807.53 - - - - 811.02 - - - - 814.61 - - - - 818.13 - - - - 821.6 - - - - 825.29 - - - - 828.89 - - - - 832.37 - - - - 836.28 - - - - 839.49 - - - - 842.19 - - - - 844.74 - - - - 847.21 - - - - 849.34 - - - - 851.3 - - - - 852.93 - - - - 854.35 - - - - 855.69 - - - - 856.86 - - - - 857.72 - - - - 858.43 - - - - 858.78 - - - - 859.01 - - - - 859.0 - - - - 858.97 - - - - 859.21 - - - - 859.45 - - - - 859.73 - - - - 860.06 - - - - 860.45 - - - - 861.08 - - - - 861.61 - - - - 862.29 - - - - 863.0 - - - - 863.9 - - - - 864.96 - - - - 866.07 - - - - 867.3 - - - - 869.0 - - - - 870.45 - - - - 871.97 - - - - 873.37 - - - - 874.8 - - - - 876.17 - - - - 877.6 - - - - 879.15 - - - - 880.87 - - - - 882.54 - - - - 884.28 - - - - 886.01 - - - - 887.84 - - - - 889.62 - - - - 891.29 - - - - 892.83 - - - - 893.87 - - - - 894.78 - - - - 895.66 - - - - 896.51 - - - - 896.83 - - - - 896.95 - - - - 896.98 - - - - 896.67 - - - - 896.92 - - - - 897.13 - - - - 897.08 - - - - 897.65 - - - - 898.62 - - - - 899.59 - - - - 900.3 - - - - 901.06 - - - - 901.98 - - - - 902.94 - - - - 904.14 - - - - 905.06 - - - - 905.5 - - - - 905.8 - - - - 905.47 - - - - 905.91 - - - - 906.01 - - - - 905.66 - - - - 904.85 - - - - 904.4 - - - - 903.49 - - - - 903.02 - - - - 901.8 - - - - 901.42 - - diff --git a/spec/fixtures/files/owntracks/2024-03.rec b/spec/fixtures/files/owntracks/2024-03.rec index 473591f7..610ffa83 100644 --- a/spec/fixtures/files/owntracks/2024-03.rec +++ b/spec/fixtures/files/owntracks/2024-03.rec @@ -1,5 +1,5 @@ -2024-03-01T09:03:09Z * {"bs":2,"p":100.266,"batt":94,"_type":"location","tid":"RO","topic":"owntracks/test/iPhone 12 Pro","alt":36,"lon":13.332,"vel":0,"t":"p","BSSID":"b0:f2:8:45:94:33","SSID":"Home Wifi","conn":"w","vac":4,"acc":10,"tst":1709283789,"lat":52.225,"m":1,"inrids":["5f1d1b"],"inregions":["home"],"_http":true} -2024-03-01T17:46:02Z * {"bs":1,"p":100.28,"batt":94,"_type":"location","tid":"RO","topic":"owntracks/test/iPhone 12 Pro","alt":36,"lon":13.333,"t":"p","vel":0,"BSSID":"b0:f2:8:45:94:33","conn":"w","SSID":"Home Wifi","vac":3,"cog":98,"acc":9,"tst":1709315162,"lat":52.226,"m":1,"inrids":["5f1d1b"],"inregions":["home"],"_http":true} +2024-03-01T09:03:09Z * {"bs":2,"p":100.266,"batt":94,"_type":"location","tid":"RO","topic":"owntracks/test/iPhone 12 Pro","alt":36,"lon":13.332,"vel":5,"t":"p","BSSID":"b0:f2:8:45:94:33","SSID":"Home Wifi","conn":"w","vac":4,"acc":10,"tst":1709283789,"lat":52.225,"m":1,"inrids":["5f1d1b"],"inregions":["home"],"_http":true} +2024-03-01T17:46:02Z * {"bs":1,"p":100.28,"batt":94,"_type":"location","tid":"RO","topic":"owntracks/test/iPhone 12 Pro","alt":36,"lon":13.333,"t":"p","vel":5,"BSSID":"b0:f2:8:45:94:33","conn":"w","SSID":"Home Wifi","vac":3,"cog":98,"acc":9,"tst":1709315162,"lat":52.226,"m":1,"inrids":["5f1d1b"],"inregions":["home"],"_http":true} 2024-03-01T18:26:55Z * {"lon":13.334,"acc":5,"wtst":1696359532,"event":"leave","rid":"5f1d1b","desc":"home","topic":"owntracks/test/iPhone 12 Pro/event","lat":52.227,"t":"c","tst":1709317615,"tid":"RO","_type":"transition","_http":true} 2024-03-01T18:26:55Z * {"cog":40,"batt":85,"lon":13.335,"acc":5,"bs":1,"p":100.279,"vel":3,"vac":3,"lat":52.228,"topic":"owntracks/test/iPhone 12 Pro","t":"c","conn":"m","m":1,"tst":1709317615,"alt":36,"_type":"location","tid":"RO","_http":true} 2024-03-01T18:28:30Z * {"cog":38,"batt":85,"lon":13.336,"acc":5,"bs":1,"p":100.349,"vel":3,"vac":3,"lat":52.229,"topic":"owntracks/test/iPhone 12 Pro","t":"v","conn":"m","m":1,"tst":1709317710,"alt":35,"_type":"location","tid":"RO","_http":true} diff --git a/spec/requests/exports_spec.rb b/spec/requests/exports_spec.rb index 0ec6fa61..2c5a6b72 100644 --- a/spec/requests/exports_spec.rb +++ b/spec/requests/exports_spec.rb @@ -76,9 +76,25 @@ RSpec.describe '/exports', type: :request do end describe 'DELETE /destroy' do - let!(:export) { create(:export, user:, url: 'exports/export.json') } + let!(:export) { create(:export, user:, url: 'exports/export.json', name: 'export.json') } + let(:export_file) { Rails.root.join('public', 'exports', export.name) } - before { sign_in user } + before do + sign_in user + + FileUtils.mkdir_p(File.dirname(export_file)) + File.write(export_file, '{"some": "data"}') + end + + after { FileUtils.rm_f(export_file) } + + it 'removes the export file from disk' do + expect(File.exist?(export_file)).to be true + + delete export_url(export) + + expect(File.exist?(export_file)).to be false + end it 'destroys the requested export' do expect { delete export_url(export) }.to change(Export, :count).by(-1) @@ -89,14 +105,5 @@ RSpec.describe '/exports', type: :request do expect(response).to redirect_to(exports_url) end - - it 'remove the export file from the disk' do - export_file = Rails.root.join('public', export.url) - FileUtils.touch(export_file) - - delete export_url(export) - - expect(File.exist?(export_file)).to be_falsey - end end end diff --git a/spec/services/gpx/track_parser_spec.rb b/spec/services/gpx/track_parser_spec.rb index c5980c91..02fa3110 100644 --- a/spec/services/gpx/track_parser_spec.rb +++ b/spec/services/gpx/track_parser_spec.rb @@ -13,11 +13,11 @@ RSpec.describe Gpx::TrackParser do context 'when file has a single segment' do it 'creates points' do - expect { parser }.to change { Point.count }.by(301) + expect { parser }.to change { Point.count }.by(10) end it 'broadcasts importing progress' do - expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(301).times + expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(10).times parser end @@ -27,11 +27,11 @@ RSpec.describe Gpx::TrackParser do let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx') } it 'creates points' do - expect { parser }.to change { Point.count }.by(558) + expect { parser }.to change { Point.count }.by(43) end it 'broadcasts importing progress' do - expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(558).times + expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(43).times parser end @@ -41,11 +41,11 @@ RSpec.describe Gpx::TrackParser do let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/gpx_track_multiple_tracks.gpx') } it 'creates points' do - expect { parser }.to change { Point.count }.by(407) + expect { parser }.to change { Point.count }.by(34) end it 'broadcasts importing progress' do - expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(407).times + expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(34).times parser end diff --git a/spec/services/own_tracks/export_parser_spec.rb b/spec/services/own_tracks/export_parser_spec.rb index b358300a..260b81ec 100644 --- a/spec/services/own_tracks/export_parser_spec.rb +++ b/spec/services/own_tracks/export_parser_spec.rb @@ -26,7 +26,7 @@ RSpec.describe OwnTracks::ExportParser do 'altitude' => 36, 'accuracy' => 10, 'vertical_accuracy' => 4, - 'velocity' => '0', + 'velocity' => '1.4', 'connection' => 'wifi', 'ssid' => 'Home Wifi', 'bssid' => 'b0:f2:8:45:94:33', @@ -51,7 +51,7 @@ RSpec.describe OwnTracks::ExportParser do 'tid' => 'RO', 'tst' => 1_709_283_789, 'vac' => 4, - 'vel' => 0, + 'vel' => 5, 'SSID' => 'Home Wifi', 'batt' => 94, 'conn' => 'w', @@ -64,6 +64,12 @@ RSpec.describe OwnTracks::ExportParser do } ) end + + it 'correctly converts speed' do + parser + + expect(Point.first.velocity).to eq('1.4') + end end end end diff --git a/spec/services/own_tracks/params_spec.rb b/spec/services/own_tracks/params_spec.rb index 64f485bf..40605759 100644 --- a/spec/services/own_tracks/params_spec.rb +++ b/spec/services/own_tracks/params_spec.rb @@ -20,7 +20,7 @@ RSpec.describe OwnTracks::Params do altitude: 36, accuracy: 10, vertical_accuracy: 4, - velocity: 0, + velocity: '1.4', ssid: 'Home Wifi', bssid: 'b0:f2:8:45:94:33', tracker_id: 'RO', @@ -39,7 +39,7 @@ RSpec.describe OwnTracks::Params do 'topic' => 'owntracks/test/iPhone 12 Pro', 'alt' => 36, 'lon' => 13.332, - 'vel' => 0, + 'vel' => 5, 't' => 'p', 'BSSID' => 'b0:f2:8:45:94:33', 'SSID' => 'Home Wifi', diff --git a/spec/swagger/api/v1/areas_controller_spec.rb b/spec/swagger/api/v1/areas_controller_spec.rb index 0bd50a31..8a7db2b6 100644 --- a/spec/swagger/api/v1/areas_controller_spec.rb +++ b/spec/swagger/api/v1/areas_controller_spec.rb @@ -16,10 +16,26 @@ describe 'Areas API', type: :request do parameter name: :area, in: :body, schema: { type: :object, properties: { - name: { type: :string }, - latitude: { type: :number }, - longitude: { type: :number }, - radius: { type: :number } + name: { + type: :string, + example: 'Home', + description: 'The name of the area' + }, + latitude: { + type: :number, + example: 40.7128, + description: 'The latitude of the area' + }, + longitude: { + type: :number, + example: -74.0060, + description: 'The longitude of the area' + }, + radius: { + type: :number, + example: 100, + description: 'The radius of the area in meters' + } }, required: %w[name latitude longitude radius] } @@ -47,11 +63,31 @@ describe 'Areas API', type: :request do items: { type: :object, properties: { - id: { type: :integer }, - name: { type: :string }, - latitude: { type: :number }, - longitude: { type: :number }, - radius: { type: :number } + id: { + type: :integer, + example: 1, + description: 'The ID of the area' + }, + name: { + type: :string, + example: 'Home', + description: 'The name of the area' + }, + latitude: { + type: :number, + example: 40.7128, + description: 'The latitude of the area' + }, + longitude: { + type: :number, + example: -74.0060, + description: 'The longitude of the area' + }, + radius: { + type: :number, + example: 100, + description: 'The radius of the area in meters' + } }, required: %w[id name latitude longitude radius] } diff --git a/spec/swagger/api/v1/countries/visited_cities_spec.rb b/spec/swagger/api/v1/countries/visited_cities_spec.rb index 5d199e15..61a7fa43 100644 --- a/spec/swagger/api/v1/countries/visited_cities_spec.rb +++ b/spec/swagger/api/v1/countries/visited_cities_spec.rb @@ -9,7 +9,12 @@ RSpec.describe 'Api::V1::Countries::VisitedCities', type: :request do description 'Returns a list of visited cities and countries based on tracked points within the specified date range' produces 'application/json' - parameter name: :api_key, in: :query, type: :string, required: true + parameter name: :api_key, + in: :query, + type: :string, + required: true, + example: 'a1b2c3d4e5f6g7h8i9j0', + description: 'Your API authentication key' parameter name: :start_at, in: :query, type: :string, @@ -32,6 +37,36 @@ RSpec.describe 'Api::V1::Countries::VisitedCities', type: :request do data: { type: :array, description: 'Array of countries and their visited cities', + example: [ + { + country: 'Germany', + cities: [ + { + city: 'Berlin', + points: 4394, + timestamp: 1_724_868_369, + stayed_for: 24_490 + }, + { + city: 'Munich', + points: 2156, + timestamp: 1_724_782_369, + stayed_for: 12_450 + } + ] + }, + { + country: 'France', + cities: [ + { + city: 'Paris', + points: 3267, + timestamp: 1_724_695_969, + stayed_for: 18_720 + } + ] + } + ], items: { type: :object, properties: { diff --git a/spec/swagger/api/v1/health_controller_spec.rb b/spec/swagger/api/v1/health_controller_spec.rb index 63ddf514..7305521f 100644 --- a/spec/swagger/api/v1/health_controller_spec.rb +++ b/spec/swagger/api/v1/health_controller_spec.rb @@ -8,6 +8,22 @@ describe 'Health API', type: :request do tags 'Health' produces 'application/json' response '200', 'Healthy' do + schema type: :object, + properties: { + status: { type: :string } + } + + header 'X-Dawarich-Response', + type: :string, + required: true, + example: 'Hey, I\'m alive!', + description: "Depending on the authentication status of the request, the response will be different. If the request is authenticated, the response will be 'Hey, I'm alive and authenticated!'. If the request is not authenticated, the response will be 'Hey, I'm alive!'." + header 'X-Dawarich-Version', + type: :string, + required: true, + example: '1.0.0', + description: 'The version of the application, for example: 1.0.0' + run_test! end end diff --git a/spec/swagger/api/v1/overland/batches_controller_spec.rb b/spec/swagger/api/v1/overland/batches_controller_spec.rb index 5fce90f1..4ba2e0d3 100644 --- a/spec/swagger/api/v1/overland/batches_controller_spec.rb +++ b/spec/swagger/api/v1/overland/batches_controller_spec.rb @@ -26,7 +26,8 @@ describe 'Overland Batches API', type: :request do deferred: 0, significant_change: 'unknown', locations_in_payload: 1, - device_id: 'Swagger', + device_id: 'iOS device #166', + unique_id: '1234567890', wifi: 'unknown', battery_state: 'unknown', battery_level: 0 @@ -39,36 +40,100 @@ describe 'Overland Batches API', type: :request do parameter name: :locations, in: :body, schema: { type: :object, properties: { - type: { type: :string }, + type: { type: :string, example: 'Feature' }, geometry: { type: :object, properties: { - type: { type: :string }, - coordinates: { type: :array } + type: { type: :string, example: 'Point' }, + coordinates: { type: :array, example: [13.356718, 52.502397] } } }, properties: { type: :object, properties: { - timestamp: { type: :string }, - altitude: { type: :number }, - speed: { type: :number }, - horizontal_accuracy: { type: :number }, - vertical_accuracy: { type: :number }, - motion: { type: :array }, - pauses: { type: :boolean }, - activity: { type: :string }, - desired_accuracy: { type: :number }, - deferred: { type: :number }, - significant_change: { type: :string }, - locations_in_payload: { type: :number }, - device_id: { type: :string }, - wifi: { type: :string }, - battery_state: { type: :string }, - battery_level: { type: :number } - } - }, - required: %w[geometry properties] + timestamp: { + type: :string, + example: '2021-06-01T12:00:00Z', + description: 'Timestamp in ISO 8601 format' + }, + altitude: { + type: :number, + example: 0, + description: 'Altitude in meters' + }, + speed: { + type: :number, + example: 0, + description: 'Speed in meters per second' + }, + horizontal_accuracy: { + type: :number, + example: 0, + description: 'Horizontal accuracy in meters' + }, + vertical_accuracy: { + type: :number, + example: 0, + description: 'Vertical accuracy in meters' + }, + motion: { + type: :array, + example: %w[walking running driving cycling stationary], + description: 'Motion type, for example: automotive_navigation, fitness, other_navigation or other' + }, + activity: { + type: :string, + example: 'unknown', + description: 'Activity type, for example: automotive_navigation, fitness, other_navigation or other' + }, + desired_accuracy: { + type: :number, + example: 0, + description: 'Desired accuracy in meters' + }, + deferred: { + type: :number, + example: 0, + description: 'the distance in meters to defer location updates' + }, + significant_change: { + type: :string, + example: 'disabled', + description: 'a significant change mode, disabled, enabled or exclusive' + }, + locations_in_payload: { + type: :number, + example: 1, + description: 'the number of locations in the payload' + }, + device_id: { + type: :string, + example: 'iOS device #166', + description: 'the device id' + }, + unique_id: { + type: :string, + example: '1234567890', + description: 'the device\'s Unique ID as set by Apple' + }, + wifi: { + type: :string, + example: 'unknown', + description: 'the WiFi network name' + }, + battery_state: { + type: :string, + example: 'unknown', + description: 'the battery state, unknown, unplugged, charging or full' + }, + battery_level: { + type: :number, + example: 0, + description: 'the battery level percentage, from 0 to 1' + } + }, + required: %w[geometry properties] + } } } diff --git a/spec/swagger/api/v1/owntracks/points_controller_spec.rb b/spec/swagger/api/v1/owntracks/points_controller_spec.rb index 8476b514..00157df8 100644 --- a/spec/swagger/api/v1/owntracks/points_controller_spec.rb +++ b/spec/swagger/api/v1/owntracks/points_controller_spec.rb @@ -39,29 +39,29 @@ describe 'OwnTracks Points API', type: :request do parameter name: :point, in: :body, schema: { type: :object, properties: { - batt: { type: :number }, - lon: { type: :number }, - acc: { type: :number }, - bs: { type: :number }, - inrids: { type: :array }, - BSSID: { type: :string }, - SSID: { type: :string }, - vac: { type: :number }, - inregions: { type: :array }, - lat: { type: :number }, - topic: { type: :string }, - t: { type: :string }, - conn: { type: :string }, - m: { type: :number }, - tst: { type: :number }, - alt: { type: :number }, - _type: { type: :string }, - tid: { type: :string }, - _http: { type: :boolean }, - ghash: { type: :string }, - isorcv: { type: :string }, - isotst: { type: :string }, - disptst: { type: :string } + batt: { type: :number, description: 'Device battery level (percentage)' }, + lon: { type: :number, description: 'Longitude coordinate' }, + acc: { type: :number, description: 'Accuracy of position in meters' }, + bs: { type: :number, description: 'Battery status (0=unknown, 1=unplugged, 2=charging, 3=full)' }, + inrids: { type: :array, description: 'Array of region IDs device is currently in' }, + BSSID: { type: :string, description: 'Connected WiFi access point MAC address' }, + SSID: { type: :string, description: 'Connected WiFi network name' }, + vac: { type: :number, description: 'Vertical accuracy in meters' }, + inregions: { type: :array, description: 'Array of region names device is currently in' }, + lat: { type: :number, description: 'Latitude coordinate' }, + topic: { type: :string, description: 'MQTT topic in format owntracks/user/device' }, + t: { type: :string, description: 'Type of message (p=position, c=circle, etc)' }, + conn: { type: :string, description: 'Connection type (w=wifi, m=mobile, o=offline)' }, + m: { type: :number, description: 'Motion state (0=stopped, 1=moving)' }, + tst: { type: :number, description: 'Timestamp in Unix epoch time' }, + alt: { type: :number, description: 'Altitude in meters' }, + _type: { type: :string, description: 'Internal message type (usually "location")' }, + tid: { type: :string, description: 'Tracker ID used to display the initials of a user' }, + _http: { type: :boolean, description: 'Whether message was sent via HTTP (true) or MQTT (false)' }, + ghash: { type: :string, description: 'Geohash of location' }, + isorcv: { type: :string, description: 'ISO 8601 timestamp when message was received' }, + isotst: { type: :string, description: 'ISO 8601 timestamp of the location fix' }, + disptst: { type: :string, description: 'Human-readable timestamp of the location fix' } }, required: %w[owntracks/jane] } diff --git a/spec/swagger/api/v1/points_controller_spec.rb b/spec/swagger/api/v1/points_controller_spec.rb index d3dc087c..e5b8bf01 100644 --- a/spec/swagger/api/v1/points_controller_spec.rb +++ b/spec/swagger/api/v1/points_controller_spec.rb @@ -101,27 +101,73 @@ describe 'Points API', type: :request do geometry: { type: :object, properties: { - type: { type: :string }, - coordinates: { type: :array, items: { type: :number } } + type: { + type: :string, + example: 'Point', + description: 'the geometry type, always Point' + }, + coordinates: { + type: :array, + items: { + type: :number, + example: [-122.40530871, 37.74430413], + description: 'the coordinates of the point, longitude and latitude' + } + } } }, properties: { type: :object, properties: { - timestamp: { type: :string }, - horizontal_accuracy: { type: :number }, - vertical_accuracy: { type: :number }, - altitude: { type: :number }, - speed: { type: :number }, - speed_accuracy: { type: :number }, - course: { type: :number }, - course_accuracy: { type: :number }, - track_id: { type: :string }, - device_id: { type: :string } + timestamp: { + type: :string, + example: '2025-01-17T21:03:01Z', + description: 'the timestamp of the point' + }, + horizontal_accuracy: { + type: :number, + example: 5, + description: 'the horizontal accuracy of the point in meters' + }, + vertical_accuracy: { + type: :number, + example: -1, + description: 'the vertical accuracy of the point in meters' + }, + altitude: { + type: :number, + example: 0, + description: 'the altitude of the point in meters' + }, + speed: { + type: :number, + example: 92.088, + description: 'the speed of the point in meters per second' + }, + speed_accuracy: { + type: :number, + example: 0, + description: 'the speed accuracy of the point in meters per second' + }, + course_accuracy: { + type: :number, + example: 0, + description: 'the course accuracy of the point in degrees' + }, + track_id: { + type: :string, + example: '799F32F5-89BB-45FB-A639-098B1B95B09F', + description: 'the track id of the point set by the device' + }, + device_id: { + type: :string, + example: '8D5D4197-245B-4619-A88B-2049100ADE46', + description: 'the device id of the point set by the device' + } } - } - }, - required: %w[geometry properties] + }, + required: %w[geometry properties] + } } parameter name: :api_key, in: :query, type: :string, required: true, description: 'API Key' diff --git a/spec/swagger/api/v1/settings_controller_spec.rb b/spec/swagger/api/v1/settings_controller_spec.rb index 523ca449..aecba56b 100644 --- a/spec/swagger/api/v1/settings_controller_spec.rb +++ b/spec/swagger/api/v1/settings_controller_spec.rb @@ -20,12 +20,26 @@ describe 'Settings API', type: :request do parameter name: :settings, in: :body, schema: { type: :object, properties: { - route_opacity: { type: :number }, - meters_between_routes: { type: :number }, - minutes_between_routes: { type: :number }, - fog_of_war_meters: { type: :number }, - time_threshold_minutes: { type: :number }, - merge_threshold_minutes: { type: :number } + route_opacity: { + type: :number, + example: 0.3, + description: 'the opacity of the route, float between 0 and 1' + }, + meters_between_routes: { + type: :number, + example: 100, + description: 'the distance between routes in meters' + }, + minutes_between_routes: { + type: :number, + example: 100, + description: 'the time between routes in minutes' + }, + fog_of_war_meters: { + type: :number, + example: 100, + description: 'the fog of war distance in meters' + } }, optional: %w[route_opacity meters_between_routes minutes_between_routes fog_of_war_meters time_threshold_minutes merge_threshold_minutes] @@ -49,12 +63,26 @@ describe 'Settings API', type: :request do settings: { type: :object, properties: { - route_opacity: { type: :string }, - meters_between_routes: { type: :string }, - minutes_between_routes: { type: :string }, - fog_of_war_meters: { type: :string }, - time_threshold_minutes: { type: :string }, - merge_threshold_minutes: { type: :string } + route_opacity: { + type: :string, + example: 0.3, + description: 'the opacity of the route, float between 0 and 1' + }, + meters_between_routes: { + type: :string, + example: 100, + description: 'the distance between routes in meters' + }, + minutes_between_routes: { + type: :string, + example: 100, + description: 'the time between routes in minutes' + }, + fog_of_war_meters: { + type: :string, + example: 100, + description: 'the fog of war distance in meters' + } }, required: %w[route_opacity meters_between_routes minutes_between_routes fog_of_war_meters time_threshold_minutes merge_threshold_minutes] diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 7264b64e..3ce30e09 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -29,12 +29,20 @@ paths: properties: name: type: string + example: Home + description: The name of the area latitude: type: number + example: 40.7128 + description: The latitude of the area longitude: type: number + example: -74.006 + description: The longitude of the area radius: type: number + example: 100 + description: The radius of the area in meters required: - name - latitude @@ -71,14 +79,24 @@ paths: properties: id: type: integer + example: 1 + description: The ID of the area name: type: string + example: Home + description: The name of the area latitude: type: number + example: 40.7128 + description: The latitude of the area longitude: type: number + example: -74.006 + description: The longitude of the area radius: type: number + example: 100 + description: The radius of the area in meters required: - id - name @@ -117,6 +135,8 @@ paths: - name: api_key in: query required: true + example: a1b2c3d4e5f6g7h8i9j0 + description: Your API authentication key schema: type: string - name: start_at @@ -146,6 +166,23 @@ paths: data: type: array description: Array of countries and their visited cities + example: + - country: Germany + cities: + - city: Berlin + points: 4394 + timestamp: 1724868369 + stayed_for: 24490 + - city: Munich + points: 2156 + timestamp: 1724782369 + stayed_for: 12450 + - country: France + cities: + - city: Paris + points: 3267 + timestamp: 1724695969 + stayed_for: 18720 items: type: object properties: @@ -192,6 +229,27 @@ paths: responses: '200': description: Healthy + headers: + X-Dawarich-Response: + type: string + required: true + example: Hey, I'm alive! + description: Depending on the authentication status of the request, + the response will be different. If the request is authenticated, the + response will be 'Hey, I'm alive and authenticated!'. If the request + is not authenticated, the response will be 'Hey, I'm alive!'. + X-Dawarich-Version: + type: string + required: true + example: 1.0.0 + description: 'The version of the application, for example: 1.0.0' + content: + application/json: + schema: + type: object + properties: + status: + type: string "/api/v1/overland/batches": post: summary: Creates a batch of points @@ -217,51 +275,97 @@ paths: properties: type: type: string + example: Feature geometry: type: object properties: type: type: string + example: Point coordinates: type: array + example: + - 13.356718 + - 52.502397 properties: type: object properties: timestamp: type: string + example: '2021-06-01T12:00:00Z' + description: Timestamp in ISO 8601 format altitude: type: number + example: 0 + description: Altitude in meters speed: type: number + example: 0 + description: Speed in meters per second horizontal_accuracy: type: number + example: 0 + description: Horizontal accuracy in meters vertical_accuracy: type: number + example: 0 + description: Vertical accuracy in meters motion: type: array - pauses: - type: boolean + example: + - walking + - running + - driving + - cycling + - stationary + description: 'Motion type, for example: automotive_navigation, + fitness, other_navigation or other' activity: type: string + example: unknown + description: 'Activity type, for example: automotive_navigation, + fitness, other_navigation or other' desired_accuracy: type: number + example: 0 + description: Desired accuracy in meters deferred: type: number + example: 0 + description: the distance in meters to defer location updates significant_change: type: string + example: disabled + description: a significant change mode, disabled, enabled or + exclusive locations_in_payload: type: number + example: 1 + description: the number of locations in the payload device_id: type: string + example: 'iOS device #166' + description: the device id + unique_id: + type: string + example: '1234567890' + description: the device's Unique ID as set by Apple wifi: type: string + example: unknown + description: the WiFi network name battery_state: type: string + example: unknown + description: the battery state, unknown, unplugged, charging + or full battery_level: type: number - required: - - geometry - - properties + example: 0 + description: the battery level percentage, from 0 to 1 + required: + - geometry + - properties examples: '0': summary: Creates a batch of points @@ -286,7 +390,8 @@ paths: deferred: 0 significant_change: unknown locations_in_payload: 1 - device_id: Swagger + device_id: 'iOS device #166' + unique_id: '1234567890' wifi: unknown battery_state: unknown battery_level: 0 @@ -315,50 +420,74 @@ paths: properties: batt: type: number + description: Device battery level (percentage) lon: type: number + description: Longitude coordinate acc: type: number + description: Accuracy of position in meters bs: type: number + description: Battery status (0=unknown, 1=unplugged, 2=charging, + 3=full) inrids: type: array + description: Array of region IDs device is currently in BSSID: type: string + description: Connected WiFi access point MAC address SSID: type: string + description: Connected WiFi network name vac: type: number + description: Vertical accuracy in meters inregions: type: array + description: Array of region names device is currently in lat: type: number + description: Latitude coordinate topic: type: string + description: MQTT topic in format owntracks/user/device t: type: string + description: Type of message (p=position, c=circle, etc) conn: type: string + description: Connection type (w=wifi, m=mobile, o=offline) m: type: number + description: Motion state (0=stopped, 1=moving) tst: type: number + description: Timestamp in Unix epoch time alt: type: number + description: Altitude in meters _type: type: string + description: Internal message type (usually "location") tid: type: string + description: Tracker ID used to display the initials of a user _http: type: boolean + description: Whether message was sent via HTTP (true) or MQTT (false) ghash: type: string + description: Geohash of location isorcv: type: string + description: ISO 8601 timestamp when message was received isotst: type: string + description: ISO 8601 timestamp of the location fix disptst: type: string + description: Human-readable timestamp of the location fix required: - owntracks/jane examples: @@ -725,36 +854,58 @@ paths: properties: type: type: string + example: Point + description: the geometry type, always Point coordinates: type: array items: type: number + example: + - -122.40530871 + - 37.74430413 + description: the coordinates of the point, longitude and latitude properties: type: object properties: timestamp: type: string + example: '2025-01-17T21:03:01Z' + description: the timestamp of the point horizontal_accuracy: type: number + example: 5 + description: the horizontal accuracy of the point in meters vertical_accuracy: type: number + example: -1 + description: the vertical accuracy of the point in meters altitude: type: number + example: 0 + description: the altitude of the point in meters speed: type: number + example: 92.088 + description: the speed of the point in meters per second speed_accuracy: type: number - course: - type: number + example: 0 + description: the speed accuracy of the point in meters per second course_accuracy: type: number + example: 0 + description: the course accuracy of the point in degrees track_id: type: string + example: 799F32F5-89BB-45FB-A639-098B1B95B09F + description: the track id of the point set by the device device_id: type: string - required: - - geometry - - properties + example: 8D5D4197-245B-4619-A88B-2049100ADE46 + description: the device id of the point set by the device + required: + - geometry + - properties examples: '0': summary: Creates a batch of points @@ -821,16 +972,20 @@ paths: properties: route_opacity: type: number + example: 0.3 + description: the opacity of the route, float between 0 and 1 meters_between_routes: type: number + example: 100 + description: the distance between routes in meters minutes_between_routes: type: number + example: 100 + description: the time between routes in minutes fog_of_war_meters: type: number - time_threshold_minutes: - type: number - merge_threshold_minutes: - type: number + example: 100 + description: the fog of war distance in meters optional: - route_opacity - meters_between_routes @@ -873,16 +1028,21 @@ paths: properties: route_opacity: type: string + example: 0.3 + description: the opacity of the route, float between 0 and + 1 meters_between_routes: type: string + example: 100 + description: the distance between routes in meters minutes_between_routes: type: string + example: 100 + description: the time between routes in minutes fog_of_war_meters: type: string - time_threshold_minutes: - type: string - merge_threshold_minutes: - type: string + example: 100 + description: the fog of war distance in meters required: - route_opacity - meters_between_routes