Skip to content

Commit 926273e

Browse files
authored
Merge pull request #20543 from opf/implementation/66698-sharepoint-copy-template-folder-command
[#66698] Sharepoint Copy Template Folder Command
2 parents 57e87aa + cf8ea45 commit 926273e

File tree

6 files changed

+547
-0
lines changed

6 files changed

+547
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module Storages
32+
module Adapters
33+
module Providers
34+
module Sharepoint
35+
module Commands
36+
class CopyTemplateFolderCommand < Base
37+
def initialize(storage)
38+
super
39+
@data = Results::CopyTemplateFolder.new(id: nil, polling_url: nil, requires_polling: true)
40+
end
41+
42+
def call(auth_strategy:, input_data:)
43+
with_tagged_logger do
44+
info "Requesting Copy of folder #{input_data.source} to #{input_data.destination}"
45+
Authentication[auth_strategy].call(storage: @storage) do |httpx|
46+
split_identifier(input_data.source) => { drive_id: source_drive_id, location: source_item_id }
47+
handle_response(
48+
httpx.post(
49+
UrlBuilder.url(base_uri,
50+
"/v1.0/drives",
51+
source_drive_id,
52+
"/items",
53+
source_item_id,
54+
"/copy") + query,
55+
json: {
56+
name: input_data.destination
57+
}
58+
)
59+
)
60+
end
61+
end
62+
end
63+
64+
private
65+
66+
def handle_response(response)
67+
error = Results::Error.new(source: self.class, payload: response)
68+
69+
case response
70+
in { status: 202 }
71+
Success(@data.with(polling_url: response.headers[:location]))
72+
in { status: 401 }
73+
Failure(error.with(code: :unauthorized))
74+
in { status: 403 }
75+
Failure(error.with(code: :forbidden))
76+
in { status: 404 }
77+
Failure(error.with(code: :not_found))
78+
in { status: 409 }
79+
Failure(error.with(code: :conflict))
80+
else
81+
Failure(error.with(code: :error))
82+
end
83+
end
84+
85+
def query = "[email protected]=fail"
86+
end
87+
end
88+
end
89+
end
90+
end
91+
end

modules/storages/app/common/storages/adapters/providers/sharepoint/sharepoint_registry.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module Sharepoint
4444
register(:rename_file, Commands::RenameFileCommand)
4545
register(:create_list, Commands::CreateListCommand)
4646
register(:set_permissions, Commands::SetPermissionsCommand)
47+
register(:copy_template_folder, Commands::CopyTemplateFolderCommand)
4748
end
4849

4950
namespace("components") do
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
require "spec_helper"
32+
require_module_spec_helper
33+
34+
module Storages
35+
module Adapters
36+
module Providers
37+
module Sharepoint
38+
module Commands
39+
RSpec.describe CopyTemplateFolderCommand, :webmock do
40+
shared_let(:storage) { create(:sharepoint_storage, :sandbox) }
41+
shared_let(:base_drive) { "b!FeOZEMfQx0eGQKqVBLcP__BG8mq-4-9FuRqOyk3MXY9jo6leJDqrT7muzvmiWjFW" }
42+
43+
let(:input_data) { Input::CopyTemplateFolder.build(source:, destination:).value! }
44+
let(:auth_strategy) { Registry["sharepoint.authentication.userless"].call }
45+
46+
it "is registered under commands.sharepoint.copy_template_folder" do
47+
expect(Registry.resolve("sharepoint.commands.copy_template_folder")).to eq(described_class)
48+
end
49+
50+
it "responds to .call" do
51+
expect(described_class).to respond_to(:call)
52+
end
53+
54+
describe "#call" do
55+
let(:source) { "#{base_drive}:01ANJ53W2LHDLFFGQN4RHJRV6HAK2CFDCT" }
56+
let(:destination) { "My New Folder" }
57+
58+
it "copies origin folder and all underlying files and folders to the destination_path",
59+
vcr: "sharepoint/copy_template_folder_copy_successful" do
60+
command_result = described_class.call(auth_strategy:, storage:, input_data:)
61+
62+
expect(command_result).to be_success
63+
data = command_result.value!
64+
65+
expect(data).to be_requires_polling
66+
expect(data.polling_url).to match %r</drives/#{base_drive}/items/.+\?.+$>
67+
end
68+
69+
describe "error handling" do
70+
context "when the source_path does not exist" do
71+
let(:source) { "#{base_drive}:TheCakeIsALie" }
72+
let(:destination) { "Not Happening" }
73+
74+
it "fails", vcr: "sharepoint/copy_template_source_not_found" do
75+
result = described_class.call(auth_strategy:, storage:, input_data:)
76+
77+
expect(result).to be_failure
78+
expect(result.failure.code).to eq(:not_found)
79+
end
80+
end
81+
82+
context "when it would overwrite an already existing folder" do
83+
let(:destination) { "My New Folder" }
84+
85+
it "fails", vcr: "sharepoint/copy_template_folder_no_overwrite" do
86+
result = described_class.call(auth_strategy:, storage:, input_data:)
87+
88+
expect(result).to be_failure
89+
expect(result.failure.code).to eq(:error)
90+
end
91+
end
92+
end
93+
end
94+
end
95+
end
96+
end
97+
end
98+
end
99+
end

modules/storages/spec/support/fixtures/vcr_cassettes/sharepoint/copy_template_folder_copy_successful.yml

Lines changed: 117 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)