From 494eb2c0ec2469722c72e1d03c1082afef8f548c Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 18 May 2024 15:00:44 +0200 Subject: [PATCH] Implement Google Maps records parser --- app/controllers/imports_controller.rb | 9 ++-- app/jobs/import_job.rb | 3 +- app/models/import.rb | 2 +- app/services/google_maps/records_parser.rb | 49 +++++++++++++++++++ ...e_parser.rb => semantic_history_parser.rb} | 2 +- spec/fixtures/files/google/records.json | 22 +++++++++ swagger/v1/swagger.yaml | 4 +- 7 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 app/services/google_maps/records_parser.rb rename app/services/google_maps/{timeline_parser.rb => semantic_history_parser.rb} (98%) create mode 100644 spec/fixtures/files/google/records.json diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index f31f50f1..428c6fab 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -1,13 +1,14 @@ +# frozen_string_literal: true + class ImportsController < ApplicationController before_action :authenticate_user! - before_action :set_import, only: %i[ show destroy ] + before_action :set_import, only: %i[show destroy] def index @imports = current_user.imports end - def show - end + def show; end def new @import = Import.new @@ -39,7 +40,7 @@ class ImportsController < ApplicationController def destroy @import.destroy! - redirect_to imports_url, notice: "Import was successfully destroyed.", status: :see_other + redirect_to imports_url, notice: 'Import was successfully destroyed.', status: :see_other end private diff --git a/app/jobs/import_job.rb b/app/jobs/import_job.rb index 9111a43d..49e7492a 100644 --- a/app/jobs/import_job.rb +++ b/app/jobs/import_job.rb @@ -20,7 +20,8 @@ class ImportJob < ApplicationJob def parser(source) case source - when 'google' then GoogleMaps::TimelineParser + when 'google_semantic_history' then GoogleMaps::SemanticHistoryParser + when 'google_records' then GoogleMaps::RecordsParser when 'owntracks' then OwnTracks::ExportParser end end diff --git a/app/models/import.rb b/app/models/import.rb index e0206a20..f7451166 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -6,5 +6,5 @@ class Import < ApplicationRecord include ImportUploader::Attachment(:raw) - enum source: { google: 0, owntracks: 1 } + enum source: { google_semantic_history: 0, owntracks: 1, google_records: 2 } end diff --git a/app/services/google_maps/records_parser.rb b/app/services/google_maps/records_parser.rb new file mode 100644 index 00000000..fae1a6d6 --- /dev/null +++ b/app/services/google_maps/records_parser.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class GoogleMaps::RecordsParser + attr_reader :import + + def initialize(import) + @import = import + end + + def call + points_data = parse_json + + points = 0 + + points_data.each do |point_data| + next if Point.exists?(timestamp: point_data[:timestamp]) + + Point.create( + latitude: point_data[:latitude], + longitude: point_data[:longitude], + timestamp: point_data[:timestamp], + raw_data: point_data[:raw_data], + topic: 'Google Maps Timeline Export', + tracker_id: 'google-maps-timeline-export', + import_id: import.id + ) + + points += 1 + end + + doubles = points_data.size - points + processed = points + doubles + + { raw_points: points_data.size, points:, doubles:, processed: } + end + + private + + def parse_json + import.raw_data['locations'].map do |record| + { + latitude: record['latitudeE7'].to_f / 10**7, + longitude: record['longitudeE7'].to_f / 10**7, + timestamp: DateTime.parse(record['timestamp']).to_i, + raw_data: record + } + end.reject(&:blank?) + end +end diff --git a/app/services/google_maps/timeline_parser.rb b/app/services/google_maps/semantic_history_parser.rb similarity index 98% rename from app/services/google_maps/timeline_parser.rb rename to app/services/google_maps/semantic_history_parser.rb index f3cc9af3..af35fd1f 100644 --- a/app/services/google_maps/timeline_parser.rb +++ b/app/services/google_maps/semantic_history_parser.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class GoogleMaps::TimelineParser +class GoogleMaps::SemanticHistoryParser attr_reader :import def initialize(import) diff --git a/spec/fixtures/files/google/records.json b/spec/fixtures/files/google/records.json new file mode 100644 index 00000000..2a213061 --- /dev/null +++ b/spec/fixtures/files/google/records.json @@ -0,0 +1,22 @@ +{ + "locations": [{ + "latitudeE7": 533690550, + "longitudeE7": 836950010, + "accuracy": 150, + "source": "UNKNOWN", + "timestamp": "2012-12-15T14:21:29.460Z" + }, { + "latitudeE7": 533563380, + "longitudeE7": 837616500, + "accuracy": 18000, + "source": "UNKNOWN", + "timestamp": "2013-01-04T10:22:43.225Z" + }, { + "latitudeE7": 533690589, + "longitudeE7": 836951347, + "accuracy": 22, + "source": "WIFI", + "deviceTag": 1184882232, + "timestamp": "2013-03-01T05:17:39.849Z" + }] +} diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index ea65b9c8..a06110fb 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -71,7 +71,7 @@ paths: summary: Creates a batch of points value: locations: - - type: FeatureCollection + - type: Feature geometry: type: Point coordinates: @@ -172,7 +172,7 @@ paths: lat: 52.502397 lon: 13.356718 tid: Swagger - tst: 1716033410 + tst: 1716036830 servers: - url: http://{defaultHost} variables: