Skip to content

Commit

Permalink
[#57708] removed file ids query
Browse files Browse the repository at this point in the history
- https://community.openproject.org/work_packages/57708
- usages replaced with file_path_to_id_map_query
- enabled file path to id query to work on different depths
  • Loading branch information
Kharonus committed Sep 9, 2024
1 parent c1bddca commit a8731ce
Show file tree
Hide file tree
Showing 13 changed files with 448 additions and 236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ module Peripherals
register(:auth_check, StorageInteraction::Nextcloud::AuthCheckQuery)
register(:capabilities, StorageInteraction::Nextcloud::CapabilitiesQuery)
register(:download_link, StorageInteraction::Nextcloud::DownloadLinkQuery)
register(:file_ids, StorageInteraction::Nextcloud::FileIdsQuery)
register(:file_info, StorageInteraction::Nextcloud::FileInfoQuery)
register(:files_info, StorageInteraction::Nextcloud::FilesInfoQuery)
register(:files, StorageInteraction::Nextcloud::FilesQuery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ def initialize(storage)

def call(auth_strategy:, source_path:, destination_path:)
with_tagged_logger do
valid_input_result = validate_inputs(source_path, destination_path).on_failure { return _1 }
Authentication[auth_strategy].call(storage: @storage) do |http|
valid_input_result = validate_inputs(source_path, destination_path).on_failure { return _1 }

remote_urls = build_origin_urls(**valid_input_result.result)
remote_urls = build_origin_urls(**valid_input_result.result)

ensure_remote_folder_does_not_exist(auth_strategy, remote_urls[:destination_url]).on_failure { return _1 }
ensure_remote_folder_does_not_exist(http, remote_urls[:destination_url]).on_failure { return _1 }

copy_folder(auth_strategy, **remote_urls).on_failure { return _1 }
copy_folder(http, **remote_urls).on_failure { return _1 }

get_folder_id(valid_input_result.result[:destination_path])
get_folder_id(auth_strategy, valid_input_result.result[:destination_path])
end
end
end

Expand All @@ -76,9 +78,9 @@ def build_origin_urls(source_path:, destination_path:)
{ source_url:, destination_url: }
end

def ensure_remote_folder_does_not_exist(auth_strategy, destination_url)
def ensure_remote_folder_does_not_exist(http, destination_url)
info "Checking if #{destination_url} does not already exists."
response = Authentication[auth_strategy].call(storage: @storage) { |http| http.head(destination_url) }
response = http.head(destination_url)

case response
in { status: 200..299 }
Expand All @@ -98,13 +100,11 @@ def ensure_remote_folder_does_not_exist(auth_strategy, destination_url)
end
end

def copy_folder(auth_strategy, source_url:, destination_url:)
def copy_folder(http, source_url:, destination_url:)
info "Copying #{source_url} to #{destination_url}"
response = Authentication[auth_strategy].call(storage: @storage) do |http|
http.request("COPY", source_url, headers: { "Destination" => destination_url, "Depth" => "infinity" })
end

handle_response(response)
handle_response http.request("COPY",
source_url,
headers: { "Destination" => destination_url, "Depth" => "infinity" })
end

# rubocop:disable Metrics/AbcSize
Expand Down Expand Up @@ -133,14 +133,14 @@ def handle_response(response)
errors: Util.storage_error(response:, code: :error, source:))
end
end
# rubocop:enable Metrics/AbcSize

def get_folder_id(destination_path)
call = Registry
.resolve("#{@storage.short_provider_type}.queries.file_ids")
.call(storage: @storage, path: destination_path)
# rubocop:enable Metrics/AbcSize

call.map { |result| @data.with(id: result[destination_path]["fileid"]) }
def get_folder_id(auth_strategy, destination_path)
Registry
.resolve("nextcloud.queries.file_path_to_id_map")
.call(storage: @storage, auth_strategy:, folder: ParentFolder.new(destination_path), depth: 0)
.map { |result| @data.with(id: result[destination_path].id) }
end

def source = self.class
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,24 @@ module Peripherals
module StorageInteraction
module Nextcloud
class FilePathToIdMapQuery
def self.call(storage:, auth_strategy:, folder:)
new(storage).call(auth_strategy:, folder:)
def self.call(storage:, auth_strategy:, folder:, depth: Float::INFINITY)
new(storage).call(auth_strategy:, folder:, depth:)
end

def initialize(storage)
@storage = storage
@propfind_query = Internal::PropfindQuery.new(storage)
end

def call(auth_strategy:, folder:)
def call(auth_strategy:, folder:, depth:)
origin_user_id = Util.origin_user_id(caller: self.class, storage: @storage, auth_strategy:)
.on_failure do |result|
return result
end
.on_failure { return _1 }
.result

Authentication[auth_strategy].call(storage: @storage, http_options:) do |http|
Authentication[auth_strategy].call(storage: @storage, http_options: headers(depth)) do |http|
# nc:acl-list is only required to avoid https://community.openproject.org/wp/49628. See comment #4.
@propfind_query.call(http:,
username: origin_user_id.result,
username: origin_user_id,
path: folder.path,
props: %w[oc:fileid nc:acl-list])
.map do |obj|
Expand All @@ -62,8 +61,8 @@ def call(auth_strategy:, folder:)

private

def http_options
Util.webdav_request_with_depth("infinity")
def headers(depth)
Util.webdav_request_with_depth(depth.to_s.downcase)
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class FilePathToIdMapQuery
CHILDREN_FIELDS = %w[id name file folder parentReference].freeze
FOLDER_FIELDS = %w[id name parentReference].freeze

def self.call(storage:, auth_strategy:, folder:)
new(storage).call(auth_strategy:, folder:)
def self.call(storage:, auth_strategy:, folder:, depth: Float::INFINITY)
new(storage).call(auth_strategy:, folder:, depth:)
end

def initialize(storage)
Expand All @@ -46,15 +46,18 @@ def initialize(storage)
@drive_item_query = Internal::DriveItemQuery.new(storage)
end

def call(auth_strategy:, folder:)
# rubocop:disable Metrics/AbcSize
def call(auth_strategy:, folder:, depth:)
Authentication[auth_strategy].call(storage: @storage) do |http|
fetch_result = fetch_folder(http, folder)
return fetch_result if fetch_result.failure?
fetched_folder = fetch_folder(http, folder)
.on_failure { return _1 }
.result

file_ids_dictionary = fetch_result.result
file_ids_dictionary = fetched_folder
queue = [folder]
level = 0

while queue.any?
while queue.any? && level < depth
dir = queue.shift

visit = visit(http, dir)
Expand All @@ -63,12 +66,15 @@ def call(auth_strategy:, folder:)
entry, to_queue = visit.result.values_at(:entry, :to_queue)
file_ids_dictionary = file_ids_dictionary.merge(entry)
queue.concat(to_queue)
level += 1
end

ServiceResult.success(result: file_ids_dictionary)
end
end

# rubocop:enable Metrics/AbcSize

private

def visit(http, folder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,14 @@ class NextcloudManagedFolderSyncService < BaseService

FILE_PERMISSIONS = OpenProject::Storages::Engine.external_file_permissions

include Injector["nextcloud.commands.create_folder", "nextcloud.commands.rename_file", "nextcloud.commands.set_permissions",
"nextcloud.queries.group_users", "nextcloud.queries.file_ids", "nextcloud.authentication.userless",
"nextcloud.commands.add_user_to_group", "nextcloud.commands.remove_user_from_group"]
include Injector["nextcloud.commands.create_folder",
"nextcloud.commands.rename_file",
"nextcloud.commands.set_permissions",
"nextcloud.queries.group_users",
"nextcloud.queries.file_path_to_id_map",
"nextcloud.authentication.userless",
"nextcloud.commands.add_user_to_group",
"nextcloud.commands.remove_user_from_group"]

def self.i18n_key = "NextcloudSyncService"

Expand Down Expand Up @@ -283,7 +288,11 @@ def ensure_root_folder_permissions(root_folder_id)

def remote_root_folder_map(group_folder)
info "Retrieving already existing folders under #{group_folder}"
file_ids.call(storage: @storage, path: group_folder).on_failure do |service_result|
file_path_to_id_map.call(storage: @storage,
auth_strategy:,
folder: Peripherals::ParentFolder.new(group_folder),
depth: 1)
.on_failure do |service_result|
log_storage_error(service_result.errors, { folder: group_folder })
add_error(:remote_folders, service_result.errors, options: { group_folder:, username: @storage.username }).fail!
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,56 @@

it_behaves_like "file_path_to_id_map_query: basic query setup"

context "with parent folder being root", vcr: "nextcloud/file_path_to_id_map_query_root" do
context "with parent folder being root" do
let(:folder) { Storages::Peripherals::ParentFolder.new("/") }
let(:expected_ids) do
{
"/" => "2",
"/Folder with spaces" => "165",
"/Folder with spaces/New Requests" => "166",
"/Folder with spaces/New Requests/request_001.md" => "167",
"/Folder with spaces/New Requests/request_002.md" => "168",
"/Folder" => "169",
"/Folder/android-studio-2021.3.1.17-linux.tar.gz" => "267",
"/Folder/empty" => "172",
"/Folder/Ümlæûts" => "350",
"/Folder/Ümlæûts/Anrüchiges deutsches Dokument.docx" => "351",
"/Practical_guide_to_BAGGM_Digital.pdf" => "295",
"/Readme.md" => "268"
}

context "with unset depth (defaults to INFINITY)", vcr: "nextcloud/file_path_to_id_map_query_root_depth_infinite" do
let(:expected_ids) do
{
"/" => "2",
"/Folder with spaces" => "165",
"/Folder with spaces/New Requests" => "166",
"/Folder with spaces/New Requests/I❤️you death star.md" => "167",
"/Folder with spaces/New Requests/request_002.md" => "168",
"/Folder with spaces/Ümläuts & spe¢iæl characters" => "360",
"/Folder with spaces/Ümläuts & spe¢iæl characters/what_have_you_done.md" => "361",
"/My files" => "169",
"/My files/android-studio-linux.tar.gz" => "267",
"/My files/empty" => "172",
"/My files/Ümlæûts" => "350",
"/My files/Ümlæûts/Anrüchiges deutsches Dokument.docx" => "351",
"/Practical_guide_to_BAGGM_Digital.pdf" => "295",
"/Readme.md" => "268",
"/VCR" => "773",
"/VCR/placeholder" => "790"
}
end

it_behaves_like "file_path_to_id_map_query: successful query"
end

it_behaves_like "file_path_to_id_map_query: successful query"
context "with depth 0", vcr: "nextcloud/file_path_to_id_map_query_root_depth_0" do
let(:depth) { 0 }
let(:expected_ids) { { "/" => "2" } }

it_behaves_like "file_path_to_id_map_query: successful query"
end

context "with depth 1", vcr: "nextcloud/file_path_to_id_map_query_root_depth_1" do
let(:depth) { 1 }
let(:expected_ids) do
{
"/" => "2",
"/Folder with spaces" => "165",
"/My files" => "169",
"/Practical_guide_to_BAGGM_Digital.pdf" => "295",
"/Readme.md" => "268",
"/VCR" => "773"
}
end

it_behaves_like "file_path_to_id_map_query: successful query"
end
end

context "with a given parent folder", vcr: "nextcloud/file_path_to_id_map_query_parent_folder" do
Expand Down
Loading

0 comments on commit a8731ce

Please sign in to comment.