From 1030bd5c37f9e9ef977cc8aa514ad26f182c9e84 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Wed, 4 Dec 2024 13:45:19 +0100 Subject: [PATCH] Rename Photos::Request to Photos::Search and add test for it --- app/controllers/api/v1/photos_controller.rb | 2 +- app/services/photos/{request.rb => search.rb} | 2 +- spec/requests/api/v1/photos_spec.rb | 2 +- spec/services/photos/search_spec.rb | 147 ++++++++++++++++++ 4 files changed, 150 insertions(+), 3 deletions(-) rename app/services/photos/{request.rb => search.rb} (97%) create mode 100644 spec/services/photos/search_spec.rb diff --git a/app/controllers/api/v1/photos_controller.rb b/app/controllers/api/v1/photos_controller.rb index b2930888..5eee82c0 100644 --- a/app/controllers/api/v1/photos_controller.rb +++ b/app/controllers/api/v1/photos_controller.rb @@ -6,7 +6,7 @@ class Api::V1::PhotosController < ApiController def index @photos = Rails.cache.fetch("photos_#{params[:start_date]}_#{params[:end_date]}", expires_in: 1.day) do - Photos::Request.new(current_api_user, start_date: params[:start_date], end_date: params[:end_date]).call + Photos::Search.new(current_api_user, start_date: params[:start_date], end_date: params[:end_date]).call end render json: @photos, status: :ok diff --git a/app/services/photos/request.rb b/app/services/photos/search.rb similarity index 97% rename from app/services/photos/request.rb rename to app/services/photos/search.rb index 3bb5d059..20046268 100644 --- a/app/services/photos/request.rb +++ b/app/services/photos/search.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Photos::Request +class Photos::Search attr_reader :user, :start_date, :end_date def initialize(user, start_date: '1970-01-01', end_date: nil) diff --git a/spec/requests/api/v1/photos_spec.rb b/spec/requests/api/v1/photos_spec.rb index c1e440bc..8c8811b6 100644 --- a/spec/requests/api/v1/photos_spec.rb +++ b/spec/requests/api/v1/photos_spec.rb @@ -38,7 +38,7 @@ RSpec.describe 'Api::V1::Photos', type: :request do context 'when the request is successful' do before do - allow_any_instance_of(Photos::Request).to receive(:call).and_return(photo_data) + allow_any_instance_of(Photos::Search).to receive(:call).and_return(photo_data) get '/api/v1/photos', params: { api_key: user.api_key } end diff --git a/spec/services/photos/search_spec.rb b/spec/services/photos/search_spec.rb new file mode 100644 index 00000000..0ce34613 --- /dev/null +++ b/spec/services/photos/search_spec.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Photos::Search do + let(:user) { create(:user) } + let(:start_date) { '2024-01-01' } + let(:end_date) { '2024-03-01' } + let(:service) { described_class.new(user, start_date: start_date, end_date: end_date) } + + describe '#call' do + context 'when user has no 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 Immich integration configured' do + let(:immich_photo) { { 'type' => 'image', 'id' => '1' } } + let(:serialized_photo) { { id: '1', source: 'immich' } } + + before do + allow(user).to receive(:immich_integration_configured?).and_return(true) + allow(user).to receive(:photoprism_integration_configured?).and_return(false) + + allow_any_instance_of(Immich::RequestPhotos).to receive(:call) + .and_return([immich_photo]) + + allow_any_instance_of(Api::PhotoSerializer).to receive(:call) + .and_return(serialized_photo) + end + + it 'fetches and transforms Immich photos' do + expect(service.call).to eq([serialized_photo]) + end + end + + context 'when user has Photoprism integration configured' do + let(:photoprism_photo) { { 'Type' => 'image', 'id' => '2' } } + let(:serialized_photo) { { id: '2', source: 'photoprism' } } + + before do + allow(user).to receive(:immich_integration_configured?).and_return(false) + allow(user).to receive(:photoprism_integration_configured?).and_return(true) + + allow_any_instance_of(Photoprism::RequestPhotos).to receive(:call) + .and_return([photoprism_photo]) + + allow_any_instance_of(Api::PhotoSerializer).to receive(:call) + .and_return(serialized_photo) + end + + it 'fetches and transforms Photoprism photos' do + expect(service.call).to eq([serialized_photo]) + end + end + + context 'when user has both integrations configured' do + let(:immich_photo) { { 'type' => 'image', 'id' => '1' } } + let(:photoprism_photo) { { 'Type' => 'image', 'id' => '2' } } + let(:serialized_immich) do + { + id: '1', + latitude: nil, + longitude: nil, + localDateTime: nil, + originalFileName: nil, + city: nil, + state: nil, + country: nil, + type: 'image', + source: 'immich' + } + end + let(:serialized_photoprism) do + { + id: '2', + latitude: nil, + longitude: nil, + localDateTime: nil, + originalFileName: nil, + city: nil, + state: nil, + country: nil, + type: 'image', + source: 'photoprism' + } + end + + before do + allow(user).to receive(:immich_integration_configured?).and_return(true) + allow(user).to receive(:photoprism_integration_configured?).and_return(true) + + allow_any_instance_of(Immich::RequestPhotos).to receive(:call) + .and_return([immich_photo]) + allow_any_instance_of(Photoprism::RequestPhotos).to receive(:call) + .and_return([photoprism_photo]) + end + + it 'fetches and transforms photos from both services' do + expect(service.call).to eq([serialized_immich, serialized_photoprism]) + end + end + + context 'when filtering out videos' do + let(:immich_photo) { { 'type' => 'video', 'id' => '1' } } + + before do + allow(user).to receive(:immich_integration_configured?).and_return(true) + allow(user).to receive(:photoprism_integration_configured?).and_return(false) + + allow_any_instance_of(Immich::RequestPhotos).to receive(:call) + .and_return([immich_photo]) + end + + it 'excludes video assets' do + expect(service.call).to eq([]) + end + end + end + + describe '#initialize' do + context 'with default parameters' do + let(:service_default) { described_class.new(user) } + + it 'sets default start_date' do + expect(service_default.start_date).to eq('1970-01-01') + end + + it 'sets default end_date to nil' do + expect(service_default.end_date).to be_nil + end + end + + context 'with custom parameters' do + it 'sets custom dates' do + expect(service.start_date).to eq(start_date) + expect(service.end_date).to eq(end_date) + end + end + end +end