diff --git a/CHANGELOG.md b/CHANGELOG.md index 3750af63..4d3c5e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Removed "Your data" page as its function was replaced by "Download JSON" button on the points page - Hovering over a route now also shows time and distance to next route as well as time and distance to previous route. This allows user to understand why routes might not be connected on the map. +--- ## [0.4.3] — 2024-05-30 diff --git a/Gemfile b/Gemfile index 2b3f7406..852cd4ff 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem 'chartkick' gem 'data_migrate' gem 'devise' gem 'geocoder' +gem 'gpx' gem 'importmap-rails' gem 'oj' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index b40a4b7c..e75744f5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -137,6 +137,9 @@ GEM csv (>= 3.0.0) globalid (1.2.1) activesupport (>= 6.1) + gpx (1.1.1) + nokogiri (~> 1.7) + rake hashdiff (1.1.0) i18n (1.14.5) concurrent-ruby (~> 1.0) @@ -405,6 +408,7 @@ DEPENDENCIES ffaker foreman geocoder + gpx importmap-rails oj pg diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index 428c6fab..3d4b976e 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -23,7 +23,11 @@ class ImportsController < ApplicationController source: params[:import][:source] ) - import.update(raw_data: JSON.parse(File.read(file))) + file = File.read(file) + + raw_data = params[:import][:source] == 'gpx' ? Hash.from_xml(file) : JSON.parse(file) + + import.update(raw_data:) import.id end diff --git a/app/jobs/import_job.rb b/app/jobs/import_job.rb index 7c1a9282..5f5b8ee2 100644 --- a/app/jobs/import_job.rb +++ b/app/jobs/import_job.rb @@ -23,6 +23,7 @@ class ImportJob < ApplicationJob when 'google_semantic_history' then GoogleMaps::SemanticHistoryParser when 'google_records' then GoogleMaps::RecordsParser when 'owntracks' then OwnTracks::ExportParser + when 'gpx' then Gpx::TrackParser end end end diff --git a/app/models/import.rb b/app/models/import.rb index dcbf8b2a..caa40666 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -8,5 +8,5 @@ class Import < ApplicationRecord include ImportUploader::Attachment(:raw) - enum source: { google_semantic_history: 0, owntracks: 1, google_records: 2 } + enum source: { google_semantic_history: 0, owntracks: 1, google_records: 2, gpx: 3 } end diff --git a/app/serializers/export_serializer.rb b/app/serializers/export_serializer.rb index 3b9d7d2c..a5d94744 100644 --- a/app/serializers/export_serializer.rb +++ b/app/serializers/export_serializer.rb @@ -9,7 +9,7 @@ class ExportSerializer end def call - Oj.dump({ user_email => { 'dawarich-export' => export_points } }) + { user_email => { 'dawarich-export' => export_points } }.to_json end private diff --git a/app/services/gpx/track_parser.rb b/app/services/gpx/track_parser.rb new file mode 100644 index 00000000..99c68752 --- /dev/null +++ b/app/services/gpx/track_parser.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class Gpx::TrackParser + attr_reader :import, :json, :user_id + + def initialize(import, user_id) + @import = import + @json = import.raw_data + @user_id = user_id + end + + def call + end +end diff --git a/spec/fixtures/files/gpx/track.gpx b/spec/fixtures/files/gpx/track.gpx new file mode 100644 index 00000000..52b4c410 --- /dev/null +++ b/spec/fixtures/files/gpx/track.gpx @@ -0,0 +1,404 @@ + + + + Thu 18 Apr 2024 + + + какое-то описание:) + + + + + + bicycle + 0 + + + + + bicycle + 36 + + + + + bicycle + 75 + + + + + Thu 18 Apr 2024 + + + 822.4 + + + + 822.8 + + + + 823 + + + + 823.2 + + + + 823.5 + + + + 823.8 + + + + 824 + + + + 824.2 + + + + 824.5 + + + + 825 + + + + 825 + + + + 825 + + + + 825 + + + + 824.8 + + + + 824.5 + + + + 824 + + + + 824 + + + + 823.5 + + + + 822.8 + + + + 822 + + + + 822 + + + + 824.5 + + + + 827 + + + + 829.5 + + + + 831.2 + + + + 833.2 + + + + 836.5 + + + + 839.8 + + + + 842.5 + + + + 846.5 + + + + 847.2 + + + + 850.2 + + + + 851.1 + + + + 851.5 + + + + 852 + + + + 852.8 + + + + 852.8 + + + + 853.5 + + + + 850.8 + + + + 849 + + + + 849.8 + + + + 850 + + + + 844.2 + + + + 840 + + + + 839 + + + + 837 + + + + 840 + + + + 841 + + + + 841.2 + + + + 842 + + + + 843.5 + + + + 844 + + + + 847.8 + + + + 850.2 + + + + 853 + + + + 853.5 + + + + 860.2 + + + + 863.2 + + + + 863.5 + + + + 867.8 + + + + 868.5 + + + + 873.8 + + + + 878.2 + + + + 881.2 + + + + 882.2 + + + + 884 + + + + 887 + + + + 888.5 + + + + 890 + + + + 892.2 + + + + 894.2 + + + + 895.2 + + + + 895.5 + + + + 898.8 + + + + 899.5 + + + + 900.4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 0.0 + no_split + none + none + top + + \ No newline at end of file diff --git a/spec/requests/export_spec.rb b/spec/requests/export_spec.rb index 3b6ccbb9..07eda5f7 100644 --- a/spec/requests/export_spec.rb +++ b/spec/requests/export_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe 'Exports', type: :request do - describe 'GET /create' do + describe 'GET /download' do before do stub_request(:any, 'https://api.github.com/repos/Freika/dawarich/tags') .to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {}) @@ -11,10 +11,11 @@ RSpec.describe 'Exports', type: :request do sign_in create(:user) end - it 'returns http success' do - get '/export' + it 'returns a success response with a file' do + get export_download_path - expect(response).to have_http_status(:success) + expect(response).to be_successful + expect(response.headers['Content-Disposition']).to include('attachment') end end end diff --git a/spec/requests/imports_spec.rb b/spec/requests/imports_spec.rb index 1dab4432..50b9eca1 100644 --- a/spec/requests/imports_spec.rb +++ b/spec/requests/imports_spec.rb @@ -37,22 +37,43 @@ RSpec.describe 'Imports', type: :request do describe 'POST /imports' do context 'when user is logged in' do let(:user) { create(:user) } - let(:file) { fixture_file_upload('owntracks/export.json', 'application/json') } before { sign_in user } - it 'queues import job' do - expect do - post imports_path, params: { import: { source: 'owntracks', files: [file] } } - end.to have_enqueued_job(ImportJob).on_queue('imports').at_least(1).times + context 'when importing owntracks data' do + let(:file) { fixture_file_upload('owntracks/export.json', 'application/json') } + + it 'queues import job' do + expect do + post imports_path, params: { import: { source: 'owntracks', files: [file] } } + end.to have_enqueued_job(ImportJob).on_queue('imports').at_least(1).times + end + + it 'creates a new import' do + expect do + post imports_path, params: { import: { source: 'owntracks', files: [file] } } + end.to change(user.imports, :count).by(1) + + expect(response).to redirect_to(imports_path) + end end - it 'creates a new import' do - expect do - post imports_path, params: { import: { source: 'owntracks', files: [file] } } - end.to change(user.imports, :count).by(1) + context 'when importing gpx data' do + let(:file) { fixture_file_upload('gpx/track.gpx', 'application/gpx+xml') } - expect(response).to redirect_to(imports_path) + it 'queues import job' do + expect do + post imports_path, params: { import: { source: 'gpx', files: [file] } } + end.to have_enqueued_job(ImportJob).on_queue('imports').at_least(1).times + end + + it 'creates a new import' do + expect do + post imports_path, params: { import: { source: 'gpx', files: [file] } } + end.to change(user.imports, :count).by(1) + + expect(response).to redirect_to(imports_path) + end end end end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 3722d11b..a329bf85 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -180,7 +180,7 @@ paths: lat: 52.502397 lon: 13.356718 tid: Swagger - tst: 1717062606 + tst: 1717182089 servers: - url: http://{defaultHost} variables: