diff --git a/lib/api/errors/internal_error.rb b/lib/api/errors/internal_error.rb index 9cc5f6cd1ff..9ef1d84304b 100644 --- a/lib/api/errors/internal_error.rb +++ b/lib/api/errors/internal_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH @@ -33,10 +35,10 @@ module API code 500 def initialize(error_message = nil, exception: nil, **) - error = I18n.t("api_v3.errors.code_500") + error = error_message if error_message && visible_exception?(exception) - error += " #{error_message}" + error.prepend(I18n.t("api_v3.errors.code_500")) end super(error) @@ -47,6 +49,8 @@ module API ## # Hide internal database errors in production def visible_exception?(exception) + return false if exception.nil? + exception_blacklist.none? do |clz| exception.is_a?(clz) end diff --git a/modules/storages/app/common/storages/peripherals/nextcloud_registry.rb b/modules/storages/app/common/storages/peripherals/nextcloud_registry.rb index 93b35affbad..f378818170c 100644 --- a/modules/storages/app/common/storages/peripherals/nextcloud_registry.rb +++ b/modules/storages/app/common/storages/peripherals/nextcloud_registry.rb @@ -67,7 +67,7 @@ module Storages namespace("authentication") do register(:userless, StorageInteraction::AuthenticationStrategies::NextcloudStrategies::UserLess, call: false) - register(:userbound, StorageInteraction::AuthenticationStrategies::NextcloudStrategies::UserBound) + register(:user_bound, StorageInteraction::AuthenticationStrategies::NextcloudStrategies::UserBound) end end end diff --git a/modules/storages/app/common/storages/peripherals/one_drive_registry.rb b/modules/storages/app/common/storages/peripherals/one_drive_registry.rb index 7fde6ef68d4..fcc33aef1bd 100644 --- a/modules/storages/app/common/storages/peripherals/one_drive_registry.rb +++ b/modules/storages/app/common/storages/peripherals/one_drive_registry.rb @@ -61,7 +61,7 @@ module Storages namespace("authentication") do register(:userless, StorageInteraction::AuthenticationStrategies::OneDriveStrategies::UserLess, call: false) - register(:userbound, StorageInteraction::AuthenticationStrategies::OneDriveStrategies::UserBound) + register(:user_bound, StorageInteraction::AuthenticationStrategies::OneDriveStrategies::UserBound) end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_error_helper.rb b/modules/storages/app/common/storages/peripherals/storage_error_helper.rb index ae5d8788d88..aa3336c80f5 100644 --- a/modules/storages/app/common/storages/peripherals/storage_error_helper.rb +++ b/modules/storages/app/common/storages/peripherals/storage_error_helper.rb @@ -37,22 +37,22 @@ module Storages::Peripherals fail ::API::Errors::MultipleErrors.create_if_many(api_errors) end - # rubocop:disable Metrics/AbcSize def handle_base_errors(errors) base_errors = errors.symbols_for(:base) + message = errors.full_messages_for(:base)&.first + if base_errors.include? :not_found - fail API::Errors::OutboundRequestNotFound.new(errors.full_messages_for(:base).first) + fail API::Errors::OutboundRequestNotFound.new(message) elsif base_errors.include? :unauthorized - fail ::API::Errors::Unauthenticated.new(errors.full_messages_for(:base).first) + fail ::API::Errors::Unauthenticated.new(message) elsif base_errors.include? :forbidden - fail API::Errors::OutboundRequestForbidden.new(errors.full_messages_for(:base).first) + fail API::Errors::OutboundRequestForbidden.new(message) elsif base_errors.include? :error - fail API::Errors::InternalError.new(errors.full_messages) + fail API::Errors::InternalError.new(message) else base_errors end end - # rubocop:enable Metrics/AbcSize def raise_error(error) Rails.logger.error(error) diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/inputs/upload_data_contract.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/inputs/upload_data_contract.rb index 8fceaa7a084..6326ce94cbd 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/inputs/upload_data_contract.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/inputs/upload_data_contract.rb @@ -1,6 +1,31 @@ # frozen_string_literal: true #-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 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. #++ module Storages diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/upload_link_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/upload_link_query.rb index a64753fb3a8..db612317e9e 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/upload_link_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/upload_link_query.rb @@ -46,6 +46,7 @@ module Storages def call(auth_strategy:, upload_data:) with_tagged_logger do Authentication[auth_strategy].call(storage: @storage) do |http| + info "Requesting an upload link on folder #{upload_data.folder_id}" handle_response http.post(url(upload_data.folder_id, upload_data.file_name), json: payload(upload_data.file_name)) end @@ -67,6 +68,7 @@ module Storages case response in { status: 200..299 } upload_url = response.json(symbolize_keys: true)[:uploadUrl] + info "Upload link generated successfully." ServiceResult.success(result: UploadLink.new(URI(upload_url), :put)) in { status: 404 | 400 } # not existent parent folder in request url is responded with 400 info "The parent folder was not found." diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/types.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/types.rb deleted file mode 100644 index 1d7408901ea..00000000000 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/types.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -#++ - -module Storages - module Peripherals - module StorageInteraction - module Types - include Dry::Types() - - ParentFolderType = Constructor(ParentFolder, ParentFolder.method(:build)) - end - end - end -end diff --git a/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb b/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb index 830ce1d647f..a5fe0f728cf 100644 --- a/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb +++ b/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- copyright # OpenProject is an open source project management software. # Copyright (C) the OpenProject GmbH @@ -29,6 +31,8 @@ module Storages module Peripherals ParentFolder = Data.define(:path) do + delegate :split, :empty?, to: :path + def root? path == "/" end diff --git a/modules/storages/app/models/storages/storage.rb b/modules/storages/app/models/storages/storage.rb index 38d4a52e1a3..068a6b316c4 100644 --- a/modules/storages/app/models/storages/storage.rb +++ b/modules/storages/app/models/storages/storage.rb @@ -188,6 +188,10 @@ module Storages @short_provider_type ||= self.class.shorten_provider_type(provider_type) end + def to_s + short_provider_type + end + def provider_type_nextcloud? provider_type == ::Storages::Storage::PROVIDER_TYPE_NEXTCLOUD end diff --git a/modules/storages/app/services/storages/file_link_sync_service.rb b/modules/storages/app/services/storages/file_link_sync_service.rb index f644170fcf7..1b7982786e4 100644 --- a/modules/storages/app/services/storages/file_link_sync_service.rb +++ b/modules/storages/app/services/storages/file_link_sync_service.rb @@ -39,6 +39,8 @@ module Storages def call(file_links) with_tagged_logger do + info "Starting File Link remote synchronization" + resulting_file_links = file_links .group_by(&:storage_id) .map { |storage_id, storage_file_links| sync_storage_data(storage_id, storage_file_links) } @@ -49,17 +51,21 @@ module Storages ) end - ServiceResult.success(result: resulting_file_links) + @result.result = resulting_file_links + info "File Link Synchronization successful" + @result end end private def sync_storage_data(storage_id, file_links) - storage = ::Storages::Storage.find(storage_id) - ::Storages::Peripherals::Registry - .resolve("#{storage.short_provider_type}.queries.files_info") - .call(storage:, auth_strategy:, file_ids: file_links.map(&:origin_id)) + storage = Storage.find(storage_id) + + info "Retrieving file link information from #{storage.name}" + Peripherals::Registry + .resolve("#{storage}.queries.files_info") + .call(storage:, auth_strategy: strategy(storage), file_ids: file_links.map(&:origin_id)) .map { |file_infos| to_hash(file_infos) } .match( on_success: set_file_link_status(file_links), @@ -72,10 +78,8 @@ module Storages ) end - def auth_strategy - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken - .strategy - .with_user(@user) + def strategy(storage) + Peripherals::Registry.resolve("#{storage}.authentication.user_bound").call(user: @user) end def to_hash(file_infos) @@ -83,24 +87,24 @@ module Storages end def set_file_link_status(file_links) + info "Updating file link status..." lambda do |file_infos| resulting_file_links = [] file_links.each do |file_link| file_info = file_infos[file_link.origin_id] - case file_info.status_code - when 200 - update_file_link(file_link, file_info) - - file_link.origin_status = :view_allowed - when 403 - file_link.origin_status = :view_not_allowed - when 404 - file_link.origin_status = :not_found - else - file_link.origin_status = :error - end + file_link.origin_status = case file_info.status_code + when 200 + update_file_link(file_link, file_info) + :view_allowed + when 403 + :view_not_allowed + when 404 + :not_found + else + :error + end resulting_file_links << file_link file_link.save diff --git a/modules/storages/app/services/storages/upload_link_service.rb b/modules/storages/app/services/storages/upload_link_service.rb index fd0bff61f8c..95040b50f20 100644 --- a/modules/storages/app/services/storages/upload_link_service.rb +++ b/modules/storages/app/services/storages/upload_link_service.rb @@ -1,6 +1,31 @@ # frozen_string_literal: true #-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 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. #++ module Storages @@ -50,7 +75,7 @@ module Storages end def auth_strategy(user) - Peripherals::Registry.resolve("#{@storage.short_provider_type}.authentication.userbound").call(user:) + Peripherals::Registry.resolve("#{@storage.short_provider_type}.authentication.user_bound").call(user:) end end end diff --git a/modules/storages/config/locales/en.yml b/modules/storages/config/locales/en.yml index a78f6dca199..12e36098ad2 100644 --- a/modules/storages/config/locales/en.yml +++ b/modules/storages/config/locales/en.yml @@ -95,10 +95,9 @@ en: error: An unexpected error occurred. Please check OpenProject logs for more information or contact an administrator unauthorized: OpenProject could not authenticate with the Storage Provider. Please ensure that you have access to it. models: - upload_link_service: - not_found: The destination folder %{folder} could not be found on %{storage_name}. copy_project_folders_service: conflict: The folder %{destination_path} already exists. Interrupting process to avoid overwrites. + error: An unexpected error occurred. Please check OpenProject logs for more information or contact an administrator forbidden: OpenProject could not access the source folder. Please check your permissions configuration on the Storage Provider not_found: The source template location %{source_path} wasn't found. unauthorized: OpenProject could not authenticate with the Storage Provider. Please check your storage configuration @@ -151,6 +150,8 @@ en: not_allowed: OpenProject wasn't allowed to access your OneDrive drive. Please check the permissions set on the Azure Application. unauthorized: OpenProject could not sync with OneDrive. Please check you storage and Azure Application configuration. user_does_not_exist: "%{user} does not exist in Nextcloud." + upload_link_service: + not_found: The destination folder %{folder} could not be found on %{storage_name}. storages: buttons: complete_without_setup: Complete without it diff --git a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb index 44278291ebf..a687ab8e5d8 100644 --- a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb +++ b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb @@ -59,7 +59,7 @@ module API::V3::StorageFiles def auth_strategy Storages::Peripherals::Registry - .resolve("#{@storage.short_provider_type}.authentication.userbound") + .resolve("#{@storage.short_provider_type}.authentication.user_bound") .call(user: current_user) end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/inputs/upload_data_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/inputs/upload_data_spec.rb new file mode 100644 index 00000000000..d0953678aaa --- /dev/null +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/inputs/upload_data_spec.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 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::Inputs::UploadData do + subject(:input) { described_class } + + it "has .new as a private method" do + expect { input.new(nil, nil) }.to raise_error NoMethodError + end + + it "returns a Success(UploadData)" do + result = input.build(folder_id: "/Folder/Subfolder", file_name: "i_am_file_with_a_name.txt") + + expect(result).to be_success + upload_data = result.value! + expect(upload_data.folder_id).to eq(Storages::Peripherals::ParentFolder.new("/Folder/Subfolder")) + expect(upload_data.file_name).to eq("i_am_file_with_a_name.txt") + end + + context "when invalid" do + context "with a nil file name" do + let(:kwargs) { { folder_id: "/folder", file_name: nil } } + + it "returns a failure" do + result = input.build(**kwargs) + expect(result).to be_failure + end + + it "contains the specific error" do + validation_result = input.build(**kwargs).failure + expect(validation_result.errors[:file_name]).to eq(["must be filled"]) + end + end + + context "with a empty file name" do + let(:kwargs) { { folder_id: "/folder", file_name: "" } } + + it "returns a failure" do + result = input.build(**kwargs) + expect(result).to be_failure + end + + it "contains the specific error" do + validation_result = input.build(**kwargs).failure + expect(validation_result.errors[:file_name]).to eq(["must be filled"]) + end + end + + context "with an empty folder_id" do + let(:kwargs) { { folder_id: "", file_name: "file_name.txt" } } + + it "returns a failure" do + result = input.build(**kwargs) + expect(result).to be_failure + end + + it "contains the specific error" do + validation_result = input.build(**kwargs).failure + expect(validation_result.errors[:folder_id]).to eq(["must be filled"]) + end + end + + context "with a nil folder id" do + let(:kwargs) { { folder_id: nil, file_name: "file_name.txt" } } + + it "returns a failure" do + result = input.build(**kwargs) + expect(result).to be_failure + expect(result.failure.errors[:folder_id]).to eq(["must be filled"]) + end + end + end +end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command_spec.rb index 2696f57b710..41077cd988b 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command_spec.rb @@ -36,7 +36,7 @@ RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::RenameFileC let(:storage) do create(:nextcloud_storage_with_local_connection, :as_not_automatically_managed, oauth_client_token_user: user) end - let(:auth_strategy) { Storages::Peripherals::Registry.resolve("nextcloud.authentication.userbound").call(user:) } + let(:auth_strategy) { Storages::Peripherals::Registry.resolve("nextcloud.authentication.user_bound").call(user:) } it_behaves_like "rename_file_command: basic command setup" diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb index 9f57257b737..4556fdc9d97 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb @@ -42,11 +42,10 @@ RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::UploadLinkQ it_behaves_like "upload_link_query: basic query setup" - it_behaves_like "upload_link_query: validating input data" - context "when requesting an upload link for an existing file", vcr: "nextcloud/upload_link_success" do let(:upload_data) do - Storages::UploadData.new(folder_id: "169", file_name: "DeathStart_blueprints.tiff") + Storages::Peripherals::StorageInteraction::Inputs::UploadData + .build(folder_id: "169", file_name: "DeathStart_blueprints.tiff").value! end let(:token) { "SrQJeC5zM3B5Gw64d7dEQFQpFw8YBAtZWoxeLb59AR7PpGPyoGAkAko5G6ZiZ2HA" } let(:upload_url) { "https://nextcloud.local/index.php/apps/integration_openproject/direct-upload/#{token}" } @@ -57,7 +56,8 @@ RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::UploadLinkQ context "when requesting an upload link for a not existing file", vcr: "nextcloud/upload_link_not_found" do let(:upload_data) do - Storages::UploadData.new(folder_id: "1337", file_name: "DeathStart_blueprints.tiff") + Storages::Peripherals::StorageInteraction::Inputs::UploadData + .build(folder_id: "1337", file_name: "DeathStart_blueprints.tiff").value! end let(:error_source) { described_class } diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/copy_template_folder_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/copy_template_folder_command_spec.rb index 0ae7e2434be..10d74cdf3da 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/copy_template_folder_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/copy_template_folder_command_spec.rb @@ -145,7 +145,7 @@ RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::CopyTemplate subfolder = command.call(auth_strategy:, folder_name: "Subfolder with File", parent_location:).result file_name = "files_query_root.yml" - upload_data = Storages::UploadData.new(folder_id: subfolder.id, file_name:) + upload_data = Storages::Peripherals::StorageInteraction::Inputs::UploadData.build(folder_id: subfolder.id, file_name:).value! upload_link = Storages::Peripherals::Registry .resolve("one_drive.queries.upload_link") .call(storage:, auth_strategy:, upload_data:) 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 2b2e0fc9630..c7ab116c6df 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 @@ -36,7 +36,7 @@ RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::FileInfoQuer let(:storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user) } let(:auth_strategy) do - Storages::Peripherals::Registry["one_drive.authentication.userbound"].call(user:) + Storages::Peripherals::Registry["one_drive.authentication.user_bound"].call(user:) end it_behaves_like "file_info_query: basic query setup" diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/open_file_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/open_file_link_query_spec.rb index 42176408a10..c34f467162c 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/open_file_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/open_file_link_query_spec.rb @@ -38,7 +38,7 @@ RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::OpenFileLink let(:storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user) } let(:file_id) { "01AZJL5PJTICED3C5YSVAY6NWTBNA2XERU" } let(:auth_strategy) do - Storages::Peripherals::Registry.resolve("one_drive.authentication.userbound").call(user:) + Storages::Peripherals::Registry.resolve("one_drive.authentication.user_bound").call(user:) end subject { described_class.new(storage) } diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb index b4ff038617a..d1d0bfb597e 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb @@ -39,11 +39,10 @@ RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::UploadLinkQu it_behaves_like "upload_link_query: basic query setup" - it_behaves_like "upload_link_query: validating input data" - context "when requesting an upload link for an existing file", vcr: "one_drive/upload_link_success" do let(:upload_data) do - Storages::UploadData.new(folder_id: "01AZJL5PN6Y2GOVW7725BZO354PWSELRRZ", file_name: "DeathStart_blueprints.tiff") + Storages::Peripherals::StorageInteraction::Inputs::UploadData + .build(folder_id: "01AZJL5PN6Y2GOVW7725BZO354PWSELRRZ", file_name: "DeathStart_blueprints.tiff").value! end let(:token) do "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfZGlzcGxheW5hbWUiOiJPcGVuUHJvamVjdCBEZXYgQXBwIiwiYXVkIjoiMDAwMDA" \ @@ -69,7 +68,8 @@ RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::UploadLinkQu context "when requesting an upload link for a not existing file", vcr: "one_drive/upload_link_not_found" do let(:upload_data) do - Storages::UploadData.new(folder_id: "04AZJL5PN6Y2GOVW7725BZO354PWSELRRZ", file_name: "DeathStart_blueprints.tiff") + Storages::Peripherals::StorageInteraction::Inputs::UploadData + .build(folder_id: "04AZJL5PN6Y2GOVW7725BZO354PWSELRRZ", file_name: "DeathStart_blueprints.tiff").value! end let(:error_source) { described_class } 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 5998e090502..4f5d4265c11 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 @@ -291,7 +291,13 @@ RSpec.describe "API v3 storage files", :webmock, content_type: :json do describe "due to internal error" do let(:error) { :error } - it { expect(last_response).to have_http_status(:internal_server_error) } + it "fails with an internal error" do + expect(last_response).to have_http_status(:internal_server_error) + + body = MultiJson.load(last_response.body, symbolize_keys: true) + expect(body[:message]).to eq(I18n.t("services.errors.messages.error")) + expect(body[:errorIdentifier]).to eq("urn:openproject-org:api:v3:errors:InternalServerError") + end end describe "due to not found" do diff --git a/modules/storages/spec/services/storages/file_links/copy_file_links_service_spec.rb b/modules/storages/spec/services/storages/file_links/copy_file_links_service_spec.rb index afe18b5932a..3f8db170fbc 100644 --- a/modules/storages/spec/services/storages/file_links/copy_file_links_service_spec.rb +++ b/modules/storages/spec/services/storages/file_links/copy_file_links_service_spec.rb @@ -1,4 +1,29 @@ #-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 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" diff --git a/modules/storages/spec/support/shared_examples_for_adapters/upload_link_query_examples.rb b/modules/storages/spec/support/shared_examples_for_adapters/upload_link_query_examples.rb index 086d1c02d7d..6c527700ff9 100644 --- a/modules/storages/spec/support/shared_examples_for_adapters/upload_link_query_examples.rb +++ b/modules/storages/spec/support/shared_examples_for_adapters/upload_link_query_examples.rb @@ -81,36 +81,3 @@ RSpec.shared_examples_for "upload_link_query: error" do expect(error.data.source).to eq(error_source) end end - -RSpec.shared_examples_for "upload_link_query: validating input data" do - let(:upload_data) { Storages::UploadData.new(folder_id:, file_name:) } - let(:error_source) { described_class } - - context "if folder id being empty" do - let(:folder_id) { "" } - let(:file_name) { "DeathStart_blueprints.tiff" } - - it_behaves_like "upload_link_query: error" - end - - context "if folder id being nil" do - let(:folder_id) { nil } - let(:file_name) { "DeathStart_blueprints.tiff" } - - it_behaves_like "upload_link_query: error" - end - - context "if file name being empty" do - let(:folder_id) { "42" } - let(:file_name) { "" } - - it_behaves_like "upload_link_query: error" - end - - context "if file name being nil" do - let(:folder_id) { "42" } - let(:file_name) { nil } - - it_behaves_like "upload_link_query: error" - end -end