diff --git a/CHANGELOG.md b/CHANGELOG.md index aaf648f0..a970503f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Internal data structure for separate devices in a single user account. - [ ] Immich and Photoprism integrations should fill all possible fields in points table +- Geodata from Immich and Photoprism now will also write `tracker_id` to the points table. This will allow to group points by device. It's a good idea to delete your existing imports from Photoprism and Immich and import them again. This will remove existing points and re-import them as long as photos are still available. +- [ ] Add tracker_id index to points table diff --git a/app/models/concerns/point_validation.rb b/app/models/concerns/point_validation.rb index 4bd919d3..f43ee169 100644 --- a/app/models/concerns/point_validation.rb +++ b/app/models/concerns/point_validation.rb @@ -7,6 +7,7 @@ module PointValidation Point.where( lonlat: params[:lonlat], timestamp: params[:timestamp].to_i, + tracker_id: params[:tracker_id], user_id: ).exists? end diff --git a/app/services/immich/import_geodata.rb b/app/services/immich/import_geodata.rb index 9f9679ee..f9106dd9 100644 --- a/app/services/immich/import_geodata.rb +++ b/app/services/immich/import_geodata.rb @@ -56,7 +56,8 @@ class Immich::ImportGeodata latitude: asset['exifInfo']['latitude'], longitude: asset['exifInfo']['longitude'], lonlat: "SRID=4326;POINT(#{asset['exifInfo']['longitude']} #{asset['exifInfo']['latitude']})", - timestamp: Time.zone.parse(asset['exifInfo']['dateTimeOriginal']).to_i + timestamp: Time.zone.parse(asset['exifInfo']['dateTimeOriginal']).to_i, + tracker_id: asset['deviceId'] } end diff --git a/app/services/photoprism/import_geodata.rb b/app/services/photoprism/import_geodata.rb index c31946c1..3e703222 100644 --- a/app/services/photoprism/import_geodata.rb +++ b/app/services/photoprism/import_geodata.rb @@ -66,7 +66,8 @@ class Photoprism::ImportGeodata latitude: asset['Lat'], longitude: asset['Lng'], lonlat: "SRID=4326;POINT(#{asset['Lng']} #{asset['Lat']})", - timestamp: Time.zone.parse(asset['TakenAt']).to_i + timestamp: Time.zone.parse(asset['TakenAt']).to_i, + tracker_id: "#{asset['CameraMake']} #{asset['CameraModel']}" } end diff --git a/app/services/photos/importer.rb b/app/services/photos/importer.rb index f3ce8fc4..4d529bd3 100644 --- a/app/services/photos/importer.rb +++ b/app/services/photos/importer.rb @@ -19,7 +19,7 @@ class Photos::Importer def create_point(point, index) return 0 unless valid?(point) - return 0 if point_exists?(point, point['timestamp']) + return 0 if point_exists?(point, user_id) Point.create( lonlat: point['lonlat'], @@ -28,6 +28,7 @@ class Photos::Importer timestamp: point['timestamp'].to_i, raw_data: point, import_id: import.id, + tracker_id: point['tracker_id'], user_id: ) diff --git a/spec/fixtures/files/immich/response.json b/spec/fixtures/files/immich/response.json index 13eb414d..54a98fbe 100644 --- a/spec/fixtures/files/immich/response.json +++ b/spec/fixtures/files/immich/response.json @@ -3,6 +3,7 @@ { "assets": [ { + "deviceId": "MyString", "exifInfo": { "dateTimeOriginal": "2022-12-31T23:17:06.170Z", "latitude": 52.0000, @@ -10,6 +11,7 @@ } }, { + "deviceId": "MyString", "exifInfo": { "dateTimeOriginal": "2022-12-31T23:21:53.140Z", "latitude": 52.0000, diff --git a/spec/models/concerns/point_validation_spec.rb b/spec/models/concerns/point_validation_spec.rb index b66755fa..71f7e091 100644 --- a/spec/models/concerns/point_validation_spec.rb +++ b/spec/models/concerns/point_validation_spec.rb @@ -104,56 +104,13 @@ RSpec.describe PointValidation do end end - context 'with integration tests', :db do - # These tests require a database with PostGIS support - # Only run them if using real database integration - - let(:existing_timestamp) { 1_650_000_000 } - let(:existing_point_params) do - { - lonlat: 'POINT(10.5 50.5)', - timestamp: existing_timestamp, - user_id: user.id - } + context 'with point existing in device scope' do + let(:existing_point) do + create(:point, lonlat: 'POINT(10.5 50.5)', timestamp: Time.now.to_i, tracker_id: '123', user_id: user.id) end - before do - # Skip this context if not in integration mode - skip 'Skipping integration tests' unless ENV['RUN_INTEGRATION_TESTS'] - - # Create a point in the database - existing_point = Point.create!( - lonlat: "POINT(#{existing_point_params[:longitude]} #{existing_point_params[:latitude]})", - timestamp: existing_timestamp, - user_id: user.id - ) - end - - it 'returns true when a point with same coordinates and timestamp exists' do - params = { - lonlat: 'POINT(10.5 50.5)', - timestamp: existing_timestamp - } - - expect(validator.point_exists?(params, user.id)).to be true - end - - it 'returns false when a point with different coordinates exists' do - params = { - lonlat: 'POINT(10.6 50.5)', - timestamp: existing_timestamp - } - - expect(validator.point_exists?(params, user.id)).to be false - end - - it 'returns false when a point with different timestamp exists' do - params = { - lonlat: 'POINT(10.5 50.5)', - timestamp: existing_timestamp + 1 - } - - expect(validator.point_exists?(params, user.id)).to be false + it 'returns true' do + expect(validator.point_exists?(existing_point, user.id)).to be true end end end diff --git a/spec/requests/api/v1/countries/borders_spec.rb b/spec/requests/api/v1/countries/borders_spec.rb index 1162e198..53a44cf3 100644 --- a/spec/requests/api/v1/countries/borders_spec.rb +++ b/spec/requests/api/v1/countries/borders_spec.rb @@ -4,12 +4,22 @@ require 'rails_helper' RSpec.describe 'Api::V1::Countries::Borders', type: :request do describe 'GET /index' do + let(:user) { create(:user) } + it 'returns a list of countries with borders' do - get '/api/v1/countries/borders' + get '/api/v1/countries/borders', headers: { 'Authorization' => "Bearer #{user.api_key}" } expect(response).to have_http_status(:success) expect(response.body).to include('AF') expect(response.body).to include('ZW') end + + context 'when user is not authenticated' do + it 'returns http unauthorized' do + get '/api/v1/countries/borders' + + expect(response).to have_http_status(:unauthorized) + end + end end end diff --git a/spec/services/photos/importer_spec.rb b/spec/services/photos/importer_spec.rb index 1425f67d..eb0fdd94 100644 --- a/spec/services/photos/importer_spec.rb +++ b/spec/services/photos/importer_spec.rb @@ -45,12 +45,28 @@ RSpec.describe Photos::Importer do context 'when there are points with the same coordinates' do let!(:existing_point) do - create(:point, lonlat: 'POINT(30.0000 59.0000)', timestamp: 978_296_400, user:, device:) + create(:point, + lonlat: 'SRID=4326;POINT(30.0000 59.0000)', + timestamp: 978_296_400, + user: user, + device: device, + tracker_id: nil + ) end it 'creates only new points' do expect { service }.to change { Point.count }.by(1) end + + it 'does not create duplicate points' do + service + points = Point.where( + lonlat: 'SRID=4326;POINT(30.0000 59.0000)', + timestamp: 978_296_400, + user_id: user.id + ) + expect(points.count).to eq(1) + end end end end