Skip to content

Commit

Permalink
[#49124] Implement open links for storages, file links
Browse files Browse the repository at this point in the history
- https://community.openproject.org/wp/49124
- added open_link method to project storages and storages
- extracted open_link for file links to storage queries
- polished code that shows elements with open link
  - storage menu items
  - file link list
- added fallback icon matching for storages without an own icon
  • Loading branch information
Kharonus committed Sep 20, 2023
1 parent eb29e55 commit 90e3462
Show file tree
Hide file tree
Showing 20 changed files with 327 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,5 @@ export const fileIconMappings:Record<string, IFileIcon> = {
export const storageIconMappings:Record<string, string> = {
[nextcloud]: 'nextcloud-circle',

default: 'ticket',
default: 'hosting',
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
>
<div class=op-tab-content--header>
<span
class="op-tab-content--header-icon spot-icon spot-icon_nextcloud-circle op-files-tab--icon op-files-tab--icon_primary"
class="op-tab-content--header-icon spot-icon spot-icon_{{icon.storageHeader((storage | async)?._links.type.href)}} op-files-tab--icon op-files-tab--icon_primary"
></span>
<span class="op-tab-content--header-text" [textContent]="(storage | async)?.name"></span>
<a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ import {
StorageInformationService,
} from 'core-app/shared/components/storages/storage-information/storage-information.service';
import { storageLocaleString } from 'core-app/shared/components/storages/functions/storages.functions';
import { storageIconMappings } from 'core-app/shared/components/storages/icons.mapping';

@Component({
selector: 'op-storage',
Expand Down Expand Up @@ -131,6 +132,10 @@ export class StorageComponent extends UntilDestroyedMixin implements OnInit, OnD

dragging = 0;

icon = {
storageHeader: (storageType:string) => storageIconMappings[storageType] || storageIconMappings.default,
};

text = {
actions: {
linkExisting: this.i18n.t('js.storages.link_existing_files'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module Nextcloud
register(:propfind, Internal::PropfindQuery)
register(:group_users, GroupUsersQuery)
register(:upload_link, UploadLinkQuery)
register(:open_link, OpenLinkQuery)
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
Expand Down Expand Up @@ -26,19 +28,28 @@
# See COPYRIGHT and LICENSE files for more details.
#++

module Storages::Peripherals
# Helper for open links for a file link object.
module StorageUrlHelper
module_function
module Storages
module Peripherals
module StorageInteraction
module Nextcloud
class OpenLinkQuery
def initialize(storage)
@uri = storage.uri
end

def storage_url_open_file(storage, file_id, open_location: false)
location_flag = ActiveModel::Type::Boolean.new.cast(open_location) ? 0 : 1
def self.call(storage:, user:, file_id:, open_location: false)
new(storage).call(user:, file_id:, open_location:)
end

"#{storage.host}/index.php/f/#{file_id}?openfile=#{location_flag}"
end
# rubocop:disable Lint/UnusedMethodArgument
def call(user:, file_id:, open_location: false)
location_flag = open_location ? 0 : 1
ServiceResult.success(result: "#{@uri}/index.php/f/#{file_id}?openfile=#{location_flag}")
end

def storage_url_open(storage)
"#{storage.host}/index.php/apps/files"
# rubocop:enable Lint/UnusedMethodArgument
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ module OneDrive
register(:files, FilesQuery)
register(:file_info, FileInfoQuery)
register(:files_info, FilesInfoQuery)
register(:open_link, OpenLinkQuery)
register(:open_drive_link, OpenDriveLinkQuery)
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,58 +33,22 @@ module Peripherals
module StorageInteraction
module OneDrive
class FileInfoQuery
using ServiceResultRefinements
FIELDS = %w[id name fileSystemInfo file size createdBy lastModifiedBy parentReference].freeze

def self.call(storage:, user:, file_id:)
new(storage).call(user:, file_id:)
end

def initialize(storage)
@storage = storage
@uri = storage.uri
@delegate = Internal::DriveItemQuery.new(storage)
end

def call(user:, file_id:)
Util.using_user_token(@storage, user) do |token|
make_file_request(file_id, token).map(&storage_file_infos)
end
@delegate.call(user:, drive_item_id: file_id, fields: FIELDS).map(&storage_file_infos)
end

private

def make_file_request(file_id, token)
response_data = Net::HTTP.start(@uri.host, @uri.port, use_ssl: true) do |http|
http.get(uri_path_for(file_id), { 'Authorization' => "Bearer #{token.access_token}" })
end

handle_responses(response_data)
end

def handle_responses(response)
json = MultiJson.load(response.body, symbolize_keys: true)

case response
when Net::HTTPSuccess
ServiceResult.success(result: json)
when Net::HTTPNotFound
ServiceResult.failure(result: :not_found,
errors: ::Storages::StorageError.new(code: :not_found, data: json))
when Net::HTTPForbidden
ServiceResult.failure(result: :forbidden,
errors: ::Storages::StorageError.new(code: :forbidden, data: json))
when Net::HTTPUnauthorized
ServiceResult.failure(result: :unauthorized,
errors: ::Storages::StorageError.new(code: :unauthorized, data: json))
else
ServiceResult.failure(result: :error,
errors: ::Storages::StorageError.new(code: :error, data: json))
end
end

def uri_path_for(file_id)
"/v1.0/drives/#{@storage.drive_id}/items/#{file_id}"
end

def storage_file_infos
->(json) do
StorageFileInfo.new(
Expand All @@ -106,10 +70,6 @@ def storage_file_infos
)
end
end

def parse_json(str)
MultiJson.load(str, symbolize_keys: true)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

module Storages
module Peripherals
module StorageInteraction
module OneDrive
module Internal
class DriveItemQuery
UTIL = ::Storages::Peripherals::StorageInteraction::OneDrive::Util

def self.call(storage:, user:, drive_item_id:, fields: [])
new(storage).call(user:, drive_item_id:, fields:)
end

def initialize(storage)
@storage = storage
@uri = storage.uri
end

def call(user:, drive_item_id:, fields: [])
select_url_query = if fields.empty?
''
else
"?$select=#{fields.join(',')}"
end

UTIL.using_user_token(@storage, user) do |token|
make_file_request(drive_item_id, token, select_url_query)
end
end

private

def make_file_request(drive_item_id, token, select_url_query)
response_data = Net::HTTP.start(@uri.host, @uri.port, use_ssl: true) do |http|
http.get(uri_path_for(drive_item_id) + select_url_query, { 'Authorization' => "Bearer #{token.access_token}" })
end

handle_responses(response_data)
end

def handle_responses(response)
json = MultiJson.load(response.body, symbolize_keys: true)

case response
when Net::HTTPSuccess
ServiceResult.success(result: json)
when Net::HTTPNotFound
ServiceResult.failure(result: :not_found,
errors: ::Storages::StorageError.new(code: :not_found, data: json))
when Net::HTTPForbidden
ServiceResult.failure(result: :forbidden,
errors: ::Storages::StorageError.new(code: :forbidden, data: json))
when Net::HTTPUnauthorized
ServiceResult.failure(result: :unauthorized,
errors: ::Storages::StorageError.new(code: :unauthorized, data: json))
else
ServiceResult.failure(result: :error,
errors: ::Storages::StorageError.new(code: :error, data: json))
end
end

def uri_path_for(file_id)
"/v1.0/drives/#{@storage.drive_id}/items/#{file_id}"
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 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
module Peripherals
module StorageInteraction
module OneDrive
class OpenDriveLinkQuery
def self.call(storage:, user:)
new(storage).call(user:)
end

def initialize(storage)
@storage = storage
@uri = storage.uri
end

def call(user:)
Util.using_user_token(@storage, user) do |token|
make_request(token).map(&web_url)
end
end

private

def make_request(token)
response_data = Net::HTTP.start(@uri.host, @uri.port, use_ssl: true) do |http|
http.get(drive_uri_path, { 'Authorization' => "Bearer #{token.access_token}" })
end

handle_responses(response_data)
end

def handle_responses(response)
json = MultiJson.load(response.body, symbolize_keys: true)

case response
when Net::HTTPSuccess
ServiceResult.success(result: json)
when Net::HTTPNotFound
ServiceResult.failure(result: :not_found,
errors: ::Storages::StorageError.new(code: :not_found, data: json))
when Net::HTTPForbidden
ServiceResult.failure(result: :forbidden,
errors: ::Storages::StorageError.new(code: :forbidden, data: json))
when Net::HTTPUnauthorized
ServiceResult.failure(result: :unauthorized,
errors: ::Storages::StorageError.new(code: :unauthorized, data: json))
else
ServiceResult.failure(result: :error,
errors: ::Storages::StorageError.new(code: :error, data: json))
end
end

def drive_uri_path
"/v1.0/drives/#{@storage.drive_id}?$select=webUrl"
end

def web_url
->(json) do
json[:webUrl]
end
end
end
end
end
end
end
Loading

0 comments on commit 90e3462

Please sign in to comment.