mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Fix GPX export timestamps and add slim version of points
This commit is contained in:
parent
2fd7c7bbf1
commit
7b876ea754
10 changed files with 180 additions and 64 deletions
|
|
@ -1 +1 @@
|
|||
0.14.3
|
||||
0.14.4
|
||||
|
|
|
|||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -5,12 +5,28 @@ 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.14.4] - 2024-09-24
|
||||
|
||||
### Fixed
|
||||
|
||||
- GPX export now has time and elevation elements for each point
|
||||
|
||||
### Changed
|
||||
|
||||
- `GET /api/v1/points` will no longer return `raw_data` attribute for each point as it's a bit too much
|
||||
|
||||
### Added
|
||||
|
||||
- "Slim" version of `GET /api/v1/points`: pass optional param `?slim=true` to it and it will return only latitude, longitude and timestamp
|
||||
|
||||
|
||||
# [0.14.3] — 2024-09-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Optimize order of the dockerfiles to leverage layer caching by @JoeyEamigh
|
||||
- Add support for alternate postgres ports and db names in docker by @JoeyEamigh
|
||||
- Creating exports directory if it doesn't exist by @tetebueno
|
||||
|
||||
|
||||
## [0.14.1] — 2024-09-16
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ class Api::V1::PointsController < ApiController
|
|||
.order(:timestamp)
|
||||
.page(params[:page])
|
||||
.per(params[:per_page] || 100)
|
||||
|
||||
serialized_points = points.map { |point| point_serializer.new(point).call }
|
||||
|
||||
response.set_header('X-Current-Page', points.current_page.to_s)
|
||||
response.set_header('X-Total-Pages', points.total_pages.to_s)
|
||||
|
||||
render json: points
|
||||
render json: serialized_points
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
|
@ -24,4 +26,10 @@ class Api::V1::PointsController < ApiController
|
|||
|
||||
render json: { message: 'Point deleted successfully' }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def point_serializer
|
||||
params[:slim] ? SlimPointSerializer : PointSerializer
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PointSerializer
|
||||
EXCLUDED_ATTRIBUTES = %w[created_at updated_at visit_id id import_id user_id].freeze
|
||||
EXCLUDED_ATTRIBUTES = %w[created_at updated_at visit_id id import_id user_id raw_data].freeze
|
||||
|
||||
def initialize(point)
|
||||
@point = point
|
||||
|
|
|
|||
|
|
@ -6,9 +6,18 @@ class Points::GpxSerializer
|
|||
end
|
||||
|
||||
def call
|
||||
geojson_data = Points::GeojsonSerializer.new(points).call
|
||||
gpx = GPX::GPXFile.new
|
||||
|
||||
GPX::GeoJSON.convert_to_gpx(geojson_data:)
|
||||
points.each do |point|
|
||||
gpx.waypoints << GPX::Waypoint.new(
|
||||
lat: point.latitude.to_f,
|
||||
lon: point.longitude.to_f,
|
||||
time: point.recorded_at.strftime('%FT%R:%SZ'),
|
||||
ele: point.altitude.to_f
|
||||
)
|
||||
end
|
||||
|
||||
gpx
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
19
app/serializers/slim_point_serializer.rb
Normal file
19
app/serializers/slim_point_serializer.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SlimPointSerializer
|
||||
def initialize(point)
|
||||
@point = point
|
||||
end
|
||||
|
||||
def call
|
||||
{
|
||||
latitude: point.latitude,
|
||||
longitude: point.longitude,
|
||||
timestamp: point.timestamp
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :point
|
||||
end
|
||||
|
|
@ -2,29 +2,29 @@
|
|||
|
||||
FactoryBot.define do
|
||||
factory :point do
|
||||
battery_status { 1 }
|
||||
ping { 'MyString' }
|
||||
battery { 1 }
|
||||
topic { 'MyString' }
|
||||
altitude { 1 }
|
||||
longitude { 'MyString' }
|
||||
velocity { 'MyString' }
|
||||
trigger { 1 }
|
||||
bssid { 'MyString' }
|
||||
ssid { 'MyString' }
|
||||
connection { 1 }
|
||||
battery_status { 1 }
|
||||
ping { 'MyString' }
|
||||
battery { 1 }
|
||||
topic { 'MyString' }
|
||||
altitude { 1 }
|
||||
longitude { FFaker::Geolocation.lng }
|
||||
velocity { 0 }
|
||||
trigger { 1 }
|
||||
bssid { 'MyString' }
|
||||
ssid { 'MyString' }
|
||||
connection { 1 }
|
||||
vertical_accuracy { 1 }
|
||||
accuracy { 1 }
|
||||
timestamp { 1 }
|
||||
latitude { 'MyString' }
|
||||
mode { 1 }
|
||||
inrids { 'MyString' }
|
||||
in_regions { 'MyString' }
|
||||
raw_data { '' }
|
||||
tracker_id { 'MyString' }
|
||||
import_id { '' }
|
||||
city { nil }
|
||||
country { nil }
|
||||
accuracy { 1 }
|
||||
timestamp { 1.year.ago.to_i }
|
||||
latitude { FFaker::Geolocation.lat }
|
||||
mode { 1 }
|
||||
inrids { 'MyString' }
|
||||
in_regions { 'MyString' }
|
||||
raw_data { '' }
|
||||
tracker_id { 'MyString' }
|
||||
import_id { '' }
|
||||
city { nil }
|
||||
country { nil }
|
||||
user
|
||||
|
||||
trait :with_geodata do
|
||||
|
|
|
|||
|
|
@ -7,39 +7,90 @@ RSpec.describe 'Api::V1::Points', type: :request do
|
|||
let!(:points) { create_list(:point, 150, user:) }
|
||||
|
||||
describe 'GET /index' do
|
||||
it 'renders a successful response' do
|
||||
get api_v1_points_url(api_key: user.api_key)
|
||||
context 'when regular version of points is requested' do
|
||||
it 'renders a successful response' do
|
||||
get api_v1_points_url(api_key: user.api_key)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'returns a list of points' do
|
||||
get api_v1_points_url(api_key: user.api_key)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
expect(json_response.size).to eq(100)
|
||||
end
|
||||
|
||||
it 'returns a list of points with pagination' do
|
||||
get api_v1_points_url(api_key: user.api_key, page: 2, per_page: 10)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
expect(json_response.size).to eq(10)
|
||||
end
|
||||
|
||||
it 'returns a list of points with pagination headers' do
|
||||
get api_v1_points_url(api_key: user.api_key, page: 2, per_page: 10)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
expect(response.headers['X-Current-Page']).to eq('2')
|
||||
expect(response.headers['X-Total-Pages']).to eq('15')
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns a list of points' do
|
||||
get api_v1_points_url(api_key: user.api_key)
|
||||
context 'when slim version of points is requested' do
|
||||
it 'renders a successful response' do
|
||||
get api_v1_points_url(api_key: user.api_key, slim: true)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
it 'returns a list of points' do
|
||||
get api_v1_points_url(api_key: user.api_key, slim: true)
|
||||
|
||||
expect(json_response.size).to eq(100)
|
||||
end
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
it 'returns a list of points with pagination' do
|
||||
get api_v1_points_url(api_key: user.api_key, page: 2, per_page: 10)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json_response.size).to eq(100)
|
||||
end
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
it 'returns a list of points with pagination' do
|
||||
get api_v1_points_url(api_key: user.api_key, slim: true, page: 2, per_page: 10)
|
||||
|
||||
expect(json_response.size).to eq(10)
|
||||
end
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
it 'returns a list of points with pagination headers' do
|
||||
get api_v1_points_url(api_key: user.api_key, page: 2, per_page: 10)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json_response.size).to eq(10)
|
||||
end
|
||||
|
||||
expect(response.headers['X-Current-Page']).to eq('2')
|
||||
expect(response.headers['X-Total-Pages']).to eq('15')
|
||||
it 'returns a list of points with pagination headers' do
|
||||
get api_v1_points_url(api_key: user.api_key, slim: true, page: 2, per_page: 10)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
expect(response.headers['X-Current-Page']).to eq('2')
|
||||
expect(response.headers['X-Total-Pages']).to eq('15')
|
||||
end
|
||||
|
||||
it 'returns a list of points with slim attributes' do
|
||||
get api_v1_points_url(api_key: user.api_key, slim: true)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
json_response.each do |point|
|
||||
expect(point.keys).to eq(%w[latitude longitude timestamp])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Points::GpxSerializer do
|
||||
describe '#call' do
|
||||
subject(:serializer) { described_class.new(points).call }
|
||||
|
||||
let(:points) { create_list(:point, 3) }
|
||||
let(:geojson_data) { Points::GeojsonSerializer.new(points).call }
|
||||
let(:gpx) { GPX::GeoJSON.convert_to_gpx(geojson_data:) }
|
||||
|
||||
it 'returns JSON' do
|
||||
expect(serializer).to be_a(GPX::GPXFile)
|
||||
end
|
||||
end
|
||||
end
|
||||
30
spec/serializers/points/gpx_serializer_spec.rb
Normal file
30
spec/serializers/points/gpx_serializer_spec.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Points::GpxSerializer do
|
||||
describe '#call' do
|
||||
subject(:serializer) { described_class.new(points).call }
|
||||
|
||||
let(:points) { create_list(:point, 3) }
|
||||
let(:geojson_data) { Points::GeojsonSerializer.new(points).call }
|
||||
let(:gpx) { GPX::GeoJSON.convert_to_gpx(geojson_data:) }
|
||||
|
||||
it 'returns GPX file' do
|
||||
expect(serializer).to be_a(GPX::GPXFile)
|
||||
end
|
||||
|
||||
it 'includes waypoints' do
|
||||
expect(serializer.waypoints.size).to eq(3)
|
||||
end
|
||||
|
||||
it 'includes waypoints with correct attributes' do
|
||||
serializer.waypoints.each_with_index do |waypoint, index|
|
||||
point = points[index]
|
||||
expect(waypoint.lat).to eq(point.latitude)
|
||||
expect(waypoint.lon).to eq(point.longitude)
|
||||
expect(waypoint.time).to eq(point.recorded_at.strftime('%FT%R:%SZ'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue