From b336172b31fce5157bed8055c46ff837a87e5afc Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 10 Dec 2024 18:49:37 +0100 Subject: [PATCH 1/5] Show photoprism photos on a trip page --- app/helpers/application_helper.rb | 13 +++++++ app/models/import.rb | 5 ++- app/models/trip.rb | 52 +++++++++++++++++-------- app/serializers/api/photo_serializer.rb | 10 +++++ app/views/trips/show.html.erb | 10 +++-- 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5495369b..8cc09c1c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -120,4 +120,17 @@ module ApplicationHelper encoded_query = URI.encode_www_form_component(query.to_json) "#{base_url}/search?query=#{encoded_query}" end + + def photoprism_search_url(base_url, start_date, _end_date) + "#{base_url}/library/browse?view=cards&year=#{start_date.year}&month=#{start_date.month}&order=newest&public=true&quality=3" + end + + def photo_search_url(source, settings, start_date, end_date) + case source + when 'immich' + immich_search_url(settings['immich_url'], start_date, end_date) + when 'photoprism' + photoprism_search_url(settings['photoprism_url'], start_date, end_date) + end + end end diff --git a/app/models/import.rb b/app/models/import.rb index 2040d738..a0fbc870 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -18,8 +18,9 @@ class Import < ApplicationRecord end def years_and_months_tracked - points.order(:timestamp).map do |point| - [Time.zone.at(point.timestamp).year, Time.zone.at(point.timestamp).month] + points.order(:timestamp).pluck(:timestamp).map do |timestamp| + time = Time.zone.at(timestamp) + [time.year, time.month] end.uniq end end diff --git a/app/models/trip.rb b/app/models/trip.rb index 52948bf4..7a0fdaba 100644 --- a/app/models/trip.rb +++ b/app/models/trip.rb @@ -18,25 +18,15 @@ class Trip < ApplicationRecord end def photos - return [] if user.settings['immich_url'].blank? || user.settings['immich_api_key'].blank? + return [] unless can_fetch_photos? - immich_photos = Immich::RequestPhotos.new( - user, - start_date: started_at.to_date.to_s, - end_date: ended_at.to_date.to_s - ).call.reject { |asset| asset['type'].downcase == 'video' } + filtered_photos.sample(12) + .sort_by { |photo| photo['localDateTime'] } + .map { |asset| photo_thumbnail(asset) } + end - # let's count what photos are more: vertical or horizontal and select the ones that are more - vertical_photos = immich_photos.select { _1['exifInfo']['orientation'] == '6' } - horizontal_photos = immich_photos.select { _1['exifInfo']['orientation'] == '3' } - - # this is ridiculous, but I couldn't find my way around frontend - # to show all photos in the same height - photos = vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos - - photos.sample(12).sort_by { _1['localDateTime'] }.map do |asset| - { url: "/api/v1/photos/#{asset['id']}/thumbnail.jpg?api_key=#{user.api_key}" } - end + def photos_sources + filtered_photos.map { _1[:source] }.uniq end private @@ -54,4 +44,32 @@ class Trip < ApplicationRecord self.distance = distance.round end + + def can_fetch_photos? + user.immich_integration_configured? || user.photoprism_integration_configured? + end + + def filtered_photos + return @filtered_photos if defined?(@filtered_photos) + + photos = Photos::Search.new( + user, + start_date: started_at.to_date.to_s, + end_date: ended_at.to_date.to_s + ).call + + @filtered_photos = select_dominant_orientation(photos) + end + + def select_dominant_orientation(photos) + vertical_photos = photos.select { |photo| photo[:orientation] == 'portrait' } + horizontal_photos = photos.select { |photo| photo[:orientation] == 'landscape' } + + vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos + end + + def photo_thumbnail(asset) + { url: "/api/v1/photos/#{asset[:id]}/thumbnail.jpg?api_key=#{user.api_key}&source=#{asset[:source]}" } + end end + diff --git a/app/serializers/api/photo_serializer.rb b/app/serializers/api/photo_serializer.rb index 5e3ce9a5..c0a1119a 100644 --- a/app/serializers/api/photo_serializer.rb +++ b/app/serializers/api/photo_serializer.rb @@ -17,6 +17,7 @@ class Api::PhotoSerializer state: state, country: country, type: type, + orientation: orientation, source: source } end @@ -60,4 +61,13 @@ class Api::PhotoSerializer def type (photo['type'] || photo['Type']).downcase end + + def orientation + case source + when 'immich' + photo.dig('exifInfo', 'orientation') == '6' ? 'portrait' : 'landscape' + when 'photoprism' + photo['Portrait'] ? 'portrait' : 'landscape' + end + end end diff --git a/app/views/trips/show.html.erb b/app/views/trips/show.html.erb index 5cc00ce6..d0b265fc 100644 --- a/app/views/trips/show.html.erb +++ b/app/views/trips/show.html.erb @@ -52,9 +52,13 @@ <% end %> <% end %> -
- <%= link_to "More photos on Immich", immich_search_url(current_user.settings['immich_url'], @trip.started_at, @trip.ended_at), class: "btn btn-primary", target: '_blank' %> -
+ <% if @trip.photos_sources.any? %> +
+ <% @trip.photos_sources.each do |source| %> + <%= link_to "More photos on #{source}", photo_search_url(source, current_user.settings, @trip.started_at, @trip.ended_at), class: "btn btn-primary mt-2", target: '_blank' %> + <% end %> +
+ <% end %> From d6b88ae9cb5f873fa44bb39904e322d040b088ea Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 10 Dec 2024 19:31:52 +0100 Subject: [PATCH 2/5] Move photos fetching for trips to a separate service --- .app_version | 2 +- CHANGELOG.md | 12 ++++ app/controllers/trips_controller.rb | 5 +- app/helpers/application_helper.rb | 23 ------ app/helpers/trips_helper.rb | 26 +++++++ app/models/trip.rb | 51 ++++--------- app/services/immich/request_photos.rb | 10 +-- app/services/trips/photos.rb | 43 +++++++++++ app/views/trips/show.html.erb | 8 +-- spec/models/trip_spec.rb | 20 ++++-- spec/requests/trips_spec.rb | 2 +- spec/serializers/api/photo_serializer_spec.rb | 2 + spec/services/photos/search_spec.rb | 6 +- spec/services/trips/photos_spec.rb | 72 +++++++++++++++++++ spec/swagger/api/v1/photos_controller_spec.rb | 4 +- swagger/v1/swagger.yaml | 7 ++ 16 files changed, 209 insertions(+), 84 deletions(-) create mode 100644 app/helpers/trips_helper.rb create mode 100644 app/services/trips/photos.rb create mode 100644 spec/services/trips/photos_spec.rb diff --git a/.app_version b/.app_version index b72b05ed..c0b8d590 100644 --- a/.app_version +++ b/.app_version @@ -1 +1 @@ -0.19.3 +0.19.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 16b6f86d..19dcf086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ 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.19.4 - 2024-12-10 + +### Fixed + +- Fixed a bug where the Photoprism photos were not being shown on the trip page. +- Fixed a bug where the Immich photos were not being shown on the trip page. + +### Added + +- A link to the Photoprism photos on the trip page if there are any. +- A `orientation` field in the Api::PhotoSerializer, hence the `GET /api/v1/photos` endpoint now includes the orientation of the photo. Valid values are `portrait` and `landscape`. + # 0.19.3 - 2024-12-06 ### Changed diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb index 97492e74..2a9a26d2 100644 --- a/app/controllers/trips_controller.rb +++ b/app/controllers/trips_controller.rb @@ -15,9 +15,10 @@ class TripsController < ApplicationController :country ).map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7.to_s, _8.to_s] } - @photos = Rails.cache.fetch("trip_photos_#{@trip.id}", expires_in: 1.day) do - @trip.photos + @photo_previews = Rails.cache.fetch("trip_photos_#{@trip.id}", expires_in: 1.day) do + @trip.photo_previews end + @photo_sources = @trip.photo_sources end def new diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8cc09c1c..3fe89204 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -110,27 +110,4 @@ module ApplicationHelper def human_date(date) date.strftime('%e %B %Y') end - - def immich_search_url(base_url, start_date, end_date) - query = { - takenAfter: "#{start_date.to_date}T00:00:00.000Z", - takenBefore: "#{end_date.to_date}T23:59:59.999Z" - } - - encoded_query = URI.encode_www_form_component(query.to_json) - "#{base_url}/search?query=#{encoded_query}" - end - - def photoprism_search_url(base_url, start_date, _end_date) - "#{base_url}/library/browse?view=cards&year=#{start_date.year}&month=#{start_date.month}&order=newest&public=true&quality=3" - end - - def photo_search_url(source, settings, start_date, end_date) - case source - when 'immich' - immich_search_url(settings['immich_url'], start_date, end_date) - when 'photoprism' - photoprism_search_url(settings['photoprism_url'], start_date, end_date) - end - end end diff --git a/app/helpers/trips_helper.rb b/app/helpers/trips_helper.rb new file mode 100644 index 00000000..fa0b77ae --- /dev/null +++ b/app/helpers/trips_helper.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module TripsHelper + def immich_search_url(base_url, start_date, end_date) + query = { + takenAfter: "#{start_date.to_date}T00:00:00.000Z", + takenBefore: "#{end_date.to_date}T23:59:59.999Z" + } + + encoded_query = URI.encode_www_form_component(query.to_json) + "#{base_url}/search?query=#{encoded_query}" + end + + def photoprism_search_url(base_url, start_date, _end_date) + "#{base_url}/library/browse?view=cards&year=#{start_date.year}&month=#{start_date.month}&order=newest&public=true&quality=3" + end + + def photo_search_url(source, settings, start_date, end_date) + case source + when 'immich' + immich_search_url(settings['immich_url'], start_date, end_date) + when 'photoprism' + photoprism_search_url(settings['photoprism_url'], start_date, end_date) + end + end +end diff --git a/app/models/trip.rb b/app/models/trip.rb index 7a0fdaba..e75103c2 100644 --- a/app/models/trip.rb +++ b/app/models/trip.rb @@ -17,20 +17,27 @@ class Trip < ApplicationRecord points.pluck(:country).uniq.compact end - def photos - return [] unless can_fetch_photos? - - filtered_photos.sample(12) - .sort_by { |photo| photo['localDateTime'] } - .map { |asset| photo_thumbnail(asset) } + def photo_previews + @photo_previews ||= select_dominant_orientation(photos).sample(12) end - def photos_sources - filtered_photos.map { _1[:source] }.uniq + def photo_sources + @photo_sources ||= photos.map { _1[:source] }.uniq end private + def photos + @photos ||= Trips::Photos.new(self, user).call + end + + def select_dominant_orientation(photos) + vertical_photos = photos.select { |photo| photo[:orientation] == 'portrait' } + horizontal_photos = photos.select { |photo| photo[:orientation] == 'landscape' } + + vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos + end + def calculate_distance distance = 0 @@ -44,32 +51,4 @@ class Trip < ApplicationRecord self.distance = distance.round end - - def can_fetch_photos? - user.immich_integration_configured? || user.photoprism_integration_configured? - end - - def filtered_photos - return @filtered_photos if defined?(@filtered_photos) - - photos = Photos::Search.new( - user, - start_date: started_at.to_date.to_s, - end_date: ended_at.to_date.to_s - ).call - - @filtered_photos = select_dominant_orientation(photos) - end - - def select_dominant_orientation(photos) - vertical_photos = photos.select { |photo| photo[:orientation] == 'portrait' } - horizontal_photos = photos.select { |photo| photo[:orientation] == 'landscape' } - - vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos - end - - def photo_thumbnail(asset) - { url: "/api/v1/photos/#{asset[:id]}/thumbnail.jpg?api_key=#{user.api_key}&source=#{asset[:source]}" } - end end - diff --git a/app/services/immich/request_photos.rb b/app/services/immich/request_photos.rb index 034a6452..59baa496 100644 --- a/app/services/immich/request_photos.rb +++ b/app/services/immich/request_photos.rb @@ -37,15 +37,7 @@ class Immich::RequestPhotos items = response.dig('assets', 'items') - if items.blank? - Rails.logger.debug('==== IMMICH RESPONSE WITH NO ITEMS ====') - Rails.logger.debug("START_DATE: #{start_date}") - Rails.logger.debug("END_DATE: #{end_date}") - Rails.logger.debug(response) - Rails.logger.debug('==== IMMICH RESPONSE WITH NO ITEMS ====') - - break - end + break if items.blank? data << items diff --git a/app/services/trips/photos.rb b/app/services/trips/photos.rb new file mode 100644 index 00000000..33442833 --- /dev/null +++ b/app/services/trips/photos.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class Trips::Photos + def initialize(trip, user) + @trip = trip + @user = user + end + + def call + return [] unless can_fetch_photos? + + photos + end + + private + + attr_reader :trip, :user + + def can_fetch_photos? + user.immich_integration_configured? || user.photoprism_integration_configured? + end + + def photos + return @photos if defined?(@photos) + + photos = Photos::Search.new( + user, + start_date: trip.started_at.to_date.to_s, + end_date: trip.ended_at.to_date.to_s + ).call + + @photos = photos.map { |photo| photo_thumbnail(photo) } + end + + def photo_thumbnail(asset) + { + id: asset[:id], + url: "/api/v1/photos/#{asset[:id]}/thumbnail.jpg?api_key=#{user.api_key}&source=#{asset[:source]}", + source: asset[:source], + orientation: asset[:orientation] + } + end +end diff --git a/app/views/trips/show.html.erb b/app/views/trips/show.html.erb index d0b265fc..f399eb3f 100644 --- a/app/views/trips/show.html.erb +++ b/app/views/trips/show.html.erb @@ -36,8 +36,8 @@ - <% if @photos.any? %> - <% @photos.each_slice(4) do |slice| %> + <% if @photo_previews.any? %> + <% @photo_previews.each_slice(4) do |slice| %>
<% slice.each do |photo| %>
@@ -52,9 +52,9 @@ <% end %> <% end %> - <% if @trip.photos_sources.any? %> + <% if @photo_sources.any? %>
- <% @trip.photos_sources.each do |source| %> + <% @photo_sources.each do |source| %> <%= link_to "More photos on #{source}", photo_search_url(source, current_user.settings, @trip.started_at, @trip.ended_at), class: "btn btn-primary mt-2", target: '_blank' %> <% end %>
diff --git a/spec/models/trip_spec.rb b/spec/models/trip_spec.rb index b19f348c..0638d781 100644 --- a/spec/models/trip_spec.rb +++ b/spec/models/trip_spec.rb @@ -41,7 +41,7 @@ RSpec.describe Trip, type: :model do end end - describe '#photos' do + describe '#photo_previews' do let(:photo_data) do [ { @@ -80,8 +80,18 @@ RSpec.describe Trip, type: :model do let(:trip) { create(:trip, user:) } let(:expected_photos) do [ - { url: "/api/v1/photos/456/thumbnail.jpg?api_key=#{user.api_key}" }, - { url: "/api/v1/photos/789/thumbnail.jpg?api_key=#{user.api_key}" } + { + id: '456', + url: "/api/v1/photos/456/thumbnail.jpg?api_key=#{user.api_key}&source=immich", + source: 'immich', + orientation: 'portrait' + }, + { + id: '789', + url: "/api/v1/photos/789/thumbnail.jpg?api_key=#{user.api_key}&source=immich", + source: 'immich', + orientation: 'portrait' + } ] end @@ -93,7 +103,7 @@ RSpec.describe Trip, type: :model do let(:settings) { {} } it 'returns an empty array' do - expect(trip.photos).to eq([]) + expect(trip.photo_previews).to eq([]) end end @@ -106,7 +116,7 @@ RSpec.describe Trip, type: :model do end it 'returns the photos' do - expect(trip.photos).to eq(expected_photos) + expect(trip.photo_previews).to eq(expected_photos) end end end diff --git a/spec/requests/trips_spec.rb b/spec/requests/trips_spec.rb index 20daa652..d0e1e794 100644 --- a/spec/requests/trips_spec.rb +++ b/spec/requests/trips_spec.rb @@ -25,7 +25,7 @@ RSpec.describe '/trips', type: :request do stub_request(:any, 'https://api.github.com/repos/Freika/dawarich/tags') .to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {}) - allow_any_instance_of(Trip).to receive(:photos).and_return([]) + allow_any_instance_of(Trip).to receive(:photo_previews).and_return([]) sign_in user end diff --git a/spec/serializers/api/photo_serializer_spec.rb b/spec/serializers/api/photo_serializer_spec.rb index 3dad077a..7d354d16 100644 --- a/spec/serializers/api/photo_serializer_spec.rb +++ b/spec/serializers/api/photo_serializer_spec.rb @@ -73,6 +73,7 @@ RSpec.describe Api::PhotoSerializer do state: 'Berlin', country: 'Germany', type: 'image', + orientation: 'portrait', source: 'immich' ) end @@ -152,6 +153,7 @@ RSpec.describe Api::PhotoSerializer do state: 'Unknown', country: 'zz', type: 'image', + orientation: 'landscape', source: 'photoprism' ) end diff --git a/spec/services/photos/search_spec.rb b/spec/services/photos/search_spec.rb index 0ce34613..ee451597 100644 --- a/spec/services/photos/search_spec.rb +++ b/spec/services/photos/search_spec.rb @@ -74,7 +74,8 @@ RSpec.describe Photos::Search do state: nil, country: nil, type: 'image', - source: 'immich' + source: 'immich', + orientation: 'landscape' } end let(:serialized_photoprism) do @@ -88,7 +89,8 @@ RSpec.describe Photos::Search do state: nil, country: nil, type: 'image', - source: 'photoprism' + source: 'photoprism', + orientation: 'landscape' } end diff --git a/spec/services/trips/photos_spec.rb b/spec/services/trips/photos_spec.rb new file mode 100644 index 00000000..abe9f52b --- /dev/null +++ b/spec/services/trips/photos_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Trips::Photos do + let(:user) { instance_double('User') } + let(:trip) { instance_double('Trip', started_at: Date.new(2024, 1, 1), ended_at: Date.new(2024, 1, 7)) } + let(:service) { described_class.new(trip, user) } + + describe '#call' do + context 'when user has no photo integrations configured' do + before do + allow(user).to receive(:immich_integration_configured?).and_return(false) + allow(user).to receive(:photoprism_integration_configured?).and_return(false) + end + + it 'returns an empty array' do + expect(service.call).to eq([]) + end + end + + context 'when user has photo integrations configured' do + let(:photo_search) { instance_double('Photos::Search') } + let(:raw_photos) do + [ + { + id: 1, + url: '/api/v1/photos/1/thumbnail.jpg?api_key=test-api-key&source=immich', + source: 'immich', + orientation: 'landscape' + }, + { + id: 2, + url: '/api/v1/photos/2/thumbnail.jpg?api_key=test-api-key&source=photoprism', + source: 'photoprism', + orientation: 'portrait' + } + ] + end + + before do + allow(user).to receive(:immich_integration_configured?).and_return(true) + allow(user).to receive(:photoprism_integration_configured?).and_return(false) + allow(user).to receive(:api_key).and_return('test-api-key') + + allow(Photos::Search).to receive(:new) + .with(user, start_date: '2024-01-01', end_date: '2024-01-07') + .and_return(photo_search) + allow(photo_search).to receive(:call).and_return(raw_photos) + end + + it 'returns formatted photo thumbnails' do + expected_result = [ + { + id: 1, + url: '/api/v1/photos/1/thumbnail.jpg?api_key=test-api-key&source=immich', + source: 'immich', + orientation: 'landscape' + }, + { + id: 2, + url: '/api/v1/photos/2/thumbnail.jpg?api_key=test-api-key&source=photoprism', + source: 'photoprism', + orientation: 'portrait' + } + ] + + expect(service.call).to eq(expected_result) + end + end + end +end diff --git a/spec/swagger/api/v1/photos_controller_spec.rb b/spec/swagger/api/v1/photos_controller_spec.rb index eef5d9a5..2c375ef1 100644 --- a/spec/swagger/api/v1/photos_controller_spec.rb +++ b/spec/swagger/api/v1/photos_controller_spec.rb @@ -111,6 +111,7 @@ RSpec.describe 'Api::V1::PhotosController', type: :request do state: { type: :string }, country: { type: :string }, type: { type: :string }, + orientation: { type: :string }, source: { type: :string } }, required: %w[id latitude longitude localDateTime originalFileName city state country type source] @@ -143,7 +144,8 @@ RSpec.describe 'Api::V1::PhotosController', type: :request do state: { type: :string }, country: { type: :string }, type: { type: :string }, - source: { type: :string } + source: { type: :string }, + orientation: { type: :string, enum: %w[portrait landscape] } } let(:id) { '7fe486e3-c3ba-4b54-bbf9-1281b39ed15c' } diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 6657aebf..49d8ef24 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -366,6 +366,8 @@ paths: type: string type: type: string + orientation: + type: string source: type: string required: @@ -431,6 +433,11 @@ paths: type: string source: type: string + orientation: + type: string + enum: + - portrait + - landscape '404': description: photo not found "/api/v1/points": From dbb737a0c45b2edb55c1af2accde44714f43df7f Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 10 Dec 2024 19:43:52 +0100 Subject: [PATCH 3/5] Update swagger docs and changelog --- CHANGELOG.md | 21 +++++++++++++++++++ app/controllers/map_controller.rb | 4 +--- app/models/trip.rb | 8 +++---- app/models/visit.rb | 4 +++- spec/models/trip_spec.rb | 4 +++- spec/swagger/api/v1/photos_controller_spec.rb | 12 +++++------ swagger/v1/swagger.yaml | 19 +++++++++++++++-- 7 files changed, 54 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19dcf086..9b5c7252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # 0.19.4 - 2024-12-10 +⚠️ This release introduces a breaking change. ⚠️ + +The `GET /api/v1/trips/:id/photos` endpoint now returns a different structure of the response: + +```diff +{ + id: 1, + latitude: 10, + longitude: 10, + localDateTime: "2024-01-01T00:00:00Z", + originalFileName: "photo.jpg", + city: "Berlin", + state: "Berlin", + country: "Germany", + type: "image", ++ orientation: "portrait", + source: "photoprism" +} +``` + ### Fixed - Fixed a bug where the Photoprism photos were not being shown on the trip page. @@ -16,6 +36,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - A link to the Photoprism photos on the trip page if there are any. - A `orientation` field in the Api::PhotoSerializer, hence the `GET /api/v1/photos` endpoint now includes the orientation of the photo. Valid values are `portrait` and `landscape`. +- Examples for the `type`, `orientation` and `source` fields in the `GET /api/v1/photos` endpoint in the Swagger UI. # 0.19.3 - 2024-12-06 diff --git a/app/controllers/map_controller.rb b/app/controllers/map_controller.rb index a0eb6e08..93657bd4 100644 --- a/app/controllers/map_controller.rb +++ b/app/controllers/map_controller.rb @@ -36,9 +36,7 @@ class MapController < ApplicationController @distance ||= 0 @coordinates.each_cons(2) do - @distance += Geocoder::Calculations.distance_between( - [_1[0], _1[1]], [_2[0], _2[1]], units: DISTANCE_UNIT - ) + @distance += DistanceCalculator.new([_1[0], _1[1]], [_2[0], _2[1]]).call end @distance.round(1) diff --git a/app/models/trip.rb b/app/models/trip.rb index e75103c2..4a2b0302 100644 --- a/app/models/trip.rb +++ b/app/models/trip.rb @@ -35,6 +35,8 @@ class Trip < ApplicationRecord vertical_photos = photos.select { |photo| photo[:orientation] == 'portrait' } horizontal_photos = photos.select { |photo| photo[:orientation] == 'landscape' } + # this is ridiculous, but I couldn't find my way around frontend + # to show all photos in the same height vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos end @@ -42,11 +44,7 @@ class Trip < ApplicationRecord distance = 0 points.each_cons(2) do |point1, point2| - distance_between = Geocoder::Calculations.distance_between( - point1.to_coordinates, point2.to_coordinates, units: ::DISTANCE_UNIT - ) - - distance += distance_between + distance += DistanceCalculator.new(point1, point2).call end self.distance = distance.round diff --git a/app/models/visit.rb b/app/models/visit.rb index 2ca496ab..bfd5b3d0 100644 --- a/app/models/visit.rb +++ b/app/models/visit.rb @@ -28,7 +28,9 @@ class Visit < ApplicationRecord def default_radius return area&.radius if area.present? - radius = points.map { Geocoder::Calculations.distance_between(center, [_1.latitude, _1.longitude]) }.max + radius = points.map do |point| + DistanceCalculator.new(center, [point.latitude, point.longitude]).call + end.max radius && radius >= 15 ? radius : 15 end diff --git a/spec/models/trip_spec.rb b/spec/models/trip_spec.rb index 0638d781..032185bd 100644 --- a/spec/models/trip_spec.rb +++ b/spec/models/trip_spec.rb @@ -116,7 +116,9 @@ RSpec.describe Trip, type: :model do end it 'returns the photos' do - expect(trip.photo_previews).to eq(expected_photos) + expect(trip.photo_previews).to include(expected_photos[0]) + expect(trip.photo_previews).to include(expected_photos[1]) + expect(trip.photo_previews.size).to eq(2) end end end diff --git a/spec/swagger/api/v1/photos_controller_spec.rb b/spec/swagger/api/v1/photos_controller_spec.rb index 2c375ef1..d7c4de4c 100644 --- a/spec/swagger/api/v1/photos_controller_spec.rb +++ b/spec/swagger/api/v1/photos_controller_spec.rb @@ -110,9 +110,9 @@ RSpec.describe 'Api::V1::PhotosController', type: :request do city: { type: :string }, state: { type: :string }, country: { type: :string }, - type: { type: :string }, - orientation: { type: :string }, - source: { type: :string } + type: { type: :string, enum: %w[image video] }, + orientation: { type: :string, enum: %w[portrait landscape] }, + source: { type: :string, enum: %w[immich photoprism] } }, required: %w[id latitude longitude localDateTime originalFileName city state country type source] } @@ -143,9 +143,9 @@ RSpec.describe 'Api::V1::PhotosController', type: :request do city: { type: :string }, state: { type: :string }, country: { type: :string }, - type: { type: :string }, - source: { type: :string }, - orientation: { type: :string, enum: %w[portrait landscape] } + type: { type: :string, enum: %w[image video] }, + orientation: { type: :string, enum: %w[portrait landscape] }, + source: { type: :string, enum: %w[immich photoprism] } } let(:id) { '7fe486e3-c3ba-4b54-bbf9-1281b39ed15c' } diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 49d8ef24..f6072149 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -366,10 +366,19 @@ paths: type: string type: type: string + enum: + - image + - video orientation: type: string + enum: + - portrait + - landscape source: type: string + enum: + - immich + - photoprism required: - id - latitude @@ -431,13 +440,19 @@ paths: type: string type: type: string - source: - type: string + enum: + - image + - video orientation: type: string enum: - portrait - landscape + source: + type: string + enum: + - immich + - photoprism '404': description: photo not found "/api/v1/points": From 14caeb61878130af094f7cfadb9f747e5ecf20e7 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 10 Dec 2024 19:45:00 +0100 Subject: [PATCH 4/5] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b5c7252..efa3cfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ The `GET /api/v1/trips/:id/photos` endpoint now returns a different structure of state: "Berlin", country: "Germany", type: "image", -+ orientation: "portrait", ++ orientation: "portrait", source: "photoprism" } ``` From 58062f652198045d48e45bdd0c98293ac99b502c Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 10 Dec 2024 19:55:59 +0100 Subject: [PATCH 5/5] Include raw, live and animated photos in the Swagger UI --- spec/swagger/api/v1/photos_controller_spec.rb | 2 +- swagger/v1/swagger.yaml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/swagger/api/v1/photos_controller_spec.rb b/spec/swagger/api/v1/photos_controller_spec.rb index d7c4de4c..16a9e85b 100644 --- a/spec/swagger/api/v1/photos_controller_spec.rb +++ b/spec/swagger/api/v1/photos_controller_spec.rb @@ -143,7 +143,7 @@ RSpec.describe 'Api::V1::PhotosController', type: :request do city: { type: :string }, state: { type: :string }, country: { type: :string }, - type: { type: :string, enum: %w[image video] }, + type: { type: :string, enum: %w[IMAGE VIDEO image video raw live animated] }, orientation: { type: :string, enum: %w[portrait landscape] }, source: { type: :string, enum: %w[immich photoprism] } } diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index f6072149..9e6a57dd 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -441,8 +441,13 @@ paths: type: type: string enum: + - IMAGE + - VIDEO - image - video + - raw + - live + - animated orientation: type: string enum: