From 0dac78903e3baeb95297a50405a1e6c72f829f9e Mon Sep 17 00:00:00 2001 From: Eric Schubert Date: Mon, 17 Jun 2024 14:41:30 +0200 Subject: [PATCH 1/2] [chore] Add regression tests for storage folders - locations with ampersands are now specifically tested in the query unit tests - file info query tests refactored to use shared examples for all storage providers - files query of one drive now return escaped location data, too --- .../storage_interaction/authentication.rb | 4 +- .../nextcloud/file_info_query.rb | 213 ++++++----- .../one_drive/file_info_query.rb | 22 +- .../one_drive/files_query.rb | 9 +- .../nextcloud/file_info_query_spec.rb | 126 +++++++ .../one_drive/file_info_query_spec.rb | 180 ++++----- .../one_drive/files_query_spec.rb | 2 +- .../nextcloud/file_info_query_not_found.yml | 82 ++++ .../file_info_query_success_deleted_file.yml | 82 ++++ .../file_info_query_success_file.yml | 81 ++++ .../file_info_query_success_folder.yml | 81 ++++ ..._info_query_success_special_characters.yml | 82 ++++ .../one_drive/file_info_query_forbidden.yml | 354 ------------------ ..._info_query_success_special_characters.yml | 48 +++ .../file_info_query_examples.rb | 88 +++++ 15 files changed, 873 insertions(+), 581 deletions(-) create mode 100644 modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/file_info_query_spec.rb create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_not_found.yml create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_deleted_file.yml create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_file.yml create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_folder.yml create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_special_characters.yml delete mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_forbidden.yml create mode 100644 modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_success_special_characters.yml create mode 100644 modules/storages/spec/support/shared_examples_for_adapters/file_info_query_examples.rb diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb index f4807cb61c22..99489f33798b 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb @@ -32,7 +32,7 @@ module Storages module Peripherals module StorageInteraction class Authentication - using ::Storages::Peripherals::ServiceResultRefinements + using ServiceResultRefinements def self.[](strategy) case strategy.key @@ -55,7 +55,7 @@ def self.[](strategy) def self.authorization_state(storage:, user:) auth_strategy = AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - ::Storages::Peripherals::Registry + Registry .resolve("#{storage.short_provider_type}.queries.auth_check") .call(storage:, auth_strategy:) .match( diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb index f5dcf9536405..ec7c8824d4d0 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb @@ -28,107 +28,122 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module Storages::Peripherals::StorageInteraction::Nextcloud - class FileInfoQuery - using Storages::Peripherals::ServiceResultRefinements - - FILE_INFO_PATH = "ocs/v1.php/apps/integration_openproject/fileinfo" - Auth = ::Storages::Peripherals::StorageInteraction::Authentication - - def self.call(storage:, auth_strategy:, file_id:) - new(storage).call(auth_strategy:, file_id:) - end - - def initialize(storage) - @storage = storage - end - - def call(auth_strategy:, file_id:) - http_options = Util.ocs_api_request.deep_merge(Util.accept_json) - Auth[auth_strategy].call(storage: @storage, http_options:) do |http| - file_info(http, file_id).map(&parse_json) >> handle_failure >> create_storage_file_info - end - end - - private - - def file_info(http, file_id) - response = http.get(Util.join_uri_path(@storage.uri, FILE_INFO_PATH, file_id)) - error_data = Storages::StorageErrorData.new(source: self.class, payload: response) - - case response - in { status: 200..299 } - ServiceResult.success(result: response.body) - in { status: 404 } - Util.error(:not_found, "Outbound request destination not found!", error_data) - in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized!", error_data) - else - Util.error(:error, "Outbound request failed!", error_data) - end - end - - def parse_json - ->(response_body) do - # rubocop:disable Style/OpenStructUse - JSON.parse(response_body, object_class: OpenStruct) - # rubocop:enable Style/OpenStructUse - end - end - - def handle_failure - ->(response_object) do - error_data = Storages::StorageErrorData.new(source: self.class, payload: response_object) - - case response_object.ocs.data.statuscode - when 200..299 - ServiceResult.success(result: response_object) - when 403 - Util.error(:forbidden, "Access to storage file forbidden!", error_data) - when 404 - Util.error(:not_found, "Storage file not found!", error_data) - else - Util.error(:error, "Outbound request failed!", error_data) +module Storages + module Peripherals + module StorageInteraction + module Nextcloud + class FileInfoQuery + using ServiceResultRefinements + + FILE_INFO_PATH = "ocs/v1.php/apps/integration_openproject/fileinfo" + + def self.call(storage:, auth_strategy:, file_id:) + new(storage).call(auth_strategy:, file_id:) + end + + def initialize(storage) + @storage = storage + end + + def call(auth_strategy:, file_id:) + validation = validate_input(file_id) + return validation if validation.failure? + + http_options = Util.ocs_api_request.deep_merge(Util.accept_json) + Authentication[auth_strategy].call(storage: @storage, http_options:) do |http| + file_info(http, file_id).map(&parse_json) >> handle_failure >> create_storage_file_info + end + end + + private + + def validate_input(file_id) + if file_id.nil? + ServiceResult.failure( + result: :error, + errors: StorageError.new(code: :error, + data: StorageErrorData.new(source: self.class), + log_message: "File ID can not be nil") + ) + else + ServiceResult.success + end + end + + def file_info(http, file_id) + response = http.get(Util.join_uri_path(@storage.uri, FILE_INFO_PATH, file_id)) + error_data = StorageErrorData.new(source: self.class, payload: response) + + case response + in { status: 200..299 } + ServiceResult.success(result: response.body) + in { status: 404 } + Util.error(:not_found, "Outbound request destination not found!", error_data) + in { status: 401 } + Util.error(:unauthorized, "Outbound request not authorized!", error_data) + else + Util.error(:error, "Outbound request failed!", error_data) + end + end + + def parse_json + ->(response_body) do + JSON.parse(response_body, object_class: OpenStruct) # rubocop:disable Style/OpenStructUse + end + end + + def handle_failure + ->(response_object) do + error_data = StorageErrorData.new(source: self.class, payload: response_object) + + case response_object.ocs.data.statuscode + when 200..299 + ServiceResult.success(result: response_object) + when 403 + Util.error(:forbidden, "Access to storage file forbidden!", error_data) + when 404 + Util.error(:not_found, "Storage file not found!", error_data) + else + Util.error(:error, "Outbound request failed!", error_data) + end + end + end + + def create_storage_file_info # rubocop:disable Metrics/AbcSize + ->(response_object) do + data = response_object.ocs.data + ServiceResult.success( + result: StorageFileInfo.new( + status: data.status.downcase, + status_code: data.statuscode, + id: data.id.to_s, + name: data.name, + last_modified_at: Time.zone.at(data.mtime), + created_at: Time.zone.at(data.ctime), + mime_type: data.mimetype, + size: data.size, + owner_name: data.owner_name, + owner_id: data.owner_id, + last_modified_by_name: data.modifier_name, + last_modified_by_id: data.modifier_id, + permissions: data.dav_permissions, + location: location(data.path) + ) + ) + end + end + + def location(file_path) + prefix = "files/" + idx = file_path.rindex(prefix) + return "/" if idx == nil + + idx += prefix.length - 1 + + Util.escape_path(file_path[idx..]).chomp("/") + end end end end - - # rubocop:disable Metrics/AbcSize - def create_storage_file_info - ->(response_object) do - data = response_object.ocs.data - ServiceResult.success( - result: ::Storages::StorageFileInfo.new( - status: data.status, - status_code: data.statuscode, - id: data.id.to_s, - name: data.name, - last_modified_at: Time.zone.at(data.mtime), - created_at: Time.zone.at(data.ctime), - mime_type: data.mimetype, - size: data.size, - owner_name: data.owner_name, - owner_id: data.owner_id, - trashed: data.trashed, - last_modified_by_name: data.modifier_name, - last_modified_by_id: data.modifier_id, - permissions: data.dav_permissions, - location: location(data.path) - ) - ) - end - end - - # rubocop:enable Metrics/AbcSize - - def location(file_path) - prefix = "files/" - idx = file_path.rindex(prefix) - return "/" if idx == nil - - idx += prefix.length - 1 - - Util.escape_path(file_path[idx..]) - end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb index a2a5d79361f1..3ecee389d033 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb @@ -46,13 +46,8 @@ def initialize(storage) end def call(auth_strategy:, file_id:) - if file_id.nil? - return ServiceResult.failure( - result: :error, - errors: StorageError.new(code: :error, - data: @error_data, log_message: "File ID can not be nil") - ) - end + validation = validate_input(file_id) + return validation if validation.failure? requested_result = Authentication[auth_strategy].call(storage: @storage) do |http| @drive_item_query.call(http:, drive_item_id: file_id, fields: FIELDS) @@ -80,6 +75,18 @@ def admin_query(file_id) end end + def validate_input(file_id) + if file_id.nil? + ServiceResult.failure( + result: :error, + errors: StorageError.new(code: :error, + data: @error_data, log_message: "File ID can not be nil") + ) + else + ServiceResult.success + end + end + def userless_strategy = Registry.resolve("one_drive.authentication.userless").call def storage_file_infos(json, status: "ok", status_code: 200) # rubocop:disable Metrics/AbcSize @@ -92,7 +99,6 @@ def storage_file_infos(json, status: "ok", status_code: 200) # rubocop:disable M size: json[:size], owner_name: json.dig(:createdBy, :user, :displayName), owner_id: json.dig(:createdBy, :user, :id), - trashed: false, permissions: nil, location: Util.escape_path(Util.extract_location(json[:parentReference], json[:name])), last_modified_at: Time.zone.parse(json.dig(:fileSystemInfo, :lastModifiedDateTime)), diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb index 91088a4cda25..0ac1d5b6d0a2 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb @@ -34,7 +34,6 @@ module StorageInteraction module OneDrive class FilesQuery FIELDS = "?$select=id,name,size,webUrl,lastModifiedBy,createdBy,fileSystemInfo,file,folder,parentReference" - Auth = ::Storages::Peripherals::StorageInteraction::Authentication using ServiceResultRefinements @@ -48,7 +47,7 @@ def initialize(storage) end def call(auth_strategy:, folder:) - Auth[auth_strategy].call(storage: @storage, http_options: { headers: { "OCS-APIRequest" => "true" } }) do |http| + Auth[auth_strategy].call(storage: @storage) do |http| call = http.get(Util.join_uri_path(@uri, children_uri_path_for(folder) + FIELDS)) response = handle_response(call, :value) @@ -73,8 +72,8 @@ def handle_response(response, map_value) ServiceResult.failure(result: :unauthorized, errors: Util.storage_error(response:, code: :unauthorized, source: self)) else - data = ::Storages::StorageErrorData.new(source: self.class, payload: response) - ServiceResult.failure(result: :error, errors: ::Storages::StorageError.new(code: :error, data:)) + data = StorageErrorData.new(source: self.class, payload: response) + ServiceResult.failure(result: :error, errors: StorageError.new(code: :error, data:)) end end @@ -95,7 +94,7 @@ def storage_file(json_file) last_modified_at: Time.zone.parse(json_file.dig(:fileSystemInfo, :lastModifiedDateTime)), created_by_name: json_file.dig(:createdBy, :user, :displayName), last_modified_by_name: json_file.dig(:lastModifiedBy, :user, :displayName), - location: Util.extract_location(json_file[:parentReference], json_file[:name]), + location: Util.escape_path(Util.extract_location(json_file[:parentReference], json_file[:name])), permissions: %i[readable writeable] ) end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/file_info_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/file_info_query_spec.rb new file mode 100644 index 000000000000..2cdf940a3604 --- /dev/null +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/file_info_query_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require "spec_helper" +require_module_spec_helper + +RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::FileInfoQuery, :vcr, :webmock do + let(:user) { create(:user) } + let(:storage) do + create(:nextcloud_storage_with_local_connection, :as_not_automatically_managed, oauth_client_token_user: user) + end + let(:auth_strategy) do + Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) + end + + it_behaves_like "file_info_query: basic query setup" + + it_behaves_like "file_info_query: validating input data" + + context "with a file id requested", vcr: "nextcloud/file_info_query_success_file" do + let(:file_id) { "267" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "android-studio-linux.tar.gz", + size: 982713473, + mime_type: "application/gzip", + created_at: Time.parse("1970-01-01T00:00:00Z"), + last_modified_at: Time.parse("2022-12-01T07:43:36Z"), + owner_name: "admin", + owner_id: "admin", + last_modified_by_name: nil, + last_modified_by_id: nil, + permissions: "RGDNVW", + location: "/Folder/android-studio-linux.tar.gz" + ) + end + + it_behaves_like "file_info_query: successful file/folder response" + end + + context "with a folder id requested", vcr: "nextcloud/file_info_query_success_folder" do + let(:file_id) { "350" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "Ümlæûts", + size: 19720, + mime_type: "application/x-op-directory", + created_at: Time.parse("1970-01-01T00:00:00Z"), + last_modified_at: Time.parse("2024-04-29T09:21:03Z"), + owner_name: "admin", + owner_id: "admin", + last_modified_by_name: nil, + last_modified_by_id: nil, + permissions: "RGDNVCK", + location: "/Folder/%C3%9Cml%C3%A6%C3%BBts" + ) + end + + it_behaves_like "file_info_query: successful file/folder response" + end + + context "with a file with special characters in the path", + vcr: "nextcloud/file_info_query_success_special_characters" do + let(:file_id) { "361" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "what_have_you_done.md", + size: 0, + mime_type: "text/markdown", + created_at: Time.parse("1970-01-01T00:00:00Z"), + last_modified_at: Time.parse("2024-06-17T09:51:59Z"), + owner_name: "admin", + owner_id: "admin", + last_modified_by_name: nil, + last_modified_by_id: nil, + permissions: "RGDNVW", + location: "/Folder%20with%20spaces/%C3%9Cml%C3%A4uts%20%26%20spe%C2%A2i%C3%A6l%20characters/what_have_you_done.md" + ) + end + + it_behaves_like "file_info_query: successful file/folder response" + end + + context "with a not existing file id", vcr: "nextcloud/file_info_query_not_found" do + let(:file_id) { "not_existent" } + let(:error_source) { described_class } + + it_behaves_like "file_info_query: not found" + end +end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/file_info_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/file_info_query_spec.rb index 4cdef0d66d14..c7378c22dcdc 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/file_info_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/file_info_query_spec.rb @@ -39,131 +39,87 @@ Storages::Peripherals::Registry["one_drive.authentication.userbound"].call(user:) end - subject(:file_info_query) { described_class.new(storage) } - - describe "#call" do - it "responds with correct parameters" do - expect(described_class).to respond_to(:call) - - method = described_class.method(:call) - expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq auth_strategy], %i[keyreq file_id]) + it_behaves_like "file_info_query: basic query setup" + + it_behaves_like "file_info_query: validating input data" + + context "with a file id requested", vcr: "one_drive/file_info_query_success_file" do + let(:file_id) { "01AZJL5PNCQCEBFI3N7JGZSX5AOX32Z3LA" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "NextcloudHub.md", + size: 1095, + mime_type: "application/octet-stream", + created_at: Time.parse("2023-09-26T14:45:25Z"), + last_modified_at: Time.parse("2023-09-26T14:46:13Z"), + owner_name: "Eric Schubert", + owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + last_modified_by_name: "Eric Schubert", + last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + permissions: nil, + location: "/Folder/Subfolder/NextcloudHub.md" + ) end - context "without outbound request involved" do - context "with nil" do - it "returns an error" do - result = file_info_query.call(auth_strategy:, file_id: nil) - - expect(result).to be_failure - expect(result.errors.data.source).to eq(described_class) - expect(result.result).to eq(:error) - end - end - end + it_behaves_like "file_info_query: successful file/folder response" end - context "with outbound requests successful" do - context "with a file id requested", vcr: "one_drive/file_info_query_success_file" do - let(:file_id) { "01AZJL5PNCQCEBFI3N7JGZSX5AOX32Z3LA" } - - it "must return the file information when called" do - result = file_info_query.call(auth_strategy:, file_id:) - expect(result).to be_success - - file_info = result.result - - expect(file_info).to be_a(Storages::StorageFileInfo) - expect(file_info.to_h) - .to eq({ - status: "ok", - status_code: 200, - id: "01AZJL5PNCQCEBFI3N7JGZSX5AOX32Z3LA", - name: "NextcloudHub.md", - size: 1095, - mime_type: "application/octet-stream", - created_at: Time.parse("2023-09-26T14:45:25Z"), - last_modified_at: Time.parse("2023-09-26T14:46:13Z"), - owner_name: "Eric Schubert", - owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - last_modified_by_name: "Eric Schubert", - last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - permissions: nil, - trashed: false, - location: "/Folder/Subfolder/NextcloudHub.md" - }) - end + context "with a folder id requested", vcr: "one_drive/file_info_query_success_folder" do + let(:file_id) { "01AZJL5PNQYF5NM3KWYNA3RJHJIB2XMMMB" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "Ümlæûts", + size: 20789, + mime_type: "application/x-op-directory", + created_at: Time.parse("2023-10-09T15:26:32Z"), + last_modified_at: Time.parse("2023-10-09T15:26:32Z"), + owner_name: "Eric Schubert", + owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + last_modified_by_name: "Eric Schubert", + last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + permissions: nil, + location: "/Folder/%C3%9Cml%C3%A6%C3%BBts" + ) end - context "with a folder id requested", vcr: "one_drive/file_info_query_success_folder" do - let(:file_id) { "01AZJL5PNQYF5NM3KWYNA3RJHJIB2XMMMB" } - - it "must return the file information when called" do - result = file_info_query.call(auth_strategy:, file_id:) - expect(result).to be_success - - file_info = result.result - - expect(file_info).to be_a(Storages::StorageFileInfo) - expect(file_info.to_h) - .to eq({ - status: "ok", - status_code: 200, - id: "01AZJL5PNQYF5NM3KWYNA3RJHJIB2XMMMB", - name: "Ümlæûts", - size: 20789, - mime_type: "application/x-op-directory", - created_at: Time.parse("2023-10-09T15:26:32Z"), - last_modified_at: Time.parse("2023-10-09T15:26:32Z"), - owner_name: "Eric Schubert", - owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - last_modified_by_name: "Eric Schubert", - last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - permissions: nil, - trashed: false, - location: "/Folder/%C3%9Cml%C3%A6%C3%BBts" - }) - end - end + it_behaves_like "file_info_query: successful file/folder response" end - context "when the user does not have access to the file", vcr: "one_drive/file_info_query_forbidden" do - let(:drive_id) { "b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy" } - let(:permission_storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user, drive_id:) } - - let(:admin_auth) { Storages::Peripherals::Registry["one_drive.authentication.userless"].call } - - let(:folder) do - Storages::Peripherals::Registry["one_drive.commands.create_folder"] - .call(storage: permission_storage, auth_strategy: admin_auth, - folder_name: "Forbidden Folder", - parent_location: Storages::Peripherals::ParentFolder.new("/")) - .result - end - - after do - Storages::Peripherals::Registry["one_drive.commands.delete_folder"] - .call(storage: permission_storage, location: folder.id, auth_strategy: admin_auth) + context "with a file with special characters in the path", + vcr: "one_drive/file_info_query_success_special_characters" do + let(:file_id) { "01AZJL5PITB4FWUTEDCZGLV3WXG5TJX5A2" } + let(:file_info) do + Storages::StorageFileInfo.new( + id: file_id, + status: "ok", + status_code: 200, + name: "what_have_you_done.png", + size: 226985, + mime_type: "image/png", + created_at: Time.parse("2024-06-17T09:37:58Z"), + last_modified_at: Time.parse("2024-06-17T09:38:15Z"), + owner_name: "Eric Schubert", + owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + last_modified_by_name: "Eric Schubert", + last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + permissions: nil, + location: "/Folder%20with%20spaces/%C3%9Cml%C3%A4uts%20%26%20spe%C2%A2i%C3%A6l%20characters/what_have_you_done.png" + ) end - it "returns the file information but with a forbidden status" do - result = described_class.call(storage: permission_storage, auth_strategy:, file_id: folder.id) - expect(result).to be_success - - file_info = result.result - expect(file_info.status_code).to eq(403) - expect(file_info.status).to eq("forbidden") - end + it_behaves_like "file_info_query: successful file/folder response" end - context "with outbound request returning not found", vcr: "one_drive/file_info_query_not_found" do + context "with a not existing file id", vcr: "one_drive/file_info_query_not_found" do let(:file_id) { "not_existent" } + let(:error_source) { Storages::Peripherals::StorageInteraction::OneDrive::Internal::DriveItemQuery } - it "must return not found" do - result = file_info_query.call(auth_strategy:, file_id:) - - expect(result).to be_failure - expect(result.errors.data.source).to be(Storages::Peripherals::StorageInteraction::OneDrive::Internal::DriveItemQuery) - expect(result.errors.code).to eq(:not_found) - end + it_behaves_like "file_info_query: not found" end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb index 53225148061d..6426bfa6bdef 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb @@ -166,7 +166,7 @@ created_by_name: "Eric Schubert", last_modified_at: "2023-10-09T15:27:25Z", last_modified_by_name: "Eric Schubert", - location: "/Folder/Ümlæûts/Anrüchiges deutsches Dokument.docx", + location: "/Folder/%C3%9Cml%C3%A6%C3%BBts/Anr%C3%BCchiges%20deutsches%20Dokument.docx", mime_type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", permissions: %i[readable writeable] } diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_not_found.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_not_found.yml new file mode 100644 index 000000000000..1f499b0f282e --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_not_found.yml @@ -0,0 +1,82 @@ +--- +http_interactions: +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/not_existent + body: + encoding: US-ASCII + string: '' + headers: + Ocs-Apirequest: + - 'true' + Accept: + - application/json + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Mon, 17 Jun 2024 09:56:31 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.59 (Debian) + Set-Cookie: + - oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=Y%2BxEVVZ9frPgDnMkZ0H2u32FXb76Uqybduqx3eeFOprGoAq6k4k8cScf6p1N6zYDKJnNV3gm%2FBU50%2FDxvBRuCKdqXM3llctBdAv%2FYx2bYhkzvKxbEq3lNQj4vP1okIbE; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=bdfb2ececfa60f483e4ac64a91d3fcfb; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.18 + X-Request-Id: + - lPkHreBxup0WK7CpjL0L + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '115' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"failure","statuscode":404,"message":"","totalitems":"","itemsperpage":""},"data":{"status":"Not + Found","statuscode":404}}}' + recorded_at: Mon, 17 Jun 2024 09:56:31 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_deleted_file.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_deleted_file.yml new file mode 100644 index 000000000000..657514f50370 --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_deleted_file.yml @@ -0,0 +1,82 @@ +--- +http_interactions: +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/47 + body: + encoding: US-ASCII + string: '' + headers: + Ocs-Apirequest: + - 'true' + Accept: + - application/json + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Mon, 17 Jun 2024 11:39:18 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.59 (Debian) + Set-Cookie: + - oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=rCjW7PVMs0Wm7Cw%2FcEI51lR1%2FV%2Bx%2BWCIx8VrzECdrUbW53QVoxVHHN4nK4fbwOe9vyJEehUu8U5sdNoLYL%2FbIcRTh9H29kT8XzeNQ8yDIV9S7AtMuL%2B3kTDCUTSlhQwS; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=e1159d217b1a2c60643d94b7d7a82944; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.18 + X-Request-Id: + - im6fmMY2IdNhzoANEckx + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '115' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"failure","statuscode":404,"message":"","totalitems":"","itemsperpage":""},"data":{"status":"Not + Found","statuscode":404}}}' + recorded_at: Mon, 17 Jun 2024 11:39:18 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_file.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_file.yml new file mode 100644 index 000000000000..7076bc1ff7fb --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_file.yml @@ -0,0 +1,81 @@ +--- +http_interactions: +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/267 + body: + encoding: US-ASCII + string: '' + headers: + Ocs-Apirequest: + - 'true' + Accept: + - application/json + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Mon, 17 Jun 2024 11:43:43 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.59 (Debian) + Set-Cookie: + - oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=HAGBPvgfdiYH1Tuxr%2FwCUL%2FZYhApHShPQ9tXd%2BOxKH%2BGAnvoku6Weti2giLaF%2BQ24C74t4TIi8CiLlrwmmOf0HhcaSvJ65vElxqvKkRWqrp2reEQJllRikJqRFzrEW%2B7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=2ec4331fc84e5fcb4de0bcf90e349f59; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.18 + X-Request-Id: + - NQcyhgHDnlIJ3vMyrEeE + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '266' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":267,"name":"android-studio-linux.tar.gz","mtime":1669880616,"ctime":0,"mimetype":"application\/gzip","size":982713473,"owner_name":"admin","owner_id":"admin","modifier_name":null,"modifier_id":null,"dav_permissions":"RGDNVW","path":"files\/Folder\/android-studio-linux.tar.gz"}}}' + recorded_at: Mon, 17 Jun 2024 11:43:43 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_folder.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_folder.yml new file mode 100644 index 000000000000..90d65aa1039c --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_folder.yml @@ -0,0 +1,81 @@ +--- +http_interactions: +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/350 + body: + encoding: US-ASCII + string: '' + headers: + Ocs-Apirequest: + - 'true' + Accept: + - application/json + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Mon, 17 Jun 2024 09:56:32 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.59 (Debian) + Set-Cookie: + - oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=BA2WnR3%2BpJYRjSV2jFTPOTyHU26u%2BFxFDIXd7%2FenVCUnvTRxMy6vn9qG6IUYVrvmyIf8f6fG4Y%2FrMZb9GWTPJTBwEsdaYtHihlTeZBToSTd1W74ZTMwguH8617%2BAj8uo; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=18e1bc2c9335a15e93d03717ecd19b6d; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.18 + X-Request-Id: + - cPTd435aoVSeWLBURCUj + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '265' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":350,"name":"\u00dcml\u00e6\u00fbts","mtime":1714382463,"ctime":0,"mimetype":"application\/x-op-directory","size":19720,"owner_name":"admin","owner_id":"admin","modifier_name":null,"modifier_id":null,"dav_permissions":"RGDNVCK","path":"files\/Folder\/\u00dcml\u00e6\u00fbts\/"}}}' + recorded_at: Mon, 17 Jun 2024 09:56:32 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_special_characters.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_special_characters.yml new file mode 100644 index 000000000000..bfd8c6d365d6 --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/file_info_query_success_special_characters.yml @@ -0,0 +1,82 @@ +--- +http_interactions: +- request: + method: get + uri: https://nextcloud.local/ocs/v1.php/apps/integration_openproject/fileinfo/361 + body: + encoding: US-ASCII + string: '' + headers: + Ocs-Apirequest: + - 'true' + Accept: + - application/json + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache, no-store, must-revalidate + Content-Encoding: + - gzip + Content-Security-Policy: + - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' + Content-Type: + - application/json; charset=utf-8 + Date: + - Mon, 17 Jun 2024 09:56:32 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Feature-Policy: + - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone + 'none';payment 'none' + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.59 (Debian) + Set-Cookie: + - oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; path=/; secure; HttpOnly; SameSite=Lax, + oc_sessionPassphrase=YGTcReH6AsifPfrLZvwjm6r8CjNwCzDVEC0VDb1SiUMxGFJaPpdetZw3ot0bKnuMF1kYsCu%2FhPAXoYyQneOVO6t6vVZ9txhv5G2d%2FQ7H2edYILZtlt3cB%2B2pneBXkISP; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; + path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, + __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax, oc07ul6b4oaw=617d1b32915ffc3d72d2d76f501756c7; + path=/; secure; HttpOnly; SameSite=Lax + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.18 + X-Request-Id: + - k9daCouL8XDIahLt2oHU + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '289' + body: + encoding: UTF-8 + string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"status":"OK","statuscode":200,"id":361,"name":"what_have_you_done.md","mtime":1718617919,"ctime":0,"mimetype":"text\/markdown","size":0,"owner_name":"admin","owner_id":"admin","modifier_name":null,"modifier_id":null,"dav_permissions":"RGDNVW","path":"files\/Folder + with spaces\/\u00dcml\u00e4uts & spe\u00a2i\u00e6l characters\/what_have_you_done.md"}}}' + recorded_at: Mon, 17 Jun 2024 09:56:32 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_forbidden.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_forbidden.yml deleted file mode 100644 index 661aa02f4e7c..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_forbidden.yml +++ /dev/null @@ -1,354 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: UTF-8 - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default - headers: - User-Agent: - - Rack::OAuth2 (2.2.1) - Authorization: - - Basic - Content-Type: - - application/x-www-form-urlencoded - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 9ccbdf3f-d9a7-45ab-b4da-b1659f74b800 - X-Ms-Ests-Server: - - 2.1.17846.6 - SEC ProdSlices - X-Ms-Srs: - - 1.P - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=Aqgdg4QXwYFCsvfdSklAGxOkbDoXAQAAAKsdvN0OAAAA; expires=Sat, 25-May-2024 - 09:47:24 GMT; path=/; secure; HttpOnly; SameSite=None - - stsservicecookie=estsfd; path=/; secure; samesite=none; httponly - - x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly - Date: - - Thu, 25 Apr 2024 09:47:23 GMT - Content-Length: - - '1708' - body: - encoding: UTF-8 - string: '{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":""}' - recorded_at: Thu, 25 Apr 2024 09:47:24 GMT -- request: - method: post - uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/root/children - body: - encoding: UTF-8 - string: '{"name":"Forbidden Folder","folder":{},"@microsoft.graph.conflictBehavior":"fail"}' - headers: - Authorization: - - Bearer - Accept: - - application/json - Content-Type: - - application/json - User-Agent: - - httpx.rb/1.2.4 - Accept-Encoding: - - gzip, deflate - Content-Length: - - '82' - response: - status: - code: 201 - message: Created - headers: - Cache-Control: - - no-store, no-cache - Content-Type: - - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 - Content-Encoding: - - gzip - Etag: - - '"{D13E6CD8-1B18-4C8B-B7F8-A3AC796798F1},1"' - Location: - - https://finn.sharepoint.com/_api/v2.0/drives('b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy')/items('root')/children('01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR') - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - 5d0d1aa8-576c-41e8-ae4b-5330c6f36e12 - Client-Request-Id: - - 5d0d1aa8-576c-41e8-ae4b-5330c6f36e12 - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"000","RoleInstance":"FR1PEPF0000107D"}}' - Odata-Version: - - '4.0' - Date: - - Thu, 25 Apr 2024 09:47:24 GMT - body: - encoding: UTF-8 - string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#drives(''b%21dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy'')/root/children/$entity","@odata.etag":"\"{D13E6CD8-1B18-4C8B-B7F8-A3AC796798F1},1\"","createdDateTime":"2024-04-25T09:47:24Z","eTag":"\"{D13E6CD8-1B18-4C8B-B7F8-A3AC796798F1},1\"","id":"01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR","lastModifiedDateTime":"2024-04-25T09:47:24Z","name":"Forbidden - Folder","size":0,"webUrl":"https://finn.sharepoint.com/sites/openprojectfilestoragetests/Manual%20Sharing%20Test/Forbidden%20Folder","cTag":"\"c:{D13E6CD8-1B18-4C8B-B7F8-A3AC796798F1},0\"","commentSettings":{"commentingDisabled":{"isDisabled":false}},"createdBy":{"application":{"displayName":"OpenProject - Dev App","id":"4262df2b-77bb-49c2-a5df-28355da676d2"},"user":{"displayName":"SharePoint - App"}},"lastModifiedBy":{"application":{"displayName":"OpenProject Dev App","id":"4262df2b-77bb-49c2-a5df-28355da676d2"},"user":{"displayName":"SharePoint - App"}},"parentReference":{"driveId":"b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy","driveType":"documentLibrary","id":"01AZJL5PN6Y2GOVW7725BZO354PWSELRRZ","path":"/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/root:","sharepointIds":{"listId":"f7f90ed1-a285-40e2-8841-e5460d76a332","listItemUniqueId":"a7a7b4ec-acc5-4a83-a405-2cd7418e7467","siteId":"1b4b6576-906d-4d94-8f49-6d00a9507b50","siteUrl":"https://finn.sharepoint.com/sites/openprojectfilestoragetests","tenantId":"4d44bf36-9b56-45c0-8807-bbf386dd047f","webId":"7ef259e8-8eed-4645-920a-8b367bb0d8e0"}},"fileSystemInfo":{"createdDateTime":"2024-04-25T09:47:24Z","lastModifiedDateTime":"2024-04-25T09:47:24Z"},"folder":{"childCount":0},"shared":{"scope":"unknown"}}' - recorded_at: Thu, 25 Apr 2024 09:47:24 GMT -- request: - method: get - uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/items/01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR?$select=id,name,fileSystemInfo,file,folder,size,createdBy,lastModifiedBy,parentReference - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.4 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 404 - message: Not Found - headers: - Cache-Control: - - no-store, no-cache - Content-Type: - - application/json; odata.metadata=minimal; odata.streaming=true; IEEE754Compatible=false; - charset=utf-8 - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - d159669c-0cc9-4891-ba35-8cb549c6338d - Client-Request-Id: - - d159669c-0cc9-4891-ba35-8cb549c6338d - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"000","RoleInstance":"FR1PEPF000007A4"}}' - Date: - - Thu, 25 Apr 2024 09:47:24 GMT - body: - encoding: UTF-8 - string: '{"error":{"code":"itemNotFound","message":"The resource could not be - found."}}' - recorded_at: Thu, 25 Apr 2024 09:47:25 GMT -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB - headers: - User-Agent: - - httpx.rb/1.2.4 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '201' - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 1928c9e5-2a3f-40ca-a045-df7153a9b500 - X-Ms-Ests-Server: - - 2.1.17846.6 - FRC ProdSlices - X-Ms-Srs: - - 1.P - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=AkmNlzqUsAhBicjKNc8eYxKkbDoXAQAAAKwdvN0OAAAA; expires=Sat, 25-May-2024 - 09:47:25 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Thu, 25 Apr 2024 09:47:24 GMT - Content-Length: - - '1735' - body: - encoding: UTF-8 - string: '{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":""}' - recorded_at: Thu, 25 Apr 2024 09:47:25 GMT -- request: - method: get - uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/items/01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR?$select=id,name,fileSystemInfo,file,folder,size,createdBy,lastModifiedBy,parentReference - body: - encoding: US-ASCII - string: '' - headers: - User-Agent: - - httpx.rb/1.2.4 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Authorization: - - Bearer - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache - Content-Type: - - application/json; odata.metadata=minimal; odata.streaming=true; IEEE754Compatible=false; - charset=utf-8 - Content-Encoding: - - gzip - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - 456700b3-96ec-43c7-80b9-5df523b5b5f0 - Client-Request-Id: - - 456700b3-96ec-43c7-80b9-5df523b5b5f0 - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"000","RoleInstance":"FR1PEPF000007AC"}}' - Date: - - Thu, 25 Apr 2024 09:47:25 GMT - body: - encoding: UTF-8 - string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)/$entity","@odata.etag":"\"{D13E6CD8-1B18-4C8B-B7F8-A3AC796798F1},2\"","createdBy":{"application":{"id":"4262df2b-77bb-49c2-a5df-28355da676d2","displayName":"OpenProject - Dev App"},"user":{"displayName":"SharePoint App"}},"id":"01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR","lastModifiedBy":{"application":{"id":"4262df2b-77bb-49c2-a5df-28355da676d2","displayName":"OpenProject - Dev App"},"user":{"displayName":"SharePoint App"}},"name":"Forbidden Folder","parentReference":{"driveType":"documentLibrary","driveId":"b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy","id":"01AZJL5PN6Y2GOVW7725BZO354PWSELRRZ","name":"Manual - Sharing Test","path":"/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/root:","siteId":"1b4b6576-906d-4d94-8f49-6d00a9507b50"},"fileSystemInfo":{"createdDateTime":"2024-04-25T09:47:24Z","lastModifiedDateTime":"2024-04-25T09:47:24Z"},"folder":{"childCount":0},"size":0}' - recorded_at: Thu, 25 Apr 2024 09:47:25 GMT -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB - headers: - User-Agent: - - httpx.rb/1.2.4 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '201' - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 9c178365-2d3d-4c25-b160-4584064cc000 - X-Ms-Ests-Server: - - 2.1.17846.6 - FRC ProdSlices - X-Ms-Srs: - - 1.P - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=AuohO-25QkJDph7AQcb6W2ukbDoXAQAAAK4dvN0OAAAA; expires=Sat, 25-May-2024 - 09:47:26 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Thu, 25 Apr 2024 09:47:25 GMT - Content-Length: - - '1735' - body: - encoding: UTF-8 - string: '{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":""}' - recorded_at: Thu, 25 Apr 2024 09:47:26 GMT -- request: - method: delete - uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy/items/01AZJL5POYNQ7NCGA3RNGLP6FDVR4WPGHR - body: - encoding: US-ASCII - string: '' - headers: - User-Agent: - - httpx.rb/1.2.4 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Authorization: - - Bearer - response: - status: - code: 204 - message: No Content - headers: - Cache-Control: - - no-store, no-cache - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - 81112f90-1d8b-4d06-89e7-e168463427d8 - Client-Request-Id: - - 81112f90-1d8b-4d06-89e7-e168463427d8 - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"000","RoleInstance":"FR1PEPF000010A0"}}' - Date: - - Thu, 25 Apr 2024 09:47:26 GMT - body: - encoding: UTF-8 - string: '' - recorded_at: Thu, 25 Apr 2024 09:47:26 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_success_special_characters.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_success_special_characters.yml new file mode 100644 index 000000000000..368ebcc78f98 --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/file_info_query_success_special_characters.yml @@ -0,0 +1,48 @@ +--- +http_interactions: +- request: + method: get + uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2OBb-brzKzZAR4DYT1k9KPXs/items/01AZJL5PITB4FWUTEDCZGLV3WXG5TJX5A2?$select=id,name,fileSystemInfo,file,folder,size,createdBy,lastModifiedBy,parentReference + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.5 + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-cache + Content-Type: + - application/json; odata.metadata=minimal; odata.streaming=true; IEEE754Compatible=false; + charset=utf-8 + Content-Encoding: + - gzip + Strict-Transport-Security: + - max-age=31536000 + Request-Id: + - 2a76cb44-5e00-4ce7-aa0e-96ff2dc2c8d9 + Client-Request-Id: + - 2a76cb44-5e00-4ce7-aa0e-96ff2dc2c8d9 + X-Ms-Ags-Diagnostic: + - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"003","RoleInstance":"FR1PEPF000011B8"}}' + Date: + - Mon, 17 Jun 2024 09:45:03 GMT + body: + encoding: UTF-8 + string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)/$entity","@odata.etag":"\"{6A0B0F13-834C-4C16-BAEE-D737669BF41A},4\"","createdBy":{"user":{"email":"eschubert.op@outlook.com","id":"0a0d38a9-a59b-4245-93fa-0d2cf727f17a","displayName":"Eric + Schubert"}},"id":"01AZJL5PITB4FWUTEDCZGLV3WXG5TJX5A2","lastModifiedBy":{"user":{"email":"eschubert.op@outlook.com","id":"0a0d38a9-a59b-4245-93fa-0d2cf727f17a","displayName":"Eric + Schubert"}},"name":"what_have_you_done.png","parentReference":{"driveType":"documentLibrary","driveId":"b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2OBb-brzKzZAR4DYT1k9KPXs","id":"01AZJL5PPGZDS2244MABEYYEXBHXZFLHUU","name":"\u00dcml\u00e4uts + & spe\u00a2i\u00e6l characters","path":"/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2OBb-brzKzZAR4DYT1k9KPXs/root:/Folder + with spaces/\u00dcml\u00e4uts & spe\u00a2i\u00e6l characters","siteId":"1b4b6576-906d-4d94-8f49-6d00a9507b50"},"file":{"hashes":{"quickXorHash":"FjSlCPUJPYY3qEKhJqMtaYohLpc="},"mimeType":"image/png"},"fileSystemInfo":{"createdDateTime":"2024-06-17T09:37:58Z","lastModifiedDateTime":"2024-06-17T09:38:15Z"},"size":226985}' + recorded_at: Mon, 17 Jun 2024 09:45:03 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/shared_examples_for_adapters/file_info_query_examples.rb b/modules/storages/spec/support/shared_examples_for_adapters/file_info_query_examples.rb new file mode 100644 index 000000000000..6a6b54e8eb67 --- /dev/null +++ b/modules/storages/spec/support/shared_examples_for_adapters/file_info_query_examples.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +RSpec.shared_examples_for "file_info_query: basic query setup" do + it "is registered as queries.file_info" do + expect(Storages::Peripherals::Registry + .resolve("#{storage.short_provider_type}.queries.file_info")).to eq(described_class) + end + + it "responds to #call with correct parameters" do + expect(described_class).to respond_to(:call) + + method = described_class.method(:call) + expect(method.parameters).to contain_exactly(%i[keyreq storage], + %i[keyreq auth_strategy], + %i[keyreq file_id]) + end +end + +RSpec.shared_examples_for "file_info_query: successful file/folder response" do + it "returns a file info object" do + result = described_class.call(storage:, auth_strategy:, file_id:) + + expect(result).to be_success + + response = result.result + expect(response).to be_a(Storages::StorageFileInfo) + expect(response).to eq(file_info) + end +end + +RSpec.shared_examples_for "file_info_query: not found" do + it "returns a failure" do + result = described_class.call(storage:, auth_strategy:, file_id:) + + expect(result).to be_failure + + error = result.errors + expect(error.code).to eq(:not_found) + expect(error.data.source).to eq(error_source) + end +end + +RSpec.shared_examples_for "file_info_query: error" do + it "returns a failure" do + result = described_class.call(storage:, auth_strategy:, file_id:) + + expect(result).to be_failure + + error = result.errors + expect(error.code).to eq(:error) + expect(error.data.source).to eq(error_source) + end +end + +RSpec.shared_examples_for "file_info_query: validating input data" do + let(:file_id) { nil } + let(:error_source) { described_class } + + it_behaves_like "file_info_query: error" +end From 6aa096a10646314e1327042e087aec96d834dcfe Mon Sep 17 00:00:00 2001 From: Eric Schubert Date: Mon, 17 Jun 2024 16:12:01 +0200 Subject: [PATCH 2/2] [chore] fixed remains of trashed property --- .../storage_interaction/nextcloud/files_info_query.rb | 1 - .../storage_interaction/one_drive/file_info_query.rb | 6 +++--- .../storage_interaction/one_drive/files_info_query.rb | 2 +- .../storage_interaction/one_drive/files_query.rb | 2 +- modules/storages/app/models/storages/storage_file_info.rb | 2 -- .../storage_interaction/one_drive/files_info_query_spec.rb | 3 --- .../storages/spec/factories/storage_file_info_factory.rb | 3 +-- .../spec/requests/api/v3/storages/storage_files_api_spec.rb | 1 - 8 files changed, 6 insertions(+), 14 deletions(-) diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb index 51866801a84e..afbd8acb9330 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb @@ -112,7 +112,6 @@ def create_storage_file_infos size: value.size, owner_name: value.owner_name, owner_id: value.owner_id, - trashed: value.trashed, last_modified_by_name: value.modifier_name, last_modified_by_id: value.modifier_id, permissions: value.dav_permissions, diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb index 3ecee389d033..81d8d60e1044 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/file_info_query.rb @@ -53,7 +53,7 @@ def call(auth_strategy:, file_id:) @drive_item_query.call(http:, drive_item_id: file_id, fields: FIELDS) end - requested_result.on_success { |sr| return ServiceResult.success(result: storage_file_infos(sr.result)) } + requested_result.on_success { |sr| return ServiceResult.success(result: storage_file_info(sr.result)) } requested_result.on_failure do |sr| return sr unless sr.result == :not_found && auth_strategy.user.present? @@ -70,7 +70,7 @@ def admin_query(file_id) admin_result.on_success do |admin_query| return ServiceResult.success( - result: storage_file_infos(admin_query.result, status: "forbidden", status_code: 403) + result: storage_file_info(admin_query.result, status: "forbidden", status_code: 403) ) end end @@ -89,7 +89,7 @@ def validate_input(file_id) def userless_strategy = Registry.resolve("one_drive.authentication.userless").call - def storage_file_infos(json, status: "ok", status_code: 200) # rubocop:disable Metrics/AbcSize + def storage_file_info(json, status: "ok", status_code: 200) # rubocop:disable Metrics/AbcSize StorageFileInfo.new( status:, status_code:, diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_info_query.rb index a28c51027e21..b0bed614838d 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_info_query.rb @@ -47,7 +47,7 @@ def call(auth_strategy:, file_ids:) if file_ids.nil? return ServiceResult.failure( result: :error, - errors: ::Storages::StorageError.new(code: :error, log_message: "File IDs can not be nil") + errors: StorageError.new(code: :error, log_message: "File IDs can not be nil") ) end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb index 0ac1d5b6d0a2..7bf160af0717 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb @@ -47,7 +47,7 @@ def initialize(storage) end def call(auth_strategy:, folder:) - Auth[auth_strategy].call(storage: @storage) do |http| + Authentication[auth_strategy].call(storage: @storage) do |http| call = http.get(Util.join_uri_path(@uri, children_uri_path_for(folder) + FIELDS)) response = handle_response(call, :value) diff --git a/modules/storages/app/models/storages/storage_file_info.rb b/modules/storages/app/models/storages/storage_file_info.rb index 7020ee3a921b..22b514da8163 100644 --- a/modules/storages/app/models/storages/storage_file_info.rb +++ b/modules/storages/app/models/storages/storage_file_info.rb @@ -38,7 +38,6 @@ module Storages :size, :owner_name, :owner_id, - :trashed, :last_modified_by_name, :last_modified_by_id, :permissions, @@ -55,7 +54,6 @@ def initialize( size: nil, owner_name: nil, owner_id: nil, - trashed: nil, last_modified_by_name: nil, last_modified_by_id: nil, permissions: nil, diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb index 2b18b07af9ce..cf74a688219a 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb @@ -105,7 +105,6 @@ last_modified_by_name: "Eric Schubert", last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", permissions: nil, - trashed: false, location: "/Folder%20with%20spaces" }, { @@ -122,7 +121,6 @@ last_modified_by_name: "Eric Schubert", last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", permissions: nil, - trashed: false, location: "/Folder/Document.docx" }, { @@ -139,7 +137,6 @@ last_modified_by_name: "Eric Schubert", last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", permissions: nil, - trashed: false, location: "/Folder/Subfolder/NextcloudHub.md" } ]) diff --git a/modules/storages/spec/factories/storage_file_info_factory.rb b/modules/storages/spec/factories/storage_file_info_factory.rb index 78558f8de1f0..65176afb087f 100644 --- a/modules/storages/spec/factories/storage_file_info_factory.rb +++ b/modules/storages/spec/factories/storage_file_info_factory.rb @@ -38,7 +38,6 @@ sequence(:size) { |n| n * 123 } owner_name { "Peter Pan" } owner_id { "peter" } - trashed { false } last_modified_by_name { "Petra Panadera" } last_modified_by_id { "petra" } permissions { "RMGDNVCK" } @@ -46,7 +45,7 @@ initialize_with do new(status, status_code, id, name, last_modified_at, created_at, mime_type, size, owner_name, owner_id, - trashed, last_modified_by_name, last_modified_by_id, permissions, location) + last_modified_by_name, last_modified_by_id, permissions, location) end end end diff --git a/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb b/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb index 325d43367fb9..ec601f9c5703 100644 --- a/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb +++ b/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb @@ -177,7 +177,6 @@ size: 1108864, owner_name: "Darth Vader", owner_id: "darthvader", - trashed: false, last_modified_by_name: "Darth Sidious", last_modified_by_id: "palpatine", permissions: "RGDNVCK",